Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pret
GitHub Repository: pret/pokered
Path: blob/master/engine/battle/core.asm
1271 views
1
BattleCore:
2
3
INCLUDE "data/battle/residual_effects_1.asm"
4
INCLUDE "data/battle/set_damage_effects.asm"
5
INCLUDE "data/battle/residual_effects_2.asm"
6
INCLUDE "data/battle/always_happen_effects.asm"
7
INCLUDE "data/battle/special_effects.asm"
8
9
SlidePlayerAndEnemySilhouettesOnScreen:
10
call LoadPlayerBackPic
11
ld a, MESSAGE_BOX ; the usual text box at the bottom of the screen
12
ld [wTextBoxID], a
13
call DisplayTextBoxID
14
hlcoord 1, 5
15
lb bc, 3, 7
16
call ClearScreenArea
17
call DisableLCD
18
call LoadFontTilePatterns
19
call LoadHudAndHpBarAndStatusTilePatterns
20
ld hl, vBGMap0
21
ld bc, TILEMAP_AREA
22
.clearBackgroundLoop
23
ld a, " "
24
ld [hli], a
25
dec bc
26
ld a, b
27
or c
28
jr nz, .clearBackgroundLoop
29
; copy the work RAM tile map to VRAM
30
hlcoord 0, 0
31
ld de, vBGMap0
32
ld b, SCREEN_HEIGHT
33
.copyRowLoop
34
ld c, SCREEN_WIDTH
35
.copyColumnLoop
36
ld a, [hli]
37
ld [de], a
38
inc e
39
dec c
40
jr nz, .copyColumnLoop
41
ld a, 12 ; number of off screen tiles to the right of screen in VRAM
42
add e ; skip the off screen tiles
43
ld e, a
44
jr nc, .noCarry
45
inc d
46
.noCarry
47
dec b
48
jr nz, .copyRowLoop
49
call EnableLCD
50
ld a, $90
51
ldh [hWY], a
52
ldh [rWY], a
53
xor a
54
ldh [hTileAnimations], a
55
ldh [hSCY], a
56
dec a
57
ld [wUpdateSpritesEnabled], a
58
call Delay3
59
xor a
60
ldh [hAutoBGTransferEnabled], a
61
ld b, $70
62
ld c, $90
63
ld a, c
64
ldh [hSCX], a
65
call DelayFrame
66
ld a, %11100100 ; inverted palette for silhouette effect
67
ldh [rBGP], a
68
ldh [rOBP0], a
69
ldh [rOBP1], a
70
.slideSilhouettesLoop ; slide silhouettes of the player's pic and the enemy's pic onto the screen
71
ld h, b
72
ld l, $40
73
call SetScrollXForSlidingPlayerBodyLeft ; begin background scrolling on line $40
74
inc b
75
inc b
76
ld h, $0
77
ld l, $60
78
call SetScrollXForSlidingPlayerBodyLeft ; end background scrolling on line $60
79
call SlidePlayerHeadLeft
80
ld a, c
81
ldh [hSCX], a
82
dec c
83
dec c
84
jr nz, .slideSilhouettesLoop
85
ld a, $1
86
ldh [hAutoBGTransferEnabled], a
87
ld a, $31
88
ldh [hStartTileID], a
89
hlcoord 1, 5
90
predef CopyUncompressedPicToTilemap
91
xor a
92
ldh [hWY], a
93
ldh [rWY], a
94
inc a
95
ldh [hAutoBGTransferEnabled], a
96
call Delay3
97
ld b, SET_PAL_BATTLE
98
call RunPaletteCommand
99
call HideSprites
100
jpfar PrintBeginningBattleText
101
102
; when a battle is starting, silhouettes of the player's pic and the enemy's pic are slid onto the screen
103
; the lower of the player's pic (his body) is part of the background, but his head is a sprite
104
; the reason for this is that it shares Y coordinates with the lower part of the enemy pic, so background scrolling wouldn't work for both pics
105
; instead, the enemy pic is part of the background and uses the scroll register, while the player's head is a sprite and is slid by changing its X coordinates in a loop
106
SlidePlayerHeadLeft:
107
push bc
108
ld hl, wShadowOAMSprite00XCoord
109
ld c, $15 ; number of OAM entries
110
ld de, $4 ; size of OAM entry
111
.loop
112
dec [hl] ; decrement X
113
dec [hl] ; decrement X
114
add hl, de ; next OAM entry
115
dec c
116
jr nz, .loop
117
pop bc
118
ret
119
120
SetScrollXForSlidingPlayerBodyLeft:
121
ldh a, [rLY]
122
cp l
123
jr nz, SetScrollXForSlidingPlayerBodyLeft
124
ld a, h
125
ldh [rSCX], a
126
.loop
127
ldh a, [rLY]
128
cp h
129
jr z, .loop
130
ret
131
132
StartBattle:
133
xor a
134
ld [wPartyGainExpFlags], a
135
ld [wPartyFoughtCurrentEnemyFlags], a
136
ld [wActionResultOrTookBattleTurn], a
137
inc a
138
ld [wFirstMonsNotOutYet], a
139
ld hl, wEnemyMon1HP
140
ld bc, wEnemyMon2 - wEnemyMon1 - 1
141
ld d, $3
142
.findFirstAliveEnemyMonLoop
143
inc d
144
ld a, [hli]
145
or [hl]
146
jr nz, .foundFirstAliveEnemyMon
147
add hl, bc
148
jr .findFirstAliveEnemyMonLoop
149
.foundFirstAliveEnemyMon
150
ld a, d
151
ld [wSerialExchangeNybbleReceiveData], a
152
ld a, [wIsInBattle]
153
dec a ; is it a trainer battle?
154
call nz, EnemySendOutFirstMon ; if it is a trainer battle, send out enemy mon
155
ld c, 40
156
call DelayFrames
157
call SaveScreenTilesToBuffer1
158
.checkAnyPartyAlive
159
call AnyPartyAlive
160
ld a, d
161
and a
162
jp z, HandlePlayerBlackOut ; jump if no mon is alive
163
call LoadScreenTilesFromBuffer1
164
ld a, [wBattleType]
165
and a ; is it a normal battle?
166
jp z, .playerSendOutFirstMon ; if so, send out player mon
167
; safari zone battle
168
.displaySafariZoneBattleMenu
169
call DisplayBattleMenu
170
ret c ; return if the player ran from battle
171
ld a, [wActionResultOrTookBattleTurn]
172
and a ; was the item used successfully?
173
jr z, .displaySafariZoneBattleMenu ; if not, display the menu again; XXX does this ever jump?
174
ld a, [wNumSafariBalls]
175
and a
176
jr nz, .notOutOfSafariBalls
177
call LoadScreenTilesFromBuffer1
178
ld hl, .outOfSafariBallsText
179
jp PrintText
180
.notOutOfSafariBalls
181
callfar PrintSafariZoneBattleText
182
ld a, [wEnemyMonSpeed + 1]
183
add a
184
ld b, a ; init b (which is later compared with random value) to (enemy speed % 256) * 2
185
jp c, EnemyRan ; if (enemy speed % 256) > 127, the enemy runs
186
ld a, [wSafariBaitFactor]
187
and a ; is bait factor 0?
188
jr z, .checkEscapeFactor
189
; bait factor is not 0
190
; divide b by 4 (making the mon less likely to run)
191
srl b
192
srl b
193
.checkEscapeFactor
194
ld a, [wSafariEscapeFactor]
195
and a ; is escape factor 0?
196
jr z, .compareWithRandomValue
197
; escape factor is not 0
198
; multiply b by 2 (making the mon more likely to run)
199
sla b
200
jr nc, .compareWithRandomValue
201
; cap b at 255
202
ld b, $ff
203
.compareWithRandomValue
204
call Random
205
cp b
206
jr nc, .checkAnyPartyAlive
207
jr EnemyRan ; if b was greater than the random value, the enemy runs
208
209
.outOfSafariBallsText
210
text_far _OutOfSafariBallsText
211
text_end
212
213
.playerSendOutFirstMon
214
xor a
215
ld [wWhichPokemon], a
216
.findFirstAliveMonLoop
217
call HasMonFainted
218
jr nz, .foundFirstAliveMon
219
; fainted, go to the next one
220
ld hl, wWhichPokemon
221
inc [hl]
222
jr .findFirstAliveMonLoop
223
.foundFirstAliveMon
224
ld a, [wWhichPokemon]
225
ld [wPlayerMonNumber], a
226
inc a
227
ld hl, wPartySpecies - 1
228
ld c, a
229
ld b, 0
230
add hl, bc
231
ld a, [hl] ; species
232
ld [wCurPartySpecies], a
233
ld [wBattleMonSpecies2], a
234
call LoadScreenTilesFromBuffer1
235
hlcoord 1, 5
236
ld a, $9
237
call SlideTrainerPicOffScreen
238
call SaveScreenTilesToBuffer1
239
ld a, [wWhichPokemon]
240
ld c, a
241
ld b, FLAG_SET
242
push bc
243
ld hl, wPartyGainExpFlags
244
predef FlagActionPredef
245
ld hl, wPartyFoughtCurrentEnemyFlags
246
pop bc
247
predef FlagActionPredef
248
call LoadBattleMonFromParty
249
call LoadScreenTilesFromBuffer1
250
call SendOutMon
251
jr MainInBattleLoop
252
253
; wild mon or link battle enemy ran from battle
254
EnemyRan:
255
call LoadScreenTilesFromBuffer1
256
ld a, [wLinkState]
257
cp LINK_STATE_BATTLING
258
ld hl, WildRanText
259
jr nz, .printText
260
; link battle
261
xor a
262
ld [wBattleResult], a
263
ld hl, EnemyRanText
264
.printText
265
call PrintText
266
ld a, SFX_RUN
267
call PlaySoundWaitForCurrent
268
xor a
269
ldh [hWhoseTurn], a
270
jpfar AnimationSlideEnemyMonOff
271
272
WildRanText:
273
text_far _WildRanText
274
text_end
275
276
EnemyRanText:
277
text_far _EnemyRanText
278
text_end
279
280
MainInBattleLoop:
281
call ReadPlayerMonCurHPAndStatus
282
ld hl, wBattleMonHP
283
ld a, [hli]
284
or [hl] ; is battle mon HP 0?
285
jp z, HandlePlayerMonFainted ; if battle mon HP is 0, jump
286
ld hl, wEnemyMonHP
287
ld a, [hli]
288
or [hl] ; is enemy mon HP 0?
289
jp z, HandleEnemyMonFainted ; if enemy mon HP is 0, jump
290
call SaveScreenTilesToBuffer1
291
xor a
292
ld [wFirstMonsNotOutYet], a
293
ld a, [wPlayerBattleStatus2]
294
and (1 << NEEDS_TO_RECHARGE) | (1 << USING_RAGE) ; check if the player is using Rage or needs to recharge
295
jr nz, .selectEnemyMove
296
; the player is not using Rage and doesn't need to recharge
297
ld hl, wEnemyBattleStatus1
298
res FLINCHED, [hl] ; reset flinch bit
299
ld hl, wPlayerBattleStatus1
300
res FLINCHED, [hl] ; reset flinch bit
301
ld a, [hl]
302
and (1 << THRASHING_ABOUT) | (1 << CHARGING_UP) ; check if the player is thrashing about or charging for an attack
303
jr nz, .selectEnemyMove ; if so, jump
304
; the player is neither thrashing about nor charging for an attack
305
call DisplayBattleMenu ; show battle menu
306
ret c ; return if player ran from battle
307
ld a, [wEscapedFromBattle]
308
and a
309
ret nz ; return if pokedoll was used to escape from battle
310
ld a, [wBattleMonStatus]
311
and (1 << FRZ) | SLP_MASK
312
jr nz, .selectEnemyMove ; if so, jump
313
ld a, [wPlayerBattleStatus1]
314
and (1 << STORING_ENERGY) | (1 << USING_TRAPPING_MOVE) ; check player is using Bide or using a multi-turn attack like wrap
315
jr nz, .selectEnemyMove ; if so, jump
316
ld a, [wEnemyBattleStatus1]
317
bit USING_TRAPPING_MOVE, a ; check if enemy is using a multi-turn attack like wrap
318
jr z, .selectPlayerMove ; if not, jump
319
; enemy is using a multi-turn attack like wrap, so player is trapped and cannot execute a move
320
ld a, CANNOT_MOVE
321
ld [wPlayerSelectedMove], a
322
jr .selectEnemyMove
323
.selectPlayerMove
324
ld a, [wActionResultOrTookBattleTurn]
325
and a ; has the player already used the turn (e.g. by using an item, trying to run or switching pokemon)
326
jr nz, .selectEnemyMove
327
ld [wMoveMenuType], a
328
inc a
329
ld [wAnimationID], a
330
xor a
331
ld [wMenuItemToSwap], a
332
call MoveSelectionMenu
333
push af
334
call LoadScreenTilesFromBuffer1
335
call DrawHUDsAndHPBars
336
pop af
337
jr nz, MainInBattleLoop ; if the player didn't select a move, jump
338
.selectEnemyMove
339
call SelectEnemyMove
340
ld a, [wLinkState]
341
cp LINK_STATE_BATTLING
342
jr nz, .noLinkBattle
343
; link battle
344
ld a, [wSerialExchangeNybbleReceiveData]
345
cp LINKBATTLE_RUN
346
jp z, EnemyRan
347
cp LINKBATTLE_STRUGGLE
348
jr z, .noLinkBattle
349
cp LINKBATTLE_NO_ACTION
350
jr z, .noLinkBattle
351
sub 4
352
jr c, .noLinkBattle
353
; the link battle enemy has switched mons
354
ld a, [wPlayerBattleStatus1]
355
bit USING_TRAPPING_MOVE, a ; check if using multi-turn move like Wrap
356
jr z, .specialMoveNotUsed
357
ld a, [wPlayerMoveListIndex]
358
ld hl, wBattleMonMoves
359
ld c, a
360
ld b, 0
361
add hl, bc
362
ld a, [hl]
363
cp METRONOME ; a MIRROR MOVE check is missing, might lead to a desync in link battles
364
; when combined with multi-turn moves
365
jr nz, .specialMoveNotUsed
366
ld [wPlayerSelectedMove], a
367
.specialMoveNotUsed
368
callfar SwitchEnemyMon
369
.noLinkBattle
370
ld a, [wPlayerSelectedMove]
371
cp QUICK_ATTACK
372
jr nz, .playerDidNotUseQuickAttack
373
ld a, [wEnemySelectedMove]
374
cp QUICK_ATTACK
375
jr z, .compareSpeed ; if both used Quick Attack
376
jp .playerMovesFirst ; if player used Quick Attack and enemy didn't
377
.playerDidNotUseQuickAttack
378
ld a, [wEnemySelectedMove]
379
cp QUICK_ATTACK
380
jr z, .enemyMovesFirst ; if enemy used Quick Attack and player didn't
381
ld a, [wPlayerSelectedMove]
382
cp COUNTER
383
jr nz, .playerDidNotUseCounter
384
ld a, [wEnemySelectedMove]
385
cp COUNTER
386
jr z, .compareSpeed ; if both used Counter
387
jr .enemyMovesFirst ; if player used Counter and enemy didn't
388
.playerDidNotUseCounter
389
ld a, [wEnemySelectedMove]
390
cp COUNTER
391
jr z, .playerMovesFirst ; if enemy used Counter and player didn't
392
.compareSpeed
393
ld de, wBattleMonSpeed ; player speed value
394
ld hl, wEnemyMonSpeed ; enemy speed value
395
ld c, $2
396
call StringCmp ; compare speed values
397
jr z, .speedEqual
398
jr nc, .playerMovesFirst ; if player is faster
399
jr .enemyMovesFirst ; if enemy is faster
400
.speedEqual ; 50/50 chance for both players
401
ldh a, [hSerialConnectionStatus]
402
cp USING_INTERNAL_CLOCK
403
jr z, .invertOutcome
404
call BattleRandom
405
cp 50 percent + 1
406
jr c, .playerMovesFirst
407
jr .enemyMovesFirst
408
.invertOutcome
409
call BattleRandom
410
cp 50 percent + 1
411
jr c, .enemyMovesFirst
412
jr .playerMovesFirst
413
.enemyMovesFirst
414
ld a, $1
415
ldh [hWhoseTurn], a
416
callfar TrainerAI
417
jr c, .AIActionUsedEnemyFirst
418
call ExecuteEnemyMove
419
ld a, [wEscapedFromBattle]
420
and a ; was Teleport, Roar, or Whirlwind used to escape from battle?
421
ret nz ; if so, return
422
ld a, b
423
and a
424
jp z, HandlePlayerMonFainted
425
.AIActionUsedEnemyFirst
426
call HandlePoisonBurnLeechSeed
427
jp z, HandleEnemyMonFainted
428
call DrawHUDsAndHPBars
429
call ExecutePlayerMove
430
ld a, [wEscapedFromBattle]
431
and a ; was Teleport, Roar, or Whirlwind used to escape from battle?
432
ret nz ; if so, return
433
ld a, b
434
and a
435
jp z, HandleEnemyMonFainted
436
call HandlePoisonBurnLeechSeed
437
jp z, HandlePlayerMonFainted
438
call DrawHUDsAndHPBars
439
call CheckNumAttacksLeft
440
jp MainInBattleLoop
441
.playerMovesFirst
442
call ExecutePlayerMove
443
ld a, [wEscapedFromBattle]
444
and a ; was Teleport, Roar, or Whirlwind used to escape from battle?
445
ret nz ; if so, return
446
ld a, b
447
and a
448
jp z, HandleEnemyMonFainted
449
call HandlePoisonBurnLeechSeed
450
jp z, HandlePlayerMonFainted
451
call DrawHUDsAndHPBars
452
ld a, $1
453
ldh [hWhoseTurn], a
454
callfar TrainerAI
455
jr c, .AIActionUsedPlayerFirst
456
call ExecuteEnemyMove
457
ld a, [wEscapedFromBattle]
458
and a ; was Teleport, Roar, or Whirlwind used to escape from battle?
459
ret nz ; if so, return
460
ld a, b
461
and a
462
jp z, HandlePlayerMonFainted
463
.AIActionUsedPlayerFirst
464
call HandlePoisonBurnLeechSeed
465
jp z, HandleEnemyMonFainted
466
call DrawHUDsAndHPBars
467
call CheckNumAttacksLeft
468
jp MainInBattleLoop
469
470
HandlePoisonBurnLeechSeed:
471
ld hl, wBattleMonHP
472
ld de, wBattleMonStatus
473
ldh a, [hWhoseTurn]
474
and a
475
jr z, .playersTurn
476
ld hl, wEnemyMonHP
477
ld de, wEnemyMonStatus
478
.playersTurn
479
ld a, [de]
480
and (1 << BRN) | (1 << PSN)
481
jr z, .notBurnedOrPoisoned
482
push hl
483
ld hl, HurtByPoisonText
484
ld a, [de]
485
and 1 << BRN
486
jr z, .poisoned
487
ld hl, HurtByBurnText
488
.poisoned
489
call PrintText
490
xor a
491
ld [wAnimationType], a
492
ld a, BURN_PSN_ANIM
493
call PlayMoveAnimation ; play burn/poison animation
494
pop hl
495
call HandlePoisonBurnLeechSeed_DecreaseOwnHP
496
.notBurnedOrPoisoned
497
ld de, wPlayerBattleStatus2
498
ldh a, [hWhoseTurn]
499
and a
500
jr z, .playersTurn2
501
ld de, wEnemyBattleStatus2
502
.playersTurn2
503
ld a, [de]
504
add a
505
jr nc, .notLeechSeeded
506
push hl
507
ldh a, [hWhoseTurn]
508
push af
509
xor $1
510
ldh [hWhoseTurn], a
511
xor a
512
ld [wAnimationType], a
513
ld a, ABSORB
514
call PlayMoveAnimation ; play leech seed animation (from opposing mon)
515
pop af
516
ldh [hWhoseTurn], a
517
pop hl
518
call HandlePoisonBurnLeechSeed_DecreaseOwnHP
519
call HandlePoisonBurnLeechSeed_IncreaseEnemyHP
520
push hl
521
ld hl, HurtByLeechSeedText
522
call PrintText
523
pop hl
524
.notLeechSeeded
525
ld a, [hli]
526
or [hl]
527
ret nz ; test if fainted
528
call DrawHUDsAndHPBars
529
ld c, 20
530
call DelayFrames
531
xor a
532
ret
533
534
HurtByPoisonText:
535
text_far _HurtByPoisonText
536
text_end
537
538
HurtByBurnText:
539
text_far _HurtByBurnText
540
text_end
541
542
HurtByLeechSeedText:
543
text_far _HurtByLeechSeedText
544
text_end
545
546
; decreases the mon's current HP by 1/16 of the Max HP (multiplied by number of toxic ticks if active)
547
; note that the toxic ticks are considered even if the damage is not poison (hence the Leech Seed glitch)
548
; hl: HP pointer
549
; bc (out): total damage
550
HandlePoisonBurnLeechSeed_DecreaseOwnHP:
551
push hl
552
push hl
553
ld bc, $e ; skip to max HP
554
add hl, bc
555
ld a, [hli] ; load max HP
556
ld [wHPBarMaxHP+1], a
557
ld b, a
558
ld a, [hl]
559
ld [wHPBarMaxHP], a
560
ld c, a
561
srl b
562
rr c
563
srl b
564
rr c
565
srl c
566
srl c ; c = max HP/16 (assumption: HP < 1024)
567
ld a, c
568
and a
569
jr nz, .nonZeroDamage
570
inc c ; damage is at least 1
571
.nonZeroDamage
572
ld hl, wPlayerBattleStatus3
573
ld de, wPlayerToxicCounter
574
ldh a, [hWhoseTurn]
575
and a
576
jr z, .playersTurn
577
ld hl, wEnemyBattleStatus3
578
ld de, wEnemyToxicCounter
579
.playersTurn
580
bit BADLY_POISONED, [hl]
581
jr z, .noToxic
582
ld a, [de] ; increment toxic counter
583
inc a
584
ld [de], a
585
ld hl, 0
586
.toxicTicksLoop
587
add hl, bc
588
dec a
589
jr nz, .toxicTicksLoop
590
ld b, h ; bc = damage * toxic counter
591
ld c, l
592
.noToxic
593
pop hl
594
inc hl
595
ld a, [hl] ; subtract total damage from current HP
596
ld [wHPBarOldHP], a
597
sub c
598
ld [hld], a
599
ld [wHPBarNewHP], a
600
ld a, [hl]
601
ld [wHPBarOldHP+1], a
602
sbc b
603
ld [hl], a
604
ld [wHPBarNewHP+1], a
605
jr nc, .noOverkill
606
xor a ; overkill: zero HP
607
ld [hli], a
608
ld [hl], a
609
ld [wHPBarNewHP], a
610
ld [wHPBarNewHP+1], a
611
.noOverkill
612
call UpdateCurMonHPBar
613
pop hl
614
ret
615
616
; adds bc to enemy HP
617
; bc isn't updated if HP subtracted was capped to prevent overkill
618
HandlePoisonBurnLeechSeed_IncreaseEnemyHP:
619
push hl
620
ld hl, wEnemyMonMaxHP
621
ldh a, [hWhoseTurn]
622
and a
623
jr z, .playersTurn
624
ld hl, wBattleMonMaxHP
625
.playersTurn
626
ld a, [hli]
627
ld [wHPBarMaxHP+1], a
628
ld a, [hl]
629
ld [wHPBarMaxHP], a
630
ld de, wBattleMonHP - wBattleMonMaxHP
631
add hl, de ; skip back from max hp to current hp
632
ld a, [hl]
633
ld [wHPBarOldHP], a ; add bc to current HP
634
add c
635
ld [hld], a
636
ld [wHPBarNewHP], a
637
ld a, [hl]
638
ld [wHPBarOldHP+1], a
639
adc b
640
ld [hli], a
641
ld [wHPBarNewHP+1], a
642
ld a, [wHPBarMaxHP]
643
ld c, a
644
ld a, [hld]
645
sub c
646
ld a, [wHPBarMaxHP+1]
647
ld b, a
648
ld a, [hl]
649
sbc b
650
jr c, .noOverfullHeal
651
ld a, b ; overfull heal, set HP to max HP
652
ld [hli], a
653
ld [wHPBarNewHP+1], a
654
ld a, c
655
ld [hl], a
656
ld [wHPBarNewHP], a
657
.noOverfullHeal
658
ldh a, [hWhoseTurn]
659
xor $1
660
ldh [hWhoseTurn], a
661
call UpdateCurMonHPBar
662
ldh a, [hWhoseTurn]
663
xor $1
664
ldh [hWhoseTurn], a
665
pop hl
666
ret
667
668
UpdateCurMonHPBar:
669
hlcoord 10, 9 ; tile pointer to player HP bar
670
ldh a, [hWhoseTurn]
671
and a
672
ld a, $1
673
jr z, .playersTurn
674
hlcoord 2, 2 ; tile pointer to enemy HP bar
675
xor a
676
.playersTurn
677
push bc
678
ld [wHPBarType], a
679
predef UpdateHPBar2
680
pop bc
681
ret
682
683
CheckNumAttacksLeft:
684
ld a, [wPlayerNumAttacksLeft]
685
and a
686
jr nz, .checkEnemy
687
; player has 0 attacks left
688
ld hl, wPlayerBattleStatus1
689
res USING_TRAPPING_MOVE, [hl] ; player not using multi-turn attack like wrap any more
690
.checkEnemy
691
ld a, [wEnemyNumAttacksLeft]
692
and a
693
ret nz
694
; enemy has 0 attacks left
695
ld hl, wEnemyBattleStatus1
696
res USING_TRAPPING_MOVE, [hl] ; enemy not using multi-turn attack like wrap any more
697
ret
698
699
HandleEnemyMonFainted:
700
xor a
701
ld [wInHandlePlayerMonFainted], a
702
call FaintEnemyPokemon
703
call AnyPartyAlive
704
ld a, d
705
and a
706
jp z, HandlePlayerBlackOut ; if no party mons are alive, the player blacks out
707
ld hl, wBattleMonHP
708
ld a, [hli]
709
or [hl] ; is battle mon HP zero?
710
call nz, DrawPlayerHUDAndHPBar ; if battle mon HP is not zero, draw player HD and HP bar
711
ld a, [wIsInBattle]
712
dec a
713
ret z ; return if it's a wild battle
714
call AnyEnemyPokemonAliveCheck
715
jp z, TrainerBattleVictory
716
ld hl, wBattleMonHP
717
ld a, [hli]
718
or [hl] ; does battle mon have 0 HP?
719
jr nz, .skipReplacingBattleMon ; if not, skip replacing battle mon
720
call DoUseNextMonDialogue ; this call is useless in a trainer battle. it shouldn't be here
721
ret c
722
call ChooseNextMon
723
.skipReplacingBattleMon
724
ld a, $1
725
ld [wActionResultOrTookBattleTurn], a
726
call ReplaceFaintedEnemyMon
727
jp z, EnemyRan
728
xor a
729
ld [wActionResultOrTookBattleTurn], a
730
jp MainInBattleLoop
731
732
FaintEnemyPokemon:
733
call ReadPlayerMonCurHPAndStatus
734
ld a, [wIsInBattle]
735
dec a
736
jr z, .wild
737
ld a, [wEnemyMonPartyPos]
738
ld hl, wEnemyMon1HP
739
ld bc, wEnemyMon2 - wEnemyMon1
740
call AddNTimes
741
xor a
742
ld [hli], a
743
ld [hl], a
744
.wild
745
ld hl, wPlayerBattleStatus1
746
res ATTACKING_MULTIPLE_TIMES, [hl]
747
; Bug. This only zeroes the high byte of the player's accumulated damage,
748
; setting the accumulated damage to itself mod 256 instead of 0 as was probably
749
; intended. That alone is problematic, but this mistake has another more severe
750
; effect. This function's counterpart for when the player mon faints,
751
; RemoveFaintedPlayerMon, zeroes both the high byte and the low byte. In a link
752
; battle, the other player's Game Boy will call that function in response to
753
; the enemy mon (the player mon from the other side's perspective) fainting,
754
; and the states of the two Game Boys will go out of sync unless the damage
755
; was congruent to 0 modulo 256.
756
xor a
757
ld [wPlayerBideAccumulatedDamage], a
758
ld hl, wEnemyStatsToDouble ; clear enemy statuses
759
ld [hli], a
760
ld [hli], a
761
ld [hli], a
762
ld [hli], a
763
ld [hl], a
764
ld [wEnemyDisabledMove], a
765
ld [wEnemyDisabledMoveNumber], a
766
ld [wEnemyMonMinimized], a
767
ld hl, wPlayerUsedMove
768
ld [hli], a
769
ld [hl], a
770
hlcoord 12, 5
771
decoord 12, 6
772
call SlideDownFaintedMonPic
773
hlcoord 0, 0
774
lb bc, 4, 11
775
call ClearScreenArea
776
ld a, [wIsInBattle]
777
dec a
778
jr z, .wild_win
779
xor a
780
ld [wFrequencyModifier], a
781
ld [wTempoModifier], a
782
ld a, SFX_FAINT_FALL
783
call PlaySoundWaitForCurrent
784
.sfxwait
785
ld a, [wChannelSoundIDs + CHAN5]
786
cp SFX_FAINT_FALL
787
jr z, .sfxwait
788
ld a, SFX_FAINT_THUD
789
call PlaySound
790
call WaitForSoundToFinish
791
jr .sfxplayed
792
.wild_win
793
call EndLowHealthAlarm
794
ld a, MUSIC_DEFEATED_WILD_MON
795
call PlayBattleVictoryMusic
796
.sfxplayed
797
; bug: win sfx is played for wild battles before checking for player mon HP
798
; this can lead to odd scenarios where both player and enemy faint, as the win sfx plays yet the player never won the battle
799
ld hl, wBattleMonHP
800
ld a, [hli]
801
or [hl]
802
jr nz, .playermonnotfaint
803
ld a, [wInHandlePlayerMonFainted]
804
and a ; was this called by HandlePlayerMonFainted?
805
jr nz, .playermonnotfaint ; if so, don't call RemoveFaintedPlayerMon twice
806
call RemoveFaintedPlayerMon
807
.playermonnotfaint
808
call AnyPartyAlive
809
ld a, d
810
and a
811
ret z
812
ld hl, EnemyMonFaintedText
813
call PrintText
814
call PrintEmptyString
815
call SaveScreenTilesToBuffer1
816
xor a
817
ld [wBattleResult], a
818
ld b, EXP_ALL
819
call IsItemInBag
820
push af
821
jr z, .giveExpToMonsThatFought ; if no exp all, then jump
822
823
; the player has exp all
824
; first, we halve the values that determine exp gain
825
; the enemy mon base stats are added to stat exp, so they are halved
826
; the base exp (which determines normal exp) is also halved
827
ld hl, wEnemyMonBaseStats
828
ld b, NUM_STATS + 2
829
.halveExpDataLoop
830
srl [hl]
831
inc hl
832
dec b
833
jr nz, .halveExpDataLoop
834
835
; give exp (divided evenly) to the mons that actually fought in battle against the enemy mon that has fainted
836
; if exp all is in the bag, this will be only be half of the stat exp and normal exp, due to the above loop
837
.giveExpToMonsThatFought
838
xor a
839
ld [wBoostExpByExpAll], a
840
callfar GainExperience
841
pop af
842
ret z ; return if no exp all
843
844
; the player has exp all
845
; now, set the gain exp flag for every party member
846
; half of the total stat exp and normal exp will divided evenly amongst every party member
847
ld a, TRUE
848
ld [wBoostExpByExpAll], a
849
ld a, [wPartyCount]
850
ld b, 0
851
.gainExpFlagsLoop
852
scf
853
rl b
854
dec a
855
jr nz, .gainExpFlagsLoop
856
ld a, b
857
ld [wPartyGainExpFlags], a
858
jpfar GainExperience
859
860
EnemyMonFaintedText:
861
text_far _EnemyMonFaintedText
862
text_end
863
864
EndLowHealthAlarm:
865
; This function is called when the player has the won the battle. It turns off
866
; the low health alarm and prevents it from reactivating until the next battle.
867
xor a
868
ld [wLowHealthAlarm], a ; turn off low health alarm
869
ld [wChannelSoundIDs + CHAN5], a
870
inc a
871
ld [wLowHealthAlarmDisabled], a ; prevent it from reactivating
872
ret
873
874
AnyEnemyPokemonAliveCheck:
875
ld a, [wEnemyPartyCount]
876
ld b, a
877
xor a
878
ld hl, wEnemyMon1HP
879
ld de, wEnemyMon2 - wEnemyMon1
880
.nextPokemon
881
or [hl]
882
inc hl
883
or [hl]
884
dec hl
885
add hl, de
886
dec b
887
jr nz, .nextPokemon
888
and a
889
ret
890
891
; stores whether enemy ran in Z flag
892
ReplaceFaintedEnemyMon:
893
ld hl, wEnemyHPBarColor
894
ld e, $30
895
call GetBattleHealthBarColor
896
callfar DrawEnemyPokeballs
897
ld a, [wLinkState]
898
cp LINK_STATE_BATTLING
899
jr nz, .notLinkBattle
900
; link battle
901
call LinkBattleExchangeData
902
ld a, [wSerialExchangeNybbleReceiveData]
903
cp LINKBATTLE_RUN
904
ret z
905
call LoadScreenTilesFromBuffer1
906
.notLinkBattle
907
call EnemySendOut
908
xor a
909
ld [wEnemyMoveNum], a
910
ld [wActionResultOrTookBattleTurn], a
911
ld [wAILayer2Encouragement], a
912
inc a ; reset Z flag
913
ret
914
915
TrainerBattleVictory:
916
call EndLowHealthAlarm
917
ld b, MUSIC_DEFEATED_GYM_LEADER
918
ld a, [wGymLeaderNo]
919
and a
920
jr nz, .gymleader
921
ld b, MUSIC_DEFEATED_TRAINER
922
.gymleader
923
ld a, [wTrainerClass]
924
cp RIVAL3 ; final battle against rival
925
jr nz, .notrival
926
ld b, MUSIC_DEFEATED_GYM_LEADER
927
ld hl, wStatusFlags7
928
set BIT_NO_MAP_MUSIC, [hl]
929
.notrival
930
ld a, [wLinkState]
931
cp LINK_STATE_BATTLING
932
ld a, b
933
call nz, PlayBattleVictoryMusic
934
ld hl, TrainerDefeatedText
935
call PrintText
936
ld a, [wLinkState]
937
cp LINK_STATE_BATTLING
938
ret z
939
call ScrollTrainerPicAfterBattle
940
ld c, 40
941
call DelayFrames
942
call PrintEndBattleText
943
; win money
944
ld hl, MoneyForWinningText
945
call PrintText
946
ld de, wPlayerMoney + 2
947
ld hl, wAmountMoneyWon + 2
948
ld c, $3
949
predef_jump AddBCDPredef
950
951
MoneyForWinningText:
952
text_far _MoneyForWinningText
953
text_end
954
955
TrainerDefeatedText:
956
text_far _TrainerDefeatedText
957
text_end
958
959
PlayBattleVictoryMusic:
960
push af
961
ld a, SFX_STOP_ALL_MUSIC
962
ld [wNewSoundID], a
963
call PlaySoundWaitForCurrent
964
ld c, BANK(Music_DefeatedTrainer)
965
pop af
966
call PlayMusic
967
jp Delay3
968
969
HandlePlayerMonFainted:
970
ld a, 1
971
ld [wInHandlePlayerMonFainted], a
972
call RemoveFaintedPlayerMon
973
call AnyPartyAlive ; test if any more mons are alive
974
ld a, d
975
and a
976
jp z, HandlePlayerBlackOut
977
ld hl, wEnemyMonHP
978
ld a, [hli]
979
or [hl] ; is enemy mon's HP 0?
980
jr nz, .doUseNextMonDialogue ; if not, jump
981
; the enemy mon has 0 HP
982
call FaintEnemyPokemon
983
ld a, [wIsInBattle]
984
dec a
985
ret z ; if wild encounter, battle is over
986
call AnyEnemyPokemonAliveCheck
987
jp z, TrainerBattleVictory
988
.doUseNextMonDialogue
989
call DoUseNextMonDialogue
990
ret c ; return if the player ran from battle
991
call ChooseNextMon
992
jp nz, MainInBattleLoop ; if the enemy mon has more than 0 HP, go back to battle loop
993
; the enemy mon has 0 HP
994
ld a, $1
995
ld [wActionResultOrTookBattleTurn], a
996
call ReplaceFaintedEnemyMon
997
jp z, EnemyRan ; if enemy ran from battle rather than sending out another mon, jump
998
xor a
999
ld [wActionResultOrTookBattleTurn], a
1000
jp MainInBattleLoop
1001
1002
; resets flags, slides mon's pic down, plays cry, and prints fainted message
1003
RemoveFaintedPlayerMon:
1004
ld a, [wPlayerMonNumber]
1005
ld c, a
1006
ld hl, wPartyGainExpFlags
1007
ld b, FLAG_RESET
1008
predef FlagActionPredef ; clear gain exp flag for fainted mon
1009
ld hl, wEnemyBattleStatus1
1010
res ATTACKING_MULTIPLE_TIMES, [hl]
1011
ld a, [wLowHealthAlarm]
1012
bit BIT_LOW_HEALTH_ALARM, a
1013
jr z, .skipWaitForSound
1014
ld a, DISABLE_LOW_HEALTH_ALARM
1015
ld [wLowHealthAlarm], a
1016
call WaitForSoundToFinish
1017
.skipWaitForSound
1018
; a is 0, so this zeroes the enemy's accumulated damage.
1019
ld hl, wEnemyBideAccumulatedDamage
1020
ld [hli], a
1021
ld [hl], a
1022
ld [wBattleMonStatus], a
1023
call ReadPlayerMonCurHPAndStatus
1024
hlcoord 9, 7
1025
lb bc, 5, 11
1026
call ClearScreenArea
1027
hlcoord 1, 10
1028
decoord 1, 11
1029
call SlideDownFaintedMonPic
1030
ld a, $1
1031
ld [wBattleResult], a
1032
1033
; When the player mon and enemy mon faint at the same time and the fact that the
1034
; enemy mon has fainted is detected first (e.g. when the player mon knocks out
1035
; the enemy mon using a move with recoil and faints due to the recoil), don't
1036
; play the player mon's cry or show the "[player mon] fainted!" message.
1037
ld a, [wInHandlePlayerMonFainted]
1038
and a ; was this called by HandleEnemyMonFainted?
1039
ret z ; if so, return
1040
1041
ld a, [wBattleMonSpecies]
1042
call PlayCry
1043
ld hl, PlayerMonFaintedText
1044
jp PrintText
1045
1046
PlayerMonFaintedText:
1047
text_far _PlayerMonFaintedText
1048
text_end
1049
1050
; asks if you want to use next mon
1051
; stores whether you ran in C flag
1052
DoUseNextMonDialogue:
1053
call PrintEmptyString
1054
call SaveScreenTilesToBuffer1
1055
ld a, [wIsInBattle]
1056
and a
1057
dec a
1058
ret nz ; return if it's a trainer battle
1059
ld hl, UseNextMonText
1060
call PrintText
1061
.displayYesNoBox
1062
hlcoord 13, 9
1063
lb bc, 10, 14
1064
ld a, TWO_OPTION_MENU
1065
ld [wTextBoxID], a
1066
call DisplayTextBoxID
1067
ld a, [wMenuExitMethod]
1068
cp CHOSE_SECOND_ITEM ; did the player choose NO?
1069
jr z, .tryRunning ; if the player chose NO, try running
1070
and a ; reset carry
1071
ret
1072
.tryRunning
1073
ld a, [wCurrentMenuItem]
1074
and a
1075
jr z, .displayYesNoBox ; xxx when does this happen?
1076
ld hl, wPartyMon1Speed
1077
ld de, wEnemyMonSpeed
1078
jp TryRunningFromBattle
1079
1080
UseNextMonText:
1081
text_far _UseNextMonText
1082
text_end
1083
1084
; choose next player mon to send out
1085
; stores whether enemy mon has no HP left in Z flag
1086
ChooseNextMon:
1087
ld a, BATTLE_PARTY_MENU
1088
ld [wPartyMenuTypeOrMessageID], a
1089
call DisplayPartyMenu
1090
.checkIfMonChosen
1091
jr nc, .monChosen
1092
.goBackToPartyMenu
1093
call GoBackToPartyMenu
1094
jr .checkIfMonChosen
1095
.monChosen
1096
call HasMonFainted
1097
jr z, .goBackToPartyMenu ; if mon fainted, you have to choose another
1098
ld a, [wLinkState]
1099
cp LINK_STATE_BATTLING
1100
jr nz, .notLinkBattle
1101
inc a ; 1
1102
ld [wActionResultOrTookBattleTurn], a
1103
call LinkBattleExchangeData
1104
.notLinkBattle
1105
xor a
1106
ld [wActionResultOrTookBattleTurn], a
1107
call ClearSprites
1108
ld a, [wWhichPokemon]
1109
ld [wPlayerMonNumber], a
1110
ld c, a
1111
ld hl, wPartyGainExpFlags
1112
ld b, FLAG_SET
1113
push bc
1114
predef FlagActionPredef
1115
pop bc
1116
ld hl, wPartyFoughtCurrentEnemyFlags
1117
predef FlagActionPredef
1118
call LoadBattleMonFromParty
1119
call GBPalWhiteOut
1120
call LoadHudTilePatterns
1121
call LoadScreenTilesFromBuffer1
1122
call RunDefaultPaletteCommand
1123
call GBPalNormal
1124
call SendOutMon
1125
ld hl, wEnemyMonHP
1126
ld a, [hli]
1127
or [hl]
1128
ret
1129
1130
; called when player is out of usable mons.
1131
; prints appropriate lose message, sets carry flag if player blacked out (special case for initial rival fight)
1132
HandlePlayerBlackOut:
1133
ld a, [wLinkState]
1134
cp LINK_STATE_BATTLING
1135
jr z, .notRival1Battle
1136
ld a, [wCurOpponent]
1137
cp OPP_RIVAL1
1138
jr nz, .notRival1Battle
1139
hlcoord 0, 0 ; rival 1 battle
1140
lb bc, 8, 21
1141
call ClearScreenArea
1142
call ScrollTrainerPicAfterBattle
1143
ld c, 40
1144
call DelayFrames
1145
ld hl, Rival1WinText
1146
call PrintText
1147
ld a, [wCurMap]
1148
cp OAKS_LAB
1149
ret z ; starter battle in oak's lab: don't black out
1150
.notRival1Battle
1151
ld b, SET_PAL_BATTLE_BLACK
1152
call RunPaletteCommand
1153
ld hl, PlayerBlackedOutText2
1154
ld a, [wLinkState]
1155
cp LINK_STATE_BATTLING
1156
jr nz, .noLinkBattle
1157
ld hl, LinkBattleLostText
1158
.noLinkBattle
1159
call PrintText
1160
ld a, [wStatusFlags6]
1161
res BIT_ALWAYS_ON_BIKE, a
1162
ld [wStatusFlags6], a
1163
call ClearScreen
1164
scf
1165
ret
1166
1167
Rival1WinText:
1168
text_far _Rival1WinText
1169
text_end
1170
1171
PlayerBlackedOutText2:
1172
text_far _PlayerBlackedOutText2
1173
text_end
1174
1175
LinkBattleLostText:
1176
text_far _LinkBattleLostText
1177
text_end
1178
1179
; slides pic of fainted mon downwards until it disappears
1180
; bug: when this is called, [hAutoBGTransferEnabled] is non-zero, so there is screen tearing
1181
SlideDownFaintedMonPic:
1182
ld a, [wStatusFlags5]
1183
push af
1184
set BIT_NO_TEXT_DELAY, a
1185
ld [wStatusFlags5], a
1186
ld b, 7 ; number of times to slide
1187
.slideStepLoop ; each iteration, the mon is slid down one row
1188
push bc
1189
push de
1190
push hl
1191
ld b, 6 ; number of rows
1192
.rowLoop
1193
push bc
1194
push hl
1195
push de
1196
ld bc, $7
1197
call CopyData
1198
pop de
1199
pop hl
1200
ld bc, -SCREEN_WIDTH
1201
add hl, bc
1202
push hl
1203
ld h, d
1204
ld l, e
1205
add hl, bc
1206
ld d, h
1207
ld e, l
1208
pop hl
1209
pop bc
1210
dec b
1211
jr nz, .rowLoop
1212
ld bc, SCREEN_WIDTH
1213
add hl, bc
1214
ld de, SevenSpacesText
1215
call PlaceString
1216
ld c, 2
1217
call DelayFrames
1218
pop hl
1219
pop de
1220
pop bc
1221
dec b
1222
jr nz, .slideStepLoop
1223
pop af
1224
ld [wStatusFlags5], a
1225
ret
1226
1227
SevenSpacesText:
1228
db " @"
1229
1230
; slides the player or enemy trainer off screen
1231
; a is the number of tiles to slide it horizontally (always 9 for the player trainer or 8 for the enemy trainer)
1232
; if a is 8, the slide is to the right, else it is to the left
1233
; bug: when this is called, [hAutoBGTransferEnabled] is non-zero, so there is screen tearing
1234
SlideTrainerPicOffScreen:
1235
ldh [hSlideAmount], a
1236
ld c, a
1237
.slideStepLoop ; each iteration, the trainer pic is slid one tile left/right
1238
push bc
1239
push hl
1240
ld b, 7 ; number of rows
1241
.rowLoop
1242
push hl
1243
ldh a, [hSlideAmount]
1244
ld c, a
1245
.columnLoop
1246
ldh a, [hSlideAmount]
1247
cp 8
1248
jr z, .slideRight
1249
.slideLeft ; slide player sprite off screen
1250
ld a, [hld]
1251
ld [hli], a
1252
inc hl
1253
jr .nextColumn
1254
.slideRight ; slide enemy trainer sprite off screen
1255
ld a, [hli]
1256
ld [hld], a
1257
dec hl
1258
.nextColumn
1259
dec c
1260
jr nz, .columnLoop
1261
pop hl
1262
ld de, SCREEN_WIDTH
1263
add hl, de
1264
dec b
1265
jr nz, .rowLoop
1266
ld c, 2
1267
call DelayFrames
1268
pop hl
1269
pop bc
1270
dec c
1271
jr nz, .slideStepLoop
1272
ret
1273
1274
; send out a trainer's mon
1275
EnemySendOut:
1276
ld hl, wPartyGainExpFlags
1277
xor a
1278
ld [hl], a
1279
ld a, [wPlayerMonNumber]
1280
ld c, a
1281
ld b, FLAG_SET
1282
push bc
1283
predef FlagActionPredef
1284
ld hl, wPartyFoughtCurrentEnemyFlags
1285
xor a
1286
ld [hl], a
1287
pop bc
1288
predef FlagActionPredef
1289
1290
; don't change wPartyGainExpFlags or wPartyFoughtCurrentEnemyFlags
1291
EnemySendOutFirstMon:
1292
xor a
1293
ld hl, wEnemyStatsToDouble ; clear enemy statuses
1294
ld [hli], a
1295
ld [hli], a
1296
ld [hli], a
1297
ld [hli], a
1298
ld [hl], a
1299
ld [wEnemyDisabledMove], a
1300
ld [wEnemyDisabledMoveNumber], a
1301
ld [wEnemyMonMinimized], a
1302
ld hl, wPlayerUsedMove
1303
ld [hli], a
1304
ld [hl], a
1305
dec a
1306
ld [wAICount], a
1307
ld hl, wPlayerBattleStatus1
1308
res USING_TRAPPING_MOVE, [hl]
1309
hlcoord 18, 0
1310
ld a, 8
1311
call SlideTrainerPicOffScreen
1312
call PrintEmptyString
1313
call SaveScreenTilesToBuffer1
1314
ld a, [wLinkState]
1315
cp LINK_STATE_BATTLING
1316
jr nz, .next
1317
ld a, [wSerialExchangeNybbleReceiveData]
1318
sub 4
1319
ld [wWhichPokemon], a
1320
jr .next3
1321
.next
1322
ld b, $ff
1323
.next2
1324
inc b
1325
ld a, [wEnemyMonPartyPos]
1326
cp b
1327
jr z, .next2
1328
ld hl, wEnemyMon1
1329
ld a, b
1330
ld [wWhichPokemon], a
1331
push bc
1332
ld bc, wEnemyMon2 - wEnemyMon1
1333
call AddNTimes
1334
pop bc
1335
inc hl
1336
ld a, [hli]
1337
ld c, a
1338
ld a, [hl]
1339
or c
1340
jr z, .next2
1341
.next3
1342
ld a, [wWhichPokemon]
1343
ld hl, wEnemyMon1Level
1344
ld bc, wEnemyMon2 - wEnemyMon1
1345
call AddNTimes
1346
ld a, [hl]
1347
ld [wCurEnemyLevel], a
1348
ld a, [wWhichPokemon]
1349
inc a
1350
ld hl, wEnemyPartyCount
1351
ld c, a
1352
ld b, 0
1353
add hl, bc
1354
ld a, [hl]
1355
ld [wEnemyMonSpecies2], a
1356
ld [wCurPartySpecies], a
1357
call LoadEnemyMonData
1358
ld hl, wEnemyMonHP
1359
ld a, [hli]
1360
ld [wLastSwitchInEnemyMonHP], a
1361
ld a, [hl]
1362
ld [wLastSwitchInEnemyMonHP + 1], a
1363
ld a, 1
1364
ld [wCurrentMenuItem], a
1365
ld a, [wFirstMonsNotOutYet]
1366
dec a
1367
jr z, .next4
1368
ld a, [wPartyCount]
1369
dec a
1370
jr z, .next4
1371
ld a, [wLinkState]
1372
cp LINK_STATE_BATTLING
1373
jr z, .next4
1374
ld a, [wOptions]
1375
bit BIT_BATTLE_SHIFT, a
1376
jr nz, .next4
1377
ld hl, TrainerAboutToUseText
1378
call PrintText
1379
hlcoord 0, 7
1380
lb bc, 8, 1
1381
ld a, TWO_OPTION_MENU
1382
ld [wTextBoxID], a
1383
call DisplayTextBoxID
1384
ld a, [wCurrentMenuItem]
1385
and a
1386
jr nz, .next4
1387
ld a, BATTLE_PARTY_MENU
1388
ld [wPartyMenuTypeOrMessageID], a
1389
call DisplayPartyMenu
1390
.next9
1391
ld a, 1
1392
ld [wCurrentMenuItem], a
1393
jr c, .next7
1394
ld hl, wPlayerMonNumber
1395
ld a, [wWhichPokemon]
1396
cp [hl]
1397
jr nz, .next6
1398
ld hl, AlreadyOutText
1399
call PrintText
1400
.next8
1401
call GoBackToPartyMenu
1402
jr .next9
1403
.next6
1404
call HasMonFainted
1405
jr z, .next8
1406
xor a
1407
ld [wCurrentMenuItem], a
1408
.next7
1409
call GBPalWhiteOut
1410
call LoadHudTilePatterns
1411
call LoadScreenTilesFromBuffer1
1412
.next4
1413
call ClearSprites
1414
hlcoord 0, 0
1415
lb bc, 4, 11
1416
call ClearScreenArea
1417
ld b, SET_PAL_BATTLE
1418
call RunPaletteCommand
1419
call GBPalNormal
1420
ld hl, TrainerSentOutText
1421
call PrintText
1422
ld a, [wEnemyMonSpecies2]
1423
ld [wCurPartySpecies], a
1424
ld [wCurSpecies], a
1425
call GetMonHeader
1426
ld de, vFrontPic
1427
call LoadMonFrontSprite
1428
ld a, -$31
1429
ldh [hStartTileID], a
1430
hlcoord 15, 6
1431
predef AnimateSendingOutMon
1432
ld a, [wEnemyMonSpecies2]
1433
call PlayCry
1434
call DrawEnemyHUDAndHPBar
1435
ld a, [wCurrentMenuItem]
1436
and a
1437
ret nz
1438
xor a
1439
ld [wPartyGainExpFlags], a
1440
ld [wPartyFoughtCurrentEnemyFlags], a
1441
call SaveScreenTilesToBuffer1
1442
jp SwitchPlayerMon
1443
1444
TrainerAboutToUseText:
1445
text_far _TrainerAboutToUseText
1446
text_end
1447
1448
TrainerSentOutText:
1449
text_far _TrainerSentOutText
1450
text_end
1451
1452
; tests if the player has any pokemon that are not fainted
1453
; sets d = 0 if all fainted, d != 0 if some mons are still alive
1454
AnyPartyAlive::
1455
ld a, [wPartyCount]
1456
ld e, a
1457
xor a
1458
ld hl, wPartyMon1HP
1459
ld bc, wPartyMon2 - wPartyMon1 - 1
1460
.partyMonsLoop
1461
or [hl]
1462
inc hl
1463
or [hl]
1464
add hl, bc
1465
dec e
1466
jr nz, .partyMonsLoop
1467
ld d, a
1468
ret
1469
1470
; tests if player mon has fainted
1471
; stores whether mon has fainted in Z flag
1472
HasMonFainted:
1473
ld a, [wWhichPokemon]
1474
ld hl, wPartyMon1HP
1475
ld bc, wPartyMon2 - wPartyMon1
1476
call AddNTimes
1477
ld a, [hli]
1478
or [hl]
1479
ret nz
1480
ld a, [wFirstMonsNotOutYet]
1481
and a
1482
jr nz, .done
1483
ld hl, NoWillText
1484
call PrintText
1485
.done
1486
xor a
1487
ret
1488
1489
NoWillText:
1490
text_far _NoWillText
1491
text_end
1492
1493
; try to run from battle (hl = player speed, de = enemy speed)
1494
; stores whether the attempt was successful in carry flag
1495
TryRunningFromBattle:
1496
call IsGhostBattle
1497
jp z, .canEscape ; jump if it's a ghost battle
1498
ld a, [wBattleType]
1499
cp BATTLE_TYPE_SAFARI
1500
jp z, .canEscape ; jump if it's a safari battle
1501
ld a, [wLinkState]
1502
cp LINK_STATE_BATTLING
1503
jp z, .canEscape
1504
ld a, [wIsInBattle]
1505
dec a
1506
jr nz, .trainerBattle ; jump if it's a trainer battle
1507
ld a, [wNumRunAttempts]
1508
inc a
1509
ld [wNumRunAttempts], a
1510
ld a, [hli]
1511
ldh [hMultiplicand + 1], a
1512
ld a, [hl]
1513
ldh [hMultiplicand + 2], a
1514
ld a, [de]
1515
ldh [hEnemySpeed], a
1516
inc de
1517
ld a, [de]
1518
ldh [hEnemySpeed + 1], a
1519
call LoadScreenTilesFromBuffer1
1520
ld de, hMultiplicand + 1
1521
ld hl, hEnemySpeed
1522
ld c, 2
1523
call StringCmp
1524
jr nc, .canEscape ; jump if player speed greater than enemy speed
1525
xor a
1526
ldh [hMultiplicand], a
1527
ld a, 32
1528
ldh [hMultiplier], a
1529
call Multiply ; multiply player speed by 32
1530
ldh a, [hProduct + 2]
1531
ldh [hDividend], a
1532
ldh a, [hProduct + 3]
1533
ldh [hDividend + 1], a
1534
ldh a, [hEnemySpeed]
1535
ld b, a
1536
ldh a, [hEnemySpeed + 1]
1537
; divide enemy speed by 4
1538
srl b
1539
rr a
1540
srl b
1541
rr a
1542
and a
1543
jr z, .canEscape ; jump if enemy speed divided by 4, mod 256 is 0
1544
ldh [hDivisor], a ; ((enemy speed / 4) % 256)
1545
ld b, $2
1546
call Divide ; divide (player speed * 32) by ((enemy speed / 4) % 256)
1547
ldh a, [hQuotient + 2]
1548
and a ; is the quotient greater than 256?
1549
jr nz, .canEscape ; if so, the player can escape
1550
ld a, [wNumRunAttempts]
1551
ld c, a
1552
; add 30 to the quotient for each run attempt
1553
.loop
1554
dec c
1555
jr z, .compareWithRandomValue
1556
ld b, 30
1557
ldh a, [hQuotient + 3]
1558
add b
1559
ldh [hQuotient + 3], a
1560
jr c, .canEscape
1561
jr .loop
1562
.compareWithRandomValue
1563
call BattleRandom
1564
ld b, a
1565
ldh a, [hQuotient + 3]
1566
cp b
1567
jr nc, .canEscape ; if the random value was less than or equal to the quotient
1568
; plus 30 times the number of attempts, the player can escape
1569
; can't escape
1570
ld a, $1
1571
ld [wActionResultOrTookBattleTurn], a ; you lose your turn when you can't escape
1572
ld hl, CantEscapeText
1573
jr .printCantEscapeOrNoRunningText
1574
.trainerBattle
1575
ld hl, NoRunningText
1576
.printCantEscapeOrNoRunningText
1577
call PrintText
1578
ld a, 1
1579
ld [wForcePlayerToChooseMon], a
1580
call SaveScreenTilesToBuffer1
1581
and a ; reset carry
1582
ret
1583
.canEscape
1584
ld a, [wLinkState]
1585
cp LINK_STATE_BATTLING
1586
ld a, $2
1587
jr nz, .playSound
1588
; link battle
1589
call SaveScreenTilesToBuffer1
1590
xor a
1591
ld [wActionResultOrTookBattleTurn], a
1592
ld a, LINKBATTLE_RUN
1593
ld [wPlayerMoveListIndex], a
1594
call LinkBattleExchangeData
1595
call LoadScreenTilesFromBuffer1
1596
ld a, [wSerialExchangeNybbleReceiveData]
1597
cp LINKBATTLE_RUN
1598
ld a, $2
1599
jr z, .playSound
1600
dec a
1601
.playSound
1602
ld [wBattleResult], a
1603
ld a, SFX_RUN
1604
call PlaySoundWaitForCurrent
1605
ld hl, GotAwayText
1606
call PrintText
1607
call WaitForSoundToFinish
1608
call SaveScreenTilesToBuffer1
1609
scf ; set carry
1610
ret
1611
1612
CantEscapeText:
1613
text_far _CantEscapeText
1614
text_end
1615
1616
NoRunningText:
1617
text_far _NoRunningText
1618
text_end
1619
1620
GotAwayText:
1621
text_far _GotAwayText
1622
text_end
1623
1624
; copies from party data to battle mon data when sending out a new player mon
1625
LoadBattleMonFromParty:
1626
ld a, [wWhichPokemon]
1627
ld bc, wPartyMon2 - wPartyMon1
1628
ld hl, wPartyMon1Species
1629
call AddNTimes
1630
ld de, wBattleMonSpecies
1631
ld bc, wBattleMonDVs - wBattleMonSpecies
1632
call CopyData
1633
ld bc, wPartyMon1DVs - wPartyMon1OTID
1634
add hl, bc
1635
ld de, wBattleMonDVs
1636
ld bc, wPartyMon1PP - wPartyMon1DVs
1637
call CopyData
1638
ld de, wBattleMonPP
1639
ld bc, NUM_MOVES
1640
call CopyData
1641
ld de, wBattleMonLevel
1642
ld bc, wBattleMonPP - wBattleMonLevel
1643
call CopyData
1644
ld a, [wBattleMonSpecies2]
1645
ld [wCurSpecies], a
1646
call GetMonHeader
1647
ld hl, wPartyMonNicks
1648
ld a, [wPlayerMonNumber]
1649
call SkipFixedLengthTextEntries
1650
ld de, wBattleMonNick
1651
ld bc, NAME_LENGTH
1652
call CopyData
1653
ld hl, wBattleMonLevel
1654
ld de, wPlayerMonUnmodifiedLevel ; block of memory used for unmodified stats
1655
ld bc, 1 + NUM_STATS * 2
1656
call CopyData
1657
call ApplyBurnAndParalysisPenaltiesToPlayer
1658
call ApplyBadgeStatBoosts
1659
ld a, $7 ; default stat modifier
1660
ld b, NUM_STAT_MODS
1661
ld hl, wPlayerMonAttackMod
1662
.statModLoop
1663
ld [hli], a
1664
dec b
1665
jr nz, .statModLoop
1666
ret
1667
1668
; copies from enemy party data to current enemy mon data when sending out a new enemy mon
1669
LoadEnemyMonFromParty:
1670
ld a, [wWhichPokemon]
1671
ld bc, wEnemyMon2 - wEnemyMon1
1672
ld hl, wEnemyMons
1673
call AddNTimes
1674
ld de, wEnemyMonSpecies
1675
ld bc, wEnemyMonDVs - wEnemyMonSpecies
1676
call CopyData
1677
ld bc, wEnemyMon1DVs - wEnemyMon1OTID
1678
add hl, bc
1679
ld de, wEnemyMonDVs
1680
ld bc, wEnemyMon1PP - wEnemyMon1DVs
1681
call CopyData
1682
ld de, wEnemyMonPP
1683
ld bc, NUM_MOVES
1684
call CopyData
1685
ld de, wEnemyMonLevel
1686
ld bc, wEnemyMonPP - wEnemyMonLevel
1687
call CopyData
1688
ld a, [wEnemyMonSpecies]
1689
ld [wCurSpecies], a
1690
call GetMonHeader
1691
ld hl, wEnemyMonNicks
1692
ld a, [wWhichPokemon]
1693
call SkipFixedLengthTextEntries
1694
ld de, wEnemyMonNick
1695
ld bc, NAME_LENGTH
1696
call CopyData
1697
ld hl, wEnemyMonLevel
1698
ld de, wEnemyMonUnmodifiedLevel ; block of memory used for unmodified stats
1699
ld bc, 1 + NUM_STATS * 2
1700
call CopyData
1701
call ApplyBurnAndParalysisPenaltiesToEnemy
1702
ld hl, wMonHBaseStats
1703
ld de, wEnemyMonBaseStats
1704
ld b, NUM_STATS
1705
.copyBaseStatsLoop
1706
ld a, [hli]
1707
ld [de], a
1708
inc de
1709
dec b
1710
jr nz, .copyBaseStatsLoop
1711
ld a, $7 ; default stat modifier
1712
ld b, NUM_STAT_MODS
1713
ld hl, wEnemyMonStatMods
1714
.statModLoop
1715
ld [hli], a
1716
dec b
1717
jr nz, .statModLoop
1718
ld a, [wWhichPokemon]
1719
ld [wEnemyMonPartyPos], a
1720
ret
1721
1722
SendOutMon:
1723
callfar PrintSendOutMonMessage
1724
ld hl, wEnemyMonHP
1725
ld a, [hli]
1726
or [hl] ; is enemy mon HP zero?
1727
jp z, .skipDrawingEnemyHUDAndHPBar ; if HP is zero, skip drawing the HUD and HP bar
1728
call DrawEnemyHUDAndHPBar
1729
.skipDrawingEnemyHUDAndHPBar
1730
call DrawPlayerHUDAndHPBar
1731
predef LoadMonBackPic
1732
xor a
1733
ldh [hStartTileID], a
1734
ld hl, wBattleAndStartSavedMenuItem
1735
ld [hli], a
1736
ld [hl], a
1737
ld [wBoostExpByExpAll], a
1738
ld [wDamageMultipliers], a
1739
ld [wPlayerMoveNum], a
1740
ld hl, wPlayerUsedMove
1741
ld [hli], a
1742
ld [hl], a
1743
ld hl, wPlayerStatsToDouble
1744
ld [hli], a
1745
ld [hli], a
1746
ld [hli], a
1747
ld [hli], a
1748
ld [hl], a
1749
ld [wPlayerDisabledMove], a
1750
ld [wPlayerDisabledMoveNumber], a
1751
ld [wPlayerMonMinimized], a
1752
ld b, SET_PAL_BATTLE
1753
call RunPaletteCommand
1754
ld hl, wEnemyBattleStatus1
1755
res USING_TRAPPING_MOVE, [hl]
1756
ld a, $1
1757
ldh [hWhoseTurn], a
1758
ld a, POOF_ANIM
1759
call PlayMoveAnimation
1760
hlcoord 4, 11
1761
predef AnimateSendingOutMon
1762
ld a, [wCurPartySpecies]
1763
call PlayCry
1764
call PrintEmptyString
1765
jp SaveScreenTilesToBuffer1
1766
1767
; show 2 stages of the player mon getting smaller before disappearing
1768
AnimateRetreatingPlayerMon:
1769
hlcoord 1, 5
1770
lb bc, 7, 7
1771
call ClearScreenArea
1772
hlcoord 3, 7
1773
lb bc, 5, 5
1774
xor a
1775
ld [wDownscaledMonSize], a
1776
ldh [hBaseTileID], a
1777
predef CopyDownscaledMonTiles
1778
ld c, 4
1779
call DelayFrames
1780
call .clearScreenArea
1781
hlcoord 4, 9
1782
lb bc, 3, 3
1783
ld a, 1
1784
ld [wDownscaledMonSize], a
1785
xor a
1786
ldh [hBaseTileID], a
1787
predef CopyDownscaledMonTiles
1788
call Delay3
1789
call .clearScreenArea
1790
ld a, $4c
1791
ldcoord_a 5, 11
1792
.clearScreenArea
1793
hlcoord 1, 5
1794
lb bc, 7, 7
1795
jp ClearScreenArea
1796
1797
; Copies player's current pokemon's current HP and status into the party
1798
; struct data so it stays after battle or switching
1799
ReadPlayerMonCurHPAndStatus:
1800
ld a, [wPlayerMonNumber]
1801
ld hl, wPartyMon1HP
1802
ld bc, wPartyMon2 - wPartyMon1
1803
call AddNTimes
1804
ld d, h
1805
ld e, l
1806
ld hl, wBattleMonHP
1807
ld bc, $4 ; 2 bytes HP, 1 byte unknown (unused?), 1 byte status
1808
jp CopyData
1809
1810
DrawHUDsAndHPBars:
1811
call DrawPlayerHUDAndHPBar
1812
jp DrawEnemyHUDAndHPBar
1813
1814
DrawPlayerHUDAndHPBar:
1815
xor a
1816
ldh [hAutoBGTransferEnabled], a
1817
hlcoord 9, 7
1818
lb bc, 5, 11
1819
call ClearScreenArea
1820
callfar PlacePlayerHUDTiles
1821
hlcoord 18, 9
1822
ld [hl], $73
1823
ld de, wBattleMonNick
1824
hlcoord 10, 7
1825
call CenterMonName
1826
call PlaceString
1827
ld hl, wBattleMonSpecies
1828
ld de, wLoadedMon
1829
ld bc, wBattleMonDVs - wBattleMonSpecies
1830
call CopyData
1831
ld hl, wBattleMonLevel
1832
ld de, wLoadedMonLevel
1833
ld bc, wBattleMonPP - wBattleMonLevel
1834
call CopyData
1835
hlcoord 14, 8
1836
push hl
1837
inc hl
1838
ld de, wLoadedMonStatus
1839
call PrintStatusConditionNotFainted
1840
pop hl
1841
jr nz, .doNotPrintLevel
1842
call PrintLevel
1843
.doNotPrintLevel
1844
ld a, [wLoadedMonSpecies]
1845
ld [wCurPartySpecies], a
1846
hlcoord 10, 9
1847
predef DrawHP
1848
ld a, $1
1849
ldh [hAutoBGTransferEnabled], a
1850
ld hl, wPlayerHPBarColor
1851
call GetBattleHealthBarColor
1852
ld hl, wBattleMonHP
1853
ld a, [hli]
1854
or [hl]
1855
jr z, .fainted
1856
ld a, [wLowHealthAlarmDisabled]
1857
and a ; has the alarm been disabled because the player has already won?
1858
ret nz ; if so, return
1859
ld a, [wPlayerHPBarColor]
1860
cp HP_BAR_RED
1861
jr z, .setLowHealthAlarm
1862
.fainted
1863
ld hl, wLowHealthAlarm
1864
bit BIT_LOW_HEALTH_ALARM, [hl]
1865
ld [hl], 0
1866
ret z
1867
xor a
1868
ld [wChannelSoundIDs + CHAN5], a
1869
ret
1870
.setLowHealthAlarm
1871
ld hl, wLowHealthAlarm
1872
set BIT_LOW_HEALTH_ALARM, [hl]
1873
ret
1874
1875
DrawEnemyHUDAndHPBar:
1876
xor a
1877
ldh [hAutoBGTransferEnabled], a
1878
hlcoord 0, 0
1879
lb bc, 4, 12
1880
call ClearScreenArea
1881
callfar PlaceEnemyHUDTiles
1882
ld de, wEnemyMonNick
1883
hlcoord 1, 0
1884
call CenterMonName
1885
call PlaceString
1886
hlcoord 4, 1
1887
push hl
1888
inc hl
1889
ld de, wEnemyMonStatus
1890
call PrintStatusConditionNotFainted
1891
pop hl
1892
jr nz, .skipPrintLevel ; if the mon has a status condition, skip printing the level
1893
ld a, [wEnemyMonLevel]
1894
ld [wLoadedMonLevel], a
1895
call PrintLevel
1896
.skipPrintLevel
1897
ld hl, wEnemyMonHP
1898
ld a, [hli]
1899
ldh [hMultiplicand + 1], a
1900
ld a, [hld]
1901
ldh [hMultiplicand + 2], a
1902
or [hl] ; is current HP zero?
1903
jr nz, .hpNonzero
1904
; current HP is 0
1905
; set variables for DrawHPBar
1906
ld c, a
1907
ld e, a
1908
ld d, $6
1909
jp .drawHPBar
1910
.hpNonzero
1911
xor a
1912
ldh [hMultiplicand], a
1913
ld a, 48
1914
ldh [hMultiplier], a
1915
call Multiply ; multiply current HP by 48
1916
ld hl, wEnemyMonMaxHP
1917
ld a, [hli]
1918
ld b, a
1919
ld a, [hl]
1920
ldh [hDivisor], a
1921
ld a, b
1922
and a ; is max HP > 255?
1923
jr z, .doDivide
1924
; if max HP > 255, scale both (current HP * 48) and max HP by dividing by 4 so that max HP fits in one byte
1925
; (it needs to be one byte so it can be used as the divisor for the Divide function)
1926
ldh a, [hDivisor]
1927
srl b
1928
rr a
1929
srl b
1930
rr a
1931
ldh [hDivisor], a
1932
ldh a, [hProduct + 2]
1933
ld b, a
1934
srl b
1935
ldh a, [hProduct + 3]
1936
rr a
1937
srl b
1938
rr a
1939
ldh [hProduct + 3], a
1940
ld a, b
1941
ldh [hProduct + 2], a
1942
.doDivide
1943
ldh a, [hProduct + 2]
1944
ldh [hDividend], a
1945
ldh a, [hProduct + 3]
1946
ldh [hDividend + 1], a
1947
ld a, $2
1948
ld b, a
1949
call Divide ; divide (current HP * 48) by max HP
1950
ldh a, [hQuotient + 3]
1951
; set variables for DrawHPBar
1952
ld e, a
1953
ld a, $6
1954
ld d, a
1955
ld c, a
1956
.drawHPBar
1957
xor a
1958
ld [wHPBarType], a
1959
hlcoord 2, 2
1960
call DrawHPBar
1961
ld a, $1
1962
ldh [hAutoBGTransferEnabled], a
1963
ld hl, wEnemyHPBarColor
1964
1965
GetBattleHealthBarColor:
1966
ld b, [hl]
1967
call GetHealthBarColor
1968
ld a, [hl]
1969
cp b
1970
ret z
1971
ld b, SET_PAL_BATTLE
1972
jp RunPaletteCommand
1973
1974
; center's mon's name on the battle screen
1975
; if the name is 1 or 2 letters long, it is printed 2 spaces more to the right than usual
1976
; (i.e. for names longer than 4 letters)
1977
; if the name is 3 or 4 letters long, it is printed 1 space more to the right than usual
1978
; (i.e. for names longer than 4 letters)
1979
CenterMonName:
1980
push de
1981
inc hl
1982
inc hl
1983
ld b, $2
1984
.loop
1985
inc de
1986
ld a, [de]
1987
cp "@"
1988
jr z, .done
1989
inc de
1990
ld a, [de]
1991
cp "@"
1992
jr z, .done
1993
dec hl
1994
dec b
1995
jr nz, .loop
1996
.done
1997
pop de
1998
ret
1999
2000
DisplayBattleMenu::
2001
call LoadScreenTilesFromBuffer1 ; restore saved screen
2002
ld a, [wBattleType]
2003
and a
2004
jr nz, .nonstandardbattle
2005
call DrawHUDsAndHPBars
2006
call PrintEmptyString
2007
call SaveScreenTilesToBuffer1
2008
.nonstandardbattle
2009
ld a, [wBattleType]
2010
cp BATTLE_TYPE_SAFARI
2011
ld a, BATTLE_MENU_TEMPLATE
2012
jr nz, .menuselected
2013
ld a, SAFARI_BATTLE_MENU_TEMPLATE
2014
.menuselected
2015
ld [wTextBoxID], a
2016
call DisplayTextBoxID
2017
; handle menu input if it's not the old man tutorial
2018
ld a, [wBattleType]
2019
ASSERT BATTLE_TYPE_OLD_MAN == 1
2020
dec a
2021
jp nz, .handleBattleMenuInput
2022
; the following happens for the old man tutorial
2023
; Temporarily save the player name in wLinkEnemyTrainerName.
2024
; Since wLinkEnemyTrainerName == wGrassRate, this affects wild encounters.
2025
; The wGrassRate byte and following wGrassMons buffer are supposed
2026
; to get overwritten when entering a map with wild Pokémon,
2027
; but an oversight prevents this in Cinnabar and Route 21,
2028
; so the infamous MissingNo. glitch can show up.
2029
ld hl, wPlayerName
2030
ld de, wLinkEnemyTrainerName
2031
ld bc, NAME_LENGTH
2032
call CopyData
2033
ld hl, .oldManName
2034
ld de, wPlayerName
2035
ld bc, NAME_LENGTH
2036
call CopyData
2037
; the following simulates the keystrokes by drawing menus on screen
2038
hlcoord 9, 14
2039
ld [hl], "▶"
2040
ld c, 80
2041
call DelayFrames
2042
ld [hl], " "
2043
hlcoord 9, 16
2044
ld [hl], "▶"
2045
ld c, 50
2046
call DelayFrames
2047
ld [hl], "▷"
2048
ld a, $2 ; select the "ITEM" menu
2049
jp .upperLeftMenuItemWasNotSelected
2050
.oldManName
2051
db "OLD MAN@"
2052
.handleBattleMenuInput
2053
ld a, [wBattleAndStartSavedMenuItem]
2054
ld [wCurrentMenuItem], a
2055
ld [wLastMenuItem], a
2056
sub 2 ; check if the cursor is in the left column
2057
jr c, .leftColumn
2058
; cursor is in the right column
2059
ld [wCurrentMenuItem], a
2060
ld [wLastMenuItem], a
2061
jr .rightColumn
2062
.leftColumn ; put cursor in left column of menu
2063
ld a, [wBattleType]
2064
cp BATTLE_TYPE_SAFARI
2065
ld a, " "
2066
jr z, .safariLeftColumn
2067
; put cursor in left column for normal battle menu (i.e. when it's not a Safari battle)
2068
ldcoord_a 15, 14 ; clear upper cursor position in right column
2069
ldcoord_a 15, 16 ; clear lower cursor position in right column
2070
ld b, $9 ; top menu item X
2071
jr .leftColumn_WaitForInput
2072
.safariLeftColumn
2073
ldcoord_a 13, 14
2074
ldcoord_a 13, 16
2075
hlcoord 7, 14
2076
ld de, wNumSafariBalls
2077
lb bc, 1, 2
2078
call PrintNumber
2079
ld b, $1 ; top menu item X
2080
.leftColumn_WaitForInput
2081
ld hl, wTopMenuItemY
2082
ld a, $e
2083
ld [hli], a ; wTopMenuItemY
2084
ld a, b
2085
ld [hli], a ; wTopMenuItemX
2086
inc hl
2087
inc hl
2088
ld a, $1
2089
ld [hli], a ; wMaxMenuItem
2090
ld [hl], PAD_RIGHT | PAD_A ; wMenuWatchedKeys
2091
call HandleMenuInput
2092
bit B_PAD_RIGHT, a
2093
jr nz, .rightColumn
2094
jr .AButtonPressed ; the A button was pressed
2095
.rightColumn ; put cursor in right column of menu
2096
ld a, [wBattleType]
2097
cp BATTLE_TYPE_SAFARI
2098
ld a, " "
2099
jr z, .safariRightColumn
2100
; put cursor in right column for normal battle menu (i.e. when it's not a Safari battle)
2101
ldcoord_a 9, 14 ; clear upper cursor position in left column
2102
ldcoord_a 9, 16 ; clear lower cursor position in left column
2103
ld b, $f ; top menu item X
2104
jr .rightColumn_WaitForInput
2105
.safariRightColumn
2106
ldcoord_a 1, 14 ; clear upper cursor position in left column
2107
ldcoord_a 1, 16 ; clear lower cursor position in left column
2108
hlcoord 7, 14
2109
ld de, wNumSafariBalls
2110
lb bc, 1, 2
2111
call PrintNumber
2112
ld b, $d ; top menu item X
2113
.rightColumn_WaitForInput
2114
ld hl, wTopMenuItemY
2115
ld a, $e
2116
ld [hli], a ; wTopMenuItemY
2117
ld a, b
2118
ld [hli], a ; wTopMenuItemX
2119
inc hl
2120
inc hl
2121
ld a, $1
2122
ld [hli], a ; wMaxMenuItem
2123
ld a, PAD_LEFT | PAD_A
2124
ld [hli], a ; wMenuWatchedKeys
2125
call HandleMenuInput
2126
bit B_PAD_LEFT, a
2127
jr nz, .leftColumn ; if left was pressed, jump
2128
ld a, [wCurrentMenuItem]
2129
add $2 ; if we're in the right column, the actual id is +2
2130
ld [wCurrentMenuItem], a
2131
.AButtonPressed
2132
call PlaceUnfilledArrowMenuCursor
2133
ld a, [wBattleType]
2134
cp BATTLE_TYPE_SAFARI
2135
ld a, [wCurrentMenuItem]
2136
ld [wBattleAndStartSavedMenuItem], a
2137
jr z, .handleMenuSelection
2138
; not Safari battle
2139
; swap the IDs of the item menu and party menu (this is probably because they swapped the positions
2140
; of these menu items in first generation English versions)
2141
cp $1 ; was the item menu selected?
2142
jr nz, .notItemMenu
2143
; item menu was selected
2144
inc a ; increment a to 2
2145
jr .handleMenuSelection
2146
.notItemMenu
2147
cp $2 ; was the party menu selected?
2148
jr nz, .handleMenuSelection
2149
; party menu selected
2150
dec a ; decrement a to 1
2151
.handleMenuSelection
2152
and a
2153
jr nz, .upperLeftMenuItemWasNotSelected
2154
; the upper left menu item was selected
2155
ld a, [wBattleType]
2156
cp BATTLE_TYPE_SAFARI
2157
jr z, .throwSafariBallWasSelected
2158
; the "FIGHT" menu was selected
2159
xor a
2160
ld [wNumRunAttempts], a
2161
jp LoadScreenTilesFromBuffer1 ; restore saved screen and return
2162
.throwSafariBallWasSelected
2163
ld a, SAFARI_BALL
2164
ld [wCurItem], a
2165
jr UseBagItem
2166
2167
.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected
2168
cp $2
2169
jp nz, PartyMenuOrRockOrRun
2170
2171
; either the bag (normal battle) or bait (safari battle) was selected
2172
ld a, [wLinkState]
2173
cp LINK_STATE_BATTLING
2174
jr nz, .notLinkBattle
2175
2176
; can't use items in link battles
2177
ld hl, ItemsCantBeUsedHereText
2178
call PrintText
2179
jp DisplayBattleMenu
2180
2181
.notLinkBattle
2182
call SaveScreenTilesToBuffer2
2183
ld a, [wBattleType]
2184
cp BATTLE_TYPE_SAFARI
2185
jr nz, BagWasSelected
2186
2187
; bait was selected
2188
ld a, SAFARI_BAIT
2189
ld [wCurItem], a
2190
jr UseBagItem
2191
2192
BagWasSelected:
2193
call LoadScreenTilesFromBuffer1
2194
ld a, [wBattleType]
2195
and a ; is it a normal battle?
2196
jr nz, .next
2197
2198
; normal battle
2199
call DrawHUDsAndHPBars
2200
.next
2201
ld a, [wBattleType]
2202
dec a ; is it the old man tutorial?
2203
jr nz, DisplayPlayerBag ; no, it is a normal battle
2204
ld hl, OldManItemList
2205
ld a, l
2206
ld [wListPointer], a
2207
ld a, h
2208
ld [wListPointer + 1], a
2209
jr DisplayBagMenu
2210
2211
OldManItemList:
2212
db 1 ; # items
2213
db POKE_BALL, 50
2214
db -1 ; end
2215
2216
DisplayPlayerBag:
2217
; get the pointer to player's bag when in a normal battle
2218
ld hl, wNumBagItems
2219
ld a, l
2220
ld [wListPointer], a
2221
ld a, h
2222
ld [wListPointer + 1], a
2223
2224
DisplayBagMenu:
2225
xor a
2226
ld [wPrintItemPrices], a
2227
ld a, ITEMLISTMENU
2228
ld [wListMenuID], a
2229
ld a, [wBagSavedMenuItem]
2230
ld [wCurrentMenuItem], a
2231
call DisplayListMenuID
2232
ld a, [wCurrentMenuItem]
2233
ld [wBagSavedMenuItem], a
2234
ld a, $0
2235
ld [wMenuWatchMovingOutOfBounds], a
2236
ld [wMenuItemToSwap], a
2237
jp c, DisplayBattleMenu ; go back to battle menu if an item was not selected
2238
2239
UseBagItem:
2240
; either use an item from the bag or use a safari zone item
2241
ld a, [wCurItem]
2242
ld [wNamedObjectIndex], a
2243
call GetItemName
2244
call CopyToStringBuffer
2245
xor a
2246
ld [wPseudoItemID], a
2247
call UseItem
2248
call LoadHudTilePatterns
2249
call ClearSprites
2250
xor a
2251
ld [wCurrentMenuItem], a
2252
ld a, [wBattleType]
2253
cp BATTLE_TYPE_SAFARI
2254
jr z, .checkIfMonCaptured
2255
2256
ld a, [wActionResultOrTookBattleTurn]
2257
and a ; was the item used successfully?
2258
jp z, BagWasSelected ; if not, go back to the bag menu
2259
2260
ld a, [wPlayerBattleStatus1]
2261
bit USING_TRAPPING_MOVE, a ; is the player using a multi-turn move like wrap?
2262
jr z, .checkIfMonCaptured
2263
ld hl, wPlayerNumAttacksLeft
2264
dec [hl]
2265
jr nz, .checkIfMonCaptured
2266
ld hl, wPlayerBattleStatus1
2267
res USING_TRAPPING_MOVE, [hl] ; not using multi-turn move any more
2268
2269
.checkIfMonCaptured
2270
ld a, [wCapturedMonSpecies]
2271
and a ; was the enemy mon captured with a ball?
2272
jr nz, .returnAfterCapturingMon
2273
2274
ld a, [wBattleType]
2275
cp BATTLE_TYPE_SAFARI
2276
jr z, .returnAfterUsingItem_NoCapture
2277
; not a safari battle
2278
call LoadScreenTilesFromBuffer1
2279
call DrawHUDsAndHPBars
2280
call Delay3
2281
.returnAfterUsingItem_NoCapture
2282
2283
call GBPalNormal
2284
and a ; reset carry
2285
ret
2286
2287
.returnAfterCapturingMon
2288
call GBPalNormal
2289
xor a
2290
ld [wCapturedMonSpecies], a
2291
ld a, $2
2292
ld [wBattleResult], a
2293
scf ; set carry
2294
ret
2295
2296
ItemsCantBeUsedHereText:
2297
text_far _ItemsCantBeUsedHereText
2298
text_end
2299
2300
PartyMenuOrRockOrRun:
2301
dec a ; was Run selected?
2302
jp nz, BattleMenu_RunWasSelected
2303
; party menu or rock was selected
2304
call SaveScreenTilesToBuffer2
2305
ld a, [wBattleType]
2306
cp BATTLE_TYPE_SAFARI
2307
jr nz, .partyMenuWasSelected
2308
; safari battle
2309
ld a, SAFARI_ROCK
2310
ld [wCurItem], a
2311
jp UseBagItem
2312
.partyMenuWasSelected
2313
call LoadScreenTilesFromBuffer1
2314
xor a ; NORMAL_PARTY_MENU
2315
ld [wPartyMenuTypeOrMessageID], a
2316
ld [wMenuItemToSwap], a
2317
call DisplayPartyMenu
2318
.checkIfPartyMonWasSelected
2319
jp nc, .partyMonWasSelected ; if a party mon was selected, jump, else we quit the party menu
2320
.quitPartyMenu
2321
call ClearSprites
2322
call GBPalWhiteOut
2323
call LoadHudTilePatterns
2324
call LoadScreenTilesFromBuffer2
2325
call RunDefaultPaletteCommand
2326
call GBPalNormal
2327
jp DisplayBattleMenu
2328
.partyMonDeselected
2329
hlcoord 11, 11
2330
ld bc, 6 * SCREEN_WIDTH + 9
2331
ld a, " "
2332
call FillMemory
2333
xor a ; NORMAL_PARTY_MENU
2334
ld [wPartyMenuTypeOrMessageID], a
2335
call GoBackToPartyMenu
2336
jr .checkIfPartyMonWasSelected
2337
.partyMonWasSelected
2338
ld a, SWITCH_STATS_CANCEL_MENU_TEMPLATE
2339
ld [wTextBoxID], a
2340
call DisplayTextBoxID
2341
ld hl, wTopMenuItemY
2342
ld a, $c
2343
ld [hli], a ; wTopMenuItemY
2344
ld [hli], a ; wTopMenuItemX
2345
xor a
2346
ld [hli], a ; wCurrentMenuItem
2347
inc hl
2348
ld a, $2
2349
ld [hli], a ; wMaxMenuItem
2350
ld a, PAD_B | PAD_A
2351
ld [hli], a ; wMenuWatchedKeys
2352
xor a
2353
ld [hl], a ; wLastMenuItem
2354
call HandleMenuInput
2355
bit B_PAD_B, a
2356
jr nz, .partyMonDeselected ; if B was pressed, jump
2357
; A was pressed
2358
call PlaceUnfilledArrowMenuCursor
2359
ld a, [wCurrentMenuItem]
2360
cp $2 ; was Cancel selected?
2361
jr z, .quitPartyMenu ; if so, quit the party menu entirely
2362
and a ; was Switch selected?
2363
jr z, .switchMon ; if so, jump
2364
; Stats was selected
2365
xor a ; PLAYER_PARTY_DATA
2366
ld [wMonDataLocation], a
2367
ld hl, wPartyMon1
2368
call ClearSprites
2369
; display the two status screens
2370
predef StatusScreen
2371
predef StatusScreen2
2372
; now we need to reload the enemy mon pic
2373
ld a, [wEnemyBattleStatus2]
2374
bit HAS_SUBSTITUTE_UP, a ; does the enemy mon have a substitute?
2375
ld hl, AnimationSubstitute
2376
jr nz, .doEnemyMonAnimation
2377
; enemy mon doesn't have substitute
2378
ld a, [wEnemyMonMinimized]
2379
and a ; has the enemy mon used Minimize?
2380
ld hl, AnimationMinimizeMon
2381
jr nz, .doEnemyMonAnimation
2382
; enemy mon is not minimized
2383
ld a, [wEnemyMonSpecies]
2384
ld [wCurPartySpecies], a
2385
ld [wCurSpecies], a
2386
call GetMonHeader
2387
ld de, vFrontPic
2388
call LoadMonFrontSprite
2389
jr .enemyMonPicReloaded
2390
.doEnemyMonAnimation
2391
ld b, BANK(AnimationSubstitute) ; BANK(AnimationMinimizeMon)
2392
call Bankswitch
2393
.enemyMonPicReloaded ; enemy mon pic has been reloaded, so return to the party menu
2394
jp .partyMenuWasSelected
2395
.switchMon
2396
ld a, [wPlayerMonNumber]
2397
ld d, a
2398
ld a, [wWhichPokemon]
2399
cp d ; check if the mon to switch to is already out
2400
jr nz, .notAlreadyOut
2401
; mon is already out
2402
ld hl, AlreadyOutText
2403
call PrintText
2404
jp .partyMonDeselected
2405
.notAlreadyOut
2406
call HasMonFainted
2407
jp z, .partyMonDeselected ; can't switch to fainted mon
2408
ld a, $1
2409
ld [wActionResultOrTookBattleTurn], a
2410
call GBPalWhiteOut
2411
call ClearSprites
2412
call LoadHudTilePatterns
2413
call LoadScreenTilesFromBuffer1
2414
call RunDefaultPaletteCommand
2415
call GBPalNormal
2416
; fall through to SwitchPlayerMon
2417
2418
SwitchPlayerMon:
2419
callfar RetreatMon
2420
ld c, 50
2421
call DelayFrames
2422
call AnimateRetreatingPlayerMon
2423
ld a, [wWhichPokemon]
2424
ld [wPlayerMonNumber], a
2425
ld c, a
2426
ld b, FLAG_SET
2427
push bc
2428
ld hl, wPartyGainExpFlags
2429
predef FlagActionPredef
2430
pop bc
2431
ld hl, wPartyFoughtCurrentEnemyFlags
2432
predef FlagActionPredef
2433
call LoadBattleMonFromParty
2434
call SendOutMon
2435
call SaveScreenTilesToBuffer1
2436
ld a, $2
2437
ld [wCurrentMenuItem], a
2438
and a
2439
ret
2440
2441
AlreadyOutText:
2442
text_far _AlreadyOutText
2443
text_end
2444
2445
BattleMenu_RunWasSelected:
2446
call LoadScreenTilesFromBuffer1
2447
ld a, $3
2448
ld [wCurrentMenuItem], a
2449
ld hl, wBattleMonSpeed
2450
ld de, wEnemyMonSpeed
2451
call TryRunningFromBattle
2452
ld a, 0
2453
ld [wForcePlayerToChooseMon], a
2454
ret c
2455
ld a, [wActionResultOrTookBattleTurn]
2456
and a
2457
ret nz ; return if the player couldn't escape
2458
jp DisplayBattleMenu
2459
2460
MoveSelectionMenu:
2461
ld a, [wMoveMenuType]
2462
dec a
2463
jr z, .mimicmenu
2464
dec a
2465
jr z, .relearnmenu
2466
jr .regularmenu
2467
2468
.loadmoves
2469
ld de, wMoves
2470
ld bc, NUM_MOVES
2471
call CopyData
2472
callfar FormatMovesString
2473
ret
2474
2475
.writemoves
2476
ld de, wMovesString
2477
ldh a, [hUILayoutFlags]
2478
set BIT_SINGLE_SPACED_LINES, a
2479
ldh [hUILayoutFlags], a
2480
call PlaceString
2481
ldh a, [hUILayoutFlags]
2482
res BIT_SINGLE_SPACED_LINES, a
2483
ldh [hUILayoutFlags], a
2484
ret
2485
2486
.regularmenu
2487
call AnyMoveToSelect
2488
ret z
2489
ld hl, wBattleMonMoves
2490
call .loadmoves
2491
hlcoord 4, 12
2492
ld b, 4
2493
ld c, 14
2494
di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
2495
; so it is necessary to put the di ei block to not cause tearing
2496
call TextBoxBorder
2497
hlcoord 4, 12
2498
ld [hl], "─"
2499
hlcoord 10, 12
2500
ld [hl], "┘"
2501
ei
2502
hlcoord 6, 13
2503
call .writemoves
2504
ld b, $5
2505
ld a, $c
2506
jr .menuset
2507
.mimicmenu
2508
ld hl, wEnemyMonMoves
2509
call .loadmoves
2510
hlcoord 0, 7
2511
ld b, 4
2512
ld c, 14
2513
call TextBoxBorder
2514
hlcoord 2, 8
2515
call .writemoves
2516
ld b, $1
2517
ld a, $7
2518
jr .menuset
2519
.relearnmenu
2520
ld a, [wWhichPokemon]
2521
ld hl, wPartyMon1Moves
2522
ld bc, wPartyMon2 - wPartyMon1
2523
call AddNTimes
2524
call .loadmoves
2525
hlcoord 4, 7
2526
ld b, 4
2527
ld c, 14
2528
call TextBoxBorder
2529
hlcoord 6, 8
2530
call .writemoves
2531
ld b, $5
2532
ld a, $7
2533
.menuset
2534
ld hl, wTopMenuItemY
2535
ld [hli], a ; wTopMenuItemY
2536
ld a, b
2537
ld [hli], a ; wTopMenuItemX
2538
ld a, [wMoveMenuType]
2539
cp $1
2540
jr z, .selectedmoveknown
2541
ld a, $1
2542
jr nc, .selectedmoveknown
2543
ld a, [wPlayerMoveListIndex]
2544
inc a
2545
.selectedmoveknown
2546
ld [hli], a ; wCurrentMenuItem
2547
inc hl ; wTileBehindCursor untouched
2548
ld a, [wNumMovesMinusOne]
2549
inc a
2550
inc a
2551
ld [hli], a ; wMaxMenuItem
2552
ld a, [wMoveMenuType]
2553
dec a
2554
ld b, PAD_UP | PAD_DOWN | PAD_A
2555
jr z, .matchedkeyspicked
2556
dec a
2557
ld b, PAD_UP | PAD_DOWN | PAD_A | PAD_B
2558
jr z, .matchedkeyspicked
2559
ld a, [wLinkState]
2560
cp LINK_STATE_BATTLING
2561
jr z, .matchedkeyspicked
2562
; Disable left, right, and START buttons in regular battles.
2563
ld a, [wStatusFlags7]
2564
bit BIT_TEST_BATTLE, a
2565
ld b, ~(PAD_LEFT | PAD_RIGHT | PAD_START)
2566
jr z, .matchedkeyspicked
2567
ld b, PAD_CTRL_PAD | PAD_BUTTONS
2568
.matchedkeyspicked
2569
ld a, b
2570
ld [hli], a ; wMenuWatchedKeys
2571
ld a, [wMoveMenuType]
2572
cp $1
2573
jr z, .movelistindex1
2574
ld a, [wPlayerMoveListIndex]
2575
inc a
2576
.movelistindex1
2577
ld [hl], a
2578
; fallthrough
2579
2580
SelectMenuItem:
2581
ld a, [wMoveMenuType]
2582
and a
2583
jr z, .battleselect
2584
dec a
2585
jr nz, .select
2586
hlcoord 1, 14
2587
ld de, WhichTechniqueString
2588
call PlaceString
2589
jr .select
2590
.battleselect
2591
; Hide move swap cursor in TestBattle.
2592
ld a, [wStatusFlags7]
2593
bit BIT_TEST_BATTLE, a
2594
; This causes PrintMenuItem to not run in TestBattle.
2595
; MoveSelectionMenu still draws part of its window, an issue
2596
; which did not seem to exist in the Japanese versions.
2597
jr nz, .select
2598
call PrintMenuItem
2599
ld a, [wMenuItemToSwap]
2600
and a
2601
jr z, .select
2602
hlcoord 5, 13
2603
dec a
2604
ld bc, SCREEN_WIDTH
2605
call AddNTimes
2606
ld [hl], "▷"
2607
.select
2608
ld hl, hUILayoutFlags
2609
set BIT_DOUBLE_SPACED_MENU, [hl]
2610
call HandleMenuInput
2611
ld hl, hUILayoutFlags
2612
res BIT_DOUBLE_SPACED_MENU, [hl]
2613
bit B_PAD_UP, a
2614
jp nz, SelectMenuItem_CursorUp
2615
bit B_PAD_DOWN, a
2616
jp nz, SelectMenuItem_CursorDown
2617
bit B_PAD_SELECT, a
2618
jp nz, SwapMovesInMenu
2619
bit B_PAD_B, a
2620
push af
2621
xor a
2622
ld [wMenuItemToSwap], a
2623
ld a, [wCurrentMenuItem]
2624
dec a
2625
ld [wCurrentMenuItem], a
2626
ld b, a
2627
ld a, [wMoveMenuType]
2628
dec a ; if not mimic
2629
jr nz, .notB
2630
pop af
2631
ret
2632
.notB
2633
dec a
2634
ld a, b
2635
ld [wPlayerMoveListIndex], a
2636
jr nz, .moveselected
2637
pop af
2638
ret
2639
.moveselected
2640
pop af
2641
ret nz
2642
ld hl, wBattleMonPP
2643
ld a, [wCurrentMenuItem]
2644
ld c, a
2645
ld b, $0
2646
add hl, bc
2647
ld a, [hl]
2648
and PP_MASK
2649
jr z, .noPP
2650
ld a, [wPlayerDisabledMove]
2651
swap a
2652
and $f
2653
dec a
2654
cp c
2655
jr z, .disabled
2656
ld a, [wPlayerBattleStatus3]
2657
bit TRANSFORMED, a
2658
jr nz, .transformedMoveSelected
2659
.transformedMoveSelected ; pointless
2660
; Allow moves copied by Transform to be used.
2661
ld a, [wCurrentMenuItem]
2662
ld hl, wBattleMonMoves
2663
ld c, a
2664
ld b, $0
2665
add hl, bc
2666
ld a, [hl]
2667
ld [wPlayerSelectedMove], a
2668
xor a
2669
ret
2670
.disabled
2671
ld hl, MoveDisabledText
2672
jr .print
2673
.noPP
2674
ld hl, MoveNoPPText
2675
.print
2676
call PrintText
2677
call LoadScreenTilesFromBuffer1
2678
jp MoveSelectionMenu
2679
2680
MoveNoPPText:
2681
text_far _MoveNoPPText
2682
text_end
2683
2684
MoveDisabledText:
2685
text_far _MoveDisabledText
2686
text_end
2687
2688
WhichTechniqueString:
2689
db "WHICH TECHNIQUE?@"
2690
2691
SelectMenuItem_CursorUp:
2692
ld a, [wCurrentMenuItem]
2693
and a
2694
jp nz, SelectMenuItem
2695
call EraseMenuCursor
2696
ld a, [wNumMovesMinusOne]
2697
inc a
2698
ld [wCurrentMenuItem], a
2699
jp SelectMenuItem
2700
2701
SelectMenuItem_CursorDown:
2702
ld a, [wCurrentMenuItem]
2703
ld b, a
2704
ld a, [wNumMovesMinusOne]
2705
inc a
2706
inc a
2707
cp b
2708
jp nz, SelectMenuItem
2709
call EraseMenuCursor
2710
ld a, $1
2711
ld [wCurrentMenuItem], a
2712
jp SelectMenuItem
2713
2714
AnyMoveToSelect:
2715
; return z and Struggle as the selected move if all moves have 0 PP and/or are disabled
2716
ld a, STRUGGLE
2717
ld [wPlayerSelectedMove], a
2718
ld a, [wPlayerDisabledMove]
2719
and a
2720
ld hl, wBattleMonPP
2721
jr nz, .handleDisabledMove
2722
ld a, [hli]
2723
or [hl]
2724
inc hl
2725
or [hl]
2726
inc hl
2727
or [hl]
2728
and PP_MASK
2729
ret nz
2730
jr .noMovesLeft
2731
.handleDisabledMove
2732
swap a
2733
and $f ; get disabled move
2734
ld b, a
2735
ld d, NUM_MOVES + 1
2736
xor a
2737
.handleDisabledMovePPLoop
2738
dec d
2739
jr z, .allMovesChecked
2740
ld c, [hl] ; get move PP
2741
inc hl
2742
dec b ; is this the disabled move?
2743
jr z, .handleDisabledMovePPLoop ; if so, ignore its PP value
2744
or c
2745
jr .handleDisabledMovePPLoop
2746
.allMovesChecked
2747
and a ; any PP left?
2748
ret nz ; return if a move has PP left
2749
.noMovesLeft
2750
ld hl, NoMovesLeftText
2751
call PrintText
2752
ld c, 60
2753
call DelayFrames
2754
xor a
2755
ret
2756
2757
NoMovesLeftText:
2758
text_far _NoMovesLeftText
2759
text_end
2760
2761
SwapMovesInMenu:
2762
ld a, [wMenuItemToSwap]
2763
and a
2764
jr z, .noMenuItemSelected
2765
ld hl, wBattleMonMoves
2766
call .swapBytes ; swap moves
2767
ld hl, wBattleMonPP
2768
call .swapBytes ; swap move PP
2769
; update the index of the disabled move if necessary
2770
ld hl, wPlayerDisabledMove
2771
ld a, [hl]
2772
swap a
2773
and $f
2774
ld b, a
2775
ld a, [wCurrentMenuItem]
2776
cp b
2777
jr nz, .next
2778
ld a, [hl]
2779
and $f
2780
ld b, a
2781
ld a, [wMenuItemToSwap]
2782
swap a
2783
add b
2784
ld [hl], a
2785
jr .swapMovesInPartyMon
2786
.next
2787
ld a, [wMenuItemToSwap]
2788
cp b
2789
jr nz, .swapMovesInPartyMon
2790
ld a, [hl]
2791
and $f
2792
ld b, a
2793
ld a, [wCurrentMenuItem]
2794
swap a
2795
add b
2796
ld [hl], a
2797
.swapMovesInPartyMon
2798
ld hl, wPartyMon1Moves
2799
ld a, [wPlayerMonNumber]
2800
ld bc, wPartyMon2 - wPartyMon1
2801
call AddNTimes
2802
push hl
2803
call .swapBytes ; swap moves
2804
pop hl
2805
ld bc, wPartyMon1PP - wPartyMon1Moves
2806
add hl, bc
2807
call .swapBytes ; swap move PP
2808
xor a
2809
ld [wMenuItemToSwap], a ; deselect the item
2810
jp MoveSelectionMenu
2811
.swapBytes
2812
push hl
2813
ld a, [wMenuItemToSwap]
2814
dec a
2815
ld c, a
2816
ld b, 0
2817
add hl, bc
2818
ld d, h
2819
ld e, l
2820
pop hl
2821
ld a, [wCurrentMenuItem]
2822
dec a
2823
ld c, a
2824
ld b, 0
2825
add hl, bc
2826
ld a, [de]
2827
ld b, [hl]
2828
ld [hl], a
2829
ld a, b
2830
ld [de], a
2831
ret
2832
.noMenuItemSelected
2833
ld a, [wCurrentMenuItem]
2834
ld [wMenuItemToSwap], a ; select the current menu item for swapping
2835
jp MoveSelectionMenu
2836
2837
PrintMenuItem:
2838
xor a
2839
ldh [hAutoBGTransferEnabled], a
2840
hlcoord 0, 8
2841
ld b, 3
2842
ld c, 9
2843
call TextBoxBorder
2844
ld a, [wPlayerDisabledMove]
2845
and a
2846
jr z, .notDisabled
2847
swap a
2848
and $f
2849
ld b, a
2850
ld a, [wCurrentMenuItem]
2851
cp b
2852
jr nz, .notDisabled
2853
hlcoord 1, 10
2854
ld de, DisabledText
2855
call PlaceString
2856
jr .moveDisabled
2857
.notDisabled
2858
ld hl, wCurrentMenuItem
2859
dec [hl]
2860
xor a
2861
ldh [hWhoseTurn], a
2862
ld hl, wBattleMonMoves
2863
ld a, [wCurrentMenuItem]
2864
ld c, a
2865
ld b, $0 ; which item in the menu is the cursor pointing to? (0-3)
2866
add hl, bc ; point to the item (move) in memory
2867
ld a, [hl]
2868
ld [wPlayerSelectedMove], a ; update wPlayerSelectedMove even if the move
2869
; isn't actually selected (just pointed to by the cursor)
2870
ld a, [wPlayerMonNumber]
2871
ld [wWhichPokemon], a
2872
ld a, BATTLE_MON_DATA
2873
ld [wMonDataLocation], a
2874
callfar GetMaxPP
2875
ld hl, wCurrentMenuItem
2876
ld c, [hl]
2877
inc [hl]
2878
ld b, $0
2879
ld hl, wBattleMonPP
2880
add hl, bc
2881
ld a, [hl]
2882
and PP_MASK
2883
ld [wBattleMenuCurrentPP], a
2884
; print TYPE/<type> and <curPP>/<maxPP>
2885
hlcoord 1, 9
2886
ld de, TypeText
2887
call PlaceString
2888
hlcoord 7, 11
2889
ld [hl], "/"
2890
hlcoord 5, 9
2891
ld [hl], "/"
2892
hlcoord 5, 11
2893
ld de, wBattleMenuCurrentPP
2894
lb bc, 1, 2
2895
call PrintNumber
2896
hlcoord 8, 11
2897
ld de, wMaxPP
2898
lb bc, 1, 2
2899
call PrintNumber
2900
call GetCurrentMove
2901
hlcoord 2, 10
2902
predef PrintMoveType
2903
.moveDisabled
2904
ld a, $1
2905
ldh [hAutoBGTransferEnabled], a
2906
jp Delay3
2907
2908
DisabledText:
2909
db "disabled!@"
2910
2911
TypeText:
2912
db "TYPE@"
2913
2914
SelectEnemyMove:
2915
ld a, [wLinkState]
2916
sub LINK_STATE_BATTLING
2917
jr nz, .noLinkBattle
2918
; link battle
2919
call SaveScreenTilesToBuffer1
2920
call LinkBattleExchangeData
2921
call LoadScreenTilesFromBuffer1
2922
ld a, [wSerialExchangeNybbleReceiveData]
2923
cp LINKBATTLE_STRUGGLE
2924
jp z, .linkedOpponentUsedStruggle
2925
cp LINKBATTLE_NO_ACTION
2926
jr z, .unableToSelectMove
2927
cp 4
2928
ret nc
2929
ld [wEnemyMoveListIndex], a
2930
ld c, a
2931
ld hl, wEnemyMonMoves
2932
ld b, 0
2933
add hl, bc
2934
ld a, [hl]
2935
jr .done
2936
.noLinkBattle
2937
ld a, [wEnemyBattleStatus2]
2938
and (1 << NEEDS_TO_RECHARGE) | (1 << USING_RAGE) ; need to recharge or using rage
2939
ret nz
2940
ld hl, wEnemyBattleStatus1
2941
ld a, [hl]
2942
and (1 << CHARGING_UP) | (1 << THRASHING_ABOUT) ; using a charging move or thrash/petal dance
2943
ret nz
2944
ld a, [wEnemyMonStatus]
2945
and (1 << FRZ) | SLP_MASK
2946
ret nz
2947
ld a, [wEnemyBattleStatus1]
2948
and (1 << USING_TRAPPING_MOVE) | (1 << STORING_ENERGY) ; using a trapping move like wrap or bide
2949
ret nz
2950
ld a, [wPlayerBattleStatus1]
2951
bit USING_TRAPPING_MOVE, a ; caught in player's trapping move (e.g. wrap)
2952
jr z, .canSelectMove
2953
.unableToSelectMove
2954
ld a, $ff
2955
jr .done
2956
.canSelectMove
2957
ld hl, wEnemyMonMoves+1 ; 2nd enemy move
2958
ld a, [hld]
2959
and a
2960
jr nz, .atLeastTwoMovesAvailable
2961
ld a, [wEnemyDisabledMove]
2962
and a
2963
ld a, STRUGGLE ; struggle if the only move is disabled
2964
jr nz, .done
2965
.atLeastTwoMovesAvailable
2966
ld a, [wIsInBattle]
2967
dec a
2968
jr z, .chooseRandomMove ; wild encounter
2969
callfar AIEnemyTrainerChooseMoves
2970
.chooseRandomMove
2971
push hl
2972
call BattleRandom
2973
ld b, 1 ; 25% chance to select move 1
2974
cp 25 percent
2975
jr c, .moveChosen
2976
inc hl
2977
inc b ; 25% chance to select move 2
2978
cp 50 percent
2979
jr c, .moveChosen
2980
inc hl
2981
inc b ; 25% chance to select move 3
2982
cp 75 percent - 1
2983
jr c, .moveChosen
2984
inc hl
2985
inc b ; 25% chance to select move 4
2986
.moveChosen
2987
ld a, b
2988
dec a
2989
ld [wEnemyMoveListIndex], a
2990
ld a, [wEnemyDisabledMove]
2991
swap a
2992
and $f
2993
cp b
2994
ld a, [hl]
2995
pop hl
2996
jr z, .chooseRandomMove ; move disabled, try again
2997
and a
2998
jr z, .chooseRandomMove ; move non-existent, try again
2999
.done
3000
ld [wEnemySelectedMove], a
3001
ret
3002
.linkedOpponentUsedStruggle
3003
ld a, STRUGGLE
3004
jr .done
3005
3006
; this appears to exchange data with the other gameboy during link battles
3007
LinkBattleExchangeData:
3008
ld a, $ff
3009
ld [wSerialExchangeNybbleReceiveData], a
3010
ld a, [wPlayerMoveListIndex]
3011
cp LINKBATTLE_RUN ; is the player running from battle?
3012
jr z, .doExchange
3013
ld a, [wActionResultOrTookBattleTurn]
3014
and a ; is the player switching in another mon?
3015
jr nz, .switching
3016
; the player used a move
3017
ld a, [wPlayerSelectedMove]
3018
cp STRUGGLE
3019
ld b, LINKBATTLE_STRUGGLE
3020
jr z, .next
3021
dec b ; LINKBATTLE_NO_ACTION
3022
ASSERT CANNOT_MOVE == $ff
3023
inc a
3024
jr z, .next
3025
ld a, [wPlayerMoveListIndex]
3026
jr .doExchange
3027
.switching
3028
ld a, [wWhichPokemon]
3029
add 4
3030
ld b, a
3031
.next
3032
ld a, b
3033
.doExchange
3034
ld [wSerialExchangeNybbleSendData], a
3035
vc_hook Wireless_start_exchange
3036
callfar PrintWaitingText
3037
.syncLoop1
3038
call Serial_ExchangeNybble
3039
call DelayFrame
3040
ld a, [wSerialExchangeNybbleReceiveData]
3041
inc a
3042
jr z, .syncLoop1
3043
vc_hook Wireless_end_exchange
3044
vc_patch Wireless_net_delay_1
3045
IF DEF(_RED_VC) || DEF(_BLUE_VC)
3046
ld b, 26
3047
ELSE
3048
ld b, 10
3049
ENDC
3050
vc_patch_end
3051
.syncLoop2
3052
call DelayFrame
3053
call Serial_ExchangeNybble
3054
dec b
3055
jr nz, .syncLoop2
3056
vc_hook Wireless_start_send_zero_bytes
3057
vc_patch Wireless_net_delay_2
3058
IF DEF(_RED_VC) || DEF(_BLUE_VC)
3059
ld b, 26
3060
ELSE
3061
ld b, 10
3062
ENDC
3063
vc_patch_end
3064
.syncLoop3
3065
call DelayFrame
3066
call Serial_SendZeroByte
3067
dec b
3068
jr nz, .syncLoop3
3069
vc_hook Wireless_end_send_zero_bytes
3070
ret
3071
3072
ExecutePlayerMove:
3073
xor a
3074
ldh [hWhoseTurn], a ; set player's turn
3075
ld a, [wPlayerSelectedMove]
3076
ASSERT CANNOT_MOVE == $ff
3077
inc a
3078
jp z, ExecutePlayerMoveDone ; if the player cannot move, skip most of their turn
3079
xor a
3080
ld [wMoveMissed], a
3081
ld [wMonIsDisobedient], a
3082
ld [wMoveDidntMiss], a
3083
ld a, EFFECTIVE
3084
ld [wDamageMultipliers], a
3085
ld a, [wActionResultOrTookBattleTurn]
3086
and a ; has the player already used the turn (e.g. by using an item, trying to run or switching pokemon)
3087
jp nz, ExecutePlayerMoveDone
3088
call PrintGhostText
3089
jp z, ExecutePlayerMoveDone
3090
call CheckPlayerStatusConditions
3091
jr nz, .playerHasNoSpecialCondition
3092
jp hl
3093
.playerHasNoSpecialCondition
3094
call GetCurrentMove
3095
ld hl, wPlayerBattleStatus1
3096
bit CHARGING_UP, [hl] ; charging up for attack
3097
jr nz, PlayerCanExecuteChargingMove
3098
call CheckForDisobedience
3099
jp z, ExecutePlayerMoveDone
3100
3101
CheckIfPlayerNeedsToChargeUp:
3102
ld a, [wPlayerMoveEffect]
3103
cp CHARGE_EFFECT
3104
jp z, JumpMoveEffect
3105
cp FLY_EFFECT
3106
jp z, JumpMoveEffect
3107
jr PlayerCanExecuteMove
3108
3109
; in-battle stuff
3110
PlayerCanExecuteChargingMove:
3111
ld hl, wPlayerBattleStatus1
3112
res CHARGING_UP, [hl] ; reset charging up and invulnerability statuses if mon was charging up for an attack
3113
; being fully paralyzed or hurting oneself in confusion removes charging up status
3114
; resulting in the Pokemon being invulnerable for the whole battle
3115
res INVULNERABLE, [hl]
3116
PlayerCanExecuteMove:
3117
call PrintMonName1Text
3118
ld hl, DecrementPP
3119
ld de, wPlayerSelectedMove ; pointer to the move just used
3120
ld b, BANK(DecrementPP)
3121
call Bankswitch
3122
ld a, [wPlayerMoveEffect] ; effect of the move just used
3123
ld hl, ResidualEffects1
3124
ld de, 1
3125
call IsInArray
3126
jp c, JumpMoveEffect ; ResidualEffects1 moves skip damage calculation and accuracy tests
3127
; unless executed as part of their exclusive effect functions
3128
ld a, [wPlayerMoveEffect]
3129
ld hl, SpecialEffectsCont
3130
ld de, 1
3131
call IsInArray
3132
call c, JumpMoveEffect ; execute the effects of SpecialEffectsCont moves (e.g. Wrap, Thrash) but don't skip anything
3133
PlayerCalcMoveDamage:
3134
ld a, [wPlayerMoveEffect]
3135
ld hl, SetDamageEffects
3136
ld de, 1
3137
call IsInArray
3138
jp c, .moveHitTest ; SetDamageEffects moves (e.g. Seismic Toss and Super Fang) skip damage calculation
3139
call CriticalHitTest
3140
call HandleCounterMove
3141
jr z, HandleIfPlayerMoveMissed
3142
call GetDamageVarsForPlayerAttack
3143
call CalculateDamage
3144
jp z, PlayerCheckIfFlyOrChargeEffect ; for moves with 0 BP, skip any further damage calculation and, for now, skip MoveHitTest
3145
; for these moves, accuracy tests will only occur if they are called as part of the effect itself
3146
call AdjustDamageForMoveType
3147
call RandomizeDamage
3148
.moveHitTest
3149
call MoveHitTest
3150
HandleIfPlayerMoveMissed:
3151
ld a, [wMoveMissed]
3152
and a
3153
jr z, GetPlayerAnimationType
3154
ld a, [wPlayerMoveEffect]
3155
sub EXPLODE_EFFECT
3156
jr z, PlayPlayerMoveAnimation ; don't play any animation if the move missed, unless it was EXPLODE_EFFECT
3157
jr PlayerCheckIfFlyOrChargeEffect
3158
GetPlayerAnimationType:
3159
ld a, [wPlayerMoveEffect]
3160
and a
3161
ld a, ANIMATIONTYPE_BLINK_ENEMY_MON_SPRITE ; move has no effect other than dealing damage
3162
jr z, PlayPlayerMoveAnimation
3163
ld a, ANIMATIONTYPE_SHAKE_SCREEN_HORIZONTALLY_LIGHT ; move has effect
3164
PlayPlayerMoveAnimation:
3165
push af
3166
ld a, [wPlayerBattleStatus2]
3167
bit HAS_SUBSTITUTE_UP, a
3168
ld hl, HideSubstituteShowMonAnim
3169
ld b, BANK(HideSubstituteShowMonAnim)
3170
call nz, Bankswitch
3171
pop af
3172
ld [wAnimationType], a
3173
ld a, [wPlayerMoveNum]
3174
call PlayMoveAnimation
3175
call HandleExplodingAnimation
3176
call DrawPlayerHUDAndHPBar
3177
ld a, [wPlayerBattleStatus2]
3178
bit HAS_SUBSTITUTE_UP, a
3179
ld hl, ReshowSubstituteAnim
3180
ld b, BANK(ReshowSubstituteAnim)
3181
call nz, Bankswitch
3182
jr MirrorMoveCheck
3183
PlayerCheckIfFlyOrChargeEffect:
3184
ld c, 30
3185
call DelayFrames
3186
ld a, [wPlayerMoveEffect]
3187
cp FLY_EFFECT
3188
jr z, .playAnim
3189
cp CHARGE_EFFECT
3190
jr z, .playAnim
3191
jr MirrorMoveCheck
3192
.playAnim
3193
xor a
3194
ld [wAnimationType], a
3195
ld a, STATUS_AFFECTED_ANIM
3196
call PlayMoveAnimation
3197
MirrorMoveCheck:
3198
ld a, [wPlayerMoveEffect]
3199
cp MIRROR_MOVE_EFFECT
3200
jr nz, .metronomeCheck
3201
call MirrorMoveCopyMove
3202
jp z, ExecutePlayerMoveDone
3203
xor a
3204
ld [wMonIsDisobedient], a
3205
jp CheckIfPlayerNeedsToChargeUp ; if Mirror Move was successful go back to damage calculation for copied move
3206
.metronomeCheck
3207
cp METRONOME_EFFECT
3208
jr nz, .next
3209
call MetronomePickMove
3210
jp CheckIfPlayerNeedsToChargeUp ; Go back to damage calculation for the move picked by Metronome
3211
.next
3212
ld a, [wPlayerMoveEffect]
3213
ld hl, ResidualEffects2
3214
ld de, 1
3215
call IsInArray
3216
jp c, JumpMoveEffect ; done here after executing effects of ResidualEffects2
3217
ld a, [wMoveMissed]
3218
and a
3219
jr z, .moveDidNotMiss
3220
call PrintMoveFailureText
3221
ld a, [wPlayerMoveEffect]
3222
cp EXPLODE_EFFECT ; even if Explosion or Selfdestruct missed, its effect still needs to be activated
3223
jr z, .notDone
3224
jp ExecutePlayerMoveDone ; otherwise, we're done if the move missed
3225
.moveDidNotMiss
3226
call ApplyAttackToEnemyPokemon
3227
call PrintCriticalOHKOText
3228
callfar DisplayEffectiveness
3229
ld a, 1
3230
ld [wMoveDidntMiss], a
3231
.notDone
3232
ld a, [wPlayerMoveEffect]
3233
ld hl, AlwaysHappenSideEffects
3234
ld de, 1
3235
call IsInArray
3236
call c, JumpMoveEffect ; not done after executing effects of AlwaysHappenSideEffects
3237
ld hl, wEnemyMonHP
3238
ld a, [hli]
3239
ld b, [hl]
3240
or b
3241
ret z ; don't do anything else if the enemy fainted
3242
call HandleBuildingRage
3243
3244
ld hl, wPlayerBattleStatus1
3245
bit ATTACKING_MULTIPLE_TIMES, [hl]
3246
jr z, .executeOtherEffects
3247
ld a, [wPlayerNumAttacksLeft]
3248
dec a
3249
ld [wPlayerNumAttacksLeft], a
3250
jp nz, GetPlayerAnimationType ; for multi-hit moves, apply attack until PlayerNumAttacksLeft hits 0 or the enemy faints.
3251
; damage calculation and accuracy tests only happen for the first hit
3252
res ATTACKING_MULTIPLE_TIMES, [hl] ; clear attacking multiple times status when all attacks are over
3253
ld hl, MultiHitText
3254
call PrintText
3255
xor a
3256
ld [wPlayerNumHits], a
3257
.executeOtherEffects
3258
ld a, [wPlayerMoveEffect]
3259
and a
3260
jp z, ExecutePlayerMoveDone
3261
ld hl, SpecialEffects
3262
ld de, 1
3263
call IsInArray
3264
call nc, JumpMoveEffect ; move effects not included in SpecialEffects or in either of the ResidualEffect arrays,
3265
; which are the effects not covered yet. Rage effect will be executed for a second time (though it's irrelevant).
3266
; Includes side effects that only need to be called if the target didn't faint.
3267
; Responsible for executing Twineedle's second side effect (poison).
3268
jp ExecutePlayerMoveDone
3269
3270
MultiHitText:
3271
text_far _MultiHitText
3272
text_end
3273
3274
ExecutePlayerMoveDone:
3275
xor a
3276
ld [wActionResultOrTookBattleTurn], a
3277
ld b, 1
3278
ret
3279
3280
PrintGhostText:
3281
; print the ghost battle messages
3282
call IsGhostBattle
3283
ret nz
3284
ldh a, [hWhoseTurn]
3285
and a
3286
jr nz, .Ghost
3287
ld a, [wBattleMonStatus] ; player's turn
3288
and (1 << FRZ) | SLP_MASK
3289
ret nz
3290
ld hl, ScaredText
3291
call PrintText
3292
xor a
3293
ret
3294
.Ghost ; ghost's turn
3295
ld hl, GetOutText
3296
call PrintText
3297
xor a
3298
ret
3299
3300
ScaredText:
3301
text_far _ScaredText
3302
text_end
3303
3304
GetOutText:
3305
text_far _GetOutText
3306
text_end
3307
3308
IsGhostBattle:
3309
ld a, [wIsInBattle]
3310
dec a
3311
ret nz
3312
ld a, [wCurMap]
3313
cp POKEMON_TOWER_1F
3314
jr c, .next
3315
cp POKEMON_TOWER_7F + 1
3316
jr nc, .next
3317
ld b, SILPH_SCOPE
3318
call IsItemInBag
3319
ret z
3320
.next
3321
ld a, 1
3322
and a
3323
ret
3324
3325
; checks for various status conditions affecting the player mon
3326
; stores whether the mon cannot use a move this turn in Z flag
3327
CheckPlayerStatusConditions:
3328
ld hl, wBattleMonStatus
3329
ld a, [hl]
3330
and SLP_MASK
3331
jr z, .FrozenCheck
3332
; sleeping
3333
dec a
3334
ld [wBattleMonStatus], a ; decrement number of turns left
3335
and a
3336
jr z, .WakeUp ; if the number of turns hit 0, wake up
3337
; fast asleep
3338
xor a
3339
ld [wAnimationType], a
3340
ld a, SLP_PLAYER_ANIM
3341
call PlayMoveAnimation
3342
ld hl, FastAsleepText
3343
call PrintText
3344
jr .sleepDone
3345
.WakeUp
3346
ld hl, WokeUpText
3347
call PrintText
3348
.sleepDone
3349
xor a
3350
ld [wPlayerUsedMove], a
3351
ld hl, ExecutePlayerMoveDone ; player can't move this turn
3352
jp .returnToHL
3353
3354
.FrozenCheck
3355
bit FRZ, [hl] ; frozen?
3356
jr z, .HeldInPlaceCheck
3357
ld hl, IsFrozenText
3358
call PrintText
3359
xor a
3360
ld [wPlayerUsedMove], a
3361
ld hl, ExecutePlayerMoveDone ; player can't move this turn
3362
jp .returnToHL
3363
3364
.HeldInPlaceCheck
3365
ld a, [wEnemyBattleStatus1]
3366
bit USING_TRAPPING_MOVE, a ; is enemy using a multi-turn move like wrap?
3367
jp z, .FlinchedCheck
3368
ld hl, CantMoveText
3369
call PrintText
3370
ld hl, ExecutePlayerMoveDone ; player can't move this turn
3371
jp .returnToHL
3372
3373
.FlinchedCheck
3374
ld hl, wPlayerBattleStatus1
3375
bit FLINCHED, [hl]
3376
jp z, .HyperBeamCheck
3377
res FLINCHED, [hl] ; reset player's flinch status
3378
ld hl, FlinchedText
3379
call PrintText
3380
ld hl, ExecutePlayerMoveDone ; player can't move this turn
3381
jp .returnToHL
3382
3383
.HyperBeamCheck
3384
ld hl, wPlayerBattleStatus2
3385
bit NEEDS_TO_RECHARGE, [hl]
3386
jr z, .AnyMoveDisabledCheck
3387
res NEEDS_TO_RECHARGE, [hl] ; reset player's recharge status
3388
ld hl, MustRechargeText
3389
call PrintText
3390
ld hl, ExecutePlayerMoveDone ; player can't move this turn
3391
jp .returnToHL
3392
3393
.AnyMoveDisabledCheck
3394
ld hl, wPlayerDisabledMove
3395
ld a, [hl]
3396
and a
3397
jr z, .ConfusedCheck
3398
dec a
3399
ld [hl], a
3400
and $f ; did Disable counter hit 0?
3401
jr nz, .ConfusedCheck
3402
ld [hl], a
3403
ld [wPlayerDisabledMoveNumber], a
3404
ld hl, DisabledNoMoreText
3405
call PrintText
3406
3407
.ConfusedCheck
3408
ld a, [wPlayerBattleStatus1]
3409
add a ; is player confused?
3410
jr nc, .TriedToUseDisabledMoveCheck
3411
ld hl, wPlayerConfusedCounter
3412
dec [hl]
3413
jr nz, .IsConfused
3414
ld hl, wPlayerBattleStatus1
3415
res CONFUSED, [hl] ; if confused counter hit 0, reset confusion status
3416
ld hl, ConfusedNoMoreText
3417
call PrintText
3418
jr .TriedToUseDisabledMoveCheck
3419
.IsConfused
3420
ld hl, IsConfusedText
3421
call PrintText
3422
xor a
3423
ld [wAnimationType], a
3424
ld a, CONF_PLAYER_ANIM
3425
call PlayMoveAnimation
3426
call BattleRandom
3427
cp 50 percent + 1 ; chance to hurt itself
3428
jr c, .TriedToUseDisabledMoveCheck
3429
ld hl, wPlayerBattleStatus1
3430
ld a, [hl]
3431
and 1 << CONFUSED ; if mon hurts itself, clear every other status from wPlayerBattleStatus1
3432
ld [hl], a
3433
call HandleSelfConfusionDamage
3434
jr .MonHurtItselfOrFullyParalysed
3435
3436
.TriedToUseDisabledMoveCheck
3437
; prevents a disabled move that was selected before being disabled from being used
3438
ld a, [wPlayerDisabledMoveNumber]
3439
and a
3440
jr z, .ParalysisCheck
3441
ld hl, wPlayerSelectedMove
3442
cp [hl]
3443
jr nz, .ParalysisCheck
3444
call PrintMoveIsDisabledText
3445
ld hl, ExecutePlayerMoveDone ; if a disabled move was somehow selected, player can't move this turn
3446
jp .returnToHL
3447
3448
.ParalysisCheck
3449
ld hl, wBattleMonStatus
3450
bit PAR, [hl]
3451
jr z, .BideCheck
3452
call BattleRandom
3453
cp $3F ; 25% to be fully paralyzed
3454
jr nc, .BideCheck
3455
ld hl, FullyParalyzedText
3456
call PrintText
3457
3458
.MonHurtItselfOrFullyParalysed
3459
ld hl, wPlayerBattleStatus1
3460
ld a, [hl]
3461
; clear bide, thrashing, charging up, and trapping moves such as warp (already cleared for confusion damage)
3462
and ~((1 << STORING_ENERGY) | (1 << THRASHING_ABOUT) | (1 << CHARGING_UP) | (1 << USING_TRAPPING_MOVE))
3463
ld [hl], a
3464
ld a, [wPlayerMoveEffect]
3465
cp FLY_EFFECT
3466
jr z, .FlyOrChargeEffect
3467
cp CHARGE_EFFECT
3468
jr z, .FlyOrChargeEffect
3469
jr .NotFlyOrChargeEffect
3470
3471
.FlyOrChargeEffect
3472
xor a
3473
ld [wAnimationType], a
3474
ld a, STATUS_AFFECTED_ANIM
3475
call PlayMoveAnimation
3476
.NotFlyOrChargeEffect
3477
ld hl, ExecutePlayerMoveDone
3478
jp .returnToHL ; if using a two-turn move, we need to recharge the first turn
3479
3480
.BideCheck
3481
ld hl, wPlayerBattleStatus1
3482
bit STORING_ENERGY, [hl] ; is mon using bide?
3483
jr z, .ThrashingAboutCheck
3484
xor a
3485
ld [wPlayerMoveNum], a
3486
ld hl, wDamage
3487
ld a, [hli]
3488
ld b, a
3489
ld c, [hl]
3490
ld hl, wPlayerBideAccumulatedDamage + 1
3491
ld a, [hl]
3492
add c ; accumulate damage taken
3493
ld [hld], a
3494
ld a, [hl]
3495
adc b
3496
ld [hl], a
3497
ld hl, wPlayerNumAttacksLeft
3498
dec [hl] ; did Bide counter hit 0?
3499
jr z, .UnleashEnergy
3500
ld hl, ExecutePlayerMoveDone
3501
jp .returnToHL ; unless mon unleashes energy, can't move this turn
3502
.UnleashEnergy
3503
ld hl, wPlayerBattleStatus1
3504
res STORING_ENERGY, [hl] ; not using bide any more
3505
ld hl, UnleashedEnergyText
3506
call PrintText
3507
ld a, 1
3508
ld [wPlayerMovePower], a
3509
ld hl, wPlayerBideAccumulatedDamage + 1
3510
ld a, [hld]
3511
add a
3512
ld b, a
3513
ld [wDamage + 1], a
3514
ld a, [hl]
3515
rl a ; double the damage
3516
ld [wDamage], a
3517
or b
3518
jr nz, .next
3519
ld a, 1
3520
ld [wMoveMissed], a
3521
.next
3522
xor a
3523
ld [hli], a
3524
ld [hl], a
3525
ld a, BIDE
3526
ld [wPlayerMoveNum], a
3527
ld hl, HandleIfPlayerMoveMissed ; skip damage calculation, DecrementPP and MoveHitTest
3528
jp .returnToHL
3529
3530
.ThrashingAboutCheck
3531
bit THRASHING_ABOUT, [hl] ; is mon using thrash or petal dance?
3532
jr z, .MultiturnMoveCheck
3533
ld a, THRASH
3534
ld [wPlayerMoveNum], a
3535
ld hl, ThrashingAboutText
3536
call PrintText
3537
ld hl, wPlayerNumAttacksLeft
3538
dec [hl] ; did Thrashing About counter hit 0?
3539
ld hl, PlayerCalcMoveDamage ; skip DecrementPP
3540
jp nz, .returnToHL
3541
push hl
3542
ld hl, wPlayerBattleStatus1
3543
res THRASHING_ABOUT, [hl] ; no longer thrashing about
3544
set CONFUSED, [hl] ; confused
3545
call BattleRandom
3546
and 3
3547
inc a
3548
inc a ; confused for 2-5 turns
3549
ld [wPlayerConfusedCounter], a
3550
pop hl ; skip DecrementPP
3551
jp .returnToHL
3552
3553
.MultiturnMoveCheck
3554
bit USING_TRAPPING_MOVE, [hl] ; is mon using multi-turn move?
3555
jp z, .RageCheck
3556
ld hl, AttackContinuesText
3557
call PrintText
3558
ld a, [wPlayerNumAttacksLeft]
3559
dec a ; did multi-turn move end?
3560
ld [wPlayerNumAttacksLeft], a
3561
ld hl, GetPlayerAnimationType ; if it didn't, skip damage calculation (deal damage equal to last hit),
3562
; DecrementPP and MoveHitTest
3563
jp nz, .returnToHL
3564
jp .returnToHL
3565
3566
.RageCheck
3567
ld a, [wPlayerBattleStatus2]
3568
bit USING_RAGE, a ; is mon using rage?
3569
jp z, .checkPlayerStatusConditionsDone ; if we made it this far, mon can move normally this turn
3570
ld a, RAGE
3571
ld [wNamedObjectIndex], a
3572
call GetMoveName
3573
call CopyToStringBuffer
3574
xor a
3575
ld [wPlayerMoveEffect], a
3576
ld hl, PlayerCanExecuteMove
3577
jp .returnToHL
3578
3579
.returnToHL
3580
xor a
3581
ret
3582
3583
.checkPlayerStatusConditionsDone
3584
ld a, $1
3585
and a
3586
ret
3587
3588
FastAsleepText:
3589
text_far _FastAsleepText
3590
text_end
3591
3592
WokeUpText:
3593
text_far _WokeUpText
3594
text_end
3595
3596
IsFrozenText:
3597
text_far _IsFrozenText
3598
text_end
3599
3600
FullyParalyzedText:
3601
text_far _FullyParalyzedText
3602
text_end
3603
3604
FlinchedText:
3605
text_far _FlinchedText
3606
text_end
3607
3608
MustRechargeText:
3609
text_far _MustRechargeText
3610
text_end
3611
3612
DisabledNoMoreText:
3613
text_far _DisabledNoMoreText
3614
text_end
3615
3616
IsConfusedText:
3617
text_far _IsConfusedText
3618
text_end
3619
3620
HurtItselfText:
3621
text_far _HurtItselfText
3622
text_end
3623
3624
ConfusedNoMoreText:
3625
text_far _ConfusedNoMoreText
3626
text_end
3627
3628
SavingEnergyText:
3629
text_far _SavingEnergyText
3630
text_end
3631
3632
UnleashedEnergyText:
3633
text_far _UnleashedEnergyText
3634
text_end
3635
3636
ThrashingAboutText:
3637
text_far _ThrashingAboutText
3638
text_end
3639
3640
AttackContinuesText:
3641
text_far _AttackContinuesText
3642
text_end
3643
3644
CantMoveText:
3645
text_far _CantMoveText
3646
text_end
3647
3648
PrintMoveIsDisabledText:
3649
ld hl, wPlayerSelectedMove
3650
ld de, wPlayerBattleStatus1
3651
ldh a, [hWhoseTurn]
3652
and a
3653
jr z, .removeChargingUp
3654
inc hl
3655
ld de, wEnemyBattleStatus1
3656
.removeChargingUp
3657
ld a, [de]
3658
res CHARGING_UP, a ; end the pokemon's
3659
ld [de], a
3660
ld a, [hl]
3661
ld [wNamedObjectIndex], a
3662
call GetMoveName
3663
ld hl, MoveIsDisabledText
3664
jp PrintText
3665
3666
MoveIsDisabledText:
3667
text_far _MoveIsDisabledText
3668
text_end
3669
3670
HandleSelfConfusionDamage:
3671
ld hl, HurtItselfText
3672
call PrintText
3673
ld hl, wEnemyMonDefense
3674
ld a, [hli]
3675
push af
3676
ld a, [hld]
3677
push af
3678
ld a, [wBattleMonDefense]
3679
ld [hli], a
3680
ld a, [wBattleMonDefense + 1]
3681
ld [hl], a
3682
ld hl, wPlayerMoveEffect
3683
push hl
3684
ld a, [hl]
3685
push af
3686
xor a
3687
ld [hli], a
3688
ld [wCriticalHitOrOHKO], a ; self-inflicted confusion damage can't be a Critical Hit
3689
ld a, 40 ; 40 base power
3690
ld [hli], a
3691
xor a
3692
ld [hl], a
3693
call GetDamageVarsForPlayerAttack
3694
call CalculateDamage ; ignores AdjustDamageForMoveType (type-less damage), RandomizeDamage,
3695
; and MoveHitTest (always hits)
3696
pop af
3697
pop hl
3698
ld [hl], a
3699
ld hl, wEnemyMonDefense + 1
3700
pop af
3701
ld [hld], a
3702
pop af
3703
ld [hl], a
3704
xor a
3705
ld [wAnimationType], a
3706
inc a
3707
ldh [hWhoseTurn], a
3708
call PlayMoveAnimation
3709
call DrawPlayerHUDAndHPBar
3710
xor a
3711
ldh [hWhoseTurn], a
3712
jp ApplyDamageToPlayerPokemon
3713
3714
PrintMonName1Text:
3715
ld hl, MonName1Text
3716
jp PrintText
3717
3718
; this function wastes time calling DetermineExclamationPointTextNum
3719
; and choosing between Used1Text and Used2Text, even though
3720
; those text strings are identical and both continue at PrintInsteadText
3721
; this likely had to do with Japanese grammar that got translated,
3722
; but the functionality didn't get removed
3723
MonName1Text:
3724
text_far _MonName1Text
3725
text_asm
3726
ldh a, [hWhoseTurn]
3727
and a
3728
ld a, [wPlayerMoveNum]
3729
ld hl, wPlayerUsedMove
3730
jr z, .playerTurn
3731
ld a, [wEnemyMoveNum]
3732
ld hl, wEnemyUsedMove
3733
.playerTurn
3734
ld [hl], a
3735
ld [wMoveGrammar], a
3736
call DetermineExclamationPointTextNum
3737
ld a, [wMonIsDisobedient]
3738
and a
3739
ld hl, Used2Text
3740
ret nz
3741
ld a, [wMoveGrammar]
3742
cp 3
3743
ld hl, Used2Text
3744
ret c
3745
ld hl, Used1Text
3746
ret
3747
3748
Used1Text:
3749
text_far _Used1Text
3750
text_asm
3751
jr PrintInsteadText
3752
3753
Used2Text:
3754
text_far _Used2Text
3755
text_asm
3756
; fall through
3757
3758
PrintInsteadText:
3759
ld a, [wMonIsDisobedient]
3760
and a
3761
jr z, PrintMoveName
3762
ld hl, InsteadText
3763
ret
3764
3765
InsteadText:
3766
text_far _InsteadText
3767
text_asm
3768
; fall through
3769
3770
PrintMoveName:
3771
ld hl, _PrintMoveName
3772
ret
3773
3774
_PrintMoveName:
3775
text_far _MoveNameText
3776
text_asm
3777
ld hl, ExclamationPointPointerTable
3778
ld a, [wMoveGrammar]
3779
add a
3780
push bc
3781
ld b, $0
3782
ld c, a
3783
add hl, bc
3784
pop bc
3785
ld a, [hli]
3786
ld h, [hl]
3787
ld l, a
3788
ret
3789
3790
ExclamationPointPointerTable:
3791
dw ExclamationPoint1Text
3792
dw ExclamationPoint2Text
3793
dw ExclamationPoint3Text
3794
dw ExclamationPoint4Text
3795
dw ExclamationPoint5Text
3796
3797
ExclamationPoint1Text:
3798
text_far _ExclamationPoint1Text
3799
text_end
3800
3801
ExclamationPoint2Text:
3802
text_far _ExclamationPoint2Text
3803
text_end
3804
3805
ExclamationPoint3Text:
3806
text_far _ExclamationPoint3Text
3807
text_end
3808
3809
ExclamationPoint4Text:
3810
text_far _ExclamationPoint4Text
3811
text_end
3812
3813
ExclamationPoint5Text:
3814
text_far _ExclamationPoint5Text
3815
text_end
3816
3817
; this function does nothing useful
3818
; if the move being used is in set [1-4] from ExclamationPointMoveSets,
3819
; use ExclamationPoint[1-4]Text
3820
; otherwise, use ExclamationPoint5Text
3821
; but all five text strings are identical
3822
; this likely had to do with Japanese grammar that got translated,
3823
; but the functionality didn't get removed
3824
DetermineExclamationPointTextNum:
3825
push bc
3826
ld a, [wMoveGrammar] ; move ID
3827
ld c, a
3828
ld b, $0
3829
ld hl, ExclamationPointMoveSets
3830
.loop
3831
ld a, [hli]
3832
cp $ff
3833
jr z, .done
3834
cp c
3835
jr z, .done
3836
and a
3837
jr nz, .loop
3838
inc b
3839
jr .loop
3840
.done
3841
ld a, b
3842
ld [wMoveGrammar], a
3843
pop bc
3844
ret
3845
3846
INCLUDE "data/moves/grammar.asm"
3847
3848
PrintMoveFailureText:
3849
ld de, wPlayerMoveEffect
3850
ldh a, [hWhoseTurn]
3851
and a
3852
jr z, .playersTurn
3853
ld de, wEnemyMoveEffect
3854
.playersTurn
3855
ld hl, DoesntAffectMonText
3856
ld a, [wDamageMultipliers]
3857
and EFFECTIVENESS_MASK
3858
jr z, .gotTextToPrint
3859
ld hl, AttackMissedText
3860
ld a, [wCriticalHitOrOHKO]
3861
cp $ff
3862
jr nz, .gotTextToPrint
3863
ld hl, UnaffectedText
3864
.gotTextToPrint
3865
push de
3866
call PrintText
3867
xor a
3868
ld [wCriticalHitOrOHKO], a
3869
pop de
3870
ld a, [de]
3871
cp JUMP_KICK_EFFECT
3872
ret nz
3873
3874
; if you get here, the mon used jump kick or hi jump kick and missed
3875
ld hl, wDamage ; since the move missed, wDamage will always contain 0 at this point.
3876
; Thus, recoil damage will always be equal to 1
3877
; even if it was intended to be potential damage/8.
3878
ld a, [hli]
3879
ld b, [hl]
3880
srl a
3881
rr b
3882
srl a
3883
rr b
3884
srl a
3885
rr b
3886
ld [hl], b
3887
dec hl
3888
ld [hli], a
3889
or b
3890
jr nz, .applyRecoil
3891
inc a
3892
ld [hl], a
3893
.applyRecoil
3894
ld hl, KeptGoingAndCrashedText
3895
call PrintText
3896
ld b, $4
3897
predef PredefShakeScreenHorizontally
3898
ldh a, [hWhoseTurn]
3899
and a
3900
jr nz, .enemyTurn
3901
jp ApplyDamageToPlayerPokemon
3902
.enemyTurn
3903
jp ApplyDamageToEnemyPokemon
3904
3905
AttackMissedText:
3906
text_far _AttackMissedText
3907
text_end
3908
3909
KeptGoingAndCrashedText:
3910
text_far _KeptGoingAndCrashedText
3911
text_end
3912
3913
UnaffectedText:
3914
text_far _UnaffectedText
3915
text_end
3916
3917
PrintDoesntAffectText:
3918
ld hl, DoesntAffectMonText
3919
jp PrintText
3920
3921
DoesntAffectMonText:
3922
text_far _DoesntAffectMonText
3923
text_end
3924
3925
; if there was a critical hit or an OHKO was successful, print the corresponding text
3926
PrintCriticalOHKOText:
3927
ld a, [wCriticalHitOrOHKO]
3928
and a
3929
jr z, .done ; do nothing if there was no critical hit or successful OHKO
3930
dec a
3931
add a
3932
ld hl, CriticalOHKOTextPointers
3933
ld b, $0
3934
ld c, a
3935
add hl, bc
3936
ld a, [hli]
3937
ld h, [hl]
3938
ld l, a
3939
call PrintText
3940
xor a
3941
ld [wCriticalHitOrOHKO], a
3942
.done
3943
ld c, 20
3944
jp DelayFrames
3945
3946
CriticalOHKOTextPointers:
3947
dw CriticalHitText
3948
dw OHKOText
3949
3950
CriticalHitText:
3951
text_far _CriticalHitText
3952
text_end
3953
3954
OHKOText:
3955
text_far _OHKOText
3956
text_end
3957
3958
; checks if a traded mon will disobey due to lack of badges
3959
; stores whether the mon will use a move in Z flag
3960
CheckForDisobedience:
3961
xor a
3962
ld [wMonIsDisobedient], a
3963
ld a, [wLinkState]
3964
cp LINK_STATE_BATTLING
3965
jr nz, .checkIfMonIsTraded
3966
ld a, $1
3967
and a
3968
ret
3969
; compare the mon's original trainer ID with the player's ID to see if it was traded
3970
.checkIfMonIsTraded
3971
ld hl, wPartyMon1OTID
3972
ld bc, wPartyMon2 - wPartyMon1
3973
ld a, [wPlayerMonNumber]
3974
call AddNTimes
3975
ld a, [wPlayerID]
3976
cp [hl]
3977
jr nz, .monIsTraded
3978
inc hl
3979
ld a, [wPlayerID + 1]
3980
cp [hl]
3981
jp z, .canUseMove
3982
; it was traded
3983
.monIsTraded
3984
; what level might disobey?
3985
ld hl, wObtainedBadges
3986
bit BIT_EARTHBADGE, [hl]
3987
ld a, 101
3988
jr nz, .next
3989
bit BIT_MARSHBADGE, [hl]
3990
ld a, 70
3991
jr nz, .next
3992
bit BIT_RAINBOWBADGE, [hl]
3993
ld a, 50
3994
jr nz, .next
3995
bit BIT_CASCADEBADGE, [hl]
3996
ld a, 30
3997
jr nz, .next
3998
ld a, 10
3999
.next
4000
ld b, a
4001
ld c, a
4002
ld a, [wBattleMonLevel]
4003
ld d, a
4004
add b
4005
ld b, a
4006
jr nc, .noCarry
4007
ld b, $ff ; cap b at $ff
4008
.noCarry
4009
ld a, c
4010
cp d
4011
jp nc, .canUseMove
4012
.loop1
4013
call BattleRandom
4014
swap a
4015
cp b
4016
jr nc, .loop1
4017
cp c
4018
jp c, .canUseMove
4019
.loop2
4020
call BattleRandom
4021
cp b
4022
jr nc, .loop2
4023
cp c
4024
jr c, .useRandomMove
4025
ld a, d
4026
sub c
4027
ld b, a
4028
call BattleRandom
4029
swap a
4030
sub b
4031
jr c, .monNaps
4032
cp b
4033
jr nc, .monDoesNothing
4034
ld hl, WontObeyText
4035
call PrintText
4036
call HandleSelfConfusionDamage
4037
jp .cannotUseMove
4038
.monNaps
4039
call BattleRandom
4040
add a
4041
swap a
4042
and SLP_MASK
4043
jr z, .monNaps ; keep trying until we get at least 1 turn of sleep
4044
ld [wBattleMonStatus], a
4045
ld hl, BeganToNapText
4046
jr .printText
4047
.monDoesNothing
4048
call BattleRandom
4049
and $3
4050
ld hl, LoafingAroundText
4051
and a
4052
jr z, .printText
4053
ld hl, WontObeyText
4054
dec a
4055
jr z, .printText
4056
ld hl, TurnedAwayText
4057
dec a
4058
jr z, .printText
4059
ld hl, IgnoredOrdersText
4060
.printText
4061
call PrintText
4062
jr .cannotUseMove
4063
.useRandomMove
4064
ld a, [wBattleMonMoves + 1]
4065
and a ; is the second move slot empty?
4066
jr z, .monDoesNothing ; mon will not use move if it only knows one move
4067
ld a, [wPlayerDisabledMoveNumber]
4068
and a
4069
jr nz, .monDoesNothing
4070
ld a, [wPlayerSelectedMove]
4071
cp STRUGGLE
4072
jr z, .monDoesNothing ; mon will not use move if struggling
4073
; check if only one move has remaining PP
4074
ld hl, wBattleMonPP
4075
push hl
4076
ld a, [hli]
4077
and PP_MASK
4078
ld b, a
4079
ld a, [hli]
4080
and PP_MASK
4081
add b
4082
ld b, a
4083
ld a, [hli]
4084
and PP_MASK
4085
add b
4086
ld b, a
4087
ld a, [hl]
4088
and PP_MASK
4089
add b
4090
pop hl
4091
push af
4092
ld a, [wCurrentMenuItem]
4093
ld c, a
4094
ld b, $0
4095
add hl, bc
4096
ld a, [hl]
4097
and PP_MASK
4098
ld b, a
4099
pop af
4100
cp b
4101
jr z, .monDoesNothing ; mon will not use move if only one move has remaining PP
4102
ld a, $1
4103
ld [wMonIsDisobedient], a
4104
ld a, [wMaxMenuItem]
4105
ld b, a
4106
ld a, [wCurrentMenuItem]
4107
ld c, a
4108
.chooseMove
4109
call BattleRandom
4110
and $3
4111
cp b
4112
jr nc, .chooseMove ; if the random number is greater than the move count, choose another
4113
cp c
4114
jr z, .chooseMove ; if the random number matches the move the player selected, choose another
4115
ld [wCurrentMenuItem], a
4116
ld hl, wBattleMonPP
4117
ld e, a
4118
ld d, $0
4119
add hl, de
4120
ld a, [hl]
4121
and a ; does the move have any PP left?
4122
jr z, .chooseMove ; if the move has no PP left, choose another
4123
ld a, [wCurrentMenuItem]
4124
ld c, a
4125
ld b, $0
4126
ld hl, wBattleMonMoves
4127
add hl, bc
4128
ld a, [hl]
4129
ld [wPlayerSelectedMove], a
4130
call GetCurrentMove
4131
.canUseMove
4132
ld a, $1
4133
and a ; clear Z flag
4134
ret
4135
.cannotUseMove
4136
xor a ; set Z flag
4137
ret
4138
4139
LoafingAroundText:
4140
text_far _LoafingAroundText
4141
text_end
4142
4143
BeganToNapText:
4144
text_far _BeganToNapText
4145
text_end
4146
4147
WontObeyText:
4148
text_far _WontObeyText
4149
text_end
4150
4151
TurnedAwayText:
4152
text_far _TurnedAwayText
4153
text_end
4154
4155
IgnoredOrdersText:
4156
text_far _IgnoredOrdersText
4157
text_end
4158
4159
; sets b, c, d, and e for the CalculateDamage routine in the case of an attack by the player mon
4160
GetDamageVarsForPlayerAttack:
4161
xor a
4162
ld hl, wDamage ; damage to eventually inflict, initialise to zero
4163
ldi [hl], a
4164
ld [hl], a
4165
ld hl, wPlayerMovePower
4166
ld a, [hli]
4167
and a
4168
ld d, a ; d = move power
4169
ret z ; return if move power is zero
4170
ld a, [hl] ; a = [wPlayerMoveType]
4171
cp SPECIAL ; types >= SPECIAL are all special
4172
jr nc, .specialAttack
4173
.physicalAttack
4174
ld hl, wEnemyMonDefense
4175
ld a, [hli]
4176
ld b, a
4177
ld c, [hl] ; bc = enemy defense
4178
ld a, [wEnemyBattleStatus3]
4179
bit HAS_REFLECT_UP, a ; check for Reflect
4180
jr z, .physicalAttackCritCheck
4181
; if the enemy has used Reflect, double the enemy's defense
4182
sla c
4183
rl b
4184
.physicalAttackCritCheck
4185
ld hl, wBattleMonAttack
4186
ld a, [wCriticalHitOrOHKO]
4187
and a ; check for critical hit
4188
jr z, .scaleStats
4189
; in the case of a critical hit, reset the player's attack and the enemy's defense to their base values
4190
ld c, STAT_DEFENSE
4191
call GetEnemyMonStat
4192
ldh a, [hProduct + 2]
4193
ld b, a
4194
ldh a, [hProduct + 3]
4195
ld c, a
4196
push bc
4197
ld hl, wPartyMon1Attack
4198
ld a, [wPlayerMonNumber]
4199
ld bc, wPartyMon2 - wPartyMon1
4200
call AddNTimes
4201
pop bc
4202
jr .scaleStats
4203
.specialAttack
4204
ld hl, wEnemyMonSpecial
4205
ld a, [hli]
4206
ld b, a
4207
ld c, [hl] ; bc = enemy special
4208
ld a, [wEnemyBattleStatus3]
4209
bit HAS_LIGHT_SCREEN_UP, a ; check for Light Screen
4210
jr z, .specialAttackCritCheck
4211
; if the enemy has used Light Screen, double the enemy's special
4212
sla c
4213
rl b
4214
; reflect and light screen boosts do not cap the stat at MAX_STAT_VALUE, so weird things will happen during stats scaling
4215
; if a Pokemon with 512 or more Defense has used Reflect, or if a Pokemon with 512 or more Special has used Light Screen
4216
.specialAttackCritCheck
4217
ld hl, wBattleMonSpecial
4218
ld a, [wCriticalHitOrOHKO]
4219
and a ; check for critical hit
4220
jr z, .scaleStats
4221
; in the case of a critical hit, reset the player's and enemy's specials to their base values
4222
ld c, STAT_SPECIAL
4223
call GetEnemyMonStat
4224
ldh a, [hProduct + 2]
4225
ld b, a
4226
ldh a, [hProduct + 3]
4227
ld c, a
4228
push bc
4229
ld hl, wPartyMon1Special
4230
ld a, [wPlayerMonNumber]
4231
ld bc, wPartyMon2 - wPartyMon1
4232
call AddNTimes
4233
pop bc
4234
; if either the offensive or defensive stat is too large to store in a byte, scale both stats by dividing them by 4
4235
; this allows values with up to 10 bits (values up to 1023) to be handled
4236
; anything larger will wrap around
4237
.scaleStats
4238
ld a, [hli]
4239
ld l, [hl]
4240
ld h, a ; hl = player's offensive stat
4241
or b ; is either high byte nonzero?
4242
jr z, .next ; if not, we don't need to scale
4243
; bc /= 4 (scale enemy's defensive stat)
4244
srl b
4245
rr c
4246
srl b
4247
rr c
4248
; defensive stat can actually end up as 0, leading to a division by 0 freeze during damage calculation
4249
; hl /= 4 (scale player's offensive stat)
4250
srl h
4251
rr l
4252
srl h
4253
rr l
4254
ld a, l
4255
or h ; is the player's offensive stat 0?
4256
jr nz, .next
4257
inc l ; if the player's offensive stat is 0, bump it up to 1
4258
.next
4259
ld b, l ; b = player's offensive stat (possibly scaled)
4260
; (c already contains enemy's defensive stat (possibly scaled))
4261
ld a, [wBattleMonLevel]
4262
ld e, a ; e = level
4263
ld a, [wCriticalHitOrOHKO]
4264
and a ; check for critical hit
4265
jr z, .done
4266
sla e ; double level if it was a critical hit
4267
.done
4268
ld a, 1
4269
and a
4270
ret
4271
4272
; sets b, c, d, and e for the CalculateDamage routine in the case of an attack by the enemy mon
4273
GetDamageVarsForEnemyAttack:
4274
ld hl, wDamage ; damage to eventually inflict, initialise to zero
4275
xor a
4276
ld [hli], a
4277
ld [hl], a
4278
ld hl, wEnemyMovePower
4279
ld a, [hli]
4280
ld d, a ; d = move power
4281
and a
4282
ret z ; return if move power is zero
4283
ld a, [hl] ; a = [wEnemyMoveType]
4284
cp SPECIAL ; types >= SPECIAL are all special
4285
jr nc, .specialAttack
4286
.physicalAttack
4287
ld hl, wBattleMonDefense
4288
ld a, [hli]
4289
ld b, a
4290
ld c, [hl] ; bc = player defense
4291
ld a, [wPlayerBattleStatus3]
4292
bit HAS_REFLECT_UP, a ; check for Reflect
4293
jr z, .physicalAttackCritCheck
4294
; if the player has used Reflect, double the player's defense
4295
sla c
4296
rl b
4297
.physicalAttackCritCheck
4298
ld hl, wEnemyMonAttack
4299
ld a, [wCriticalHitOrOHKO]
4300
and a ; check for critical hit
4301
jr z, .scaleStats
4302
; in the case of a critical hit, reset the player's defense and the enemy's attack to their base values
4303
ld hl, wPartyMon1Defense
4304
ld a, [wPlayerMonNumber]
4305
ld bc, wPartyMon2 - wPartyMon1
4306
call AddNTimes
4307
ld a, [hli]
4308
ld b, a
4309
ld c, [hl]
4310
push bc
4311
ld c, STAT_ATTACK
4312
call GetEnemyMonStat
4313
ld hl, hProduct + 2
4314
pop bc
4315
jr .scaleStats
4316
.specialAttack
4317
ld hl, wBattleMonSpecial
4318
ld a, [hli]
4319
ld b, a
4320
ld c, [hl]
4321
ld a, [wPlayerBattleStatus3]
4322
bit HAS_LIGHT_SCREEN_UP, a ; check for Light Screen
4323
jr z, .specialAttackCritCheck
4324
; if the player has used Light Screen, double the player's special
4325
sla c
4326
rl b
4327
; reflect and light screen boosts do not cap the stat at MAX_STAT_VALUE, so weird things will happen during stats scaling
4328
; if a Pokemon with 512 or more Defense has used Reflect, or if a Pokemon with 512 or more Special has used Light Screen
4329
.specialAttackCritCheck
4330
ld hl, wEnemyMonSpecial
4331
ld a, [wCriticalHitOrOHKO]
4332
and a ; check for critical hit
4333
jr z, .scaleStats
4334
; in the case of a critical hit, reset the player's and enemy's specials to their base values
4335
ld hl, wPartyMon1Special
4336
ld a, [wPlayerMonNumber]
4337
ld bc, wPartyMon2 - wPartyMon1
4338
call AddNTimes
4339
ld a, [hli]
4340
ld b, a
4341
ld c, [hl]
4342
push bc
4343
ld c, STAT_SPECIAL
4344
call GetEnemyMonStat
4345
ld hl, hProduct + 2
4346
pop bc
4347
; if either the offensive or defensive stat is too large to store in a byte, scale both stats by dividing them by 4
4348
; this allows values with up to 10 bits (values up to 1023) to be handled
4349
; anything larger will wrap around
4350
.scaleStats
4351
ld a, [hli]
4352
ld l, [hl]
4353
ld h, a ; hl = enemy's offensive stat
4354
or b ; is either high byte nonzero?
4355
jr z, .next ; if not, we don't need to scale
4356
; bc /= 4 (scale player's defensive stat)
4357
srl b
4358
rr c
4359
srl b
4360
rr c
4361
; defensive stat can actually end up as 0, leading to a division by 0 freeze during damage calculation
4362
; hl /= 4 (scale enemy's offensive stat)
4363
srl h
4364
rr l
4365
srl h
4366
rr l
4367
ld a, l
4368
or h ; is the enemy's offensive stat 0?
4369
jr nz, .next
4370
inc l ; if the enemy's offensive stat is 0, bump it up to 1
4371
.next
4372
ld b, l ; b = enemy's offensive stat (possibly scaled)
4373
; (c already contains player's defensive stat (possibly scaled))
4374
ld a, [wEnemyMonLevel]
4375
ld e, a
4376
ld a, [wCriticalHitOrOHKO]
4377
and a ; check for critical hit
4378
jr z, .done
4379
sla e ; double level if it was a critical hit
4380
.done
4381
ld a, $1
4382
and a
4383
and a
4384
ret
4385
4386
; get stat c of enemy mon
4387
; c: stat to get (STAT_* constant)
4388
GetEnemyMonStat:
4389
push de
4390
push bc
4391
ld a, [wLinkState]
4392
cp LINK_STATE_BATTLING
4393
jr nz, .notLinkBattle
4394
ld hl, wEnemyMon1Stats
4395
dec c
4396
sla c
4397
ld b, $0
4398
add hl, bc
4399
ld a, [wEnemyMonPartyPos]
4400
ld bc, wEnemyMon2 - wEnemyMon1
4401
call AddNTimes
4402
ld a, [hli]
4403
ldh [hMultiplicand + 1], a
4404
ld a, [hl]
4405
ldh [hMultiplicand + 2], a
4406
pop bc
4407
pop de
4408
ret
4409
.notLinkBattle
4410
ld a, [wEnemyMonLevel]
4411
ld [wCurEnemyLevel], a
4412
ld a, [wEnemyMonSpecies]
4413
ld [wCurSpecies], a
4414
call GetMonHeader
4415
ld hl, wEnemyMonDVs
4416
ld de, wLoadedMonSpeedExp
4417
ld a, [hli]
4418
ld [de], a
4419
inc de
4420
ld a, [hl]
4421
ld [de], a
4422
pop bc
4423
ld b, $0
4424
ld hl, wLoadedMonSpeedExp - $b ; this base address makes CalcStat look in [wLoadedMonSpeedExp] for DVs
4425
call CalcStat
4426
pop de
4427
ret
4428
4429
CalculateDamage:
4430
; input:
4431
; b: attack
4432
; c: opponent defense
4433
; d: base power
4434
; e: level
4435
4436
ldh a, [hWhoseTurn] ; whose turn?
4437
and a
4438
ld a, [wPlayerMoveEffect]
4439
jr z, .effect
4440
ld a, [wEnemyMoveEffect]
4441
.effect
4442
4443
; EXPLODE_EFFECT halves defense.
4444
cp EXPLODE_EFFECT
4445
jr nz, .ok
4446
srl c
4447
jr nz, .ok
4448
inc c ; ...with a minimum value of 1 (used as a divisor later on)
4449
.ok
4450
4451
; Multi-hit attacks may or may not have 0 bp.
4452
cp TWO_TO_FIVE_ATTACKS_EFFECT
4453
jr z, .skipbp
4454
cp EFFECT_1E
4455
jr z, .skipbp
4456
4457
; Calculate OHKO damage based on remaining HP.
4458
cp OHKO_EFFECT
4459
jp z, JumpToOHKOMoveEffect
4460
4461
; Don't calculate damage for moves that don't do any.
4462
ld a, d ; base power
4463
and a
4464
ret z
4465
.skipbp
4466
4467
xor a
4468
ld hl, hDividend
4469
ldi [hl], a
4470
ldi [hl], a
4471
ld [hl], a
4472
4473
; Multiply level by 2
4474
ld a, e ; level
4475
add a
4476
jr nc, .nc
4477
push af
4478
ld a, 1
4479
ld [hl], a
4480
pop af
4481
.nc
4482
inc hl
4483
ldi [hl], a
4484
4485
; Divide by 5
4486
ld a, 5
4487
ldd [hl], a
4488
push bc
4489
ld b, 4
4490
call Divide
4491
pop bc
4492
4493
; Add 2
4494
inc [hl]
4495
inc [hl]
4496
4497
inc hl ; multiplier
4498
4499
; Multiply by attack base power
4500
ld [hl], d
4501
call Multiply
4502
4503
; Multiply by attack stat
4504
ld [hl], b
4505
call Multiply
4506
4507
; Divide by defender's defense stat
4508
ld [hl], c
4509
ld b, 4
4510
call Divide
4511
4512
; Divide by 50
4513
ld [hl], 50
4514
ld b, 4
4515
call Divide
4516
4517
; Update wCurDamage.
4518
; Capped at MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE: 999 - 2 = 997.
4519
ld hl, wDamage
4520
ld b, [hl]
4521
ldh a, [hQuotient + 3]
4522
add b
4523
ldh [hQuotient + 3], a
4524
jr nc, .dont_cap_1
4525
4526
ldh a, [hQuotient + 2]
4527
inc a
4528
ldh [hQuotient + 2], a
4529
and a
4530
jr z, .cap
4531
4532
.dont_cap_1
4533
ldh a, [hQuotient]
4534
ld b, a
4535
ldh a, [hQuotient + 1]
4536
or a
4537
jr nz, .cap
4538
4539
ldh a, [hQuotient + 2]
4540
cp HIGH(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE + 1)
4541
jr c, .dont_cap_2
4542
4543
cp HIGH(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE + 1) + 1
4544
jr nc, .cap
4545
4546
ldh a, [hQuotient + 3]
4547
cp LOW(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE + 1)
4548
jr nc, .cap
4549
4550
.dont_cap_2
4551
inc hl
4552
4553
ldh a, [hQuotient + 3]
4554
ld b, [hl]
4555
add b
4556
ld [hld], a
4557
4558
ldh a, [hQuotient + 2]
4559
ld b, [hl]
4560
adc b
4561
ld [hl], a
4562
jr c, .cap
4563
4564
ld a, [hl]
4565
cp HIGH(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE + 1)
4566
jr c, .dont_cap_3
4567
4568
cp HIGH(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE + 1) + 1
4569
jr nc, .cap
4570
4571
inc hl
4572
ld a, [hld]
4573
cp LOW(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE + 1)
4574
jr c, .dont_cap_3
4575
4576
.cap
4577
ld a, HIGH(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE)
4578
ld [hli], a
4579
ld a, LOW(MAX_NEUTRAL_DAMAGE - MIN_NEUTRAL_DAMAGE)
4580
ld [hld], a
4581
4582
.dont_cap_3
4583
; Add back MIN_NEUTRAL_DAMAGE (capping at 999).
4584
inc hl
4585
ld a, [hl]
4586
add MIN_NEUTRAL_DAMAGE
4587
ld [hld], a
4588
jr nc, .dont_floor
4589
inc [hl]
4590
.dont_floor
4591
4592
; Returns nz and nc.
4593
ld a, 1
4594
and a
4595
ret
4596
4597
JumpToOHKOMoveEffect:
4598
call JumpMoveEffect
4599
ld a, [wMoveMissed]
4600
dec a
4601
ret
4602
4603
INCLUDE "data/battle/unused_critical_hit_moves.asm"
4604
4605
; determines if attack is a critical hit
4606
; Azure Heights claims "the fastest pokémon (who are, not coincidentally,
4607
; among the most popular) tend to CH about 20 to 25% of the time."
4608
CriticalHitTest:
4609
xor a
4610
ld [wCriticalHitOrOHKO], a
4611
ldh a, [hWhoseTurn]
4612
and a
4613
ld a, [wEnemyMonSpecies]
4614
jr nz, .handleEnemy
4615
ld a, [wBattleMonSpecies]
4616
.handleEnemy
4617
ld [wCurSpecies], a
4618
call GetMonHeader
4619
ld a, [wMonHBaseSpeed]
4620
ld b, a
4621
srl b ; (effective (base speed/2))
4622
ldh a, [hWhoseTurn]
4623
and a
4624
ld hl, wPlayerMovePower
4625
ld de, wPlayerBattleStatus2
4626
jr z, .calcCriticalHitProbability
4627
ld hl, wEnemyMovePower
4628
ld de, wEnemyBattleStatus2
4629
.calcCriticalHitProbability
4630
ld a, [hld] ; read base power from RAM
4631
and a
4632
ret z ; do nothing if zero
4633
dec hl
4634
ld c, [hl] ; read move id
4635
ld a, [de]
4636
bit GETTING_PUMPED, a ; test for focus energy
4637
jr nz, .focusEnergyUsed ; bug: using focus energy causes a shift to the right instead of left,
4638
; resulting in 1/4 the usual crit chance
4639
sla b ; (effective (base speed/2)*2)
4640
jr nc, .noFocusEnergyUsed
4641
ld b, $ff ; cap at 255/256
4642
jr .noFocusEnergyUsed
4643
.focusEnergyUsed
4644
srl b
4645
.noFocusEnergyUsed
4646
ld hl, HighCriticalMoves ; table of high critical hit moves
4647
.Loop
4648
ld a, [hli] ; read move from move table
4649
cp c ; does it match the move about to be used?
4650
jr z, .HighCritical ; if so, the move about to be used is a high critical hit ratio move
4651
inc a ; move on to the next move, FF terminates loop
4652
jr nz, .Loop ; check the next move in HighCriticalMoves
4653
srl b ; /2 for regular move (effective (base speed / 2))
4654
jr .SkipHighCritical ; continue as a normal move
4655
.HighCritical
4656
sla b ; *2 for high critical hit moves
4657
jr nc, .noCarry
4658
ld b, $ff ; cap at 255/256
4659
.noCarry
4660
sla b ; *4 for high critical move (effective (base speed/2)*8))
4661
jr nc, .SkipHighCritical
4662
ld b, $ff
4663
.SkipHighCritical
4664
call BattleRandom ; generates a random value, in "a"
4665
rlc a
4666
rlc a
4667
rlc a
4668
cp b ; check a against calculated crit rate
4669
ret nc ; no critical hit if no borrow
4670
ld a, $1
4671
ld [wCriticalHitOrOHKO], a ; set critical hit flag
4672
ret
4673
4674
INCLUDE "data/battle/critical_hit_moves.asm"
4675
4676
; function to determine if Counter hits and if so, how much damage it does
4677
HandleCounterMove:
4678
; The variables checked by Counter are updated whenever the cursor points to a new move in the battle selection menu.
4679
; This is irrelevant for the opponent's side outside of link battles, since the move selection is controlled by the AI.
4680
; However, in the scenario where the player switches out and the opponent uses Counter,
4681
; the outcome may be affected by the player's actions in the move selection menu prior to switching the Pokemon.
4682
; This might also lead to desync glitches in link battles.
4683
4684
ldh a, [hWhoseTurn] ; whose turn
4685
and a
4686
; player's turn
4687
ld hl, wEnemySelectedMove
4688
ld de, wEnemyMovePower
4689
ld a, [wPlayerSelectedMove]
4690
jr z, .next
4691
; enemy's turn
4692
ld hl, wPlayerSelectedMove
4693
ld de, wPlayerMovePower
4694
ld a, [wEnemySelectedMove]
4695
.next
4696
cp COUNTER
4697
ret nz ; return if not using Counter
4698
ld a, $01
4699
ld [wMoveMissed], a ; initialize the move missed variable to true (it is set to false below if the move hits)
4700
ld a, [hl]
4701
cp COUNTER
4702
ret z ; miss if the opponent's last selected move is Counter.
4703
ld a, [de]
4704
and a
4705
ret z ; miss if the opponent's last selected move's Base Power is 0.
4706
; check if the move the target last selected was Normal or Fighting type
4707
inc de
4708
ld a, [de]
4709
and a ; normal type
4710
jr z, .counterableType
4711
cp FIGHTING
4712
jr z, .counterableType
4713
; if the move wasn't Normal or Fighting type, miss
4714
xor a
4715
ret
4716
.counterableType
4717
ld hl, wDamage
4718
ld a, [hli]
4719
or [hl]
4720
ret z ; If we made it here, Counter still misses if the last move used in battle did no damage to its target.
4721
; wDamage is shared by both players, so Counter may strike back damage dealt by the Counter user itself
4722
; if the conditions meet, even though 99% of the times damage will come from the target.
4723
; if it did damage, double it
4724
ld a, [hl]
4725
add a
4726
ldd [hl], a
4727
ld a, [hl]
4728
adc a
4729
ld [hl], a
4730
jr nc, .noCarry
4731
; damage is capped at 0xFFFF
4732
ld a, $ff
4733
ld [hli], a
4734
ld [hl], a
4735
.noCarry
4736
xor a
4737
ld [wMoveMissed], a
4738
call MoveHitTest ; do the normal move hit test in addition to Counter's special rules
4739
xor a
4740
ret
4741
4742
ApplyAttackToEnemyPokemon:
4743
ld a, [wPlayerMoveEffect]
4744
cp OHKO_EFFECT
4745
jr z, ApplyDamageToEnemyPokemon
4746
cp SUPER_FANG_EFFECT
4747
jr z, .superFangEffect
4748
cp SPECIAL_DAMAGE_EFFECT
4749
jr z, .specialDamage
4750
ld a, [wPlayerMovePower]
4751
and a
4752
jp z, ApplyAttackToEnemyPokemonDone ; no attack to apply if base power is 0
4753
jr ApplyDamageToEnemyPokemon
4754
.superFangEffect
4755
; set the damage to half the target's HP
4756
ld hl, wEnemyMonHP
4757
ld de, wDamage
4758
ld a, [hli]
4759
srl a
4760
ld [de], a
4761
inc de
4762
ld b, a
4763
ld a, [hl]
4764
rr a
4765
ld [de], a
4766
or b
4767
jr nz, ApplyDamageToEnemyPokemon
4768
; make sure Super Fang's damage is always at least 1
4769
ld a, $01
4770
ld [de], a
4771
jr ApplyDamageToEnemyPokemon
4772
.specialDamage
4773
ld hl, wBattleMonLevel
4774
ld a, [hl]
4775
ld b, a ; Seismic Toss deals damage equal to the user's level
4776
ld a, [wPlayerMoveNum]
4777
cp SEISMIC_TOSS
4778
jr z, .storeDamage
4779
cp NIGHT_SHADE
4780
jr z, .storeDamage
4781
ld b, SONICBOOM_DAMAGE ; 20
4782
cp SONICBOOM
4783
jr z, .storeDamage
4784
ld b, DRAGON_RAGE_DAMAGE ; 40
4785
cp DRAGON_RAGE
4786
jr z, .storeDamage
4787
; Psywave
4788
ld a, [hl]
4789
ld b, a
4790
srl a
4791
add b
4792
ld b, a ; b = level * 1.5
4793
; loop until a random number in the range [1, b) is found
4794
.loop
4795
call BattleRandom
4796
and a
4797
jr z, .loop
4798
cp b
4799
jr nc, .loop
4800
ld b, a
4801
.storeDamage ; store damage value at b
4802
ld hl, wDamage
4803
xor a
4804
ld [hli], a
4805
ld a, b
4806
ld [hl], a
4807
4808
ApplyDamageToEnemyPokemon:
4809
ld hl, wDamage
4810
ld a, [hli]
4811
ld b, a
4812
ld a, [hl]
4813
or b
4814
jr z, ApplyAttackToEnemyPokemonDone ; we're done if damage is 0
4815
ld a, [wEnemyBattleStatus2]
4816
bit HAS_SUBSTITUTE_UP, a ; does the enemy have a substitute?
4817
jp nz, AttackSubstitute
4818
; subtract the damage from the pokemon's current HP
4819
; also, save the current HP at wHPBarOldHP
4820
ld a, [hld]
4821
ld b, a
4822
ld a, [wEnemyMonHP + 1]
4823
ld [wHPBarOldHP], a
4824
sub b
4825
ld [wEnemyMonHP + 1], a
4826
ld a, [hl]
4827
ld b, a
4828
ld a, [wEnemyMonHP]
4829
ld [wHPBarOldHP+1], a
4830
sbc b
4831
ld [wEnemyMonHP], a
4832
jr nc, .animateHpBar
4833
; if more damage was done than the current HP, zero the HP and set the damage (wDamage)
4834
; equal to how much HP the pokemon had before the attack
4835
ld a, [wHPBarOldHP+1]
4836
ld [hli], a
4837
ld a, [wHPBarOldHP]
4838
ld [hl], a
4839
xor a
4840
ld hl, wEnemyMonHP
4841
ld [hli], a
4842
ld [hl], a
4843
.animateHpBar
4844
ld hl, wEnemyMonMaxHP
4845
ld a, [hli]
4846
ld [wHPBarMaxHP+1], a
4847
ld a, [hl]
4848
ld [wHPBarMaxHP], a
4849
ld hl, wEnemyMonHP
4850
ld a, [hli]
4851
ld [wHPBarNewHP+1], a
4852
ld a, [hl]
4853
ld [wHPBarNewHP], a
4854
hlcoord 2, 2
4855
xor a
4856
ld [wHPBarType], a
4857
predef UpdateHPBar2 ; animate the HP bar shortening
4858
ApplyAttackToEnemyPokemonDone:
4859
jp DrawHUDsAndHPBars
4860
4861
ApplyAttackToPlayerPokemon:
4862
ld a, [wEnemyMoveEffect]
4863
cp OHKO_EFFECT
4864
jr z, ApplyDamageToPlayerPokemon
4865
cp SUPER_FANG_EFFECT
4866
jr z, .superFangEffect
4867
cp SPECIAL_DAMAGE_EFFECT
4868
jr z, .specialDamage
4869
ld a, [wEnemyMovePower]
4870
and a
4871
jp z, ApplyAttackToPlayerPokemonDone
4872
jr ApplyDamageToPlayerPokemon
4873
.superFangEffect
4874
; set the damage to half the target's HP
4875
ld hl, wBattleMonHP
4876
ld de, wDamage
4877
ld a, [hli]
4878
srl a
4879
ld [de], a
4880
inc de
4881
ld b, a
4882
ld a, [hl]
4883
rr a
4884
ld [de], a
4885
or b
4886
jr nz, ApplyDamageToPlayerPokemon
4887
; make sure Super Fang's damage is always at least 1
4888
ld a, $01
4889
ld [de], a
4890
jr ApplyDamageToPlayerPokemon
4891
.specialDamage
4892
ld hl, wEnemyMonLevel
4893
ld a, [hl]
4894
ld b, a
4895
ld a, [wEnemyMoveNum]
4896
cp SEISMIC_TOSS
4897
jr z, .storeDamage
4898
cp NIGHT_SHADE
4899
jr z, .storeDamage
4900
ld b, SONICBOOM_DAMAGE
4901
cp SONICBOOM
4902
jr z, .storeDamage
4903
ld b, DRAGON_RAGE_DAMAGE
4904
cp DRAGON_RAGE
4905
jr z, .storeDamage
4906
; Psywave
4907
ld a, [hl]
4908
ld b, a
4909
srl a
4910
add b
4911
ld b, a ; b = attacker's level * 1.5
4912
; loop until a random number in the range [0, b) is found
4913
; this differs from the range when the player attacks, which is [1, b)
4914
; it's possible for the enemy to do 0 damage with Psywave, but the player always does at least 1 damage
4915
.loop
4916
call BattleRandom
4917
cp b
4918
jr nc, .loop
4919
ld b, a
4920
.storeDamage
4921
ld hl, wDamage
4922
xor a
4923
ld [hli], a
4924
ld a, b
4925
ld [hl], a
4926
4927
ApplyDamageToPlayerPokemon:
4928
ld hl, wDamage
4929
ld a, [hli]
4930
ld b, a
4931
ld a, [hl]
4932
or b
4933
jr z, ApplyAttackToPlayerPokemonDone ; we're done if damage is 0
4934
ld a, [wPlayerBattleStatus2]
4935
bit HAS_SUBSTITUTE_UP, a ; does the player have a substitute?
4936
jp nz, AttackSubstitute
4937
; subtract the damage from the pokemon's current HP
4938
; also, save the current HP at wHPBarOldHP and the new HP at wHPBarNewHP
4939
ld a, [hld]
4940
ld b, a
4941
ld a, [wBattleMonHP + 1]
4942
ld [wHPBarOldHP], a
4943
sub b
4944
ld [wBattleMonHP + 1], a
4945
ld [wHPBarNewHP], a
4946
ld b, [hl]
4947
ld a, [wBattleMonHP]
4948
ld [wHPBarOldHP+1], a
4949
sbc b
4950
ld [wBattleMonHP], a
4951
ld [wHPBarNewHP+1], a
4952
jr nc, .animateHpBar
4953
; if more damage was done than the current HP, zero the HP and set the damage (wDamage)
4954
; equal to how much HP the pokemon had before the attack
4955
ld a, [wHPBarOldHP+1]
4956
ld [hli], a
4957
ld a, [wHPBarOldHP]
4958
ld [hl], a
4959
xor a
4960
ld hl, wBattleMonHP
4961
ld [hli], a
4962
ld [hl], a
4963
ld hl, wHPBarNewHP
4964
ld [hli], a
4965
ld [hl], a
4966
.animateHpBar
4967
ld hl, wBattleMonMaxHP
4968
ld a, [hli]
4969
ld [wHPBarMaxHP+1], a
4970
ld a, [hl]
4971
ld [wHPBarMaxHP], a
4972
hlcoord 10, 9
4973
ld a, $01
4974
ld [wHPBarType], a
4975
predef UpdateHPBar2 ; animate the HP bar shortening
4976
ApplyAttackToPlayerPokemonDone:
4977
jp DrawHUDsAndHPBars
4978
4979
AttackSubstitute:
4980
; Unlike the two ApplyAttackToPokemon functions, Attack Substitute is shared by player and enemy.
4981
; Self-confusion damage as well as Hi-Jump Kick and Jump Kick recoil cause a momentary turn swap before being applied.
4982
; If the user has a Substitute up and would take damage because of that,
4983
; damage will be applied to the other player's Substitute.
4984
; Normal recoil such as from Double-Edge isn't affected by this glitch,
4985
; because this function is never called in that case.
4986
4987
ld hl, SubstituteTookDamageText
4988
call PrintText
4989
; values for player turn
4990
ld de, wEnemySubstituteHP
4991
ld bc, wEnemyBattleStatus2
4992
ldh a, [hWhoseTurn]
4993
and a
4994
jr z, .applyDamageToSubstitute
4995
; values for enemy turn
4996
ld de, wPlayerSubstituteHP
4997
ld bc, wPlayerBattleStatus2
4998
.applyDamageToSubstitute
4999
ld hl, wDamage
5000
ld a, [hli]
5001
and a
5002
jr nz, .substituteBroke ; damage > 0xFF always breaks substitutes
5003
; subtract damage from HP of substitute
5004
ld a, [de]
5005
sub [hl]
5006
ld [de], a
5007
ret nc
5008
.substituteBroke
5009
; If the target's Substitute breaks, wDamage isn't updated with the amount of HP
5010
; the Substitute had before being attacked.
5011
ld h, b
5012
ld l, c
5013
res HAS_SUBSTITUTE_UP, [hl] ; unset the substitute bit
5014
ld hl, SubstituteBrokeText
5015
call PrintText
5016
; flip whose turn it is for the next function call
5017
ldh a, [hWhoseTurn]
5018
xor $01
5019
ldh [hWhoseTurn], a
5020
callfar HideSubstituteShowMonAnim ; animate the substitute breaking
5021
; flip the turn back to the way it was
5022
ldh a, [hWhoseTurn]
5023
xor $01
5024
ldh [hWhoseTurn], a
5025
ld hl, wPlayerMoveEffect ; value for player's turn
5026
and a
5027
jr z, .nullifyEffect
5028
ld hl, wEnemyMoveEffect ; value for enemy's turn
5029
.nullifyEffect
5030
xor a
5031
ld [hl], a ; zero the effect of the attacker's move
5032
jp DrawHUDsAndHPBars
5033
5034
SubstituteTookDamageText:
5035
text_far _SubstituteTookDamageText
5036
text_end
5037
5038
SubstituteBrokeText:
5039
text_far _SubstituteBrokeText
5040
text_end
5041
5042
; this function raises the attack modifier of a pokemon using Rage when that pokemon is attacked
5043
HandleBuildingRage:
5044
; values for the player turn
5045
ld hl, wEnemyBattleStatus2
5046
ld de, wEnemyMonStatMods
5047
ld bc, wEnemyMoveNum
5048
ldh a, [hWhoseTurn]
5049
and a
5050
jr z, .next
5051
; values for the enemy turn
5052
ld hl, wPlayerBattleStatus2
5053
ld de, wPlayerMonStatMods
5054
ld bc, wPlayerMoveNum
5055
.next
5056
bit USING_RAGE, [hl] ; is the pokemon being attacked under the effect of Rage?
5057
ret z ; return if not
5058
ld a, [de]
5059
cp $0d ; maximum stat modifier value
5060
ret z ; return if attack modifier is already maxed
5061
ldh a, [hWhoseTurn]
5062
xor $01 ; flip turn for the stat modifier raising function
5063
ldh [hWhoseTurn], a
5064
; temporarily change the target pokemon's move to $00 and the effect to the one
5065
; that causes the attack modifier to go up one stage
5066
ld h, b
5067
ld l, c
5068
ld [hl], $00 ; null move number
5069
inc hl
5070
ld [hl], ATTACK_UP1_EFFECT
5071
push hl
5072
ld hl, BuildingRageText
5073
call PrintText
5074
call StatModifierUpEffect ; stat modifier raising function
5075
pop hl
5076
xor a
5077
ldd [hl], a ; null move effect
5078
ld a, RAGE
5079
ld [hl], a ; restore the target pokemon's move number to Rage
5080
ldh a, [hWhoseTurn]
5081
xor $01 ; flip turn back to the way it was
5082
ldh [hWhoseTurn], a
5083
ret
5084
5085
BuildingRageText:
5086
text_far _BuildingRageText
5087
text_end
5088
5089
; copy last move for Mirror Move
5090
; sets zero flag on failure and unsets zero flag on success
5091
MirrorMoveCopyMove:
5092
; Mirror Move makes use of wPlayerUsedMove and wEnemyUsedMove,
5093
; which are mainly used to print the "[Pokemon] used [Move]" text.
5094
; Both are set to 0 whenever a new Pokemon is sent out
5095
; wPlayerUsedMove is also set to 0 whenever the player is fast asleep or frozen solid.
5096
; wEnemyUsedMove is also set to 0 whenever the enemy is fast asleep or frozen solid.
5097
5098
ldh a, [hWhoseTurn]
5099
and a
5100
; values for player turn
5101
ld a, [wEnemyUsedMove]
5102
ld hl, wPlayerSelectedMove
5103
ld de, wPlayerMoveNum
5104
jr z, .next
5105
; values for enemy turn
5106
ld a, [wPlayerUsedMove]
5107
ld de, wEnemyMoveNum
5108
ld hl, wEnemySelectedMove
5109
.next
5110
ld [hl], a
5111
cp MIRROR_MOVE ; did the target Pokemon last use Mirror Move, and miss?
5112
jr z, .mirrorMoveFailed
5113
and a ; has the target selected any move yet?
5114
jr nz, ReloadMoveData
5115
.mirrorMoveFailed
5116
ld hl, MirrorMoveFailedText
5117
call PrintText
5118
xor a
5119
ret
5120
5121
MirrorMoveFailedText:
5122
text_far _MirrorMoveFailedText
5123
text_end
5124
5125
; function used to reload move data for moves like Mirror Move and Metronome
5126
ReloadMoveData:
5127
ld [wNamedObjectIndex], a
5128
dec a
5129
ld hl, Moves
5130
ld bc, MOVE_LENGTH
5131
call AddNTimes
5132
ld a, BANK(Moves)
5133
call FarCopyData ; copy the move's stats
5134
call IncrementMovePP
5135
; the follow two function calls are used to reload the move name
5136
call GetMoveName
5137
call CopyToStringBuffer
5138
ld a, $01
5139
and a
5140
ret
5141
5142
; function that picks a random move for metronome
5143
MetronomePickMove:
5144
xor a
5145
ld [wAnimationType], a
5146
ld a, METRONOME
5147
call PlayMoveAnimation ; play Metronome's animation
5148
; values for player turn
5149
ld de, wPlayerMoveNum
5150
ld hl, wPlayerSelectedMove
5151
ldh a, [hWhoseTurn]
5152
and a
5153
jr z, .pickMoveLoop
5154
; values for enemy turn
5155
ld de, wEnemyMoveNum
5156
ld hl, wEnemySelectedMove
5157
; loop to pick a random number in the range of valid moves used by Metronome
5158
.pickMoveLoop
5159
call BattleRandom
5160
and a
5161
jr z, .pickMoveLoop
5162
cp STRUGGLE
5163
ASSERT NUM_ATTACKS == STRUGGLE ; random numbers greater than STRUGGLE are not moves
5164
jr nc, .pickMoveLoop
5165
cp METRONOME
5166
jr z, .pickMoveLoop
5167
ld [hl], a
5168
jr ReloadMoveData
5169
5170
; this function increments the current move's PP
5171
; it's used to prevent moves that run another move within the same turn
5172
; (like Mirror Move and Metronome) from losing 2 PP
5173
IncrementMovePP:
5174
ldh a, [hWhoseTurn]
5175
and a
5176
; values for player turn
5177
ld hl, wBattleMonPP
5178
ld de, wPartyMon1PP
5179
ld a, [wPlayerMoveListIndex]
5180
jr z, .next
5181
; values for enemy turn
5182
ld hl, wEnemyMonPP
5183
ld de, wEnemyMon1PP
5184
ld a, [wEnemyMoveListIndex]
5185
.next
5186
ld b, $00
5187
ld c, a
5188
add hl, bc
5189
inc [hl] ; increment PP in the currently battling pokemon memory location
5190
ld h, d
5191
ld l, e
5192
add hl, bc
5193
ldh a, [hWhoseTurn]
5194
and a
5195
ld a, [wPlayerMonNumber] ; value for player turn
5196
jr z, .updatePP
5197
ld a, [wEnemyMonPartyPos] ; value for enemy turn
5198
.updatePP
5199
ld bc, wEnemyMon2 - wEnemyMon1
5200
call AddNTimes
5201
inc [hl] ; increment PP in the party memory location
5202
ret
5203
5204
; function to adjust the base damage of an attack to account for type effectiveness
5205
AdjustDamageForMoveType:
5206
; values for player turn
5207
ld hl, wBattleMonType
5208
ld a, [hli]
5209
ld b, a ; b = type 1 of attacker
5210
ld c, [hl] ; c = type 2 of attacker
5211
ld hl, wEnemyMonType
5212
ld a, [hli]
5213
ld d, a ; d = type 1 of defender
5214
ld e, [hl] ; e = type 2 of defender
5215
ld a, [wPlayerMoveType]
5216
ld [wMoveType], a
5217
ldh a, [hWhoseTurn]
5218
and a
5219
jr z, .next
5220
; values for enemy turn
5221
ld hl, wEnemyMonType
5222
ld a, [hli]
5223
ld b, a ; b = type 1 of attacker
5224
ld c, [hl] ; c = type 2 of attacker
5225
ld hl, wBattleMonType
5226
ld a, [hli]
5227
ld d, a ; d = type 1 of defender
5228
ld e, [hl] ; e = type 2 of defender
5229
ld a, [wEnemyMoveType]
5230
ld [wMoveType], a
5231
.next
5232
ld a, [wMoveType]
5233
cp b ; does the move type match type 1 of the attacker?
5234
jr z, .sameTypeAttackBonus
5235
cp c ; does the move type match type 2 of the attacker?
5236
jr z, .sameTypeAttackBonus
5237
jr .skipSameTypeAttackBonus
5238
.sameTypeAttackBonus
5239
; if the move type matches one of the attacker's types
5240
ld hl, wDamage + 1
5241
ld a, [hld]
5242
ld h, [hl]
5243
ld l, a ; hl = damage
5244
ld b, h
5245
ld c, l ; bc = damage
5246
srl b
5247
rr c ; bc = floor(0.5 * damage)
5248
add hl, bc ; hl = floor(1.5 * damage)
5249
; store damage
5250
ld a, h
5251
ld [wDamage], a
5252
ld a, l
5253
ld [wDamage + 1], a
5254
ld hl, wDamageMultipliers
5255
set BIT_STAB_DAMAGE, [hl]
5256
.skipSameTypeAttackBonus
5257
ld a, [wMoveType]
5258
ld b, a
5259
ld hl, TypeEffects
5260
.loop
5261
ld a, [hli] ; a = "attacking type" of the current type pair
5262
cp $ff
5263
jr z, .done
5264
cp b ; does move type match "attacking type"?
5265
jr nz, .nextTypePair
5266
ld a, [hl] ; a = "defending type" of the current type pair
5267
cp d ; does type 1 of defender match "defending type"?
5268
jr z, .matchingPairFound
5269
cp e ; does type 2 of defender match "defending type"?
5270
jr z, .matchingPairFound
5271
jr .nextTypePair
5272
.matchingPairFound
5273
; if the move type matches the "attacking type" and one of the defender's types matches the "defending type"
5274
push hl
5275
push bc
5276
inc hl
5277
ld a, [wDamageMultipliers]
5278
and 1 << BIT_STAB_DAMAGE
5279
ld b, a
5280
ld a, [hl] ; a = damage multiplier
5281
ldh [hMultiplier], a
5282
add b
5283
ld [wDamageMultipliers], a
5284
xor a
5285
ldh [hMultiplicand], a
5286
ld hl, wDamage
5287
ld a, [hli]
5288
ldh [hMultiplicand + 1], a
5289
ld a, [hld]
5290
ldh [hMultiplicand + 2], a
5291
call Multiply
5292
ld a, 10
5293
ldh [hDivisor], a
5294
ld b, 4
5295
call Divide
5296
ldh a, [hQuotient + 2]
5297
ld [hli], a
5298
ld b, a
5299
ldh a, [hQuotient + 3]
5300
ld [hl], a
5301
or b ; is damage 0?
5302
jr nz, .skipTypeImmunity
5303
.typeImmunity
5304
; if damage is 0, make the move miss
5305
; this only occurs if a move that would do 2 or 3 damage is 0.25x effective against the target
5306
inc a
5307
ld [wMoveMissed], a
5308
.skipTypeImmunity
5309
pop bc
5310
pop hl
5311
.nextTypePair
5312
inc hl
5313
inc hl
5314
jp .loop
5315
.done
5316
ret
5317
5318
; function to tell how effective the type of an enemy attack is on the player's current pokemon
5319
; this doesn't take into account the effects that dual types can have
5320
; (e.g. 4x weakness / resistance, weaknesses and resistances canceling)
5321
; the result is stored in [wTypeEffectiveness]
5322
; as far is can tell, this is only used once in some AI code to help decide which move to use
5323
AIGetTypeEffectiveness:
5324
ld a, [wEnemyMoveType]
5325
ld d, a ; d = type of enemy move
5326
ld hl, wBattleMonType
5327
ld b, [hl] ; b = type 1 of player's pokemon
5328
inc hl
5329
ld c, [hl] ; c = type 2 of player's pokemon
5330
; initialize to neutral effectiveness
5331
ld a, $10 ; bug: should be EFFECTIVE (10)
5332
ld [wTypeEffectiveness], a
5333
ld hl, TypeEffects
5334
.loop
5335
ld a, [hli]
5336
cp $ff
5337
ret z
5338
cp d ; match the type of the move
5339
jr nz, .nextTypePair1
5340
ld a, [hli]
5341
cp b ; match with type 1 of pokemon
5342
jr z, .done
5343
cp c ; or match with type 2 of pokemon
5344
jr z, .done
5345
jr .nextTypePair2
5346
.nextTypePair1
5347
inc hl
5348
.nextTypePair2
5349
inc hl
5350
jr .loop
5351
.done
5352
ld a, [hl]
5353
ld [wTypeEffectiveness], a ; store damage multiplier
5354
ret
5355
5356
INCLUDE "data/types/type_matchups.asm"
5357
5358
; some tests that need to pass for a move to hit
5359
MoveHitTest:
5360
; player's turn
5361
ld hl, wEnemyBattleStatus1
5362
ld de, wPlayerMoveEffect
5363
ld bc, wEnemyMonStatus
5364
ldh a, [hWhoseTurn]
5365
and a
5366
jr z, .dreamEaterCheck
5367
; enemy's turn
5368
ld hl, wPlayerBattleStatus1
5369
ld de, wEnemyMoveEffect
5370
ld bc, wBattleMonStatus
5371
.dreamEaterCheck
5372
ld a, [de]
5373
cp DREAM_EATER_EFFECT
5374
jr nz, .swiftCheck
5375
ld a, [bc]
5376
and SLP_MASK
5377
jp z, .moveMissed
5378
.swiftCheck
5379
ld a, [de]
5380
cp SWIFT_EFFECT
5381
ret z ; Swift never misses (this was fixed from the Japanese versions)
5382
call CheckTargetSubstitute ; substitute check (note that this overwrites a)
5383
jr z, .checkForDigOrFlyStatus
5384
; The fix for Swift broke this code. It's supposed to prevent HP draining moves from working on Substitutes.
5385
; Since CheckTargetSubstitute overwrites a with either $00 or $01, it never works.
5386
cp DRAIN_HP_EFFECT
5387
jp z, .moveMissed
5388
cp DREAM_EATER_EFFECT
5389
jp z, .moveMissed
5390
.checkForDigOrFlyStatus
5391
bit INVULNERABLE, [hl]
5392
jp nz, .moveMissed
5393
ldh a, [hWhoseTurn]
5394
and a
5395
jr nz, .enemyTurn
5396
.playerTurn
5397
; this checks if the move effect is disallowed by mist
5398
ld a, [wPlayerMoveEffect]
5399
cp ATTACK_DOWN1_EFFECT
5400
jr c, .skipEnemyMistCheck
5401
cp HAZE_EFFECT + 1
5402
jr c, .enemyMistCheck
5403
cp ATTACK_DOWN2_EFFECT
5404
jr c, .skipEnemyMistCheck
5405
cp REFLECT_EFFECT + 1
5406
jr c, .enemyMistCheck
5407
jr .skipEnemyMistCheck
5408
.enemyMistCheck
5409
; if move effect is from $12 to $19 inclusive or $3a to $41 inclusive
5410
; i.e. the following moves
5411
; GROWL, TAIL WHIP, LEER, STRING SHOT, SAND-ATTACK, SMOKESCREEN, KINESIS,
5412
; FLASH, CONVERSION*, HAZE*, SCREECH, LIGHT SCREEN*, REFLECT*
5413
; the moves that are marked with an asterisk are not affected since this
5414
; function is not called when those moves are used
5415
ld a, [wEnemyBattleStatus2]
5416
bit PROTECTED_BY_MIST, a ; is mon protected by mist?
5417
jp nz, .moveMissed
5418
.skipEnemyMistCheck
5419
ld a, [wPlayerBattleStatus2]
5420
bit USING_X_ACCURACY, a ; is the player using X Accuracy?
5421
ret nz ; if so, always hit regardless of accuracy/evasion
5422
jr .calcHitChance
5423
.enemyTurn
5424
ld a, [wEnemyMoveEffect]
5425
cp ATTACK_DOWN1_EFFECT
5426
jr c, .skipPlayerMistCheck
5427
cp HAZE_EFFECT + 1
5428
jr c, .playerMistCheck
5429
cp ATTACK_DOWN2_EFFECT
5430
jr c, .skipPlayerMistCheck
5431
cp REFLECT_EFFECT + 1
5432
jr c, .playerMistCheck
5433
jr .skipPlayerMistCheck
5434
.playerMistCheck
5435
; similar to enemy mist check
5436
ld a, [wPlayerBattleStatus2]
5437
bit PROTECTED_BY_MIST, a ; is mon protected by mist?
5438
jp nz, .moveMissed
5439
.skipPlayerMistCheck
5440
ld a, [wEnemyBattleStatus2]
5441
bit USING_X_ACCURACY, a ; is the enemy using X Accuracy?
5442
ret nz ; if so, always hit regardless of accuracy/evasion
5443
.calcHitChance
5444
call CalcHitChance ; scale the move accuracy according to attacker's accuracy and target's evasion
5445
ld a, [wPlayerMoveAccuracy]
5446
ld b, a
5447
ldh a, [hWhoseTurn]
5448
and a
5449
jr z, .doAccuracyCheck
5450
ld a, [wEnemyMoveAccuracy]
5451
ld b, a
5452
.doAccuracyCheck
5453
; if the random number generated is greater than or equal to the scaled accuracy, the move misses
5454
; note that this means that even the highest accuracy is still just a 255/256 chance, not 100%
5455
call BattleRandom
5456
cp b
5457
jr nc, .moveMissed
5458
ret
5459
.moveMissed
5460
xor a
5461
ld hl, wDamage ; zero the damage
5462
ld [hli], a
5463
ld [hl], a
5464
inc a
5465
ld [wMoveMissed], a
5466
ldh a, [hWhoseTurn]
5467
and a
5468
jr z, .playerTurn2
5469
.enemyTurn2
5470
ld hl, wEnemyBattleStatus1
5471
res USING_TRAPPING_MOVE, [hl] ; end multi-turn attack e.g. wrap
5472
ret
5473
.playerTurn2
5474
ld hl, wPlayerBattleStatus1
5475
res USING_TRAPPING_MOVE, [hl] ; end multi-turn attack e.g. wrap
5476
ret
5477
5478
; values for player turn
5479
CalcHitChance:
5480
ld hl, wPlayerMoveAccuracy
5481
ldh a, [hWhoseTurn]
5482
and a
5483
ld a, [wPlayerMonAccuracyMod]
5484
ld b, a
5485
ld a, [wEnemyMonEvasionMod]
5486
ld c, a
5487
jr z, .next
5488
; values for enemy turn
5489
ld hl, wEnemyMoveAccuracy
5490
ld a, [wEnemyMonAccuracyMod]
5491
ld b, a
5492
ld a, [wPlayerMonEvasionMod]
5493
ld c, a
5494
.next
5495
ld a, $0e
5496
sub c
5497
ld c, a ; c = 14 - EVASIONMOD (this "reflects" the value over 7, so that an increase in the target's evasion
5498
; decreases the hit chance instead of increasing the hit chance)
5499
; zero the high bytes of the multiplicand
5500
xor a
5501
ldh [hMultiplicand], a
5502
ldh [hMultiplicand + 1], a
5503
ld a, [hl]
5504
ldh [hMultiplicand + 2], a ; set multiplicand to move accuracy
5505
push hl
5506
ld d, $02 ; loop has two iterations
5507
; loop to do the calculations, the first iteration multiplies by the accuracy ratio and
5508
; the second iteration multiplies by the evasion ratio
5509
.loop
5510
push bc
5511
ld hl, StatModifierRatios ; stat modifier ratios
5512
dec b
5513
sla b
5514
ld c, b
5515
ld b, $00
5516
add hl, bc ; hl = address of stat modifier ratio
5517
pop bc
5518
ld a, [hli]
5519
ldh [hMultiplier], a ; set multiplier to the numerator of the ratio
5520
call Multiply
5521
ld a, [hl]
5522
ldh [hDivisor], a ; set divisor to the the denominator of the ratio
5523
; (the dividend is the product of the previous multiplication)
5524
ld b, $04 ; number of bytes in the dividend
5525
call Divide
5526
ldh a, [hQuotient + 3]
5527
ld b, a
5528
ldh a, [hQuotient + 2]
5529
or b
5530
jp nz, .nextCalculation
5531
; make sure the result is always at least one
5532
ldh [hQuotient + 2], a
5533
ld a, $01
5534
ldh [hQuotient + 3], a
5535
.nextCalculation
5536
ld b, c
5537
dec d
5538
jr nz, .loop
5539
ldh a, [hQuotient + 2]
5540
and a ; is the calculated hit chance over 0xFF?
5541
ldh a, [hQuotient + 3]
5542
jr z, .storeAccuracy
5543
; if calculated hit chance over 0xFF
5544
ld a, $ff ; set the hit chance to 0xFF
5545
.storeAccuracy
5546
pop hl
5547
ld [hl], a ; store the hit chance in the move accuracy variable
5548
ret
5549
5550
; multiplies damage by a random percentage from ~85% to 100%
5551
RandomizeDamage:
5552
ld hl, wDamage
5553
ld a, [hli]
5554
and a
5555
jr nz, .DamageGreaterThanOne
5556
ld a, [hl]
5557
cp 2
5558
ret c ; return if damage is equal to 0 or 1
5559
.DamageGreaterThanOne
5560
xor a
5561
ldh [hMultiplicand], a
5562
dec hl
5563
ld a, [hli]
5564
ldh [hMultiplicand + 1], a
5565
ld a, [hl]
5566
ldh [hMultiplicand + 2], a
5567
; loop until a random number greater than or equal to 217 is generated
5568
.loop
5569
call BattleRandom
5570
rrca
5571
cp 85 percent + 1
5572
jr c, .loop
5573
ldh [hMultiplier], a
5574
call Multiply ; multiply damage by the random number, which is in the range [217, 255]
5575
ld a, 255
5576
ldh [hDivisor], a
5577
ld b, $4
5578
call Divide ; divide the result by 255
5579
; store the modified damage
5580
ldh a, [hQuotient + 2]
5581
ld hl, wDamage
5582
ld [hli], a
5583
ldh a, [hQuotient + 3]
5584
ld [hl], a
5585
ret
5586
5587
; for more detailed commentary, see equivalent function for player side (ExecutePlayerMove)
5588
ExecuteEnemyMove:
5589
ld a, [wEnemySelectedMove]
5590
ASSERT CANNOT_MOVE == $ff
5591
inc a
5592
jp z, ExecuteEnemyMoveDone
5593
call PrintGhostText
5594
jp z, ExecuteEnemyMoveDone
5595
ld a, [wLinkState]
5596
cp LINK_STATE_BATTLING
5597
jr nz, .executeEnemyMove
5598
ld b, $1
5599
ld a, [wSerialExchangeNybbleReceiveData]
5600
cp LINKBATTLE_STRUGGLE
5601
jr z, .executeEnemyMove
5602
cp 4
5603
ret nc
5604
.executeEnemyMove
5605
ld hl, wAILayer2Encouragement
5606
inc [hl]
5607
xor a
5608
ld [wMoveMissed], a
5609
ld [wMoveDidntMiss], a
5610
ld a, EFFECTIVE
5611
ld [wDamageMultipliers], a
5612
call CheckEnemyStatusConditions
5613
jr nz, .enemyHasNoSpecialConditions
5614
jp hl
5615
.enemyHasNoSpecialConditions
5616
ld hl, wEnemyBattleStatus1
5617
bit CHARGING_UP, [hl] ; is the enemy charging up for attack?
5618
jr nz, EnemyCanExecuteChargingMove ; if so, jump
5619
call GetCurrentMove
5620
5621
CheckIfEnemyNeedsToChargeUp:
5622
ld a, [wEnemyMoveEffect]
5623
cp CHARGE_EFFECT
5624
jp z, JumpMoveEffect
5625
cp FLY_EFFECT
5626
jp z, JumpMoveEffect
5627
jr EnemyCanExecuteMove
5628
EnemyCanExecuteChargingMove:
5629
ld hl, wEnemyBattleStatus1
5630
res CHARGING_UP, [hl] ; no longer charging up for attack
5631
res INVULNERABLE, [hl] ; no longer invulnerable to typical attacks
5632
ld a, [wEnemyMoveNum]
5633
ld [wNameListIndex], a
5634
ld a, BANK(MoveNames)
5635
ld [wPredefBank], a
5636
ld a, MOVE_NAME
5637
ld [wNameListType], a
5638
call GetName
5639
ld de, wNameBuffer
5640
call CopyToStringBuffer
5641
EnemyCanExecuteMove:
5642
xor a
5643
ld [wMonIsDisobedient], a
5644
call PrintMonName1Text
5645
ld a, [wEnemyMoveEffect]
5646
ld hl, ResidualEffects1
5647
ld de, $1
5648
call IsInArray
5649
jp c, JumpMoveEffect
5650
ld a, [wEnemyMoveEffect]
5651
ld hl, SpecialEffectsCont
5652
ld de, $1
5653
call IsInArray
5654
call c, JumpMoveEffect
5655
EnemyCalcMoveDamage:
5656
call SwapPlayerAndEnemyLevels
5657
ld a, [wEnemyMoveEffect]
5658
ld hl, SetDamageEffects
5659
ld de, $1
5660
call IsInArray
5661
jp c, EnemyMoveHitTest
5662
call CriticalHitTest
5663
call HandleCounterMove
5664
jr z, HandleIfEnemyMoveMissed
5665
call SwapPlayerAndEnemyLevels
5666
call GetDamageVarsForEnemyAttack
5667
call SwapPlayerAndEnemyLevels
5668
call CalculateDamage
5669
jp z, EnemyCheckIfFlyOrChargeEffect
5670
call AdjustDamageForMoveType
5671
call RandomizeDamage
5672
5673
EnemyMoveHitTest:
5674
call MoveHitTest
5675
HandleIfEnemyMoveMissed:
5676
ld a, [wMoveMissed]
5677
and a
5678
jr z, .moveDidNotMiss
5679
ld a, [wEnemyMoveEffect]
5680
cp EXPLODE_EFFECT
5681
jr z, HandleExplosionMiss
5682
jr EnemyCheckIfFlyOrChargeEffect
5683
.moveDidNotMiss
5684
call SwapPlayerAndEnemyLevels
5685
5686
GetEnemyAnimationType:
5687
ld a, [wEnemyMoveEffect]
5688
and a
5689
ld a, ANIMATIONTYPE_SHAKE_SCREEN_VERTICALLY
5690
jr z, PlayEnemyMoveAnimation
5691
ld a, ANIMATIONTYPE_SHAKE_SCREEN_HORIZONTALLY_HEAVY
5692
jr PlayEnemyMoveAnimation
5693
HandleExplosionMiss:
5694
call SwapPlayerAndEnemyLevels
5695
xor a
5696
PlayEnemyMoveAnimation:
5697
push af
5698
ld a, [wEnemyBattleStatus2]
5699
bit HAS_SUBSTITUTE_UP, a ; does mon have a substitute?
5700
ld hl, HideSubstituteShowMonAnim
5701
ld b, BANK(HideSubstituteShowMonAnim)
5702
call nz, Bankswitch
5703
pop af
5704
ld [wAnimationType], a
5705
ld a, [wEnemyMoveNum]
5706
call PlayMoveAnimation
5707
call HandleExplodingAnimation
5708
call DrawEnemyHUDAndHPBar
5709
ld a, [wEnemyBattleStatus2]
5710
bit HAS_SUBSTITUTE_UP, a ; does mon have a substitute?
5711
ld hl, ReshowSubstituteAnim
5712
ld b, BANK(ReshowSubstituteAnim)
5713
call nz, Bankswitch ; slide the substitute's sprite out
5714
jr EnemyCheckIfMirrorMoveEffect
5715
5716
EnemyCheckIfFlyOrChargeEffect:
5717
call SwapPlayerAndEnemyLevels
5718
ld c, 30
5719
call DelayFrames
5720
ld a, [wEnemyMoveEffect]
5721
cp FLY_EFFECT
5722
jr z, .playAnim
5723
cp CHARGE_EFFECT
5724
jr z, .playAnim
5725
jr EnemyCheckIfMirrorMoveEffect
5726
.playAnim
5727
xor a
5728
ld [wAnimationType], a
5729
ld a, STATUS_AFFECTED_ANIM
5730
call PlayMoveAnimation
5731
EnemyCheckIfMirrorMoveEffect:
5732
ld a, [wEnemyMoveEffect]
5733
cp MIRROR_MOVE_EFFECT
5734
jr nz, .notMirrorMoveEffect
5735
call MirrorMoveCopyMove
5736
jp z, ExecuteEnemyMoveDone
5737
jp CheckIfEnemyNeedsToChargeUp
5738
.notMirrorMoveEffect
5739
cp METRONOME_EFFECT
5740
jr nz, .notMetronomeEffect
5741
call MetronomePickMove
5742
jp CheckIfEnemyNeedsToChargeUp
5743
.notMetronomeEffect
5744
ld a, [wEnemyMoveEffect]
5745
ld hl, ResidualEffects2
5746
ld de, $1
5747
call IsInArray
5748
jp c, JumpMoveEffect
5749
ld a, [wMoveMissed]
5750
and a
5751
jr z, .moveDidNotMiss
5752
call PrintMoveFailureText
5753
ld a, [wEnemyMoveEffect]
5754
cp EXPLODE_EFFECT
5755
jr z, .handleExplosionMiss
5756
jp ExecuteEnemyMoveDone
5757
.moveDidNotMiss
5758
call ApplyAttackToPlayerPokemon
5759
call PrintCriticalOHKOText
5760
callfar DisplayEffectiveness
5761
ld a, 1
5762
ld [wMoveDidntMiss], a
5763
.handleExplosionMiss
5764
ld a, [wEnemyMoveEffect]
5765
ld hl, AlwaysHappenSideEffects
5766
ld de, $1
5767
call IsInArray
5768
call c, JumpMoveEffect
5769
ld hl, wBattleMonHP
5770
ld a, [hli]
5771
ld b, [hl]
5772
or b
5773
ret z
5774
call HandleBuildingRage
5775
ld hl, wEnemyBattleStatus1
5776
bit ATTACKING_MULTIPLE_TIMES, [hl] ; is mon hitting multiple times? (example: double kick)
5777
jr z, .notMultiHitMove
5778
push hl
5779
ld hl, wEnemyNumAttacksLeft
5780
dec [hl]
5781
pop hl
5782
jp nz, GetEnemyAnimationType
5783
res ATTACKING_MULTIPLE_TIMES, [hl] ; mon is no longer hitting multiple times
5784
ld hl, HitXTimesText
5785
call PrintText
5786
xor a
5787
ld [wEnemyNumHits], a
5788
.notMultiHitMove
5789
ld a, [wEnemyMoveEffect]
5790
and a
5791
jr z, ExecuteEnemyMoveDone
5792
ld hl, SpecialEffects
5793
ld de, $1
5794
call IsInArray
5795
call nc, JumpMoveEffect
5796
jr ExecuteEnemyMoveDone
5797
5798
HitXTimesText:
5799
text_far _HitXTimesText
5800
text_end
5801
5802
ExecuteEnemyMoveDone:
5803
ld b, $1
5804
ret
5805
5806
; checks for various status conditions affecting the enemy mon
5807
; stores whether the mon cannot use a move this turn in Z flag
5808
CheckEnemyStatusConditions:
5809
ld hl, wEnemyMonStatus
5810
ld a, [hl]
5811
and SLP_MASK
5812
jr z, .checkIfFrozen
5813
dec a ; decrement number of turns left
5814
ld [wEnemyMonStatus], a
5815
and a
5816
jr z, .wokeUp ; if the number of turns hit 0, wake up
5817
ld hl, FastAsleepText
5818
call PrintText
5819
xor a
5820
ld [wAnimationType], a
5821
ld a, SLP_ANIM
5822
call PlayMoveAnimation
5823
jr .sleepDone
5824
.wokeUp
5825
ld hl, WokeUpText
5826
call PrintText
5827
.sleepDone
5828
xor a
5829
ld [wEnemyUsedMove], a
5830
ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
5831
jp .enemyReturnToHL
5832
.checkIfFrozen
5833
bit FRZ, [hl]
5834
jr z, .checkIfTrapped
5835
ld hl, IsFrozenText
5836
call PrintText
5837
xor a
5838
ld [wEnemyUsedMove], a
5839
ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
5840
jp .enemyReturnToHL
5841
.checkIfTrapped
5842
ld a, [wPlayerBattleStatus1]
5843
bit USING_TRAPPING_MOVE, a ; is the player using a multi-turn attack like warp
5844
jp z, .checkIfFlinched
5845
ld hl, CantMoveText
5846
call PrintText
5847
ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
5848
jp .enemyReturnToHL
5849
.checkIfFlinched
5850
ld hl, wEnemyBattleStatus1
5851
bit FLINCHED, [hl] ; check if enemy mon flinched
5852
jp z, .checkIfMustRecharge
5853
res FLINCHED, [hl]
5854
ld hl, FlinchedText
5855
call PrintText
5856
ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
5857
jp .enemyReturnToHL
5858
.checkIfMustRecharge
5859
ld hl, wEnemyBattleStatus2
5860
bit NEEDS_TO_RECHARGE, [hl] ; check if enemy mon has to recharge after using a move
5861
jr z, .checkIfAnyMoveDisabled
5862
res NEEDS_TO_RECHARGE, [hl]
5863
ld hl, MustRechargeText
5864
call PrintText
5865
ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
5866
jp .enemyReturnToHL
5867
.checkIfAnyMoveDisabled
5868
ld hl, wEnemyDisabledMove
5869
ld a, [hl]
5870
and a
5871
jr z, .checkIfConfused
5872
dec a ; decrement disable counter
5873
ld [hl], a
5874
and $f ; did disable counter hit 0?
5875
jr nz, .checkIfConfused
5876
ld [hl], a
5877
ld [wEnemyDisabledMoveNumber], a
5878
ld hl, DisabledNoMoreText
5879
call PrintText
5880
.checkIfConfused
5881
ld a, [wEnemyBattleStatus1]
5882
add a ; check if enemy mon is confused
5883
jp nc, .checkIfTriedToUseDisabledMove
5884
ld hl, wEnemyConfusedCounter
5885
dec [hl]
5886
jr nz, .isConfused
5887
ld hl, wEnemyBattleStatus1
5888
res CONFUSED, [hl] ; if confused counter hit 0, reset confusion status
5889
ld hl, ConfusedNoMoreText
5890
call PrintText
5891
jp .checkIfTriedToUseDisabledMove
5892
.isConfused
5893
ld hl, IsConfusedText
5894
call PrintText
5895
xor a
5896
ld [wAnimationType], a
5897
ld a, CONF_ANIM
5898
call PlayMoveAnimation
5899
call BattleRandom
5900
cp $80
5901
jr c, .checkIfTriedToUseDisabledMove
5902
ld hl, wEnemyBattleStatus1
5903
ld a, [hl]
5904
and 1 << CONFUSED ; if mon hurts itself, clear every other status from wEnemyBattleStatus1
5905
ld [hl], a
5906
ld hl, HurtItselfText
5907
call PrintText
5908
ld hl, wBattleMonDefense
5909
ld a, [hli]
5910
push af
5911
ld a, [hld]
5912
push af
5913
ld a, [wEnemyMonDefense]
5914
ld [hli], a
5915
ld a, [wEnemyMonDefense + 1]
5916
ld [hl], a
5917
ld hl, wEnemyMoveEffect
5918
push hl
5919
ld a, [hl]
5920
push af
5921
xor a
5922
ld [hli], a
5923
ld [wCriticalHitOrOHKO], a
5924
ld a, 40
5925
ld [hli], a
5926
xor a
5927
ld [hl], a
5928
call GetDamageVarsForEnemyAttack
5929
call CalculateDamage
5930
pop af
5931
pop hl
5932
ld [hl], a
5933
ld hl, wBattleMonDefense + 1
5934
pop af
5935
ld [hld], a
5936
pop af
5937
ld [hl], a
5938
xor a
5939
ld [wAnimationType], a
5940
ldh [hWhoseTurn], a
5941
ld a, POUND
5942
call PlayMoveAnimation
5943
ld a, $1
5944
ldh [hWhoseTurn], a
5945
call ApplyDamageToEnemyPokemon
5946
jr .monHurtItselfOrFullyParalysed
5947
.checkIfTriedToUseDisabledMove
5948
; prevents a disabled move that was selected before being disabled from being used
5949
ld a, [wEnemyDisabledMoveNumber]
5950
and a
5951
jr z, .checkIfParalysed
5952
ld hl, wEnemySelectedMove
5953
cp [hl]
5954
jr nz, .checkIfParalysed
5955
call PrintMoveIsDisabledText
5956
ld hl, ExecuteEnemyMoveDone ; if a disabled move was somehow selected, player can't move this turn
5957
jp .enemyReturnToHL
5958
.checkIfParalysed
5959
ld hl, wEnemyMonStatus
5960
bit PAR, [hl]
5961
jr z, .checkIfUsingBide
5962
call BattleRandom
5963
cp 25 percent ; chance to be fully paralysed
5964
jr nc, .checkIfUsingBide
5965
ld hl, FullyParalyzedText
5966
call PrintText
5967
.monHurtItselfOrFullyParalysed
5968
ld hl, wEnemyBattleStatus1
5969
ld a, [hl]
5970
; clear bide, thrashing about, charging up, and multi-turn moves such as warp
5971
and ~((1 << STORING_ENERGY) | (1 << THRASHING_ABOUT) | (1 << CHARGING_UP) | (1 << USING_TRAPPING_MOVE))
5972
ld [hl], a
5973
ld a, [wEnemyMoveEffect]
5974
cp FLY_EFFECT
5975
jr z, .flyOrChargeEffect
5976
cp CHARGE_EFFECT
5977
jr z, .flyOrChargeEffect
5978
jr .notFlyOrChargeEffect
5979
.flyOrChargeEffect
5980
xor a
5981
ld [wAnimationType], a
5982
ld a, STATUS_AFFECTED_ANIM
5983
call PlayMoveAnimation
5984
.notFlyOrChargeEffect
5985
ld hl, ExecuteEnemyMoveDone
5986
jp .enemyReturnToHL ; if using a two-turn move, enemy needs to recharge the first turn
5987
.checkIfUsingBide
5988
ld hl, wEnemyBattleStatus1
5989
bit STORING_ENERGY, [hl] ; is mon using bide?
5990
jr z, .checkIfThrashingAbout
5991
xor a
5992
ld [wEnemyMoveNum], a
5993
ld hl, wDamage
5994
ld a, [hli]
5995
ld b, a
5996
ld c, [hl]
5997
ld hl, wEnemyBideAccumulatedDamage + 1
5998
ld a, [hl]
5999
add c ; accumulate damage taken
6000
ld [hld], a
6001
ld a, [hl]
6002
adc b
6003
ld [hl], a
6004
ld hl, wEnemyNumAttacksLeft
6005
dec [hl] ; did Bide counter hit 0?
6006
jr z, .unleashEnergy
6007
ld hl, ExecuteEnemyMoveDone
6008
jp .enemyReturnToHL ; unless mon unleashes energy, can't move this turn
6009
.unleashEnergy
6010
ld hl, wEnemyBattleStatus1
6011
res STORING_ENERGY, [hl] ; not using bide any more
6012
ld hl, UnleashedEnergyText
6013
call PrintText
6014
ld a, $1
6015
ld [wEnemyMovePower], a
6016
ld hl, wEnemyBideAccumulatedDamage + 1
6017
ld a, [hld]
6018
add a
6019
ld b, a
6020
ld [wDamage + 1], a
6021
ld a, [hl]
6022
rl a ; double the damage
6023
ld [wDamage], a
6024
or b
6025
jr nz, .next
6026
ld a, $1
6027
ld [wMoveMissed], a
6028
.next
6029
xor a
6030
ld [hli], a
6031
ld [hl], a
6032
ld a, BIDE
6033
ld [wEnemyMoveNum], a
6034
call SwapPlayerAndEnemyLevels
6035
ld hl, HandleIfEnemyMoveMissed ; skip damage calculation, DecrementPP and MoveHitTest
6036
jp .enemyReturnToHL
6037
.checkIfThrashingAbout
6038
bit THRASHING_ABOUT, [hl] ; is mon using thrash or petal dance?
6039
jr z, .checkIfUsingMultiturnMove
6040
ld a, THRASH
6041
ld [wEnemyMoveNum], a
6042
ld hl, ThrashingAboutText
6043
call PrintText
6044
ld hl, wEnemyNumAttacksLeft
6045
dec [hl] ; did Thrashing About counter hit 0?
6046
ld hl, EnemyCalcMoveDamage ; skip DecrementPP
6047
jp nz, .enemyReturnToHL
6048
push hl
6049
ld hl, wEnemyBattleStatus1
6050
res THRASHING_ABOUT, [hl] ; mon is no longer using thrash or petal dance
6051
set CONFUSED, [hl] ; mon is now confused
6052
call BattleRandom
6053
and $3
6054
inc a
6055
inc a ; confused for 2-5 turns
6056
ld [wEnemyConfusedCounter], a
6057
pop hl ; skip DecrementPP
6058
jp .enemyReturnToHL
6059
.checkIfUsingMultiturnMove
6060
bit USING_TRAPPING_MOVE, [hl] ; is mon using multi-turn move?
6061
jp z, .checkIfUsingRage
6062
ld hl, AttackContinuesText
6063
call PrintText
6064
ld hl, wEnemyNumAttacksLeft
6065
dec [hl] ; did multi-turn move end?
6066
ld hl, GetEnemyAnimationType ; if it didn't, skip damage calculation (deal damage equal to last hit),
6067
; DecrementPP and MoveHitTest
6068
jp nz, .enemyReturnToHL
6069
jp .enemyReturnToHL
6070
.checkIfUsingRage
6071
ld a, [wEnemyBattleStatus2]
6072
bit USING_RAGE, a ; is mon using rage?
6073
jp z, .checkEnemyStatusConditionsDone ; if we made it this far, mon can move normally this turn
6074
ld a, RAGE
6075
ld [wNamedObjectIndex], a
6076
call GetMoveName
6077
call CopyToStringBuffer
6078
xor a
6079
ld [wEnemyMoveEffect], a
6080
ld hl, EnemyCanExecuteMove
6081
jp .enemyReturnToHL
6082
.enemyReturnToHL
6083
xor a ; set Z flag
6084
ret
6085
.checkEnemyStatusConditionsDone
6086
ld a, $1
6087
and a ; clear Z flag
6088
ret
6089
6090
GetCurrentMove:
6091
ldh a, [hWhoseTurn]
6092
and a
6093
jp z, .player
6094
ld de, wEnemyMoveNum
6095
ld a, [wEnemySelectedMove]
6096
jr .selected
6097
.player
6098
ld de, wPlayerMoveNum
6099
; Apply InitBattleVariables to TestBattle.
6100
ld a, [wStatusFlags7]
6101
bit BIT_TEST_BATTLE, a
6102
ld a, [wTestBattlePlayerSelectedMove]
6103
jr nz, .selected
6104
ld a, [wPlayerSelectedMove]
6105
.selected
6106
ld [wNameListIndex], a
6107
dec a
6108
ld hl, Moves
6109
ld bc, MOVE_LENGTH
6110
call AddNTimes
6111
ld a, BANK(Moves)
6112
call FarCopyData
6113
6114
ld a, BANK(MoveNames)
6115
ld [wPredefBank], a
6116
ld a, MOVE_NAME
6117
ld [wNameListType], a
6118
call GetName
6119
ld de, wNameBuffer
6120
jp CopyToStringBuffer
6121
6122
LoadEnemyMonData:
6123
ld a, [wLinkState]
6124
cp LINK_STATE_BATTLING
6125
jp z, LoadEnemyMonFromParty
6126
ld a, [wEnemyMonSpecies2]
6127
ld [wEnemyMonSpecies], a
6128
ld [wCurSpecies], a
6129
call GetMonHeader
6130
ld a, [wEnemyBattleStatus3]
6131
bit TRANSFORMED, a ; is enemy mon transformed?
6132
ld hl, wTransformedEnemyMonOriginalDVs ; original DVs before transforming
6133
ld a, [hli]
6134
ld b, [hl]
6135
jr nz, .storeDVs
6136
ld a, [wIsInBattle]
6137
cp $2 ; is it a trainer battle?
6138
; fixed DVs for trainer mon
6139
ld a, ATKDEFDV_TRAINER
6140
ld b, SPDSPCDV_TRAINER
6141
jr z, .storeDVs
6142
; random DVs for wild mon
6143
call BattleRandom
6144
ld b, a
6145
call BattleRandom
6146
.storeDVs
6147
ld hl, wEnemyMonDVs
6148
ld [hli], a
6149
ld [hl], b
6150
ld de, wEnemyMonLevel
6151
ld a, [wCurEnemyLevel]
6152
ld [de], a
6153
inc de
6154
ld b, $0
6155
ld hl, wEnemyMonHP
6156
push hl
6157
call CalcStats
6158
pop hl
6159
ld a, [wIsInBattle]
6160
cp $2 ; is it a trainer battle?
6161
jr z, .copyHPAndStatusFromPartyData
6162
ld a, [wEnemyBattleStatus3]
6163
bit TRANSFORMED, a ; is enemy mon transformed?
6164
jr nz, .copyTypes ; if transformed, jump
6165
; if it's a wild mon and not transformed, init the current HP to max HP and the status to 0
6166
ld a, [wEnemyMonMaxHP]
6167
ld [hli], a
6168
ld a, [wEnemyMonMaxHP+1]
6169
ld [hli], a
6170
xor a
6171
inc hl
6172
ld [hl], a ; init status to 0
6173
jr .copyTypes
6174
; if it's a trainer mon, copy the HP and status from the enemy party data
6175
.copyHPAndStatusFromPartyData
6176
ld hl, wEnemyMon1HP
6177
ld a, [wWhichPokemon]
6178
ld bc, wEnemyMon2 - wEnemyMon1
6179
call AddNTimes
6180
ld a, [hli]
6181
ld [wEnemyMonHP], a
6182
ld a, [hli]
6183
ld [wEnemyMonHP + 1], a
6184
ld a, [wWhichPokemon]
6185
ld [wEnemyMonPartyPos], a
6186
inc hl
6187
ld a, [hl]
6188
ld [wEnemyMonStatus], a
6189
jr .copyTypes
6190
.copyTypes
6191
ld hl, wMonHTypes
6192
ld de, wEnemyMonType
6193
ld a, [hli] ; copy type 1
6194
ld [de], a
6195
inc de
6196
ld a, [hli] ; copy type 2
6197
ld [de], a
6198
inc de
6199
ld a, [hli] ; copy catch rate
6200
ld [de], a
6201
inc de
6202
ld a, [wIsInBattle]
6203
cp $2 ; is it a trainer battle?
6204
jr nz, .copyStandardMoves
6205
; if it's a trainer battle, copy moves from enemy party data
6206
ld hl, wEnemyMon1Moves
6207
ld a, [wWhichPokemon]
6208
ld bc, wEnemyMon2 - wEnemyMon1
6209
call AddNTimes
6210
ld bc, NUM_MOVES
6211
call CopyData
6212
jr .loadMovePPs
6213
.copyStandardMoves
6214
; for a wild mon, first copy default moves from the mon header
6215
ld hl, wMonHMoves
6216
ld a, [hli]
6217
ld [de], a
6218
inc de
6219
ld a, [hli]
6220
ld [de], a
6221
inc de
6222
ld a, [hli]
6223
ld [de], a
6224
inc de
6225
ld a, [hl]
6226
ld [de], a
6227
dec de
6228
dec de
6229
dec de
6230
xor a
6231
ld [wLearningMovesFromDayCare], a
6232
predef WriteMonMoves ; get moves based on current level
6233
.loadMovePPs
6234
ld hl, wEnemyMonMoves
6235
ld de, wEnemyMonPP - 1
6236
predef LoadMovePPs
6237
ld hl, wMonHBaseStats
6238
ld de, wEnemyMonBaseStats
6239
ld b, NUM_STATS
6240
.copyBaseStatsLoop
6241
ld a, [hli]
6242
ld [de], a
6243
inc de
6244
dec b
6245
jr nz, .copyBaseStatsLoop
6246
ld hl, wMonHCatchRate
6247
ld a, [hli]
6248
ld [de], a
6249
inc de
6250
ld a, [hl] ; base exp
6251
ld [de], a
6252
ld a, [wEnemyMonSpecies2]
6253
ld [wNamedObjectIndex], a
6254
call GetMonName
6255
ld hl, wNameBuffer
6256
ld de, wEnemyMonNick
6257
ld bc, NAME_LENGTH
6258
call CopyData
6259
ld a, [wEnemyMonSpecies2]
6260
ld [wPokedexNum], a
6261
predef IndexToPokedex
6262
ld a, [wPokedexNum]
6263
dec a
6264
ld c, a
6265
ld b, FLAG_SET
6266
ld hl, wPokedexSeen
6267
predef FlagActionPredef ; mark this mon as seen in the pokedex
6268
ld hl, wEnemyMonLevel
6269
ld de, wEnemyMonUnmodifiedLevel
6270
ld bc, 1 + NUM_STATS * 2
6271
call CopyData
6272
ld a, $7 ; default stat mod
6273
ld b, NUM_STAT_MODS ; number of stat mods
6274
ld hl, wEnemyMonStatMods
6275
.statModLoop
6276
ld [hli], a
6277
dec b
6278
jr nz, .statModLoop
6279
ret
6280
6281
; calls BattleTransition to show the battle transition animation and initializes some battle variables
6282
DoBattleTransitionAndInitBattleVariables:
6283
ld a, [wLinkState]
6284
cp LINK_STATE_BATTLING
6285
jr nz, .next
6286
; link battle
6287
xor a
6288
ld [wMenuJoypadPollCount], a
6289
callfar DisplayLinkBattleVersusTextBox
6290
ld a, $1
6291
ld [wUpdateSpritesEnabled], a
6292
call ClearScreen
6293
.next
6294
call DelayFrame
6295
predef BattleTransition
6296
callfar LoadHudAndHpBarAndStatusTilePatterns
6297
ld a, $1
6298
ldh [hAutoBGTransferEnabled], a
6299
ld a, $ff
6300
ld [wUpdateSpritesEnabled], a
6301
call ClearSprites
6302
call ClearScreen
6303
xor a
6304
ldh [hAutoBGTransferEnabled], a
6305
ldh [hWY], a
6306
ldh [rWY], a
6307
ldh [hTileAnimations], a
6308
ld hl, wPlayerStatsToDouble
6309
ld [hli], a
6310
ld [hli], a
6311
ld [hli], a
6312
ld [hli], a
6313
ld [hl], a
6314
ld [wPlayerDisabledMove], a
6315
ret
6316
6317
; swaps the level values of the BattleMon and EnemyMon structs
6318
SwapPlayerAndEnemyLevels:
6319
push bc
6320
ld a, [wBattleMonLevel]
6321
ld b, a
6322
ld a, [wEnemyMonLevel]
6323
ld [wBattleMonLevel], a
6324
ld a, b
6325
ld [wEnemyMonLevel], a
6326
pop bc
6327
ret
6328
6329
; loads either red back pic or old man back pic
6330
; also writes OAM data and loads tile patterns for the Red or Old Man back sprite's head
6331
; (for use when scrolling the player sprite and enemy's silhouettes on screen)
6332
LoadPlayerBackPic:
6333
ld a, [wBattleType]
6334
dec a ; is it the old man tutorial?
6335
ld de, RedPicBack
6336
jr nz, .next
6337
ld de, OldManPicBack
6338
.next
6339
ld a, BANK(RedPicBack)
6340
ASSERT BANK(RedPicBack) == BANK(OldManPicBack)
6341
call UncompressSpriteFromDE
6342
predef ScaleSpriteByTwo
6343
ld hl, wShadowOAM
6344
xor a
6345
ldh [hOAMTile], a ; initial tile number
6346
ld b, $7 ; 7 columns
6347
ld e, $a0 ; X for the left-most column
6348
.loop ; each loop iteration writes 3 OAM entries in a vertical column
6349
ld c, $3 ; 3 tiles per column
6350
ld d, $38 ; Y for the top of each column
6351
.innerLoop ; each loop iteration writes 1 OAM entry in the column
6352
ld [hl], d ; OAM Y
6353
inc hl
6354
ld [hl], e ; OAM X
6355
ld a, $8 ; height of tile
6356
add d ; increase Y by height of tile
6357
ld d, a
6358
inc hl
6359
ldh a, [hOAMTile]
6360
ld [hli], a ; OAM tile number
6361
inc a ; increment tile number
6362
ldh [hOAMTile], a
6363
inc hl
6364
dec c
6365
jr nz, .innerLoop
6366
ldh a, [hOAMTile]
6367
add $4 ; increase tile number by 4
6368
ldh [hOAMTile], a
6369
ld a, $8 ; width of tile
6370
add e ; increase X by width of tile
6371
ld e, a
6372
dec b
6373
jr nz, .loop
6374
ld de, vBackPic
6375
call InterlaceMergeSpriteBuffers
6376
ld a, RAMG_SRAM_ENABLE
6377
ld [rRAMG], a
6378
xor a
6379
ld [rRAMB], a
6380
ld hl, vSprites
6381
ld de, sSpriteBuffer1
6382
ldh a, [hLoadedROMBank]
6383
ld b, a
6384
ld c, 7 * 7
6385
call CopyVideoData
6386
xor a
6387
ld [rRAMG], a
6388
ld a, $31
6389
ldh [hStartTileID], a
6390
hlcoord 1, 5
6391
predef_jump CopyUncompressedPicToTilemap
6392
6393
; does nothing since no stats are ever selected (barring glitches)
6394
DoubleOrHalveSelectedStats:
6395
callfar DoubleSelectedStats
6396
jpfar HalveSelectedStats
6397
6398
ScrollTrainerPicAfterBattle:
6399
jpfar _ScrollTrainerPicAfterBattle
6400
6401
ApplyBurnAndParalysisPenaltiesToPlayer:
6402
ld a, $1
6403
jr ApplyBurnAndParalysisPenalties
6404
6405
ApplyBurnAndParalysisPenaltiesToEnemy:
6406
xor a
6407
6408
ApplyBurnAndParalysisPenalties:
6409
ldh [hWhoseTurn], a
6410
call QuarterSpeedDueToParalysis
6411
jp HalveAttackDueToBurn
6412
6413
QuarterSpeedDueToParalysis:
6414
ldh a, [hWhoseTurn]
6415
and a
6416
jr z, .playerTurn
6417
.enemyTurn ; quarter the player's speed
6418
ld a, [wBattleMonStatus]
6419
and 1 << PAR
6420
ret z ; return if player not paralysed
6421
ld hl, wBattleMonSpeed + 1
6422
ld a, [hld]
6423
ld b, a
6424
ld a, [hl]
6425
srl a
6426
rr b
6427
srl a
6428
rr b
6429
ld [hli], a
6430
or b
6431
jr nz, .storePlayerSpeed
6432
ld b, 1 ; give the player a minimum of at least one speed point
6433
.storePlayerSpeed
6434
ld [hl], b
6435
ret
6436
.playerTurn ; quarter the enemy's speed
6437
ld a, [wEnemyMonStatus]
6438
and 1 << PAR
6439
ret z ; return if enemy not paralysed
6440
ld hl, wEnemyMonSpeed + 1
6441
ld a, [hld]
6442
ld b, a
6443
ld a, [hl]
6444
srl a
6445
rr b
6446
srl a
6447
rr b
6448
ld [hli], a
6449
or b
6450
jr nz, .storeEnemySpeed
6451
ld b, 1 ; give the enemy a minimum of at least one speed point
6452
.storeEnemySpeed
6453
ld [hl], b
6454
ret
6455
6456
HalveAttackDueToBurn:
6457
ldh a, [hWhoseTurn]
6458
and a
6459
jr z, .playerTurn
6460
.enemyTurn ; halve the player's attack
6461
ld a, [wBattleMonStatus]
6462
and 1 << BRN
6463
ret z ; return if player not burnt
6464
ld hl, wBattleMonAttack + 1
6465
ld a, [hld]
6466
ld b, a
6467
ld a, [hl]
6468
srl a
6469
rr b
6470
ld [hli], a
6471
or b
6472
jr nz, .storePlayerAttack
6473
ld b, 1 ; give the player a minimum of at least one attack point
6474
.storePlayerAttack
6475
ld [hl], b
6476
ret
6477
.playerTurn ; halve the enemy's attack
6478
ld a, [wEnemyMonStatus]
6479
and 1 << BRN
6480
ret z ; return if enemy not burnt
6481
ld hl, wEnemyMonAttack + 1
6482
ld a, [hld]
6483
ld b, a
6484
ld a, [hl]
6485
srl a
6486
rr b
6487
ld [hli], a
6488
or b
6489
jr nz, .storeEnemyAttack
6490
ld b, 1 ; give the enemy a minimum of at least one attack point
6491
.storeEnemyAttack
6492
ld [hl], b
6493
ret
6494
6495
CalculateModifiedStats:
6496
ld c, 0
6497
.loop
6498
call CalculateModifiedStat
6499
inc c
6500
ld a, c
6501
cp NUM_STATS - 1
6502
jr nz, .loop
6503
ret
6504
6505
; calculate modified stat for stat c (0 = attack, 1 = defense, 2 = speed, 3 = special)
6506
CalculateModifiedStat:
6507
push bc
6508
push bc
6509
ld a, [wCalculateWhoseStats]
6510
and a
6511
ld a, c
6512
ld hl, wBattleMonAttack
6513
ld de, wPlayerMonUnmodifiedAttack
6514
ld bc, wPlayerMonStatMods
6515
jr z, .next
6516
ld hl, wEnemyMonAttack
6517
ld de, wEnemyMonUnmodifiedAttack
6518
ld bc, wEnemyMonStatMods
6519
.next
6520
add c
6521
ld c, a
6522
jr nc, .noCarry1
6523
inc b
6524
.noCarry1
6525
ld a, [bc]
6526
pop bc
6527
ld b, a
6528
push bc
6529
sla c
6530
ld b, 0
6531
add hl, bc
6532
ld a, c
6533
add e
6534
ld e, a
6535
jr nc, .noCarry2
6536
inc d
6537
.noCarry2
6538
pop bc
6539
push hl
6540
ld hl, StatModifierRatios
6541
dec b
6542
sla b
6543
ld c, b
6544
ld b, 0
6545
add hl, bc
6546
xor a
6547
ldh [hMultiplicand], a
6548
ld a, [de]
6549
ldh [hMultiplicand + 1], a
6550
inc de
6551
ld a, [de]
6552
ldh [hMultiplicand + 2], a
6553
ld a, [hli]
6554
ldh [hMultiplier], a
6555
call Multiply
6556
ld a, [hl]
6557
ldh [hDivisor], a
6558
ld b, $4
6559
call Divide
6560
pop hl
6561
ldh a, [hDividend + 3]
6562
sub LOW(MAX_STAT_VALUE)
6563
ldh a, [hDividend + 2]
6564
sbc HIGH(MAX_STAT_VALUE)
6565
jp c, .storeNewStatValue
6566
; cap the stat at MAX_STAT_VALUE (999)
6567
ld a, HIGH(MAX_STAT_VALUE)
6568
ldh [hDividend + 2], a
6569
ld a, LOW(MAX_STAT_VALUE)
6570
ldh [hDividend + 3], a
6571
.storeNewStatValue
6572
ldh a, [hDividend + 2]
6573
ld [hli], a
6574
ld b, a
6575
ldh a, [hDividend + 3]
6576
ld [hl], a
6577
or b
6578
jr nz, .done
6579
inc [hl] ; if the stat is 0, bump it up to 1
6580
.done
6581
pop bc
6582
ret
6583
6584
ApplyBadgeStatBoosts:
6585
ld a, [wLinkState]
6586
cp LINK_STATE_BATTLING
6587
ret z ; return if link battle
6588
ld a, [wObtainedBadges]
6589
ld b, a
6590
ld hl, wBattleMonAttack
6591
ld c, $4
6592
; the boost is applied for badges whose bit position is even
6593
; the order of boosts matches the order they are laid out in RAM
6594
; Boulder (bit 0) - attack
6595
; Thunder (bit 2) - defense
6596
; Soul (bit 4) - speed
6597
; Volcano (bit 6) - special
6598
.loop
6599
srl b
6600
call c, .applyBoostToStat
6601
inc hl
6602
inc hl
6603
srl b
6604
dec c
6605
jr nz, .loop
6606
ret
6607
6608
; multiply stat at hl by 1.125
6609
; cap stat at MAX_STAT_VALUE
6610
.applyBoostToStat
6611
ld a, [hli]
6612
ld d, a
6613
ld e, [hl]
6614
srl d
6615
rr e
6616
srl d
6617
rr e
6618
srl d
6619
rr e
6620
ld a, [hl]
6621
add e
6622
ld [hld], a
6623
ld a, [hl]
6624
adc d
6625
ld [hli], a
6626
ld a, [hld]
6627
sub LOW(MAX_STAT_VALUE)
6628
ld a, [hl]
6629
sbc HIGH(MAX_STAT_VALUE)
6630
ret c
6631
ld a, HIGH(MAX_STAT_VALUE)
6632
ld [hli], a
6633
ld a, LOW(MAX_STAT_VALUE)
6634
ld [hld], a
6635
ret
6636
6637
LoadHudAndHpBarAndStatusTilePatterns:
6638
call LoadHpBarAndStatusTilePatterns
6639
6640
LoadHudTilePatterns:
6641
ldh a, [rLCDC]
6642
add a ; is LCD disabled?
6643
jr c, .lcdEnabled
6644
.lcdDisabled
6645
ld hl, BattleHudTiles1
6646
ld de, vChars2 tile $6d
6647
ld bc, BattleHudTiles1End - BattleHudTiles1
6648
ld a, BANK(BattleHudTiles1)
6649
call FarCopyDataDouble
6650
ld hl, BattleHudTiles2
6651
ld de, vChars2 tile $73
6652
ld bc, BattleHudTiles3End - BattleHudTiles2
6653
ld a, BANK(BattleHudTiles2)
6654
jp FarCopyDataDouble
6655
.lcdEnabled
6656
ld de, BattleHudTiles1
6657
ld hl, vChars2 tile $6d
6658
lb bc, BANK(BattleHudTiles1), (BattleHudTiles1End - BattleHudTiles1) / $8
6659
call CopyVideoDataDouble
6660
ld de, BattleHudTiles2
6661
ld hl, vChars2 tile $73
6662
lb bc, BANK(BattleHudTiles2), (BattleHudTiles3End - BattleHudTiles2) / $8
6663
jp CopyVideoDataDouble
6664
6665
PrintEmptyString:
6666
ld hl, .emptyString
6667
jp PrintText
6668
6669
.emptyString
6670
db "@"
6671
6672
6673
BattleRandom:
6674
; Link battles use a shared PRNG.
6675
6676
ld a, [wLinkState]
6677
cp LINK_STATE_BATTLING
6678
jp nz, Random
6679
6680
push hl
6681
push bc
6682
ld a, [wLinkBattleRandomNumberListIndex]
6683
ld c, a
6684
ld b, 0
6685
ld hl, wLinkBattleRandomNumberList
6686
add hl, bc
6687
inc a
6688
ld [wLinkBattleRandomNumberListIndex], a
6689
cp SERIAL_RNS_LENGTH - 1
6690
ld a, [hl]
6691
pop bc
6692
pop hl
6693
vc_hook Unknown_BattleRandom_ret_c
6694
vc_patch BattleRandom_ret
6695
IF DEF(_RED_VC) || DEF(_BLUE_VC)
6696
ret
6697
ELSE
6698
ret c
6699
ENDC
6700
vc_patch_end
6701
6702
; if we picked the last seed, we need to recalculate the nine seeds
6703
push hl
6704
push bc
6705
push af
6706
6707
; point to seed 0 so we pick the first number the next time
6708
xor a
6709
ld [wLinkBattleRandomNumberListIndex], a
6710
6711
ld hl, wLinkBattleRandomNumberList
6712
ld b, SERIAL_RNS_LENGTH - 1
6713
.loop
6714
ld a, [hl]
6715
ld c, a
6716
; multiply by 5
6717
add a
6718
add a
6719
add c
6720
; add 1
6721
inc a
6722
ld [hli], a
6723
dec b
6724
jr nz, .loop
6725
6726
pop af
6727
pop bc
6728
pop hl
6729
ret
6730
6731
6732
HandleExplodingAnimation:
6733
ldh a, [hWhoseTurn]
6734
and a
6735
ld hl, wEnemyMonType1
6736
ld de, wEnemyBattleStatus1
6737
ld a, [wPlayerMoveNum]
6738
jr z, .player
6739
ld hl, wBattleMonType1
6740
ld de, wEnemyBattleStatus1
6741
ld a, [wEnemyMoveNum]
6742
.player
6743
cp SELFDESTRUCT
6744
jr z, .isExplodingMove
6745
cp EXPLOSION
6746
ret nz
6747
.isExplodingMove
6748
ld a, [de]
6749
bit INVULNERABLE, a ; fly/dig
6750
ret nz
6751
ld a, [hli]
6752
cp GHOST
6753
ret z
6754
ld a, [hl]
6755
cp GHOST
6756
ret z
6757
ld a, [wMoveMissed]
6758
and a
6759
ret nz
6760
ld a, ANIMATIONTYPE_SHAKE_SCREEN_HORIZONTALLY_LIGHT
6761
ld [wAnimationType], a
6762
ASSERT ANIMATIONTYPE_SHAKE_SCREEN_HORIZONTALLY_LIGHT == MEGA_PUNCH
6763
; ld a, MEGA_PUNCH
6764
; fallthrough
6765
PlayMoveAnimation:
6766
ld [wAnimationID], a
6767
vc_hook_red Reduce_move_anim_flashing_Confusion
6768
call Delay3
6769
vc_hook_red Reduce_move_anim_flashing_Psychic
6770
predef_jump MoveAnimation
6771
6772
InitBattle::
6773
ld a, [wCurOpponent]
6774
and a
6775
jr z, DetermineWildOpponent
6776
6777
InitOpponent:
6778
ld a, [wCurOpponent]
6779
ld [wCurPartySpecies], a
6780
ld [wEnemyMonSpecies2], a
6781
jr InitBattleCommon
6782
6783
DetermineWildOpponent:
6784
ld a, [wStatusFlags6]
6785
bit BIT_DEBUG_MODE, a
6786
jr z, .notDebugMode
6787
ldh a, [hJoyHeld]
6788
bit B_PAD_B, a ; disable wild encounters
6789
ret nz
6790
.notDebugMode
6791
ld a, [wNumberOfNoRandomBattleStepsLeft]
6792
and a
6793
ret nz
6794
callfar TryDoWildEncounter
6795
ret nz
6796
InitBattleCommon:
6797
ld a, [wMapPalOffset]
6798
push af
6799
ld hl, wLetterPrintingDelayFlags
6800
ld a, [hl]
6801
push af
6802
res BIT_TEXT_DELAY, [hl] ; no delay
6803
callfar InitBattleVariables
6804
ld a, [wEnemyMonSpecies2]
6805
sub OPP_ID_OFFSET
6806
jp c, InitWildBattle
6807
ld [wTrainerClass], a
6808
call GetTrainerInformation
6809
callfar ReadTrainer
6810
call DoBattleTransitionAndInitBattleVariables
6811
call _LoadTrainerPic
6812
xor a
6813
ld [wEnemyMonSpecies2], a
6814
ldh [hStartTileID], a
6815
dec a
6816
ld [wAICount], a
6817
hlcoord 12, 0
6818
predef CopyUncompressedPicToTilemap
6819
ld a, $ff
6820
ld [wEnemyMonPartyPos], a
6821
ld a, $2
6822
ld [wIsInBattle], a
6823
jp _InitBattleCommon
6824
6825
InitWildBattle:
6826
ld a, $1
6827
ld [wIsInBattle], a
6828
call LoadEnemyMonData
6829
call DoBattleTransitionAndInitBattleVariables
6830
ld a, [wCurOpponent]
6831
cp RESTLESS_SOUL
6832
jr z, .isGhost
6833
call IsGhostBattle
6834
jr nz, .isNoGhost
6835
.isGhost
6836
ld hl, wMonHSpriteDim
6837
ld a, $66
6838
ld [hli], a ; write sprite dimensions
6839
ld bc, GhostPic
6840
ld a, c
6841
ld [hli], a ; write front sprite pointer
6842
ld [hl], b
6843
ld hl, wEnemyMonNick ; set name to "GHOST"
6844
ld a, "G"
6845
ld [hli], a
6846
ld a, "H"
6847
ld [hli], a
6848
ld a, "O"
6849
ld [hli], a
6850
ld a, "S"
6851
ld [hli], a
6852
ld a, "T"
6853
ld [hli], a
6854
ld [hl], "@"
6855
ld a, [wCurPartySpecies]
6856
push af
6857
ld a, MON_GHOST
6858
ld [wCurPartySpecies], a
6859
ld de, vFrontPic
6860
call LoadMonFrontSprite ; load ghost sprite
6861
pop af
6862
ld [wCurPartySpecies], a
6863
jr .spriteLoaded
6864
.isNoGhost
6865
ld de, vFrontPic
6866
call LoadMonFrontSprite ; load mon sprite
6867
.spriteLoaded
6868
xor a
6869
ld [wTrainerClass], a
6870
ldh [hStartTileID], a
6871
hlcoord 12, 0
6872
predef CopyUncompressedPicToTilemap
6873
6874
; common code that executes after init battle code specific to trainer or wild battles
6875
_InitBattleCommon:
6876
ld b, SET_PAL_BATTLE_BLACK
6877
call RunPaletteCommand
6878
call SlidePlayerAndEnemySilhouettesOnScreen
6879
xor a
6880
ldh [hAutoBGTransferEnabled], a
6881
ld hl, .emptyString
6882
call PrintText
6883
call SaveScreenTilesToBuffer1
6884
call ClearScreen
6885
ld a, HIGH(vBGMap0)
6886
ldh [hAutoBGTransferDest + 1], a
6887
ld a, $1
6888
ldh [hAutoBGTransferEnabled], a
6889
call Delay3
6890
ld a, HIGH(vBGMap1)
6891
ldh [hAutoBGTransferDest + 1], a
6892
call LoadScreenTilesFromBuffer1
6893
hlcoord 9, 7
6894
lb bc, 5, 10
6895
call ClearScreenArea
6896
hlcoord 1, 0
6897
lb bc, 4, 10
6898
call ClearScreenArea
6899
call ClearSprites
6900
ld a, [wIsInBattle]
6901
dec a ; is it a wild battle?
6902
call z, DrawEnemyHUDAndHPBar ; draw enemy HUD and HP bar if it's a wild battle
6903
call StartBattle
6904
callfar EndOfBattle
6905
pop af
6906
ld [wLetterPrintingDelayFlags], a
6907
pop af
6908
ld [wMapPalOffset], a
6909
ld a, [wSavedTileAnimations]
6910
ldh [hTileAnimations], a
6911
scf
6912
ret
6913
.emptyString
6914
db "@"
6915
6916
_LoadTrainerPic:
6917
ld a, [wTrainerPicPointer]
6918
ld e, a
6919
ld a, [wTrainerPicPointer + 1]
6920
ld d, a ; de contains pointer to trainer pic
6921
ld a, [wLinkState]
6922
and a
6923
ld a, BANK("Trainer Pics")
6924
jr z, .loadSprite
6925
ld a, BANK(RedPicFront)
6926
.loadSprite
6927
call UncompressSpriteFromDE
6928
ld de, vFrontPic
6929
ld a, $77
6930
ld c, a
6931
jp LoadUncompressedSpriteData
6932
6933
; unreferenced
6934
ResetCryModifiers:
6935
xor a
6936
ld [wFrequencyModifier], a
6937
ld [wTempoModifier], a
6938
jp PlaySound
6939
6940
; animates the mon "growing" out of the pokeball
6941
AnimateSendingOutMon:
6942
ld a, [wPredefHL]
6943
ld h, a
6944
ld a, [wPredefHL + 1]
6945
ld l, a
6946
ldh a, [hStartTileID]
6947
ldh [hBaseTileID], a
6948
ld b, $4c
6949
ld a, [wIsInBattle]
6950
and a
6951
jr z, .notInBattle
6952
add b
6953
ld [hl], a
6954
call Delay3
6955
ld bc, -(SCREEN_WIDTH * 2 + 1)
6956
add hl, bc
6957
ld a, 1
6958
ld [wDownscaledMonSize], a
6959
lb bc, 3, 3
6960
predef CopyDownscaledMonTiles
6961
ld c, 4
6962
call DelayFrames
6963
ld bc, -(SCREEN_WIDTH * 2 + 1)
6964
add hl, bc
6965
xor a
6966
ld [wDownscaledMonSize], a
6967
lb bc, 5, 5
6968
predef CopyDownscaledMonTiles
6969
ld c, 5
6970
call DelayFrames
6971
ld bc, -(SCREEN_WIDTH * 2 + 1)
6972
jr .next
6973
.notInBattle
6974
ld bc, -(SCREEN_WIDTH * 6 + 3)
6975
.next
6976
add hl, bc
6977
ldh a, [hBaseTileID]
6978
add $31
6979
jr CopyUncompressedPicToHL
6980
6981
CopyUncompressedPicToTilemap:
6982
ld a, [wPredefHL]
6983
ld h, a
6984
ld a, [wPredefHL + 1]
6985
ld l, a
6986
ldh a, [hStartTileID]
6987
CopyUncompressedPicToHL::
6988
lb bc, 7, 7
6989
ld de, SCREEN_WIDTH
6990
push af
6991
ld a, [wSpriteFlipped]
6992
and a
6993
jr nz, .flipped
6994
pop af
6995
.loop
6996
push bc
6997
push hl
6998
.innerLoop
6999
ld [hl], a
7000
add hl, de
7001
inc a
7002
dec c
7003
jr nz, .innerLoop
7004
pop hl
7005
inc hl
7006
pop bc
7007
dec b
7008
jr nz, .loop
7009
ret
7010
7011
.flipped
7012
push bc
7013
ld b, 0
7014
dec c
7015
add hl, bc
7016
pop bc
7017
pop af
7018
.flippedLoop
7019
push bc
7020
push hl
7021
.flippedInnerLoop
7022
ld [hl], a
7023
add hl, de
7024
inc a
7025
dec c
7026
jr nz, .flippedInnerLoop
7027
pop hl
7028
dec hl
7029
pop bc
7030
dec b
7031
jr nz, .flippedLoop
7032
ret
7033
7034
LoadMonBackPic:
7035
; Assumes the monster's attributes have
7036
; been loaded with GetMonHeader.
7037
ld a, [wBattleMonSpecies2]
7038
ld [wCurPartySpecies], a
7039
hlcoord 1, 5
7040
ld b, 7
7041
ld c, 8
7042
call ClearScreenArea
7043
ld hl, wMonHBackSprite - wMonHeader
7044
call UncompressMonSprite
7045
predef ScaleSpriteByTwo
7046
ld de, vBackPic
7047
call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
7048
ld hl, vSprites
7049
ld de, vBackPic
7050
ld c, (2 * SPRITEBUFFERSIZE) / 16 ; count of 16-byte chunks to be copied
7051
ldh a, [hLoadedROMBank]
7052
ld b, a
7053
jp CopyVideoData
7054
7055