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