diff options
Diffstat (limited to 'engine')
132 files changed, 50640 insertions, 348 deletions
diff --git a/engine/battle/ai/items.asm b/engine/battle/ai/items.asm new file mode 100644 index 000000000..09595077a --- /dev/null +++ b/engine/battle/ai/items.asm @@ -0,0 +1,882 @@ +AI_SwitchOrTryItem: ; 38000 + and a + + ld a, [wBattleMode] + dec a + ret z + + ld a, [wLinkMode] + and a + ret nz + + farcall CheckEnemyLockedIn + ret nz + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, DontSwitch + + ld a, [wEnemyWrapCount] + and a + jr nz, DontSwitch + + ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH + ld a, [InBattleTowerBattle] ; Load always the first TrainerClass for BattleTower-Trainers + and a + jr nz, .ok + + ld a, [TrainerClass] + dec a + ld bc, NUM_TRAINER_ATTRIBUTES + call AddNTimes +.ok + bit SWITCH_OFTEN_F, [hl] + jp nz, SwitchOften + bit SWITCH_RARELY_F, [hl] + jp nz, SwitchRarely + bit SWITCH_SOMETIMES_F, [hl] + jp nz, SwitchSometimes + ; fallthrough + +DontSwitch: ; 38041 + call AI_TryItem + ret +; 38045 + +SwitchOften: ; 38045 + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp 1 + 50 percent + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp -1 + 79 percent + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp 4 percent + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ; In register 'a' is the number (1-6) of the Pkmn to switch to + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch +; 38083 + +SwitchRarely: ; 38083 + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp 8 percent + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp 12 percent + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp -1 + 79 percent + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch +; 380c1 + +SwitchSometimes: ; 380c1 + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp -1 + 20 percent + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp 1 + 50 percent + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp -1 + 20 percent + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch +; 380ff + + +CheckSubstatusCantRun: ; 380ff + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + ret +; 38105 + + +AI_TryItem: ; 38105 + ; items are not allowed in the BattleTower + ld a, [InBattleTowerBattle] + and a + ret nz + + ld a, [wEnemyTrainerItem1] + ld b, a + ld a, [wEnemyTrainerItem2] + or b + ret z + + call .IsHighestLevel + ret nc + + ld a, [TrainerClass] + dec a + ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH + ld bc, NUM_TRAINER_ATTRIBUTES + call AddNTimes + ld b, h + ld c, l + ld hl, AI_Items + ld de, wEnemyTrainerItem1 +.loop + ld a, [hl] + and a + inc a + ret z + + ld a, [de] + cp [hl] + jr z, .has_item + inc de + ld a, [de] + cp [hl] + jr z, .has_item + + dec de + inc hl + inc hl + inc hl + jr .loop + +.has_item + inc hl + + push hl + push de + ld de, .callback + push de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +.callback + pop de + pop hl + + inc hl + inc hl + jr c, .loop + +.used_item + xor a + ld [de], a + inc a + ld [wEnemyGoesFirst], a + + ld hl, EnemySubStatus3 + res SUBSTATUS_BIDE, [hl] + + xor a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + + xor a + ld [LastEnemyCounterMove], a + + scf + ret + + +.IsHighestLevel: ; 38170 + ld a, [OTPartyCount] + ld d, a + ld e, 0 + ld hl, OTPartyMon1Level + ld bc, PARTYMON_STRUCT_LENGTH +.next + ld a, [hl] + cp e + jr c, .ok + ld e, a +.ok + add hl, bc + dec d + jr nz, .next + + ld a, [CurOTMon] + ld hl, OTPartyMon1Level + call AddNTimes + ld a, [hl] + cp e + jr nc, .yes + +.no + and a + ret + +.yes + scf + ret +; 38196 + + +AI_Items: ; 39196 + dbw FULL_RESTORE, .FullRestore + dbw MAX_POTION, .MaxPotion + dbw HYPER_POTION, .HyperPotion + dbw SUPER_POTION, .SuperPotion + dbw POTION, .Potion + dbw X_ACCURACY, .XAccuracy + dbw FULL_HEAL, .FullHeal + dbw GUARD_SPEC, .GuardSpec + dbw DIRE_HIT, .DireHit + dbw X_ATTACK, .XAttack + dbw X_DEFEND, .XDefend + dbw X_SPEED, .XSpeed + dbw X_SPECIAL, .XSpecial + db $ff +; 381be + +.FullHeal: ; 381be + call .Status + jp c, .DontUse + call EnemyUsedFullHeal + jp .Use +; 381ca + +.Status: ; 381ca (e:41ca) + ld a, [EnemyMonStatus] + and a + jp z, .DontUse + + ld a, [bc] + bit CONTEXT_USE_F, a + jr nz, .StatusCheckContext + ld a, [bc] + bit ALWAYS_USE_F, a + jp nz, .Use + call Random + cp -1 + 20 percent + jp c, .Use + jp .DontUse + +.StatusCheckContext: + ld a, [EnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr z, .FailToxicCheck + ld a, [EnemyToxicCount] + cp 4 + jr c, .FailToxicCheck + call Random + cp 1 + 50 percent + jp c, .Use +.FailToxicCheck: + ld a, [EnemyMonStatus] + and 1 << FRZ | SLP + jp z, .DontUse + jp .Use +; 38208 + +.FullRestore: ; 38208 + call .HealItem + jp nc, .UseFullRestore + ld a, [bc] + bit CONTEXT_USE_F, a + jp z, .DontUse + call .Status + jp c, .DontUse + +.UseFullRestore: + call EnemyUsedFullRestore + jp .Use +; 38220 + +.MaxPotion: ; 38220 + call .HealItem + jp c, .DontUse + call EnemyUsedMaxPotion + jp .Use + +.HealItem: ; 3822c (e:422c) + ld a, [bc] + bit CONTEXT_USE_F, a + jr nz, .CheckHalfOrQuarterHP + callfar AICheckEnemyHalfHP + jp c, .DontUse + ld a, [bc] + bit UNKNOWN_USE_F, a + jp nz, .CheckQuarterHP + callfar AICheckEnemyQuarterHP + jp nc, .UseHealItem + call Random + cp 1 + 50 percent + jp c, .UseHealItem + jp .DontUse + +.CheckQuarterHP: ; 38254 (e:4254) + callfar AICheckEnemyQuarterHP + jp c, .DontUse + call Random + cp -1 + 20 percent + jp c, .DontUse + jr .UseHealItem + +.CheckHalfOrQuarterHP: ; 38267 (e:4267) + callfar AICheckEnemyHalfHP + jp c, .DontUse + callfar AICheckEnemyQuarterHP + jp nc, .UseHealItem + call Random + cp -1 + 20 percent + jp nc, .DontUse + +.UseHealItem: ; 38281 (e:4281) + jp .Use +; 38284 + +.HyperPotion: ; 38284 + call .HealItem + jp c, .DontUse + ld b, 200 + call EnemyUsedHyperPotion + jp .Use +; 38292 (e:4292) + +.SuperPotion: ; 38292 + call .HealItem + jp c, .DontUse + ld b, 50 + call EnemyUsedSuperPotion + jp .Use +; 382a0 + +.Potion: ; 382a0 + call .HealItem + jp c, .DontUse + ld b, 20 + call EnemyUsedPotion + jp .Use +; 382ae + +.asm_382ae ; This appears to be unused + callfar AICheckEnemyMaxHP + jr c, .dont_use + push bc + ld de, EnemyMonMaxHP + 1 + ld hl, EnemyMonHP + 1 + ld a, [de] + sub [hl] + jr z, .check_40_percent + dec hl + dec de + ld c, a + sbc [hl] + and a + jr nz, .check_40_percent + ld a, c + cp b + jp c, .check_50_percent + callfar AICheckEnemyQuarterHP + jr c, .check_40_percent + +.check_50_percent + pop bc + ld a, [bc] + bit UNKNOWN_USE_F, a + jp z, .Use + call Random + cp 1 + 50 percent + jp c, .Use + +.dont_use + jp .DontUse + +.check_40_percent + pop bc + ld a, [bc] + bit UNKNOWN_USE_F, a + jp z, .DontUse + call Random + cp 1 + 39 percent + jp c, .Use + jp .DontUse +; 382f9 + +.XAccuracy: ; 382f9 + call .XItem + jp c, .DontUse + call EnemyUsedXAccuracy + jp .Use +; 38305 + +.GuardSpec: ; 38305 + call .XItem + jp c, .DontUse + call EnemyUsedGuardSpec + jp .Use +; 38311 + +.DireHit: ; 38311 + call .XItem + jp c, .DontUse + call EnemyUsedDireHit + jp .Use +; 3831d (e:431d) + +.XAttack: ; 3831d + call .XItem + jp c, .DontUse + call EnemyUsedXAttack + jp .Use +; 38329 + +.XDefend: ; 38329 + call .XItem + jp c, .DontUse + call EnemyUsedXDefend + jp .Use +; 38335 + +.XSpeed: ; 38335 + call .XItem + jp c, .DontUse + call EnemyUsedXSpeed + jp .Use +; 38341 + +.XSpecial: ; 38341 + call .XItem + jp c, .DontUse + call EnemyUsedXSpecial + jp .Use +; 3834d + +.XItem: ; 3834d (e:434d) + ld a, [EnemyTurnsTaken] + and a + jr nz, .notfirstturnout + ld a, [bc] + bit ALWAYS_USE_F, a + jp nz, .Use + call Random + cp 1 + 50 percent + jp c, .DontUse + ld a, [bc] + bit CONTEXT_USE_F, a + jp nz, .Use + call Random + cp 1 + 50 percent + jp c, .DontUse + jp .Use +.notfirstturnout + ld a, [bc] + bit ALWAYS_USE_F, a + jp z, .DontUse + call Random + cp -1 + 20 percent + jp nc, .DontUse + jp .Use + +.DontUse: + scf + ret + +.Use: + and a + ret + + +AIUpdateHUD: ; 38387 + call UpdateEnemyMonInParty + farcall UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ld hl, wEnemyItemState + dec [hl] + scf + ret +; 3839a + +AIUsedItemSound: ; 3839a + push de + ld de, SFX_FULL_HEAL + call PlaySFX + pop de + ret +; 383a3 + + +EnemyUsedFullHeal: ; 383a3 (e:43a3) + call AIUsedItemSound + call AI_HealStatus + ld a, FULL_HEAL + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +EnemyUsedMaxPotion: ; 383ae (e:43ae) + ld a, MAX_POTION + ld [CurEnemyItem], a + jr FullRestoreContinue + +EnemyUsedFullRestore: ; 383b5 (e:43b5) + call AI_HealStatus + ld a, FULL_RESTORE + ld [CurEnemyItem], a + ld hl, EnemySubStatus3 + res SUBSTATUS_CONFUSED, [hl] + xor a + ld [EnemyConfuseCount], a + +FullRestoreContinue: ; 383c6 + ld de, wCurHPAnimOldHP + ld hl, EnemyMonHP + 1 + ld a, [hld] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + ld hl, EnemyMonMaxHP + 1 + ld a, [hld] + ld [de], a + inc de + ld [wCurHPAnimMaxHP], a + ld [EnemyMonHP + 1], a + ld a, [hl] + ld [de], a + ld [wCurHPAnimMaxHP + 1], a + ld [EnemyMonHP], a + jr EnemyPotionFinish +; 383e8 (e:43e8) + +EnemyUsedPotion: ; 383e8 + ld a, POTION + ld b, 20 + jr EnemyPotionContinue + +EnemyUsedSuperPotion: ; 383ee + ld a, SUPER_POTION + ld b, 50 + jr EnemyPotionContinue + +EnemyUsedHyperPotion: ; 383f4 (e:43f4) + ld a, HYPER_POTION + ld b, 200 + +EnemyPotionContinue: ; 383f8 + ld [CurEnemyItem], a + ld hl, EnemyMonHP + 1 + ld a, [hl] + ld [wCurHPAnimOldHP], a + add b + ld [hld], a + ld [wCurHPAnimNewHP], a + ld a, [hl] + ld [wCurHPAnimOldHP + 1], a + ld [wCurHPAnimNewHP + 1], a + jr nc, .ok + inc a + ld [hl], a + ld [wCurHPAnimNewHP + 1], a +.ok + inc hl + ld a, [hld] + ld b, a + ld de, EnemyMonMaxHP + 1 + ld a, [de] + dec de + ld [wCurHPAnimMaxHP], a + sub b + ld a, [hli] + ld b, a + ld a, [de] + ld [wCurHPAnimMaxHP + 1], a + sbc b + jr nc, EnemyPotionFinish + inc de + ld a, [de] + dec de + ld [hld], a + ld [wCurHPAnimNewHP], a + ld a, [de] + ld [hl], a + ld [wCurHPAnimNewHP + 1], a + +EnemyPotionFinish: ; 38436 + call PrintText_UsedItemOn + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + call AIUsedItemSound + predef AnimateHPBar + jp AIUpdateHUD + + +AI_TrySwitch: ; 3844b +; Determine whether the AI can switch based on how many Pokemon are still alive. +; If it can switch, it will. + ld a, [OTPartyCount] + ld c, a + ld hl, OTPartyMon1HP + ld d, 0 +.SwitchLoop: + ld a, [hli] + ld b, a + ld a, [hld] + or b + jr z, .fainted + inc d +.fainted + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + dec c + jr nz, .SwitchLoop + + ld a, d + cp 2 + jp nc, AI_Switch + and a + ret +; 3846c + +AI_Switch: ; 3846c + ld a, $1 + ld [wEnemyIsSwitching], a + ld [wEnemyGoesFirst], a + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [hBattleTurn], a + callfar PursuitSwitch + + push af + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, EnemyMonStatus + ld bc, MON_MAXHP - MON_STATUS + call CopyBytes + pop af + + jr c, .skiptext + ld hl, TextJump_EnemyWithdrew + call PrintText + +.skiptext + ld a, 1 + ld [wBattleHasJustStarted], a + callfar NewEnemyMonStatus + callfar ResetEnemyStatLevels + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + farcall EnemySwitch + farcall ResetBattleParticipants + xor a + ld [wBattleHasJustStarted], a + ld a, [wLinkMode] + and a + ret nz + scf + ret +; 384d0 + +TextJump_EnemyWithdrew: ; 384d0 + text_jump Text_EnemyWithdrew + db "@" +; 384d5 + +Function384d5: ; This appears to be unused + call AIUsedItemSound + call AI_HealStatus + ld a, FULL_HEAL_RED ; X_SPEED + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 384e0 + +AI_HealStatus: ; 384e0 + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + xor a + ld [hl], a + ld [EnemyMonStatus], a + ; Bug: this should reset SUBSTATUS_NIGHTMARE too + ; Uncomment the lines below to fix + ; ld hl, EnemySubStatus1 + ; res SUBSTATUS_NIGHTMARE, [hl] + ld hl, EnemySubStatus5 + res SUBSTATUS_TOXIC, [hl] + ret +; 384f7 + +EnemyUsedXAccuracy: ; 384f7 + call AIUsedItemSound + ld hl, EnemySubStatus4 + set SUBSTATUS_X_ACCURACY, [hl] + ld a, X_ACCURACY + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 38504 + +EnemyUsedGuardSpec: ; 38504 + call AIUsedItemSound + ld hl, EnemySubStatus4 + set SUBSTATUS_MIST, [hl] + ld a, GUARD_SPEC + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 38511 + +EnemyUsedDireHit: ; 38511 + call AIUsedItemSound + ld hl, EnemySubStatus4 + set SUBSTATUS_FOCUS_ENERGY, [hl] + ld a, DIRE_HIT + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 3851e + +Function3851e: ; This appears to be unused + ld [hDivisor], a + ld hl, EnemyMonMaxHP + ld a, [hli] + ld [hDividend], a + ld a, [hl] + ld [hDividend + 1], a + ld b, 2 + call Divide + ld a, [hQuotient + 2] + ld c, a + ld a, [hQuotient + 1] + ld b, a + ld hl, EnemyMonHP + 1 + ld a, [hld] + ld e, a + ld a, [hl] + ld d, a + ld a, d + sub b + ret nz + ld a, e + sub c + ret +; 38541 + +EnemyUsedXAttack: ; 38541 + ld b, ATTACK + ld a, X_ATTACK + jr EnemyUsedXItem +; 38547 + +EnemyUsedXDefend: ; 38547 + ld b, DEFENSE + ld a, X_DEFEND + jr EnemyUsedXItem +; 3854d + +EnemyUsedXSpeed: ; 3854d + ld b, SPEED + ld a, X_SPEED + jr EnemyUsedXItem +; 38553 + +EnemyUsedXSpecial: ; 38553 + ld b, SP_ATTACK + ld a, X_SPECIAL + + +; Parameter +; a = ITEM_CONSTANT +; b = BATTLE_CONSTANT (ATTACK, DEFENSE, SPEED, SP_ATTACK, SP_DEFENSE, ACCURACY, EVASION) +EnemyUsedXItem: + ld [CurEnemyItem], a + push bc + call PrintText_UsedItemOn + pop bc + farcall CheckIfStatCanBeRaised + jp AIUpdateHUD +; 38568 + + +; Parameter +; a = ITEM_CONSTANT +PrintText_UsedItemOn_AND_AIUpdateHUD: ; 38568 + ld [CurEnemyItem], a + call PrintText_UsedItemOn + jp AIUpdateHUD +; 38571 + +PrintText_UsedItemOn: ; 38571 + ld a, [CurEnemyItem] + ld [wd265], a + call GetItemName + ld hl, StringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, ITEM_NAME_LENGTH + call CopyBytes + ld hl, TextJump_EnemyUsedOn + jp PrintText +; 3858c + +TextJump_EnemyUsedOn: ; 3858c + text_jump Text_EnemyUsedOn + db "@" +; 38591 diff --git a/engine/battle/ai/move.asm b/engine/battle/ai/move.asm new file mode 100755 index 000000000..11586c0da --- /dev/null +++ b/engine/battle/ai/move.asm @@ -0,0 +1,221 @@ +AIChooseMove: ; 440ce +; Score each move in EnemyMonMoves starting from Buffer1. Lower is better. +; Pick the move with the lowest score. + +; Wildmons attack at random. + ld a, [wBattleMode] + dec a + ret z + + ld a, [wLinkMode] + and a + ret nz + +; No use picking a move if there's no choice. + farcall CheckEnemyLockedIn + ret nz + + +; The default score is 20. Unusable moves are given a score of 80. + ld a, 20 + ld hl, Buffer1 + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + +; Don't pick disabled moves. + ld a, [EnemyDisabledMove] + and a + jr z, .CheckPP + + ld hl, EnemyMonMoves + ld c, 0 +.CheckDisabledMove: + cp [hl] + jr z, .ScoreDisabledMove + inc c + inc hl + jr .CheckDisabledMove +.ScoreDisabledMove: + ld hl, Buffer1 + ld b, 0 + add hl, bc + ld [hl], 80 + +; Don't pick moves with 0 PP. +.CheckPP: + ld hl, Buffer1 - 1 + ld de, EnemyMonPP + ld b, 0 +.CheckMovePP: + inc b + ld a, b + cp EnemyMonMovesEnd - EnemyMonMoves + 1 + jr z, .ApplyLayers + inc hl + ld a, [de] + inc de + and $3f + jr nz, .CheckMovePP + ld [hl], 80 + jr .CheckMovePP + + +; Apply AI scoring layers depending on the trainer class. +.ApplyLayers: + ld hl, TrainerClassAttributes + TRNATTR_AI_MOVE_WEIGHTS + + ; If we have a battle in BattleTower just load the Attributes of the first TrainerClass (Falkner) + ; so we have always the same AI, regardless of the loaded class of trainer + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower_skip + + ld a, [TrainerClass] + dec a + ld bc, 7 ; Trainer2AI - Trainer1AI + call AddNTimes + +.battle_tower_skip + lb bc, CHECK_FLAG, 0 + push bc + push hl + +.CheckLayer: + pop hl + pop bc + + ld a, c + cp 16 ; up to 16 scoring layers + jr z, .DecrementScores + + push bc + ld d, BANK(TrainerClassAttributes) + predef FlagPredef + ld d, c + pop bc + + inc c + push bc + push hl + + ld a, d + and a + jr z, .CheckLayer + + ld hl, AIScoringPointers + dec c + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(AIScoring) + call FarCall_hl + + jr .CheckLayer + +; Decrement the scores of all moves one by one until one reaches 0. +.DecrementScores: + ld hl, Buffer1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + +.DecrementNextScore: + ; If the enemy has no moves, this will infinite. + ld a, [de] + inc de + and a + jr z, .DecrementScores + + ; We are done whenever a score reaches 0 + dec [hl] + jr z, .PickLowestScoreMoves + + ; If we just decremented the fourth move's score, go back to the first move + inc hl + dec c + jr z, .DecrementScores + + jr .DecrementNextScore + +; In order to avoid bias towards the moves located first in memory, increment the scores +; that were decremented one more time than the rest (in case there was a tie). +; This means that the minimum score will be 1. +.PickLowestScoreMoves: + ld a, c + +.move_loop + inc [hl] + dec hl + inc a + cp NUM_MOVES + 1 + jr nz, .move_loop + + ld hl, Buffer1 + ld de, EnemyMonMoves + ld c, NUM_MOVES + +; Give a score of 0 to a blank move +.loop2 + ld a, [de] + and a + jr nz, .skip_load + ld [hl], a + +; Disregard the move if its score is not 1 +.skip_load + ld a, [hl] + dec a + jr z, .keep + xor a + ld [hli], a + jr .after_toss + +.keep + ld a, [de] + ld [hli], a +.after_toss + inc de + dec c + jr nz, .loop2 + +; Randomly choose one of the moves with a score of 1 +.ChooseMove: + ld hl, Buffer1 + call Random + and 3 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and a + jr z, .ChooseMove + + ld [CurEnemyMove], a + ld a, c + ld [CurEnemyMoveNum], a + ret +; 441af + + +AIScoringPointers: ; 441af + dw AI_Basic + dw AI_Setup + dw AI_Types + dw AI_Offensive + dw AI_Smart + dw AI_Opportunist + dw AI_Aggressive + dw AI_Cautious + dw AI_Status + dw AI_Risky + dw AI_None + dw AI_None + dw AI_None + dw AI_None + dw AI_None + dw AI_None +; 441cf diff --git a/engine/battle/ai/redundant.asm b/engine/battle/ai/redundant.asm new file mode 100755 index 000000000..2e8f7c6df --- /dev/null +++ b/engine/battle/ai/redundant.asm @@ -0,0 +1,198 @@ +AI_Redundant: ; 2c41a +; Check if move effect c will fail because it's already been used. +; Return z if the move is a good choice. +; Return nz if the move is a bad choice. + ld a, c + ld de, 3 + ld hl, .Moves + call IsInArray + jp nc, .NotRedundant + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.Moves: ; 2c42c + dbw EFFECT_DREAM_EATER, .DreamEater + dbw EFFECT_HEAL, .Heal + dbw EFFECT_LIGHT_SCREEN, .LightScreen + dbw EFFECT_MIST, .Mist + dbw EFFECT_FOCUS_ENERGY, .FocusEnergy + dbw EFFECT_CONFUSE, .Confuse + dbw EFFECT_TRANSFORM, .Transform + dbw EFFECT_REFLECT, .Reflect + dbw EFFECT_SUBSTITUTE, .Substitute + dbw EFFECT_LEECH_SEED, .LeechSeed + dbw EFFECT_DISABLE, .Disable + dbw EFFECT_ENCORE, .Encore + dbw EFFECT_SNORE, .Snore + dbw EFFECT_SLEEP_TALK, .SleepTalk + dbw EFFECT_MEAN_LOOK, .MeanLook + dbw EFFECT_NIGHTMARE, .Nightmare + dbw EFFECT_SPIKES, .Spikes + dbw EFFECT_FORESIGHT, .Foresight + dbw EFFECT_PERISH_SONG, .PerishSong + dbw EFFECT_SANDSTORM, .Sandstorm + dbw EFFECT_ATTRACT, .Attract + dbw EFFECT_SAFEGUARD, .Safeguard + dbw EFFECT_RAIN_DANCE, .RainDance + dbw EFFECT_SUNNY_DAY, .SunnyDay + dbw EFFECT_TELEPORT, .Teleport + dbw EFFECT_MORNING_SUN, .MorningSun + dbw EFFECT_SYNTHESIS, .Synthesis + dbw EFFECT_MOONLIGHT, .Moonlight + dbw EFFECT_SWAGGER, .Swagger + dbw EFFECT_FUTURE_SIGHT, .FutureSight + db -1 + +.LightScreen: ; 2c487 + ld a, [EnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + ret + +.Mist: ; 2c48d + ld a, [EnemySubStatus4] + bit SUBSTATUS_MIST, a + ret + +.FocusEnergy: ; 2c493 + ld a, [EnemySubStatus4] + bit SUBSTATUS_FOCUS_ENERGY, a + ret + +.Confuse: ; 2c499 + ld a, [PlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + ret nz + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + ret + +.Transform: ; 2c4a5 + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret + +.Reflect: ; 2c4ab + ld a, [EnemyScreens] + bit SCREENS_REFLECT, a + ret + +.Substitute: ; 2c4b1 + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ret + +.LeechSeed: ; 2c4b7 + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + ret + +.Disable: ; 2c4bd + ld a, [PlayerDisableCount] + and a + ret + +.Encore: ; 2c4c2 + ld a, [PlayerSubStatus5] + bit SUBSTATUS_ENCORED, a + ret + +.Snore: +.SleepTalk: ; 2c4c8 + ld a, [EnemyMonStatus] + and SLP + jr z, .Redundant + jr .NotRedundant + +.MeanLook: ; 2c4d1 + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + ret + +.Nightmare: ; 2c4d7 + ld a, [BattleMonStatus] + and a + jr z, .Redundant + ld a, [PlayerSubStatus1] + bit SUBSTATUS_NIGHTMARE, a + ret + +.Spikes: ; 2c4e3 + ld a, [PlayerScreens] + bit SCREENS_SPIKES, a + ret + +.Foresight: ; 2c4e9 + ld a, [PlayerSubStatus1] + bit SUBSTATUS_IDENTIFIED, a + ret + +.PerishSong: ; 2c4ef + ld a, [PlayerSubStatus1] + bit SUBSTATUS_PERISH, a + ret + +.Sandstorm: ; 2c4f5 + ld a, [Weather] + cp WEATHER_SANDSTORM + jr z, .Redundant + jr .NotRedundant + +.Attract: ; 2c4fe + farcall CheckOppositeGender + jr c, .Redundant + ld a, [PlayerSubStatus1] + bit SUBSTATUS_IN_LOVE, a + ret + +.Safeguard: ; 2c50c + ld a, [EnemyScreens] + bit SCREENS_SAFEGUARD, a + ret + +.RainDance: ; 2c512 + ld a, [Weather] + cp WEATHER_RAIN + jr z, .Redundant + jr .NotRedundant + +.SunnyDay: ; 2c51b + ld a, [Weather] + cp WEATHER_SUN + jr z, .Redundant + jr .NotRedundant + +.DreamEater: ; 2c524 + ld a, [BattleMonStatus] + and SLP + jr z, .Redundant + jr .NotRedundant + +.Swagger: ; 2c52d + ld a, [PlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + ret + +.FutureSight: ; 2c533 + ld a, [EnemyScreens] + bit 5, a + ret + +.Heal: +.MorningSun: +.Synthesis: +.Moonlight: ; 2c539 + farcall AICheckEnemyMaxHP + jr nc, .NotRedundant + +.Teleport: +.Redundant: ; 2c541 + ld a, 1 + and a + ret + +.NotRedundant: ; 2c545 + xor a + ret diff --git a/engine/battle/ai/scoring.asm b/engine/battle/ai/scoring.asm new file mode 100644 index 000000000..44194d6f7 --- /dev/null +++ b/engine/battle/ai/scoring.asm @@ -0,0 +1,3598 @@ +AIScoring: ; 38591 + +AI_Basic: ; 38591 +; Don't do anything redundant: +; -Using status-only moves if the player can't be statused +; -Using moves that fail if they've already been used + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld c, a + +; Dismiss moves with special effects if they are +; useless or not a good choice right now. +; For example, healing moves, weather moves, Dream Eater... + push hl + push de + push bc + farcall AI_Redundant + pop bc + pop de + pop hl + jr nz, .discourage + +; Dismiss status-only moves if the player can't be statused. + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + push hl + push de + push bc + ld hl, .statusonlyeffects + ld de, 1 + call IsInArray + + pop bc + pop de + pop hl + jr nc, .checkmove + + ld a, [BattleMonStatus] + and a + jr nz, .discourage + +; Dismiss Safeguard if it's already active. + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + jr z, .checkmove + +.discourage + call AIDiscourageMove + jr .checkmove +; 385db + +.statusonlyeffects + db EFFECT_SLEEP + db EFFECT_TOXIC + db EFFECT_POISON + db EFFECT_PARALYZE + db $ff +; 385e0 + + + +AI_Setup: ; 385e0 +; Use stat-modifying moves on turn 1. + +; 50% chance to greatly encourage stat-up moves during the first turn of enemy's Pokemon. +; 50% chance to greatly encourage stat-down moves during the first turn of player's Pokemon. +; Almost 90% chance to greatly discourage stat-modifying moves otherwise. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + + cp EFFECT_ATTACK_UP + jr c, .checkmove + cp EFFECT_EVASION_UP + 1 + jr c, .statup + +; cp EFFECT_ATTACK_DOWN - 1 + jr z, .checkmove + cp EFFECT_EVASION_DOWN + 1 + jr c, .statdown + + cp EFFECT_ATTACK_UP_2 + jr c, .checkmove + cp EFFECT_EVASION_UP_2 + 1 + jr c, .statup + +; cp EFFECT_ATTACK_DOWN_2 - 1 + jr z, .checkmove + cp EFFECT_EVASION_DOWN_2 + 1 + jr c, .statdown + + jr .checkmove + +.statup + ld a, [EnemyTurnsTaken] + and a + jr nz, .discourage + + jr .encourage + +.statdown + ld a, [PlayerTurnsTaken] + and a + jr nz, .discourage + +.encourage + call AI_50_50 + jr c, .checkmove + + dec [hl] + dec [hl] + jr .checkmove + +.discourage + call Random + cp 12 percent + jr c, .checkmove + inc [hl] + inc [hl] + jr .checkmove +; 38635 + + + +AI_Types: ; 38635 +; Dismiss any move that the player is immune to. +; Encourage super-effective moves. +; Discourage not very effective moves unless +; all damaging moves are of the same type. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + push hl + push bc + push de + ld a, 1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop de + pop bc + pop hl + + ld a, [wd265] + and a + jr z, .immune + cp 10 ; 1.0 + jr z, .checkmove + jr c, .noteffective + +; effective + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .checkmove + dec [hl] + jr .checkmove + +.noteffective +; Discourage this move if there are any moves +; that do damage of a different type. + push hl + push de + push bc + ld a, [wEnemyMoveStruct + MOVE_TYPE] + ld d, a + ld hl, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 + ld c, 0 +.checkmove2 + dec b + jr z, .asm_38693 + + ld a, [hli] + and a + jr z, .asm_38693 + + call AIGetEnemyMove + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp d + jr z, .checkmove2 + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr nz, .asm_38692 + jr .checkmove2 + +.asm_38692 + ld c, a +.asm_38693 + ld a, c + pop bc + pop de + pop hl + and a + jr z, .checkmove + inc [hl] + jr .checkmove + +.immune + call AIDiscourageMove + jr .checkmove +; 386a2 + + + +AI_Offensive: ; 386a2 +; Greatly discourage non-damaging moves. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr nz, .checkmove + + inc [hl] + inc [hl] + jr .checkmove +; 386be + + + +AI_Smart: ; 386be +; Context-specific scoring. + + ld hl, Buffer1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + ld a, [de] + inc de + and a + ret z + + push de + push bc + push hl + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld hl, .table_386f2 + ld de, 3 + call IsInArray + + inc hl + jr nc, .nextmove + + ld a, [hli] + ld e, a + ld d, [hl] + + pop hl + push hl + + ld bc, .nextmove + push bc + + push de + ret + +.nextmove + pop hl + pop bc + pop de + inc hl + jr .checkmove + +.table_386f2 + dbw EFFECT_SLEEP, AI_Smart_Sleep + dbw EFFECT_LEECH_HIT, AI_Smart_LeechHit + dbw EFFECT_SELFDESTRUCT, AI_Smart_Selfdestruct + dbw EFFECT_DREAM_EATER, AI_Smart_DreamEater + dbw EFFECT_MIRROR_MOVE, AI_Smart_MirrorMove + dbw EFFECT_EVASION_UP, AI_Smart_EvasionUp + dbw EFFECT_ALWAYS_HIT, AI_Smart_AlwaysHit + dbw EFFECT_ACCURACY_DOWN, AI_Smart_AccuracyDown + dbw EFFECT_RESET_STATS, AI_Smart_ResetStats + dbw EFFECT_BIDE, AI_Smart_Bide + dbw EFFECT_FORCE_SWITCH, AI_Smart_ForceSwitch + dbw EFFECT_HEAL, AI_Smart_Heal + dbw EFFECT_TOXIC, AI_Smart_Toxic + dbw EFFECT_LIGHT_SCREEN, AI_Smart_LightScreen + dbw EFFECT_OHKO, AI_Smart_Ohko + dbw EFFECT_RAZOR_WIND, AI_Smart_RazorWind + dbw EFFECT_SUPER_FANG, AI_Smart_SuperFang + dbw EFFECT_TRAP_TARGET, AI_Smart_TrapTarget + dbw EFFECT_UNUSED_2B, AI_Smart_Unused2B + dbw EFFECT_CONFUSE, AI_Smart_Confuse + dbw EFFECT_SP_DEF_UP_2, AI_Smart_SpDefenseUp2 + dbw EFFECT_REFLECT, AI_Smart_Reflect + dbw EFFECT_PARALYZE, AI_Smart_Paralyze + dbw EFFECT_SPEED_DOWN_HIT, AI_Smart_SpeedDownHit + dbw EFFECT_SUBSTITUTE, AI_Smart_Substitute + dbw EFFECT_HYPER_BEAM, AI_Smart_HyperBeam + dbw EFFECT_RAGE, AI_Smart_Rage + dbw EFFECT_MIMIC, AI_Smart_Mimic + dbw EFFECT_LEECH_SEED, AI_Smart_LeechSeed + dbw EFFECT_DISABLE, AI_Smart_Disable + dbw EFFECT_COUNTER, AI_Smart_Counter + dbw EFFECT_ENCORE, AI_Smart_Encore + dbw EFFECT_PAIN_SPLIT, AI_Smart_PainSplit + dbw EFFECT_SNORE, AI_Smart_Snore + dbw EFFECT_CONVERSION2, AI_Smart_Conversion2 + dbw EFFECT_LOCK_ON, AI_Smart_LockOn + dbw EFFECT_DEFROST_OPPONENT, AI_Smart_DefrostOpponent + dbw EFFECT_SLEEP_TALK, AI_Smart_SleepTalk + dbw EFFECT_DESTINY_BOND, AI_Smart_DestinyBond + dbw EFFECT_REVERSAL, AI_Smart_Reversal + dbw EFFECT_SPITE, AI_Smart_Spite + dbw EFFECT_HEAL_BELL, AI_Smart_HealBell + dbw EFFECT_PRIORITY_HIT, AI_Smart_PriorityHit + dbw EFFECT_THIEF, AI_Smart_Thief + dbw EFFECT_MEAN_LOOK, AI_Smart_MeanLook + dbw EFFECT_NIGHTMARE, AI_Smart_Nightmare + dbw EFFECT_FLAME_WHEEL, AI_Smart_FlameWheel + dbw EFFECT_CURSE, AI_Smart_Curse + dbw EFFECT_PROTECT, AI_Smart_Protect + dbw EFFECT_FORESIGHT, AI_Smart_Foresight + dbw EFFECT_PERISH_SONG, AI_Smart_PerishSong + dbw EFFECT_SANDSTORM, AI_Smart_Sandstorm + dbw EFFECT_ENDURE, AI_Smart_Endure + dbw EFFECT_ROLLOUT, AI_Smart_Rollout + dbw EFFECT_SWAGGER, AI_Smart_Swagger + dbw EFFECT_FURY_CUTTER, AI_Smart_FuryCutter + dbw EFFECT_ATTRACT, AI_Smart_Attract + dbw EFFECT_SAFEGUARD, AI_Smart_Safeguard + dbw EFFECT_MAGNITUDE, AI_Smart_Magnitude + dbw EFFECT_BATON_PASS, AI_Smart_BatonPass + dbw EFFECT_PURSUIT, AI_Smart_Pursuit + dbw EFFECT_RAPID_SPIN, AI_Smart_RapidSpin + dbw EFFECT_MORNING_SUN, AI_Smart_MorningSun + dbw EFFECT_SYNTHESIS, AI_Smart_Synthesis + dbw EFFECT_MOONLIGHT, AI_Smart_Moonlight + dbw EFFECT_HIDDEN_POWER, AI_Smart_HiddenPower + dbw EFFECT_RAIN_DANCE, AI_Smart_RainDance + dbw EFFECT_SUNNY_DAY, AI_Smart_SunnyDay + dbw EFFECT_BELLY_DRUM, AI_Smart_BellyDrum + dbw EFFECT_PSYCH_UP, AI_Smart_PsychUp + dbw EFFECT_MIRROR_COAT, AI_Smart_MirrorCoat + dbw EFFECT_SKULL_BASH, AI_Smart_SkullBash + dbw EFFECT_TWISTER, AI_Smart_Twister + dbw EFFECT_EARTHQUAKE, AI_Smart_Earthquake + dbw EFFECT_FUTURE_SIGHT, AI_Smart_FutureSight + dbw EFFECT_GUST, AI_Smart_Gust + dbw EFFECT_STOMP, AI_Smart_Stomp + dbw EFFECT_SOLARBEAM, AI_Smart_Solarbeam + dbw EFFECT_THUNDER, AI_Smart_Thunder + dbw EFFECT_FLY, AI_Smart_Fly + db $ff +; 387e3 + + +AI_Smart_Sleep: ; 387e3 +; Greatly encourage sleep inducing moves if the enemy has either Dream Eater or Nightmare. +; 50% chance to greatly encourage sleep inducing moves otherwise. + + ld b, EFFECT_DREAM_EATER + call AIHasMoveEffect + jr c, .asm_387f0 + + ld b, EFFECT_NIGHTMARE + call AIHasMoveEffect + ret nc + +.asm_387f0 + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret +; 387f7 + + +AI_Smart_LeechHit: ; 387f7 + push hl + ld a, 1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop hl + +; 60% chance to discourage this move if not very effective. + ld a, [wd265] + cp 10 ; 1.0 + jr c, .asm_38815 + +; Do nothing if effectiveness is neutral. + ret z + +; Do nothing if enemy's HP is full. + call AICheckEnemyMaxHP + ret c + +; 80% chance to encourage this move otherwise. + call AI_80_20 + ret c + + dec [hl] + ret + +.asm_38815 + call Random + cp 39 percent + 1 + ret c + + inc [hl] + ret +; 3881d + + +AI_Smart_LockOn: ; 3881d + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .asm_38882 + + push hl + call AICheckEnemyQuarterHP + jr nc, .asm_38877 + + call AICheckEnemyHalfHP + jr c, .asm_38834 + + call AICompareSpeed + jr nc, .asm_38877 + +.asm_38834 + ld a, [PlayerEvaLevel] + cp $a + jr nc, .asm_3887a + cp $8 + jr nc, .asm_38875 + + ld a, [EnemyAccLevel] + cp $5 + jr c, .asm_3887a + cp $7 + jr c, .asm_38875 + + ld hl, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.asm_3884f + dec c + jr z, .asm_38877 + + ld a, [hli] + and a + jr z, .asm_38877 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_ACC] + cp 180 + jr nc, .asm_3884f + + ld a, $1 + ld [hBattleTurn], a + + push hl + push bc + farcall BattleCheckTypeMatchup + ld a, [wd265] + cp $a + pop bc + pop hl + jr c, .asm_3884f + +.asm_38875 + pop hl + ret + +.asm_38877 + pop hl + inc [hl] + ret + +.asm_3887a + pop hl + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +.asm_38882 + push hl + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 + +.asm_3888b + inc hl + dec c + jr z, .asm_388a2 + + ld a, [de] + and a + jr z, .asm_388a2 + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_ACC] + cp 180 + jr nc, .asm_3888b + + dec [hl] + dec [hl] + jr .asm_3888b + +.asm_388a2 + pop hl + jp AIDiscourageMove +; 388a6 + + +AI_Smart_Selfdestruct: ; 388a6 +; Selfdestruct, Explosion + +; Unless this is the enemy's last Pokemon... + push hl + farcall FindAliveEnemyMons + pop hl + jr nc, .asm_388b7 + +; ...greatly discourage this move unless this is the player's last Pokemon too. + push hl + call AICheckLastPlayerMon + pop hl + jr nz, .asm_388c6 + +.asm_388b7 +; Greatly discourage this move if enemy's HP is above 50%. + call AICheckEnemyHalfHP + jr c, .asm_388c6 + +; Do nothing if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + ret nc + +; If enemy's HP is between 25% and 50%, +; over 90% chance to greatly discourage this move. + call Random + cp 9 percent - 2 + ret c + +.asm_388c6 + inc [hl] + inc [hl] + inc [hl] + ret +; 388ca + + +AI_Smart_DreamEater: ; 388ca +; 90% chance to greatly encourage this move. +; The AI_Basic layer will make sure that +; Dream Eater is only used against sleeping targets. + call Random + cp 10 percent + ret c + dec [hl] + dec [hl] + dec [hl] + ret +; 388d4 + + +AI_Smart_EvasionUp: ; 388d4 + +; Dismiss this move if enemy's evasion can't raise anymore. + ld a, [EnemyEvaLevel] + cp $d + jp nc, AIDiscourageMove + +; If enemy's HP is full... + call AICheckEnemyMaxHP + jr nc, .asm_388f2 + +; ...greatly encourage this move if player is badly poisoned. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_388ef + +; ...70% chance to greatly encourage this move if player is not badly poisoned. + call Random + cp 70 percent + jr nc, .asm_38911 + +.asm_388ef + dec [hl] + dec [hl] + ret + +.asm_388f2 + +; Greatly discourage this move if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + jr nc, .asm_3890f + +; If enemy's HP is above 25% but not full, 4% chance to greatly encourage this move. + call Random + cp 4 percent + jr c, .asm_388ef + +; If enemy's HP is between 25% and 50%,... + call AICheckEnemyHalfHP + jr nc, .asm_3890a + +; If enemy's HP is above 50% but not full, 20% chance to greatly encourage this move. + call AI_80_20 + jr c, .asm_388ef + jr .asm_38911 + +.asm_3890a +; ...50% chance to greatly discourage this move. + call AI_50_50 + jr c, .asm_38911 + +.asm_3890f + inc [hl] + inc [hl] + +; 30% chance to end up here if enemy's HP is full and player is not badly poisoned. +; 77% chance to end up here if enemy's HP is above 50% but not full. +; 96% chance to end up here if enemy's HP is between 25% and 50%. +; 100% chance to end up here if enemy's HP is below 25%. +; In other words, we only end up here if the move has not been encouraged or dismissed. +.asm_38911 + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38938 + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_38941 + +; Discourage this move if enemy's evasion level is higher than player's accuracy level. + ld a, [EnemyEvaLevel] + ld b, a + ld a, [PlayerAccLevel] + cp b + jr c, .asm_38936 + +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. + ld a, [PlayerFuryCutterCount] + and a + jr nz, .asm_388ef + + ld a, [PlayerSubStatus1] + bit SUBSTATUS_ROLLOUT, a + jr nz, .asm_388ef + + +.asm_38936 + inc [hl] + ret + +; Player is badly poisoned. +; 70% chance to greatly encourage this move. +; This would counter any previous discouragement. +.asm_38938 + call Random + cp 31 percent + 1 + ret c + dec [hl] + dec [hl] + ret + +; Player is seeded. +; 50% chance to encourage this move. +; This would partly counter any previous discouragement. +.asm_38941 + call AI_50_50 + ret c + + dec [hl] + ret +; 38947 + + +AI_Smart_AlwaysHit: ; 38947 +; 80% chance to greatly encourage this move if either... + +; ...enemy's accuracy level has been lowered three or more stages + ld a, [EnemyAccLevel] + cp $5 + jr c, .asm_38954 + +; ...or player's evasion level has been raised three or more stages. + ld a, [PlayerEvaLevel] + cp $a + ret c + +.asm_38954 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret +; 3895b + + +AI_Smart_MirrorMove: ; 3895b + +; If the player did not use any move last turn... + ld a, [LastPlayerCounterMove] + and a + jr nz, .asm_38968 + +; ...do nothing if enemy is slower than player + call AICompareSpeed + ret nc + +; ...or dismiss this move if enemy is faster than player. + jp AIDiscourageMove + +; If the player did use a move last turn... +.asm_38968 + push hl + ld hl, UsefulMoves + ld de, 1 + call IsInArray + pop hl + +; ...do nothing if he didn't use a useful move. + ret nc + +; If he did, 50% chance to encourage this move... + call AI_50_50 + ret c + + dec [hl] + +; ...and 90% chance to encourage this move again if the enemy is faster. + call AICompareSpeed + ret nc + + call Random + cp 10 percent + ret c + + dec [hl] + ret +; 38985 + + +AI_Smart_AccuracyDown: ; 38985 + +; If player's HP is full... + call AICheckPlayerMaxHP + jr nc, .asm_389a0 + +; ...and enemy's HP is above 50%... + call AICheckEnemyHalfHP + jr nc, .asm_389a0 + +; ...greatly encourage this move if player is badly poisoned. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_3899d + +; ...70% chance to greatly encourage this move if player is not badly poisoned. + call Random + cp 70 percent + jr nc, .asm_389bf + +.asm_3899d + dec [hl] + dec [hl] + ret + +.asm_389a0 + +; Greatly discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP + jr nc, .asm_389bd + +; If player's HP is above 25% but not full, 4% chance to greatly encourage this move. + call Random + cp 4 percent + jr c, .asm_3899d + +; If player's HP is between 25% and 50%,... + call AICheckPlayerHalfHP + jr nc, .asm_389b8 + +; If player's HP is above 50% but not full, 20% chance to greatly encourage this move. + call AI_80_20 + jr c, .asm_3899d + jr .asm_389bf + +; ...50% chance to greatly discourage this move. +.asm_389b8 + call AI_50_50 + jr c, .asm_389bf + +.asm_389bd + inc [hl] + inc [hl] + +; We only end up here if the move has not been already encouraged. +.asm_389bf + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_389e6 + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_389ef + +; Discourage this move if enemy's evasion level is higher than player's accuracy level. + ld a, [EnemyEvaLevel] + ld b, a + ld a, [PlayerAccLevel] + cp b + jr c, .asm_389e4 + +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. + ld a, [PlayerFuryCutterCount] + and a + jr nz, .asm_3899d + + ld a, [PlayerSubStatus1] + bit SUBSTATUS_ROLLOUT, a + jr nz, .asm_3899d + +.asm_389e4 + inc [hl] + ret + +; Player is badly poisoned. +; 70% chance to greatly encourage this move. +; This would counter any previous discouragement. +.asm_389e6 + call Random + cp 31 percent + 1 + ret c + dec [hl] + dec [hl] + ret + +; Player is seeded. +; 50% chance to encourage this move. +; This would partly counter any previous discouragement. +.asm_389ef + call AI_50_50 + ret c + + dec [hl] + ret +; 389f5 + + +AI_Smart_ResetStats: ; 389f5 + +; 85% chance to encourage this move if any of enemy's stat levels is lower than -2. + push hl + ld hl, EnemyAtkLevel + ld c, $8 +.asm_389fb + dec c + jr z, .asm_38a05 + ld a, [hli] + cp $5 + jr c, .asm_38a12 + jr .asm_389fb + +; 85% chance to encourage this move if any of player's stat levels is higher than +2. +.asm_38a05 + ld hl, PlayerAtkLevel + ld c, $8 +.asm_38a0a + dec c + jr z, .asm_38a1b + ld a, [hli] + cp $a + jr c, .asm_38a0a + +.asm_38a12 + pop hl + call Random + cp 16 percent + ret c + dec [hl] + ret + +; Discourage this move if neither: +; Any of enemy's stat levels is lower than -2. +; Any of player's stat levels is higher than +2. +.asm_38a1b + pop hl + inc [hl] + ret +; 38a1e + + +AI_Smart_Bide: ; 38a1e +; 90% chance to discourage this move unless enemy's HP is full. + + call AICheckEnemyMaxHP + ret c + call Random + cp 10 percent + ret c + inc [hl] + ret +; 38a2a + + +AI_Smart_ForceSwitch: ; 38a2a +; Whirlwind, Roar. + +; Discourage this move if the player has not shown +; a super-effective move against the enemy. +; Consider player's type(s) if its moves are unknown. + + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 ; neutral + pop hl + ret c + inc [hl] + ret +; 38a3a + + +AI_Smart_Heal: +AI_Smart_MorningSun: +AI_Smart_Synthesis: +AI_Smart_Moonlight: ; 38a3a +; 90% chance to greatly encourage this move if enemy's HP is below 25%. +; Discourage this move if enemy's HP is higher than 50%. +; Do nothing otherwise. + + call AICheckEnemyQuarterHP + jr nc, .asm_38a45 + call AICheckEnemyHalfHP + ret nc + inc [hl] + ret + +.asm_38a45 + call Random + cp 10 percent + ret c + dec [hl] + dec [hl] + ret +; 38a4e + + +AI_Smart_Toxic: +AI_Smart_LeechSeed: ; 38a4e +; Discourage this move if player's HP is below 50%. + + call AICheckPlayerHalfHP + ret c + inc [hl] + ret +; 38a54 + + +AI_Smart_LightScreen: +AI_Smart_Reflect: ; 38a54 +; Over 90% chance to discourage this move unless enemy's HP is full. + + call AICheckEnemyMaxHP + ret c + call Random + cp 8 percent + ret c + inc [hl] + ret +; 38a60 + + +AI_Smart_Ohko: ; 38a60 +; Dismiss this move if player's level is higher than enemy's level. +; Else, discourage this move is player's HP is below 50%. + + ld a, [BattleMonLevel] + ld b, a + ld a, [EnemyMonLevel] + cp b + jp c, AIDiscourageMove + call AICheckPlayerHalfHP + ret c + inc [hl] + ret +; 38a71 + + +AI_Smart_TrapTarget: ; 38a71 +; Bind, Wrap, Fire Spin, Clamp + +; 50% chance to discourage this move if the player is already trapped. + ld a, [wPlayerWrapCount] + and a + jr nz, .asm_38a8b + +; 50% chance to greatly encourage this move if player is either +; badly poisoned, in love, identified, stuck in Rollout, or has a Nightmare. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38a91 + + ld a, [PlayerSubStatus1] + and 1<<SUBSTATUS_IN_LOVE | 1<<SUBSTATUS_ROLLOUT | 1<<SUBSTATUS_IDENTIFIED | 1<<SUBSTATUS_NIGHTMARE + jr nz, .asm_38a91 + +; Else, 50% chance to greatly encourage this move if it's the player's Pokemon first turn. + ld a, [PlayerTurnsTaken] + and a + jr z, .asm_38a91 + +; 50% chance to discourage this move otherwise. +.asm_38a8b + call AI_50_50 + ret c + inc [hl] + ret + +.asm_38a91 + call AICheckEnemyQuarterHP + ret nc + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret +; 38a9c + + +AI_Smart_RazorWind: +AI_Smart_Unused2B: ; 38a9c + ld a, [EnemySubStatus1] + bit SUBSTATUS_PERISH, a + jr z, .asm_38aaa + + ld a, [EnemyPerishCount] + cp 3 + jr c, .asm_38ad3 + +.asm_38aaa + push hl + ld hl, PlayerUsedMoves + ld c, 4 + +.asm_38ab0 + ld a, [hli] + and a + jr z, .asm_38ac1 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + jr z, .asm_38ad5 + dec c + jr nz, .asm_38ab0 + +.asm_38ac1 + pop hl + ld a, [EnemySubStatus3] + bit SUBSTATUS_CONFUSED, a + jr nz, .asm_38acd + + call AICheckEnemyHalfHP + ret c + +.asm_38acd + call Random + cp 79 percent - 1 + ret c + +.asm_38ad3 + inc [hl] + ret + +.asm_38ad5 + pop hl + ld a, [hl] + add 6 + ld [hl], a + ret +; 38adb + + +AI_Smart_Confuse: ; 38adb + +; 90% chance to discourage this move if player's HP is between 25% and 50%. + call AICheckPlayerHalfHP + ret c + call Random + cp 10 percent + jr c, .asm_38ae7 + inc [hl] + +.asm_38ae7 +; Discourage again if player's HP is below 25%. + call AICheckPlayerQuarterHP + ret c + inc [hl] + ret +; 38aed + + +AI_Smart_SpDefenseUp2: ; 38aed + +; Discourage this move if enemy's HP is lower than 50%. + call AICheckEnemyHalfHP + jr nc, .asm_38b10 + +; Discourage this move if enemy's special defense level is higher than +3. + ld a, [EnemySDefLevel] + cp $b + jr nc, .asm_38b10 + +; 80% chance to greatly encourage this move if +; enemy's Special Defense level is lower than +2, and the player is of a special type. + cp $9 + ret nc + + ld a, [BattleMonType1] + cp SPECIAL + jr nc, .asm_38b09 + ld a, [BattleMonType2] + cp SPECIAL + ret c + +.asm_38b09 + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38b10 + inc [hl] + ret +; 38b12 + + +AI_Smart_Fly: ; 38b12 +; Fly, Dig + +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + call AICompareSpeed + ret nc + + dec [hl] + dec [hl] + dec [hl] + ret +; 38b20 + + +AI_Smart_SuperFang: ; 38b20 +; Discourage this move if player's HP is below 25%. + + call AICheckPlayerQuarterHP + ret c + inc [hl] + ret +; 38b26 + + +AI_Smart_Paralyze: ; 38b26 + +; 50% chance to discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP + jr nc, .asm_38b3a + +; 80% chance to greatly encourage this move +; if enemy is slower than player and its HP is above 25%. + call AICompareSpeed + ret c + call AICheckEnemyQuarterHP + ret nc + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38b3a + call AI_50_50 + ret c + inc [hl] + ret +; 38b40 + + +AI_Smart_SpeedDownHit: ; 38b40 +; Icy Wind + +; Almost 90% chance to greatly encourage this move if the following conditions all meet: +; Enemy's HP is higher than 25%. +; It's the first turn of player's Pokemon. +; Player is faster than enemy. + + ld a, [wEnemyMoveStruct + MOVE_ANIM] + cp ICY_WIND + ret nz + call AICheckEnemyQuarterHP + ret nc + ld a, [PlayerTurnsTaken] + and a + ret nz + call AICompareSpeed + ret c + call Random + cp 12 percent + ret c + dec [hl] + dec [hl] + ret +; 38b5c + + +AI_Smart_Substitute: ; 38b5c +; Dismiss this move if enemy's HP is below 50%. + + call AICheckEnemyHalfHP + ret c + jp AIDiscourageMove +; 38b63 + + +AI_Smart_HyperBeam: ; 38b63 + call AICheckEnemyHalfHP + jr c, .asm_38b72 + +; 50% chance to encourage this move if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + ret c + call AI_50_50 + ret c + dec [hl] + ret + +.asm_38b72 +; If enemy's HP is above 50%, discourage this move at random + call Random + cp 16 percent + ret c + inc [hl] + call AI_50_50 + ret c + inc [hl] + ret +; 38b7f + + +AI_Smart_Rage: ; 38b7f + ld a, [EnemySubStatus4] + bit SUBSTATUS_RAGE, a + jr z, .asm_38b9b + +; If enemy's Rage is building, 50% chance to encourage this move. + call AI_50_50 + jr c, .asm_38b8c + + dec [hl] + +; Encourage this move based on Rage's counter. +.asm_38b8c + ld a, [wEnemyRageCounter] + cp $2 + ret c + dec [hl] + ld a, [wEnemyRageCounter] + cp $3 + ret c + dec [hl] + ret + +.asm_38b9b +; If enemy's Rage is not building, discourage this move if enemy's HP is below 50%. + call AICheckEnemyHalfHP + jr nc, .asm_38ba6 + +; 50% chance to encourage this move otherwise. + call AI_80_20 + ret nc + dec [hl] + ret + +.asm_38ba6 + inc [hl] + ret +; 38ba8 + + +AI_Smart_Mimic: ; 38ba8 + ld a, [LastPlayerCounterMove] + and a + jr z, .asm_38be9 + + call AICheckEnemyHalfHP + jr nc, .asm_38bef + + push hl + ld a, [LastPlayerCounterMove] + call AIGetEnemyMove + + ld a, $1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + + ld a, [wd265] + cp $a + pop hl + jr c, .asm_38bef + jr z, .asm_38bd4 + + call AI_50_50 + jr c, .asm_38bd4 + + dec [hl] + +.asm_38bd4 + ld a, [LastPlayerCounterMove] + push hl + ld hl, UsefulMoves + ld de, 1 + call IsInArray + + pop hl + ret nc + call AI_50_50 + ret c + dec [hl] + ret + +.asm_38be9 + call AICompareSpeed + jp c, AIDiscourageMove + +.asm_38bef + inc [hl] + ret +; 38bf1 + + +AI_Smart_Counter: ; 38bf1 + push hl + ld hl, PlayerUsedMoves + ld c, 4 + ld b, 0 + +.asm_38bf9 + ld a, [hli] + and a + jr z, .asm_38c0e + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c0e + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr nc, .asm_38c0e + + inc b + +.asm_38c0e + dec c + jr nz, .asm_38bf9 + + pop hl + ld a, b + and a + jr z, .asm_38c39 + + cp $3 + jr nc, .asm_38c30 + + ld a, [LastPlayerCounterMove] + and a + jr z, .asm_38c38 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c38 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr nc, .asm_38c38 + + +.asm_38c30 + call Random + cp 39 percent + 1 + jr c, .asm_38c38 + + dec [hl] + +.asm_38c38 + ret + +.asm_38c39 + inc [hl] + ret +; 38c3b + + +AI_Smart_Encore: ; 38c3b + call AICompareSpeed + jr nc, .asm_38c81 + + ld a, [LastPlayerMove] + and a + jp z, AIDiscourageMove + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c68 + + push hl + ld a, [wEnemyMoveStruct + MOVE_TYPE] + ld hl, EnemyMonType1 + predef CheckTypeMatchup + + pop hl + ld a, [wd265] + cp $a + jr nc, .asm_38c68 + + and a + ret nz + jr .asm_38c78 + +.asm_38c68 + push hl + ld a, [LastPlayerCounterMove] + ld hl, .EncoreMoves + ld de, 1 + call IsInArray + pop hl + jr nc, .asm_38c81 + +.asm_38c78 + call Random + cp 28 percent - 1 + ret c + dec [hl] + dec [hl] + ret + +.asm_38c81 + inc [hl] + inc [hl] + inc [hl] + ret + +.EncoreMoves: + db SWORDS_DANCE + db WHIRLWIND + db LEER + db ROAR + db DISABLE + db MIST + db LEECH_SEED + db GROWTH + db POISONPOWDER + db STRING_SHOT + db MEDITATE + db AGILITY + db TELEPORT + db SCREECH + db HAZE + db FOCUS_ENERGY + db DREAM_EATER + db POISON_GAS + db SPLASH + db SHARPEN + db CONVERSION + db SUPER_FANG + db SUBSTITUTE + db TRIPLE_KICK + db SPIDER_WEB + db MIND_READER + db FLAME_WHEEL + db AEROBLAST + db COTTON_SPORE + db POWDER_SNOW + db $ff +; 38ca4 + + +AI_Smart_PainSplit: ; 38ca4 +; Discourage this move if [enemy's current HP * 2 > player's current HP]. + + push hl + ld hl, EnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + ld hl, BattleMonHP + 1 + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret nc + inc [hl] + ret +; 38cba + + +AI_Smart_Snore: +AI_Smart_SleepTalk: ; 38cba +; Greatly encourage this move if enemy is fast asleep. +; Greatly discourage this move otherwise. + + ld a, [EnemyMonStatus] + and $7 + cp $1 + jr z, .asm_38cc7 + + dec [hl] + dec [hl] + dec [hl] + ret + +.asm_38cc7 + inc [hl] + inc [hl] + inc [hl] + ret +; 38ccb + + +AI_Smart_DefrostOpponent: ; 38ccb +; Greatly encourage this move if enemy is frozen. +; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused. + + ld a, [EnemyMonStatus] + and $20 + ret z + dec [hl] + dec [hl] + dec [hl] + ret +; 38cd5 + + +AI_Smart_Spite: ; 38cd5 + ld a, [LastPlayerCounterMove] + and a + jr nz, .asm_38ce7 + + call AICompareSpeed + jp c, AIDiscourageMove + + call AI_50_50 + ret c + inc [hl] + ret + +.asm_38ce7 + push hl + ld b, a + ld c, 4 + ld hl, BattleMonMoves + ld de, BattleMonPP + +.asm_38cf1 + ld a, [hli] + cp b + jr z, .asm_38cfb + + inc de + dec c + jr nz, .asm_38cf1 + + pop hl + ret + +.asm_38cfb + pop hl + ld a, [de] + cp $6 + jr c, .asm_38d0d + cp $f + jr nc, .asm_38d0b + + call Random + cp 39 percent + 1 + ret nc + +.asm_38d0b + inc [hl] + ret + +.asm_38d0d + call Random + cp 39 percent + 1 + ret c + dec [hl] + dec [hl] + ret +; 38d16 + + +Function_0x38d16; 38d16 + jp AIDiscourageMove +; 38d19 + + +AI_Smart_DestinyBond: +AI_Smart_Reversal: +AI_Smart_SkullBash: ; 38d19 +; Discourage this move if enemy's HP is above 25%. + + call AICheckEnemyQuarterHP + ret nc + inc [hl] + ret +; 38d1f + + +AI_Smart_HealBell: ; 38d1f +; Dismiss this move if none of the opponent's Pokemon is statused. +; Encourage this move if the enemy is statused. +; 50% chance to greatly encourage this move if the enemy is fast asleep or frozen. + + push hl + ld a, [OTPartyCount] + ld b, a + ld c, 0 + ld hl, OTPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + push hl + ld a, [hli] + or [hl] + jr z, .next + + ; status + dec hl + dec hl + dec hl + ld a, [hl] + or c + ld c, a + +.next + pop hl + add hl, de + dec b + jr nz, .loop + + pop hl + ld a, c + and a + jr z, .no_status + + ld a, [EnemyMonStatus] + and a + jr z, .ok + dec [hl] +.ok + and 1 << FRZ | SLP + ret z + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret + +.no_status + ld a, [EnemyMonStatus] + and a + ret nz + jp AIDiscourageMove + +; 38d5a + + +AI_Smart_PriorityHit: ; 38d5a + call AICompareSpeed + ret c + +; Dismiss this move if the player is flying or underground. + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + jp nz, AIDiscourageMove + +; Greatly encourage this move if it will KO the player. + ld a, $1 + ld [hBattleTurn], a + push hl + callfar EnemyAttackDamage + callfar BattleCommand_DamageCalc + callfar BattleCommand_Stab + pop hl + ld a, [CurDamage + 1] + ld c, a + ld a, [CurDamage] + ld b, a + ld a, [BattleMonHP + 1] + cp c + ld a, [BattleMonHP] + sbc b + ret nc + dec [hl] + dec [hl] + dec [hl] + ret +; 38d93 + + +AI_Smart_Thief: ; 38d93 +; Don't use Thief unless it's the only move available. + + ld a, [hl] + add $1e + ld [hl], a + ret +; 38d98 + + +AI_Smart_Conversion2: ; 38d98 + ld a, [LastPlayerMove] + and a + jr nz, .asm_38dc9 + + push hl + dec a + ld hl, Moves + MOVE_TYPE + ld bc, MOVE_LENGTH + call AddNTimes + + ld a, BANK(Moves) + call GetFarByte + ld [wPlayerMoveStruct + MOVE_TYPE], a + + xor a + ld [hBattleTurn], a + + callfar BattleCheckTypeMatchup + + ld a, [wd265] + cp $a + pop hl + jr c, .asm_38dc9 + ret z + + call AI_50_50 + ret c + + dec [hl] + ret + +.asm_38dc9 + call Random + cp 10 percent + ret c + inc [hl] + ret +; 38dd1 + + +AI_Smart_Disable: ; 38dd1 + call AICompareSpeed + jr nc, .asm_38df3 + + push hl + ld a, [LastPlayerCounterMove] + ld hl, UsefulMoves + ld de, 1 + call IsInArray + + pop hl + jr nc, .asm_38dee + + call Random + cp 39 percent + 1 + ret c + dec [hl] + ret + +.asm_38dee + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + ret nz + +.asm_38df3 + call Random + cp 8 percent + ret c + inc [hl] + ret +; 38dfb + + +AI_Smart_MeanLook: ; 38dfb + call AICheckEnemyHalfHP + jr nc, .asm_38e24 + + push hl + call AICheckLastPlayerMon + pop hl + jp z, AIDiscourageMove + +; 80% chance to greatly encourage this move if the enemy is badly poisoned (buggy). +; Should check PlayerSubStatus5 instead. + ld a, [EnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38e26 + +; 80% chance to greatly encourage this move if the player is either +; in love, identified, stuck in Rollout, or has a Nightmare. + ld a, [PlayerSubStatus1] + and 1<<SUBSTATUS_IN_LOVE | 1<<SUBSTATUS_ROLLOUT | 1<<SUBSTATUS_IDENTIFIED | 1<<SUBSTATUS_NIGHTMARE + jr nz, .asm_38e26 + +; Otherwise, discourage this move unless the player only has not very effective moves against the enemy. + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp $b ; not very effective + pop hl + ret nc + +.asm_38e24 + inc [hl] + ret + +.asm_38e26 + call AI_80_20 + ret c + dec [hl] + dec [hl] + dec [hl] + ret +; 38e2e + + +AICheckLastPlayerMon: ; 38e2e + ld a, [PartyCount] + ld b, a + ld c, 0 + ld hl, PartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + ld a, [CurBattleMon] + cp c + jr z, .asm_38e44 + + ld a, [hli] + or [hl] + ret nz + dec hl + +.asm_38e44 + add hl, de + inc c + dec b + jr nz, .loop + + ret +; 38e4a + + +AI_Smart_Nightmare: ; 38e4a +; 50% chance to encourage this move. +; The AI_Basic layer will make sure that +; Dream Eater is only used against sleeping targets. + + call AI_50_50 + ret c + dec [hl] + ret +; 38e50 + + +AI_Smart_FlameWheel: ; 38e50 +; Use this move if the enemy is frozen. + + ld a, [EnemyMonStatus] + bit FRZ, a + ret z +rept 5 + dec [hl] +endr + ret +; 38e5c + + +AI_Smart_Curse: ; 38e5c + ld a, [EnemyMonType1] + cp GHOST + jr z, .ghostcurse + ld a, [EnemyMonType2] + cp GHOST + jr z, .ghostcurse + + call AICheckEnemyHalfHP + jr nc, .asm_38e93 + + ld a, [EnemyAtkLevel] + cp $b + jr nc, .asm_38e93 + cp $9 + ret nc + + ld a, [BattleMonType1] + cp GHOST + jr z, .asm_38e92 + cp SPECIAL + ret nc + ld a, [BattleMonType2] + cp SPECIAL + ret nc + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38e90 + inc [hl] + inc [hl] +.asm_38e92 + inc [hl] +.asm_38e93 + inc [hl] + ret + +.ghostcurse + ld a, [PlayerSubStatus1] + bit SUBSTATUS_CURSE, a + jp nz, AIDiscourageMove + + push hl + farcall FindAliveEnemyMons + pop hl + jr nc, .asm_38eb0 + + push hl + call AICheckLastPlayerMon + pop hl + jr nz, .asm_38e90 + + jr .asm_38eb7 + + +.asm_38eb0 + push hl + call AICheckLastPlayerMon + pop hl + jr z, .asm_38ecb + + +.asm_38eb7 + call AICheckEnemyQuarterHP + jp nc, .asm_38e90 + + call AICheckEnemyHalfHP + jr nc, .asm_38e92 + + call AICheckEnemyMaxHP + ret nc + + ld a, [PlayerTurnsTaken] + and a + ret nz + +.asm_38ecb + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret +; 38ed2 + + +AI_Smart_Protect: ; 38ed2 + ld a, [EnemyProtectCount] + and a + jr nz, .asm_38f13 + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .asm_38f14 + + ld a, [PlayerFuryCutterCount] + cp 3 + jr nc, .asm_38f0d + + ld a, [PlayerSubStatus3] + bit SUBSTATUS_CHARGED, a + jr nz, .asm_38f0d + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38f0d + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_38f0d + ld a, [PlayerSubStatus1] + bit SUBSTATUS_CURSE, a + jr nz, .asm_38f0d + + bit SUBSTATUS_ROLLOUT, a + jr z, .asm_38f14 + + ld a, [PlayerRolloutCount] + cp 3 + jr c, .asm_38f14 + +.asm_38f0d + call AI_80_20 + ret c + dec [hl] + ret + +.asm_38f13 + inc [hl] + +.asm_38f14 + call Random + cp 8 percent + ret c + inc [hl] + inc [hl] + ret +; 38f1d + + +AI_Smart_Foresight: ; 38f1d + ld a, [EnemyAccLevel] + cp $5 + jr c, .asm_38f41 + ld a, [PlayerEvaLevel] + cp $a + jr nc, .asm_38f41 + + ld a, [BattleMonType1] + cp GHOST + jr z, .asm_38f41 + ld a, [BattleMonType2] + cp GHOST + jr z, .asm_38f41 + + call Random + cp 8 percent + ret c + inc [hl] + ret + +.asm_38f41 + call Random + cp 39 percent + 1 + ret c + dec [hl] + dec [hl] + ret +; 38f4a + + +AI_Smart_PerishSong: ; 38f4a + push hl + callfar FindAliveEnemyMons + pop hl + jr c, .no + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, .yes + + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 ; 1.0 + pop hl + ret c + + call AI_50_50 + ret c + + inc [hl] + ret + +.yes + call AI_50_50 + ret c + + dec [hl] + ret + +.no + ld a, [hl] + add 5 + ld [hl], a + ret +; 38f7a + + +AI_Smart_Sandstorm: ; 38f7a + +; Greatly discourage this move if the player is immune to Sandstorm damage. + ld a, [BattleMonType1] + push hl + ld hl, .SandstormImmuneTypes + ld de, 1 + call IsInArray + pop hl + jr c, .asm_38fa5 + + ld a, [BattleMonType2] + push hl + ld hl, .SandstormImmuneTypes + ld de, 1 + call IsInArray + pop hl + jr c, .asm_38fa5 + +; Discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP + jr nc, .asm_38fa6 + +; 50% chance to encourage this move otherwise. + call AI_50_50 + ret c + + dec [hl] + ret + +.asm_38fa5 + inc [hl] + +.asm_38fa6 + inc [hl] + ret + +.SandstormImmuneTypes: + db ROCK + db GROUND + db STEEL + db $ff +; 38fac + + +AI_Smart_Endure: ; 38fac + ld a, [EnemyProtectCount] + and a + jr nz, .asm_38fd8 + + call AICheckEnemyMaxHP + jr c, .asm_38fd8 + + call AICheckEnemyQuarterHP + jr c, .asm_38fd9 + + ld b, EFFECT_REVERSAL + call AIHasMoveEffect + jr nc, .asm_38fcb + + call AI_80_20 + ret c + + dec [hl] + dec [hl] + dec [hl] + ret + +.asm_38fcb + ld a, [EnemySubStatus5] + bit SUBSTATUS_LOCK_ON, a + ret z + + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +.asm_38fd8 + inc [hl] + +.asm_38fd9 + inc [hl] + ret +; 38fdb + + +AI_Smart_FuryCutter: ; 38fdb +; Encourage this move based on Fury Cutter's count. + + ld a, [EnemyFuryCutterCount] + and a + jr z, .end + dec [hl] + + cp 2 + jr c, .end + dec [hl] + dec [hl] + + cp 3 + jr c, .end + dec [hl] + dec [hl] + dec [hl] + +.end + + ; fallthrough +; 38fef + + +AI_Smart_Rollout: ; 38fef +; Rollout, Fury Cutter + +; 80% chance to discourage this move if the enemy is in love, confused, or paralyzed. + ld a, [EnemySubStatus1] + bit SUBSTATUS_IN_LOVE, a + jr nz, .asm_39020 + + ld a, [EnemySubStatus3] + bit SUBSTATUS_CONFUSED, a + jr nz, .asm_39020 + + ld a, [EnemyMonStatus] + bit PAR, a + jr nz, .asm_39020 + +; 80% chance to discourage this move if the enemy's HP is below 25%, +; or if accuracy or evasion modifiers favour the player. + call AICheckEnemyQuarterHP + jr nc, .asm_39020 + + ld a, [EnemyAccLevel] + cp 7 + jr c, .asm_39020 + ld a, [PlayerEvaLevel] + cp 8 + jr nc, .asm_39020 + +; Otherwise, 80% chance to greatly encourage this move. + call Random + cp 79 percent - 1 + ret nc + dec [hl] + dec [hl] + ret + +.asm_39020 + call AI_80_20 + ret c + inc [hl] + ret +; 39026 + + +AI_Smart_Swagger: +AI_Smart_Attract: ; 39026 +; 80% chance to encourage this move during the first turn of player's Pokemon. +; 80% chance to discourage this move otherwise. + + ld a, [PlayerTurnsTaken] + and a + jr z, .first_turn + + call AI_80_20 + ret c + inc [hl] + ret + +.first_turn + call Random + cp 79 percent - 1 + ret nc + dec [hl] + ret +; 3903a + + +AI_Smart_Safeguard: ; 3903a +; 80% chance to discourage this move if player's HP is below 50%. + + call AICheckPlayerHalfHP + ret c + call AI_80_20 + ret c + inc [hl] + ret +; 39044 + + +AI_Smart_Magnitude: +AI_Smart_Earthquake: ; 39044 + +; Greatly encourage this move if the player is underground and the enemy is faster. + ld a, [LastPlayerCounterMove] + cp DIG + ret nz + + ld a, [PlayerSubStatus3] + bit SUBSTATUS_UNDERGROUND, a + jr z, .could_dig + + call AICompareSpeed + ret nc + dec [hl] + dec [hl] + ret + +.could_dig + ; Try to predict if the player will use Dig this turn. + + ; 50% chance to encourage this move if the enemy is slower than the player. + call AICompareSpeed + ret c + + call AI_50_50 + ret c + + dec [hl] + ret +; 39062 + + +AI_Smart_BatonPass: ; 39062 +; Discourage this move if the player hasn't shown super-effective moves against the enemy. +; Consider player's type(s) if its moves are unknown. + + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 ; neutral + pop hl + ret c + inc [hl] + ret +; 39072 + + +AI_Smart_Pursuit: ; 39072 +; 50% chance to greatly encourage this move if player's HP is below 25%. +; 80% chance to discourage this move otherwise. + + call AICheckPlayerQuarterHP + jr nc, .asm_3907d + call AI_80_20 + ret c + inc [hl] + ret + +.asm_3907d + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret +; 39084 + + +AI_Smart_RapidSpin: ; 39084 +; 80% chance to greatly encourage this move if the enemy is +; trapped (Bind effect), seeded, or scattered with spikes. + + ld a, [wEnemyWrapCount] + and a + jr nz, .asm_39097 + + ld a, [EnemySubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_39097 + + ld a, [EnemyScreens] + bit SCREENS_SPIKES, a + ret z + +.asm_39097 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret +; 3909e + + +AI_Smart_HiddenPower: ; 3909e + push hl + ld a, 1 + ld [hBattleTurn], a + +; Calculate Hidden Power's type and base power based on enemy's DVs. + callfar HiddenPowerDamage + callfar BattleCheckTypeMatchup + pop hl + +; Discourage Hidden Power if not very effective. + ld a, [wd265] + cp 10 + jr c, .bad + +; Discourage Hidden Power if its base power is lower than 50. + ld a, d + cp 50 + jr c, .bad + +; Encourage Hidden Power if super-effective. + ld a, [wd265] + cp 11 + jr nc, .good + +; Encourage Hidden Power if its base power is 70. + ld a, d + cp 70 + ret c + +.good + dec [hl] + ret + +.bad + inc [hl] + ret +; 390cb + + +AI_Smart_RainDance: ; 390cb + +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Water-type. + ld a, [BattleMonType1] + cp WATER + jr z, AIBadWeatherType + cp FIRE + jr z, AIGoodWeatherType + + ld a, [BattleMonType2] + cp WATER + jr z, AIBadWeatherType + cp FIRE + jr z, AIGoodWeatherType + + push hl + ld hl, RainDanceMoves + jr AI_Smart_WeatherMove +; 390e7 + +RainDanceMoves: ; 390e7 + db WATER_GUN + db HYDRO_PUMP + db SURF + db BUBBLEBEAM + db THUNDER + db WATERFALL + db CLAMP + db BUBBLE + db CRABHAMMER + db OCTAZOOKA + db WHIRLPOOL + db $ff +; 390f3 + + +AI_Smart_SunnyDay: ; 390f3 + +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Fire-type. + ld a, [BattleMonType1] + cp FIRE + jr z, AIBadWeatherType + cp WATER + jr z, AIGoodWeatherType + + ld a, [BattleMonType2] + cp FIRE + jr z, AIBadWeatherType + cp WATER + jr z, AIGoodWeatherType + + push hl + ld hl, SunnyDayMoves + + ; fallthrough +; 3910d + + +AI_Smart_WeatherMove: ; 3910d +; Rain Dance, Sunny Day + +; Greatly discourage this move if the enemy doesn't have +; one of the useful Rain Dance or Sunny Day moves. + call AIHasMoveInArray + pop hl + jr nc, AIBadWeatherType + +; Greatly discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP + jr nc, AIBadWeatherType + +; 50% chance to encourage this move otherwise. + call AI_50_50 + ret c + + dec [hl] + ret +; 3911e + +AIBadWeatherType: ; 3911e + inc [hl] + inc [hl] + inc [hl] + ret +; 39122 + +AIGoodWeatherType: ; 39122 +; Rain Dance, Sunny Day + +; Greatly encourage this move if it would disfavour the player type-wise and player's HP is above 50%... + call AICheckPlayerHalfHP + ret nc + +; ...as long as one of the following conditions meet: +; It's the first turn of the player's Pokemon. + ld a, [PlayerTurnsTaken] + and a + jr z, .good + +; Or it's the first turn of the enemy's Pokemon. + ld a, [EnemyTurnsTaken] + and a + ret nz + +.good + dec [hl] + dec [hl] + ret +; 39134 + + +SunnyDayMoves: ; 39134 + db FIRE_PUNCH + db EMBER + db FLAMETHROWER + db FIRE_SPIN + db FIRE_BLAST + db SACRED_FIRE + db MORNING_SUN + db SYNTHESIS + db $ff +; 3913d + + +AI_Smart_BellyDrum: ; 3913d +; Dismiss this move if enemy's attack is higher than +2 or if enemy's HP is below 50%. +; Else, discourage this move if enemy's HP is not full. + + ld a, [EnemyAtkLevel] + cp $a + jr nc, .asm_3914d + + call AICheckEnemyMaxHP + ret c + + inc [hl] + + call AICheckEnemyHalfHP + ret c + +.asm_3914d + ld a, [hl] + add $5 + ld [hl], a + ret +; 39152 + + +AI_Smart_PsychUp: ; 39152 + push hl + ld hl, EnemyAtkLevel + ld b, $8 + ld c, 100 + +; Calculate the sum of all enemy's stat level modifiers. Add 100 first to prevent underflow. +; Put the result in c. c will range between 58 and 142. +.asm_3915a + ld a, [hli] + sub $7 + add c + ld c, a + dec b + jr nz, .asm_3915a + +; Calculate the sum of all player's stat level modifiers. Add 100 first to prevent underflow. +; Put the result in d. d will range between 58 and 142. + ld hl, PlayerAtkLevel + ld b, $8 + ld d, 100 + +.asm_39169 + ld a, [hli] + sub $7 + add d + ld d, a + dec b + jr nz, .asm_39169 + +; Greatly discourage this move if enemy's stat levels are higher than player's (if c>=d). + ld a, c + sub d + pop hl + jr nc, .asm_39188 + +; Else, 80% chance to encourage this move unless player's accuracy level is lower than -1... + ld a, [PlayerAccLevel] + cp $6 + ret c + +; ...or enemy's evasion level is higher than +0. + ld a, [EnemyEvaLevel] + cp $8 + ret nc + + call AI_80_20 + ret c + + dec [hl] + ret + +.asm_39188 + inc [hl] + inc [hl] + ret +; 3918b + + +AI_Smart_MirrorCoat: ; 3918b + push hl + ld hl, PlayerUsedMoves + ld c, $4 + ld b, $0 + +.asm_39193 + ld a, [hli] + and a + jr z, .asm_391a8 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_391a8 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr c, .asm_391a8 + + inc b + +.asm_391a8 + dec c + jr nz, .asm_39193 + + pop hl + ld a, b + and a + jr z, .asm_391d3 + + cp $3 + jr nc, .asm_391ca + + ld a, [LastPlayerCounterMove] + and a + jr z, .asm_391d2 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_391d2 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr c, .asm_391d2 + + +.asm_391ca + call Random + cp 100 + jr c, .asm_391d2 + dec [hl] + +.asm_391d2 + ret + +.asm_391d3 + inc [hl] + ret +; 391d5 + + +AI_Smart_Twister: +AI_Smart_Gust: ; 391d5 + +; Greatly encourage this move if the player is flying and the enemy is faster. + ld a, [LastPlayerCounterMove] + cp FLY + ret nz + + ld a, [PlayerSubStatus3] + bit SUBSTATUS_FLYING, a + jr z, .couldFly + + call AICompareSpeed + ret nc + + dec [hl] + dec [hl] + ret + +; Try to predict if the player will use Fly this turn. +.couldFly + +; 50% chance to encourage this move if the enemy is slower than the player. + call AICompareSpeed + ret c + call AI_50_50 + ret c + dec [hl] + ret +; 391f3 + + +AI_Smart_FutureSight: ; 391f3 +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + + call AICompareSpeed + ret nc + + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + dec [hl] + dec [hl] + ret +; 39200 + + +AI_Smart_Stomp: ; 39200 +; 80% chance to encourage this move if the player has used Minimize. + + ld a, [wPlayerMinimized] + and a + ret z + + call AI_80_20 + ret c + + dec [hl] + ret +; 3920b + + +AI_Smart_Solarbeam: ; 3920b +; 80% chance to encourage this move when it's sunny. +; 90% chance to discourage this move when it's raining. + + ld a, [Weather] + cp WEATHER_SUN + jr z, .asm_3921e + + cp WEATHER_RAIN + ret nz + + call Random + cp 10 percent + ret c + + inc [hl] + inc [hl] + ret + +.asm_3921e + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret +; 39225 + + +AI_Smart_Thunder: ; 39225 +; 90% chance to discourage this move when it's sunny. + + ld a, [Weather] + cp WEATHER_SUN + ret nz + + call Random + cp 10 percent + ret c + + inc [hl] + ret +; 39233 + + +AICompareSpeed: ; 39233 +; Return carry if enemy is faster than player. + + push bc + ld a, [EnemyMonSpeed + 1] + ld b, a + ld a, [BattleMonSpeed + 1] + cp b + ld a, [EnemyMonSpeed] + ld b, a + ld a, [BattleMonSpeed] + sbc b + pop bc + ret +; 39246 + + +AICheckPlayerMaxHP: ; 39246 + push hl + push de + push bc + ld de, BattleMonHP + ld hl, BattleMonMaxHP + jr AICheckMaxHP +; 39251 + + +AICheckEnemyMaxHP: ; 39251 + push hl + push de + push bc + ld de, EnemyMonHP + ld hl, EnemyMonMaxHP + ; fallthrough +; 3925a + + +AICheckMaxHP: ; 3925a +; Return carry if hp at de matches max hp at hl. + + ld a, [de] + inc de + cp [hl] + jr nz, .asm_39269 + + inc hl + ld a, [de] + cp [hl] + jr nz, .asm_39269 + + pop bc + pop de + pop hl + scf + ret + +.asm_39269 + pop bc + pop de + pop hl + and a + ret +; 3926e + + +AICheckPlayerHalfHP: ; 3926e + push hl + ld hl, BattleMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret +; 39281 + + +AICheckEnemyHalfHP: ; 39281 + push hl + push de + push bc + ld hl, EnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop bc + pop de + pop hl + ret +; 39298 + + +AICheckEnemyQuarterHP: ; 39298 + push hl + push de + push bc + ld hl, EnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop bc + pop de + pop hl + ret +; 392b3 + + +AICheckPlayerQuarterHP: ; 392b3 + push hl + ld hl, BattleMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret +; 392ca + + +AIHasMoveEffect: ; 392ca +; Return carry if the enemy has move b. + + push hl + ld hl, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + +.checkmove + ld a, [hli] + and a + jr z, .no + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp b + jr z, .yes + + dec c + jr nz, .checkmove + +.no + pop hl + and a + ret + +.yes + pop hl + scf + ret +; 392e6 + + +AIHasMoveInArray: ; 392e6 +; Return carry if the enemy has a move in array hl. + + push hl + push de + push bc + +.next + ld a, [hli] + cp $ff + jr z, .done + + ld b, a + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 + ld de, EnemyMonMoves + +.check + dec c + jr z, .next + + ld a, [de] + inc de + cp b + jr nz, .check + + scf + +.done + pop bc + pop de + pop hl + ret +; 39301 + + +UsefulMoves: ; 39301 +; Moves that are usable all-around. + db DOUBLE_EDGE + db SING + db FLAMETHROWER + db HYDRO_PUMP + db SURF + db ICE_BEAM + db BLIZZARD + db HYPER_BEAM + db SLEEP_POWDER + db THUNDERBOLT + db THUNDER + db EARTHQUAKE + db TOXIC + db PSYCHIC_M + db HYPNOSIS + db RECOVER + db FIRE_BLAST + db SOFTBOILED + db SUPER_FANG + db $ff +; 39315 + + +AI_Opportunist: ; 39315 +; Discourage stall moves when the enemy's HP is low. + +; Do nothing if enemy's HP is above 50%. + call AICheckEnemyHalfHP + ret c + +; Discourage stall moves if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + jr nc, .asm_39322 + +; 50% chance to discourage stall moves if enemy's HP is between 25% and 50%. + call AI_50_50 + ret c + +.asm_39322 + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + inc hl + dec c + jr z, .asm_39347 + + ld a, [de] + inc de + and a + jr z, .asm_39347 + + push hl + push de + push bc + ld hl, .stallmoves + ld de, 1 + call IsInArray + + pop bc + pop de + pop hl + jr nc, .checkmove + + inc [hl] + jr .checkmove + +.asm_39347 + ret + +.stallmoves + db SWORDS_DANCE + db TAIL_WHIP + db LEER + db GROWL + db DISABLE + db MIST + db COUNTER + db LEECH_SEED + db GROWTH + db STRING_SHOT + db MEDITATE + db AGILITY + db RAGE + db MIMIC + db SCREECH + db HARDEN + db WITHDRAW + db DEFENSE_CURL + db BARRIER + db LIGHT_SCREEN + db HAZE + db REFLECT + db FOCUS_ENERGY + db BIDE + db AMNESIA + db TRANSFORM + db SPLASH + db ACID_ARMOR + db SHARPEN + db CONVERSION + db SUBSTITUTE + db FLAME_WHEEL + db $ff +; 39369 + + + +AI_Aggressive: ; 39369 +; Use whatever does the most damage. + +; Discourage all damaging moves but the one that does the most damage. +; If no damaging move deals damage to the player (immune), +; no move will be discouraged + +; Figure out which attack does the most damage and put it in c. + ld hl, EnemyMonMoves + ld bc, 0 + ld de, 0 +.checkmove + inc b + ld a, b + cp EnemyMonMovesEnd - EnemyMonMoves + 1 + jr z, .gotstrongestmove + + ld a, [hli] + and a + jr z, .gotstrongestmove + + push hl + push de + push bc + call AIGetEnemyMove + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .nodamage + call AIDamageCalc + pop bc + pop de + pop hl + +; Update current move if damage is highest so far + ld a, [CurDamage + 1] + cp e + ld a, [CurDamage] + sbc d + jr c, .checkmove + + ld a, [CurDamage + 1] + ld e, a + ld a, [CurDamage] + ld d, a + ld c, b + jr .checkmove + +.nodamage + pop bc + pop de + pop hl + jr .checkmove + +.gotstrongestmove +; Nothing we can do if no attacks did damage. + ld a, c + and a + jr z, .done + +; Discourage moves that do less damage unless they're reckless too. + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, 0 +.checkmove2 + inc b + ld a, b + cp EnemyMonMovesEnd - EnemyMonMoves + 1 + jr z, .done + +; Ignore this move if it is the highest damaging one. + cp c + ld a, [de] + inc de + inc hl + jr z, .checkmove2 + + call AIGetEnemyMove + +; Ignore this move if its power is 0 or 1. +; Moves such as Seismic Toss, Hidden Power, +; Counter and Fissure have a base power of 1. + ld a, [wEnemyMoveStruct + MOVE_POWER] + cp 2 + jr c, .checkmove2 + +; Ignore this move if it is reckless. + push hl + push de + push bc + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld hl, .RecklessMoves + ld de, 1 + call IsInArray + pop bc + pop de + pop hl + jr c, .checkmove2 + +; If we made it this far, discourage this move. + inc [hl] + jr .checkmove2 + +.done + ret + +.RecklessMoves: + db EFFECT_SELFDESTRUCT + db EFFECT_RAMPAGE + db EFFECT_MULTI_HIT + db EFFECT_DOUBLE_HIT + db $ff +; 393e7 + + +AIDamageCalc: ; 393e7 + ld a, 1 + ld [hBattleTurn], a + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld de, 1 + ld hl, .ConstantDamageEffects + call IsInArray + jr nc, .asm_39400 + callfar BattleCommand_ConstantDamage + ret + +.asm_39400 + callfar EnemyAttackDamage + callfar BattleCommand_DamageCalc + callfar BattleCommand_Stab + ret + +.ConstantDamageEffects: + db EFFECT_SUPER_FANG + db EFFECT_STATIC_DAMAGE + db EFFECT_LEVEL_DAMAGE + db EFFECT_PSYWAVE + db $ff +; 39418 + + +AI_Cautious: ; 39418 +; 90% chance to discourage moves with residual effects after the first turn. + + ld a, [EnemyTurnsTaken] + and a + ret z + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.asm_39425 + inc hl + dec c + ret z + + ld a, [de] + inc de + and a + ret z + + push hl + push de + push bc + ld hl, .residualmoves + ld de, 1 + call IsInArray + + pop bc + pop de + pop hl + jr nc, .asm_39425 + + call Random + cp 90 percent + 1 + ret nc + + inc [hl] + jr .asm_39425 + +.residualmoves + db MIST + db LEECH_SEED + db POISONPOWDER + db STUN_SPORE + db THUNDER_WAVE + db FOCUS_ENERGY + db BIDE + db POISON_GAS + db TRANSFORM + db CONVERSION + db SUBSTITUTE + db SPIKES + db $ff +; 39453 + + + +AI_Status: ; 39453 +; Dismiss status moves that don't affect the player. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_TOXIC + jr z, .poisonimmunity + cp EFFECT_POISON + jr z, .poisonimmunity + cp EFFECT_SLEEP + jr z, .typeimmunity + cp EFFECT_PARALYZE + jr z, .typeimmunity + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .checkmove + + jr .typeimmunity + +.poisonimmunity + ld a, [BattleMonType1] + cp POISON + jr z, .immune + ld a, [BattleMonType2] + cp POISON + jr z, .immune + +.typeimmunity + push hl + push bc + push de + ld a, 1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop de + pop bc + pop hl + + ld a, [wd265] + and a + jr nz, .checkmove + +.immune + call AIDiscourageMove + jr .checkmove +; 394a9 + + + +AI_Risky: ; 394a9 +; Use any move that will KO the target. +; Risky moves will often be an exception (see below). + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + inc hl + dec c + ret z + + ld a, [de] + inc de + and a + ret z + + push de + push bc + push hl + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .nextmove + +; Don't use risky moves at max hp. + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld de, 1 + ld hl, .RiskyMoves + call IsInArray + jr nc, .checkko + + call AICheckEnemyMaxHP + jr c, .nextmove + +; Else, 80% chance to exclude them. + call Random + cp 79 percent - 1 + jr c, .nextmove + +.checkko + call AIDamageCalc + + ld a, [CurDamage + 1] + ld e, a + ld a, [CurDamage] + ld d, a + ld a, [BattleMonHP + 1] + cp e + ld a, [BattleMonHP] + sbc d + jr nc, .nextmove + + pop hl +rept 5 + dec [hl] +endr + push hl + +.nextmove + pop hl + pop bc + pop de + jr .checkmove + +.RiskyMoves: + db EFFECT_SELFDESTRUCT + db EFFECT_OHKO + db $ff +; 39502 + + + +AI_None: ; 39502 + ret +; 39503 + + +AIDiscourageMove: ; 39503 + ld a, [hl] + add 10 + ld [hl], a + ret +; 39508 + + +AIGetEnemyMove: ; 39508 +; Load attributes of move a into ram + + push hl + push de + push bc + dec a + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + + ld de, wEnemyMoveStruct + ld a, BANK(Moves) + call FarCopyBytes + + pop bc + pop de + pop hl + ret +; 39521 + + +AI_80_20: ; 39521 + call Random + cp 20 percent - 1 + ret +; 39527 + + +AI_50_50: ; 39527 + call Random + cp 50 percent + 1 + ret +; 3952d diff --git a/engine/battle/ai/switch.asm b/engine/battle/ai/switch.asm new file mode 100755 index 000000000..c2f83fa1f --- /dev/null +++ b/engine/battle/ai/switch.asm @@ -0,0 +1,672 @@ +CheckPlayerMoveTypeMatchups: ; 3484e +; Check how well the moves you've already used +; fare against the enemy's Pokemon. Used to +; score a potential switch. + push hl + push de + push bc + ld a, 10 + ld [wEnemyAISwitchScore], a + ld hl, PlayerUsedMoves + ld a, [hl] + and a + jr z, .unknown_moves + + ld d, NUM_MOVES + ld e, 0 +.loop + ld a, [hli] + and a + jr z, .exit + push hl + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .next + + inc hl + call GetMoveByte + ld hl, EnemyMonType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + and a + jr z, .next + cp 10 ; 1.0 + jr nc, .neutral + +.not_very_effective + ld a, e + cp 1 ; 0.1 + jr nc, .next + ld e, 1 + jr .next + +.neutral + ld e, 2 + jr .next + +.super_effective + call .DecreaseScore + pop hl + jr .done + +.next + pop hl + dec d + jr nz, .loop + +.exit + ld a, e + cp 2 + jr z, .done + call .IncreaseScore + ld a, e + and a + jr nz, .done + call .IncreaseScore + jr .done + +.unknown_moves + ld a, [BattleMonType1] + ld b, a + ld hl, EnemyMonType1 + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 ; 1.0 + 0.1 + jr c, .ok + call .DecreaseScore +.ok + ld a, [BattleMonType2] + cp b + jr z, .ok2 + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 ; 1.0 + 0.1 + jr c, .ok2 + call .DecreaseScore +.ok2 + +.done + call .CheckEnemyMoveMatchups + pop bc + pop de + pop hl + ret +; 348de + + +.CheckEnemyMoveMatchups: ; 348de + ld de, EnemyMonMoves + ld b, NUM_MOVES + 1 + ld c, 0 + + ld a, [wTypeMatchup] + push af +.loop2 + dec b + jr z, .exit2 + + ld a, [de] + and a + jr z, .exit2 + + inc de + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .loop2 + + inc hl + call GetMoveByte + ld hl, BattleMonType1 + call CheckTypeMatchup + + ld a, [wTypeMatchup] + ; immune + and a + jr z, .loop2 + + ; not very effective + inc c + cp 10 + jr c, .loop2 + + ; neutral + inc c + inc c + inc c + inc c + inc c + cp 10 + jr z, .loop2 + + ; super effective + ld c, 100 + jr .loop2 + +.exit2 + pop af + ld [wTypeMatchup], a + + ld a, c + and a + jr z, .doubledown ; double down + cp 5 + jr c, .DecreaseScore ; down + cp 100 + ret c + jr .IncreaseScore ; up + +.doubledown + call .DecreaseScore +.DecreaseScore: ; 34931 + ld a, [wEnemyAISwitchScore] + dec a + ld [wEnemyAISwitchScore], a + ret +; 34939 + +.IncreaseScore: ; 34939 + ld a, [wEnemyAISwitchScore] + inc a + ld [wEnemyAISwitchScore], a + ret +; 34941 + +CheckAbleToSwitch: ; 34941 + xor a + ld [wEnemySwitchMonParam], a + call FindAliveEnemyMons + ret c + + ld a, [EnemySubStatus1] + bit SUBSTATUS_PERISH, a + jr z, .no_perish + + ld a, [EnemyPerishCount] + cp 1 + jr nz, .no_perish + + ; Perish count is 1 + + call FindAliveEnemyMons + call FindEnemyMonsWithAtLeastQuarterMaxHP + call FindEnemyMonsThatResistPlayer + call FindAliveEnemyMonsWithASuperEffectiveMove + + ld a, e + cp 2 + jr nz, .not_2 + + ld a, [wEnemyAISwitchScore] + add $30 ; maximum chance + ld [wEnemySwitchMonParam], a + ret + +.not_2 + call FindAliveEnemyMons + sla c + sla c + ld b, $ff + +.loop1 + inc b + sla c + jr nc, .loop1 + + ld a, b + add $30 ; maximum chance + ld [wEnemySwitchMonParam], a + ret + +.no_perish + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 11 + ret nc + + ld a, [LastPlayerCounterMove] + and a + jr z, .no_last_counter_move + + call FindEnemyMonsImmuneToLastCounterMove + ld a, [wEnemyAISwitchScore] + and a + jr z, .no_last_counter_move + + ld c, a + call FindEnemyMonsWithASuperEffectiveMove + ld a, [wEnemyAISwitchScore] + cp $ff + ret z + + ld b, a + ld a, e + cp 2 + jr z, .not_2_again + + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 + ret nc + + ld a, b + add $10 + ld [wEnemySwitchMonParam], a + ret + +.not_2_again + ld c, $10 + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 + jr nc, .okay + ld c, $20 + +.okay + ld a, b + add c + ld [wEnemySwitchMonParam], a + ret + +.no_last_counter_move + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 + ret nc + + call FindAliveEnemyMons + call FindEnemyMonsWithAtLeastQuarterMaxHP + call FindEnemyMonsThatResistPlayer + call FindAliveEnemyMonsWithASuperEffectiveMove + + ld a, e + cp $2 + ret nz + + ld a, [wEnemyAISwitchScore] + add $10 + ld [wEnemySwitchMonParam], a + ret +; 349f4 + + +FindAliveEnemyMons: ; 349f4 + ld a, [OTPartyCount] + cp 2 + jr c, .only_one + + ld d, a + ld e, 0 + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + ld hl, OTPartyMon1HP + +.loop + ld a, [CurOTMon] + cp e + jr z, .next + + push bc + ld b, [hl] + inc hl + ld a, [hld] + or b + pop bc + jr z, .next + + ld a, c + or b + ld c, a + +.next + srl b + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + inc e + dec d + jr nz, .loop + + ld a, c + and a + jr nz, .more_than_one + +.only_one + scf + ret + +.more_than_one + and a + ret +; 34a2a + + +FindEnemyMonsImmuneToLastCounterMove: ; 34a2a + ld hl, OTPartyMon1 + ld a, [OTPartyCount] + ld b, a + ld c, 1 << (PARTY_LENGTH - 1) + ld d, 0 + xor a + ld [wEnemyAISwitchScore], a + +.loop + ld a, [CurOTMon] + cp d + push hl + jr z, .next + + push hl + push bc + + ; If the Pokemon has at least 1 HP... + ld bc, MON_HP + add hl, bc + pop bc + ld a, [hli] + or [hl] + pop hl + jr z, .next + + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + + ; the player's last move is damaging... + ld a, [LastPlayerCounterMove] + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .next + + ; and the Pokemon is immune to it... + inc hl + call GetMoveByte + ld hl, BaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + and a + jr nz, .next + + ; ... encourage that Pokemon. + ld a, [wEnemyAISwitchScore] + or c + ld [wEnemyAISwitchScore], a +.next + pop hl + dec b + ret z + + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + + inc d + srl c + jr .loop +; 34a85 + + +FindAliveEnemyMonsWithASuperEffectiveMove: ; 34a85 + push bc + ld a, [OTPartyCount] + ld e, a + ld hl, OTPartyMon1HP + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 +.loop + ld a, [hli] + or [hl] + jr z, .next + + ld a, b + or c + ld c, a + +.next + srl b + push bc + ld bc, PartyMon2HP - (PartyMon1HP + 1) + add hl, bc + pop bc + dec e + jr nz, .loop + + ld a, c + pop bc + + and c + ld c, a +FindEnemyMonsWithASuperEffectiveMove: ; 34aa7 + + ld a, -1 + ld [wEnemyAISwitchScore], a + ld hl, OTPartyMon1Moves + ld b, 1 << (PARTY_LENGTH - 1) + ld d, 0 + ld e, 0 +.loop + ld a, b + and c + jr z, .next + + push hl + push bc + ; for move on mon: + ld b, NUM_MOVES + ld c, 0 +.loop3 + ; if move is None: break + ld a, [hli] + and a + push hl + jr z, .break3 + + ; if move has no power: continue + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .nope + + ; check type matchups + inc hl + call GetMoveByte + ld hl, BattleMonType1 + call CheckTypeMatchup + + ; if immune or not very effective: continue + ld a, [wTypeMatchup] + cp 10 + jr c, .nope + + ; if neutral: load 1 and continue + ld e, 1 + cp 10 + 1 + jr c, .nope + + ; if super-effective: load 2 and break + ld e, 2 + jr .break3 + +.nope + pop hl + dec b + jr nz, .loop3 + + jr .done + +.break3 + pop hl +.done + ld a, e + pop bc + pop hl + cp 2 + jr z, .done2 ; at least one move is super-effective + cp 1 + jr nz, .next ; no move does more than half damage + + ; encourage this pokemon + ld a, d + or b + ld d, a + jr .next ; such a long jump + +.next + ; next pokemon? + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + srl b + jr nc, .loop + + ; if no pokemon has a super-effective move: return + ld a, d + ld b, a + and a + ret z + +.done2 + ; convert the bit flag to an int and return + push bc + sla b + sla b + ld c, $ff +.loop2 + inc c + sla b + jr nc, .loop2 + + ld a, c + ld [wEnemyAISwitchScore], a + pop bc + ret +; 34b20 + + +FindEnemyMonsThatResistPlayer: ; 34b20 + push bc + ld hl, OTPartySpecies + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + +.loop + ld a, [hli] + cp $ff + jr z, .done + + push hl + ld [CurSpecies], a + call GetBaseData + ld a, [LastPlayerCounterMove] + and a + jr z, .skip_move + + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .skip_move + + inc hl + call GetMoveByte + jr .check_type + +.skip_move + ld a, [BattleMonType1] + ld hl, BaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 + jr nc, .dont_choose_mon + ld a, [BattleMonType2] + +.check_type + ld hl, BaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 + jr nc, .dont_choose_mon + + ld a, b + or c + ld c, a + +.dont_choose_mon + srl b + pop hl + jr .loop + +.done + ld a, c + pop bc + and c + ld c, a + ret +; 34b77 + + +FindEnemyMonsWithAtLeastQuarterMaxHP: ; 34b77 + push bc + ld de, OTPartySpecies + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + ld hl, OTPartyMon1HP + +.loop + ld a, [de] + inc de + cp $ff + jr z, .done + + push hl + push bc + ld b, [hl] + inc hl + ld c, [hl] + inc hl + inc hl +; hl = MaxHP + 1 +; bc = [CurHP] * 4 + srl c + rl b + srl c + rl b +; if bc >= [hl], encourage + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop bc + jr nc, .next + + ld a, b + or c + ld c, a + +.next + srl b + pop hl + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + jr .loop + +.done + ld a, c + pop bc + and c + ld c, a + ret +; 34bb1 diff --git a/engine/anim_hp_bar.asm b/engine/battle/anim_hp_bar.asm index 78062b547..78062b547 100755 --- a/engine/anim_hp_bar.asm +++ b/engine/battle/anim_hp_bar.asm diff --git a/engine/battle_transition.asm b/engine/battle/battle_transition.asm index bef74ad29..bef74ad29 100644 --- a/engine/battle_transition.asm +++ b/engine/battle/battle_transition.asm diff --git a/engine/routines/battlestart_copytilemapatonce.asm b/engine/battle/battlestart_copytilemapatonce.asm index 2952e833b..2952e833b 100644 --- a/engine/routines/battlestart_copytilemapatonce.asm +++ b/engine/battle/battlestart_copytilemapatonce.asm diff --git a/engine/routines/checkbattlescene.asm b/engine/battle/checkbattlescene.asm index b63f00907..b63f00907 100644 --- a/engine/routines/checkbattlescene.asm +++ b/engine/battle/checkbattlescene.asm diff --git a/engine/routines/consumehelditem.asm b/engine/battle/consumehelditem.asm index a6f7766fb..a6f7766fb 100644 --- a/engine/routines/consumehelditem.asm +++ b/engine/battle/consumehelditem.asm diff --git a/engine/battle/core.asm b/engine/battle/core.asm new file mode 100644 index 000000000..a62b70d72 --- /dev/null +++ b/engine/battle/core.asm @@ -0,0 +1,9511 @@ +; Core components of the battle engine. +BattleCore: +DoBattle: ; 3c000 + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wPlayerAction], a + ld [BattleEnded], a + inc a + ld [wBattleHasJustStarted], a + ld hl, OTPartyMon1HP + ld bc, PARTYMON_STRUCT_LENGTH - 1 + ld d, BATTLEACTION_SWITCH1 - 1 +.loop + inc d + ld a, [hli] + or [hl] + jr nz, .alive + add hl, bc + jr .loop + +.alive + ld a, d + ld [wBattleAction], a + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2 + +.not_linked + ld a, [wBattleMode] + dec a + jr z, .wild + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + +.wild + ld c, 40 + call DelayFrames + +.player_2 + call LoadTileMapToTempTileMap + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + call Call_LoadTempTileMapToTileMap + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jp z, .tutorial_debug + cp BATTLETYPE_TUTORIAL + jp z, .tutorial_debug + xor a + ld [CurPartyMon], a +.loop2 + call CheckIfCurPartyMonIsFitToFight + jr nz, .alive2 + ld hl, CurPartyMon + inc [hl] + jr .loop2 + +.alive2 + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + inc a + ld hl, PartySpecies - 1 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [CurPartySpecies], a + ld [TempBattleMonSpecies], a + hlcoord 1, 5 + ld a, 9 + call SlideBattlePicOut + call LoadTileMapToTempTileMap + call ResetBattleParticipants + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, [wLinkMode] + and a + jr z, .not_linked_2 + ld a, [hLinkPlayerNumber] + cp $2 + jr nz, .not_linked_2 + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + call SetEnemyTurn + call SpikesDamage + +.not_linked_2 + jp BattleTurn + +.tutorial_debug + jp BattleMenu +; 3c0e5 + +WildFled_EnemyFled_LinkBattleCanceled: ; 3c0e5 + call Call_LoadTempTileMapToTileMap + ld a, [wBattleResult] + and $c0 + add $2 + ld [wBattleResult], a + ld a, [wLinkMode] + and a + ld hl, BattleText_WildFled + jr z, .print_text + + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + ld hl, BattleText_EnemyFled + call CheckMobileBattleError + jr nc, .print_text + + ld hl, wcd2a + bit 4, [hl] + jr nz, .skip_text + + ld hl, BattleText_LinkErrorBattleCanceled + +.print_text + call StdBattleTextBox + +.skip_text + call StopDangerSound + call CheckMobileBattleError + jr c, .skip_sfx + + ld de, SFX_RUN + call PlaySFX + +.skip_sfx + call SetPlayerTurn + ld a, 1 + ld [BattleEnded], a + ret +; 3c12f + +BattleTurn: ; 3c12f +.loop + call MobileFn_3c1bf + call CheckContestBattleOver + jp c, .quit + + xor a + ld [wPlayerIsSwitching], a + ld [wEnemyIsSwitching], a + ld [wBattleHasJustStarted], a + ld [wPlayerJustGotFrozen], a + ld [wEnemyJustGotFrozen], a + ld [CurDamage], a + ld [CurDamage + 1], a + + call HandleBerserkGene + call UpdateBattleMonInParty + farcall AIChooseMove + + call IsMobileBattle + jr nz, .not_disconnected + farcall Function100da5 + farcall StartMobileInactivityTimer + farcall Function100dd8 + jp c, .quit +.not_disconnected + + call CheckPlayerLockedIn + jr c, .skip_iteration +.loop1 + call BattleMenu + jr c, .quit + ld a, [BattleEnded] + and a + jr nz, .quit + ld a, [wForcedSwitch] ; roared/whirlwinded/teleported + and a + jr nz, .quit +.skip_iteration + call ParsePlayerAction + jr nz, .loop1 + + call EnemyTriesToFlee + jr c, .quit + + call DetermineMoveOrder + jr c, .false + call Battle_EnemyFirst + jr .proceed +.false + call Battle_PlayerFirst +.proceed + call CheckMobileBattleError + jr c, .quit + + ld a, [wForcedSwitch] + and a + jr nz, .quit + + ld a, [BattleEnded] + and a + jr nz, .quit + + call HandleBetweenTurnEffects + ld a, [BattleEnded] + and a + jr nz, .quit + jp .loop + +.quit + ret +; 3c1bf + +MobileFn_3c1bf: mobile + ld a, $5 + call GetSRAMBank + ld hl, $a89b ; s5_a89b + inc [hl] + jr nz, .finish + dec hl + inc [hl] + jr nz, .finish + dec [hl] + inc hl + dec [hl] + +.finish + call CloseSRAM + ret +; 3c1d6 + +HandleBetweenTurnEffects: ; 3c1d6 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .CheckEnemyFirst + call CheckFaint_PlayerThenEnemy + ret c + call HandleFutureSight + call CheckFaint_PlayerThenEnemy + ret c + call HandleWeather + call CheckFaint_PlayerThenEnemy + ret c + call HandleWrap + call CheckFaint_PlayerThenEnemy + ret c + call HandlePerishSong + call CheckFaint_PlayerThenEnemy + ret c + jr .NoMoreFaintingConditions + +.CheckEnemyFirst: + call CheckFaint_EnemyThenPlayer + ret c + call HandleFutureSight + call CheckFaint_EnemyThenPlayer + ret c + call HandleWeather + call CheckFaint_EnemyThenPlayer + ret c + call HandleWrap + call CheckFaint_EnemyThenPlayer + ret c + call HandlePerishSong + call CheckFaint_EnemyThenPlayer + ret c + +.NoMoreFaintingConditions: + call HandleLeftovers + call HandleMysteryberry + call HanleDefrost + call HandleSafeguard + call HandleScreens + call HandleStatBoostingHeldItems + call HandleHealingItems + call UpdateBattleMonInParty + call LoadTileMapToTempTileMap + jp HandleEncore +; 3c23c + +CheckFaint_PlayerThenEnemy: ; 3c23c + call HasPlayerFainted + jr nz, .PlayerNotFainted + call HandlePlayerMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.PlayerNotFainted: + call HasEnemyFainted + jr nz, .BattleContinues + call HandleEnemyMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret +; 3c25c + +CheckFaint_EnemyThenPlayer: ; 3c25c + call HasEnemyFainted + jr nz, .EnemyNotFainted + call HandleEnemyMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.EnemyNotFainted: + call HasPlayerFainted + jr nz, .BattleContinues + call HandlePlayerMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret +; 3c27c + +HandleBerserkGene: ; 3c27c + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .reverse + + call .player + jr .enemy + +.reverse + call .enemy +; jr .player + +.player + call SetPlayerTurn + ld de, PartyMon1Item + ld a, [CurBattleMon] + ld b, a + jr .go + +.enemy + call SetEnemyTurn + ld de, OTPartyMon1Item + ld a, [CurOTMon] + ld b, a +; jr .go + +.go + push de + push bc + callfar GetUserItem + ld a, [hl] + ld [wd265], a + sub BERSERK_GENE + pop bc + pop de + ret nz + + ld [hl], a + + ld h, d + ld l, e + ld a, b + call GetPartyLocation + xor a + ld [hl], a + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + push af + set SUBSTATUS_CONFUSED, [hl] + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + push hl + push af + xor a + ld [hl], a + ld [AttackMissed], a + ld [EffectFailed], a + farcall BattleCommand_AttackUp2 + pop af + pop hl + ld [hl], a + call GetItemName + ld hl, BattleText_UsersStringBuffer1Activated + call StdBattleTextBox + callfar BattleCommand_StatUpMessage + pop af + bit SUBSTATUS_CONFUSED, a + ret nz + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call Call_PlayBattleAnim_OnlyIfVisible + call SwitchTurnCore + ld hl, BecameConfusedText + jp StdBattleTextBox +; 3c300 + +EnemyTriesToFlee: ; 3c300 + ld a, [wLinkMode] + and a + jr z, .not_linked + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + jr z, .forfeit + +.not_linked + and a + ret + +.forfeit + call WildFled_EnemyFled_LinkBattleCanceled + scf + ret +; 3c314 + +DetermineMoveOrder: ; 3c314 + ld a, [wLinkMode] + and a + jr z, .use_move + ld a, [wBattleAction] + cp BATTLEACTION_E + jr z, .use_move + cp BATTLEACTION_D + jr z, .use_move + sub BATTLEACTION_SWITCH1 + jr c, .use_move + ld a, [wPlayerAction] + cp $2 + jr nz, .switch + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2 + + call BattleRandom + cp 1 + (50 percent) + jp c, .player_first + jp .enemy_first + +.player_2 + call BattleRandom + cp 1 + (50 percent) + jp c, .enemy_first + jp .player_first + +.switch + callfar AI_Switch + call SetEnemyTurn + call SpikesDamage + jp .enemy_first + +.use_move + ld a, [wPlayerAction] + and a + jp nz, .player_first + call CompareMovePriority + jr z, .equal_priority + jp c, .player_first ; player goes first + jp .enemy_first + +.equal_priority + call SetPlayerTurn + callfar GetUserItem + push bc + callfar GetOpponentItem + pop de + ld a, d + cp HELD_QUICK_CLAW + jr nz, .player_no_quick_claw + ld a, b + cp HELD_QUICK_CLAW + jr z, .both_have_quick_claw + call BattleRandom + cp e + jr nc, .speed_check + jp .player_first + +.player_no_quick_claw + ld a, b + cp HELD_QUICK_CLAW + jr nz, .speed_check + call BattleRandom + cp c + jr nc, .speed_check + jp .enemy_first + +.both_have_quick_claw + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2b + call BattleRandom + cp c + jp c, .enemy_first + call BattleRandom + cp e + jp c, .player_first + jr .speed_check + +.player_2b + call BattleRandom + cp e + jp c, .player_first + call BattleRandom + cp c + jp c, .enemy_first + jr .speed_check + +.speed_check + ld de, BattleMonSpeed + ld hl, EnemyMonSpeed + ld c, 2 + call StringCmp + jr z, .speed_tie + jp nc, .player_first + jp .enemy_first + +.speed_tie + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2c + call BattleRandom + cp 1 + (50 percent) + jp c, .player_first + jp .enemy_first + +.player_2c + call BattleRandom + cp 1 + (50 percent) + jp c, .enemy_first +.player_first + scf + ret +; 3c3f3 + +.enemy_first ; 3c3f3 + and a + ret +; 3c3f5 + +CheckContestBattleOver: ; 3c3f5 + ld a, [BattleType] + cp BATTLETYPE_CONTEST + jr nz, .contest_not_over + ld a, [wParkBallsRemaining] + and a + jr nz, .contest_not_over + ld a, [wBattleResult] + and $c0 + add $2 + ld [wBattleResult], a + scf + ret + +.contest_not_over + and a + ret +; 3c410 + +CheckPlayerLockedIn: ; 3c410 + ld a, [PlayerSubStatus4] + and 1 << SUBSTATUS_RECHARGE + jp nz, .quit + + ld hl, EnemySubStatus3 + res SUBSTATUS_FLINCHED, [hl] + ld hl, PlayerSubStatus3 + res SUBSTATUS_FLINCHED, [hl] + + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE + jp nz, .quit + + ld hl, PlayerSubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + jp nz, .quit + + and a + ret + +.quit + scf + ret +; 3c434 + +ParsePlayerAction: ; 3c434 + call CheckPlayerLockedIn + jp c, .locked_in + ld hl, PlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .not_encored + ld a, [LastPlayerMove] + ld [CurPlayerMove], a + jr .encored + +.not_encored + ld a, [wPlayerAction] + cp $2 + jr z, .reset_rage + and a + jr nz, .reset_bide + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_BIDE + jr nz, .locked_in + xor a + ld [wMoveSelectionMenuType], a + inc a ; POUND + ld [FXAnimID], a + call MoveSelectionScreen + push af + call Call_LoadTempTileMapToTileMap + call UpdateBattleHuds + ld a, [CurPlayerMove] + cp STRUGGLE + jr z, .struggle + call PlayClickSFX + +.struggle + ld a, $1 + ld [hBGMapMode], a + pop af + ret nz + +.encored + call SetPlayerTurn + callfar UpdateMoveData + xor a + ld [wPlayerCharging], a + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_FURY_CUTTER + jr z, .continue_fury_cutter + xor a + ld [PlayerFuryCutterCount], a + +.continue_fury_cutter + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .continue_rage + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [wPlayerRageCounter], a + +.continue_rage + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + jr z, .continue_protect + cp EFFECT_ENDURE + jr z, .continue_protect + xor a + ld [PlayerProtectCount], a + jr .continue_protect + +.reset_bide + ld hl, PlayerSubStatus3 + res SUBSTATUS_BIDE, [hl] + +.locked_in + xor a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + +.continue_protect + call ParseEnemyAction + xor a + ret + +.reset_rage + xor a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ret +; 3c4df + +HandleEncore: ; 3c4df + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call .do_player + jr .do_enemy + +.player_1 + call .do_enemy +.do_player + ld hl, PlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [PlayerEncoreCount] + dec a + ld [PlayerEncoreCount], a + jr z, .end_player_encore + ld hl, BattleMonPP + ld a, [CurMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + ret nz + +.end_player_encore + ld hl, PlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetEnemyTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextBox + +.do_enemy + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [EnemyEncoreCount] + dec a + ld [EnemyEncoreCount], a + jr z, .end_enemy_encore + ld hl, EnemyMonPP + ld a, [CurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + ret nz + +.end_enemy_encore + ld hl, EnemySubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetPlayerTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextBox +; 3c543 + +TryEnemyFlee: ; 3c543 + ld a, [wBattleMode] + dec a + jr nz, .Stay + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, .Stay + + ld a, [wEnemyWrapCount] + and a + jr nz, .Stay + + ld a, [EnemyMonStatus] + and 1 << FRZ | SLP + jr nz, .Stay + + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, AlwaysFleeMons + call IsInArray + jr c, .Flee + + call BattleRandom + ld b, a + cp 1 + (50 percent) + jr nc, .Stay + + push bc + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, OftenFleeMons + call IsInArray + pop bc + jr c, .Flee + + ld a, b + cp 1 + (10 percent) + jr nc, .Stay + + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, SometimesFleeMons + call IsInArray + jr c, .Flee + +.Stay: + and a + ret + +.Flee: + scf + ret +; 3c59a + +INCLUDE "data/wild/flee_mons.asm" + +CompareMovePriority: ; 3c5b4 +; Compare the priority of the player and enemy's moves. +; Return carry if the player goes first, or z if they match. + + ld a, [CurPlayerMove] + call GetMovePriority + ld b, a + push bc + ld a, [CurEnemyMove] + call GetMovePriority + pop bc + cp b + ret +; 3c5c5 + +GetMovePriority: ; 3c5c5 +; Return the priority (0-3) of move a. + + ld b, a + + ; Vital Throw goes last. + cp VITAL_THROW + ld a, 0 + ret z + + call GetMoveEffect + ld hl, MoveEffectPriorities +.loop + ld a, [hli] + cp b + jr z, .done + inc hl + cp -1 + jr nz, .loop + + ld a, 1 + ret + +.done + ld a, [hl] + ret +; 3c5df + +MoveEffectPriorities: ; 3c5df + db EFFECT_PROTECT, 3 + db EFFECT_ENDURE, 3 + db EFFECT_PRIORITY_HIT, 2 + db EFFECT_FORCE_SWITCH, 0 + db EFFECT_COUNTER, 0 + db EFFECT_MIRROR_COAT, 0 + db -1 +; 3c5ec + +GetMoveEffect: ; 3c5ec + ld a, b + dec a + ld hl, Moves + MOVE_EFFECT + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + ld b, a + ret +; 3c5fe + +Battle_EnemyFirst: ; 3c5fe + call LoadTileMapToTempTileMap + call TryEnemyFlee + jp c, WildFled_EnemyFled_LinkBattleCanceled + call SetEnemyTurn + ld a, $1 + ld [wEnemyGoesFirst], a + callfar AI_SwitchOrTryItem + jr c, .switch_item + call EnemyTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call HasEnemyFainted + jp z, HandleEnemyMonFaint + +.switch_item + call SetEnemyTurn + call ResidualDamage + jp z, HandleEnemyMonFaint + call RefreshBattleHuds + call PlayerTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasEnemyFainted + jp z, HandleEnemyMonFaint + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call SetPlayerTurn + call ResidualDamage + jp z, HandlePlayerMonFaint + call RefreshBattleHuds + xor a + ld [wPlayerAction], a + ret +; 3c664 + +Battle_PlayerFirst: ; 3c664 + xor a + ld [wEnemyGoesFirst], a + call SetEnemyTurn + callfar AI_SwitchOrTryItem + push af + call PlayerTurn_EndOpponentProtectEndureDestinyBond + pop bc + ld a, [wForcedSwitch] + and a + ret nz + call CheckMobileBattleError + ret c + call HasEnemyFainted + jp z, HandleEnemyMonFaint + call HasPlayerFainted + jp z, HandlePlayerMonFaint + push bc + call SetPlayerTurn + call ResidualDamage + pop bc + jp z, HandlePlayerMonFaint + push bc + call RefreshBattleHuds + pop af + jr c, .switched_or_used_item + call LoadTileMapToTempTileMap + call TryEnemyFlee + jp c, WildFled_EnemyFled_LinkBattleCanceled + call EnemyTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call HasEnemyFainted + jp z, HandleEnemyMonFaint + +.switched_or_used_item + call SetEnemyTurn + call ResidualDamage + jp z, HandleEnemyMonFaint + call RefreshBattleHuds + xor a + ld [wPlayerAction], a + ret +; 3c6cf + +PlayerTurn_EndOpponentProtectEndureDestinyBond: ; 3c6cf + call SetPlayerTurn + call EndUserDestinyBond + callfar DoPlayerTurn + jp EndOpponentProtectEndureDestinyBond +; 3c6de + +EnemyTurn_EndOpponentProtectEndureDestinyBond: ; 3c6de + call SetEnemyTurn + call EndUserDestinyBond + callfar DoEnemyTurn + jp EndOpponentProtectEndureDestinyBond +; 3c6ed + +EndOpponentProtectEndureDestinyBond: ; 3c6ed + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + res SUBSTATUS_PROTECT, [hl] + res SUBSTATUS_ENDURE, [hl] + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret +; 3c6fe + +EndUserDestinyBond: ; 3c6fe + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret +; 3c706 + +HasUserFainted: ; 3c706 + ld a, [hBattleTurn] + and a + jr z, HasPlayerFainted +HasEnemyFainted: ; 3c70b + ld hl, EnemyMonHP + jr CheckIfHPIsZero + +HasPlayerFainted: ; 3c710 + ld hl, BattleMonHP + +CheckIfHPIsZero: ; 3c713 + ld a, [hli] + or [hl] + ret +; 3c716 + +ResidualDamage: ; 3c716 +; Return z if the user fainted before +; or as a result of residual damage. +; For Sandstorm damage, see HandleWeather. + + call HasUserFainted + ret z + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and 1 << PSN | 1 << BRN + jr z, .did_psn_brn + + ld hl, HurtByPoisonText + ld de, ANIM_PSN + and 1 << BRN + jr z, .got_anim + ld hl, HurtByBurnText + ld de, ANIM_BRN +.got_anim + + push de + call StdBattleTextBox + pop de + + xor a + ld [wNumHits], a + call Call_PlayBattleAnim_OnlyIfVisible + call GetEighthMaxHP + ld de, PlayerToxicCount + ld a, [hBattleTurn] + and a + jr z, .check_toxic + ld de, EnemyToxicCount +.check_toxic + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVar + bit SUBSTATUS_TOXIC, a + jr z, .did_toxic + call GetSixteenthMaxHP + ld a, [de] + inc a + ld [de], a + ld hl, 0 +.add + add hl, bc + dec a + jr nz, .add + ld b, h + ld c, l +.did_toxic + + call SubtractHPFromUser +.did_psn_brn + + call HasUserFainted + jp z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr z, .not_seeded + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld de, ANIM_SAP + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, Call_PlayBattleAnim_OnlyIfVisible + call SwitchTurnCore + + call GetEighthMaxHP + call SubtractHPFromUser + ld a, $1 + ld [hBGMapMode], a + call RestoreHP + ld hl, LeechSeedSapsText + call StdBattleTextBox +.not_seeded + + call HasUserFainted + jr z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + bit SUBSTATUS_NIGHTMARE, [hl] + jr z, .not_nightmare + xor a + ld [wNumHits], a + ld de, ANIM_IN_NIGHTMARE + call Call_PlayBattleAnim_OnlyIfVisible + call GetQuarterMaxHP + call SubtractHPFromUser + ld hl, HasANightmareText + call StdBattleTextBox +.not_nightmare + + call HasUserFainted + jr z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + bit SUBSTATUS_CURSE, [hl] + jr z, .not_cursed + + xor a + ld [wNumHits], a + ld de, ANIM_IN_NIGHTMARE + call Call_PlayBattleAnim_OnlyIfVisible + call GetQuarterMaxHP + call SubtractHPFromUser + ld hl, HurtByCurseText + call StdBattleTextBox + +.not_cursed + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .check_fainted + ld hl, EnemyMonHP + +.check_fainted + ld a, [hli] + or [hl] + ret nz + +.fainted + call RefreshBattleHuds + ld c, 20 + call DelayFrames + xor a + ret +; 3c801 + +HandlePerishSong: ; 3c801 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .EnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.EnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, PlayerPerishCount + ld a, [hBattleTurn] + and a + jr z, .got_count + ld hl, EnemyPerishCount + +.got_count + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_PERISH, a + ret z + dec [hl] + ld a, [hl] + ld [wd265], a + push af + ld hl, PerishCountText + call StdBattleTextBox + pop af + ret nz + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_PERISH, [hl] + ld a, [hBattleTurn] + and a + jr nz, .kill_enemy + ld hl, BattleMonHP + xor a + ld [hli], a + ld [hl], a + ld hl, PartyMon1HP + ld a, [CurBattleMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret + +.kill_enemy + ld hl, EnemyMonHP + xor a + ld [hli], a + ld [hl], a + ld a, [wBattleMode] + dec a + ret z + ld hl, OTPartyMon1HP + ld a, [CurOTMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret +; 3c874 + +HandleWrap: ; 3c874 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .EnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.EnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + ld a, [hBattleTurn] + and a + jr z, .got_addrs + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + +.got_addrs + ld a, [hl] + and a + ret z + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld a, [de] + ld [wd265], a + ld [FXAnimID], a + call GetMoveName + dec [hl] + jr z, .release_from_bounds + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + jr nz, .skip_anim + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + +.skip_anim + call GetSixteenthMaxHP + call SubtractHPFromUser + ld hl, BattleText_UsersHurtByStringBuffer1 + jr .print_text + +.release_from_bounds + ld hl, BattleText_UserWasReleasedFromStringBuffer1 + +.print_text + jp StdBattleTextBox +; 3c8e4 + +SwitchTurnCore: ; 3c8e4 + ld a, [hBattleTurn] + xor 1 + ld [hBattleTurn], a + ret +; 3c8eb + +HandleLeftovers: ; 3c8eb + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .DoEnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.DoEnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn +.do_it + + callfar GetUserItem + ld a, [hl] + ld [wd265], a + call GetItemName + ld a, b + cp HELD_LEFTOVERS + ret nz + + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonHP + +.got_hp +; Don't restore if we're already at max HP + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + ld a, [hli] + cp b + jr nz, .restore + ld a, [hl] + cp c + ret z + +.restore + call GetSixteenthMaxHP + call SwitchTurnCore + call RestoreHP + ld hl, BattleText_TargetRecoveredWithItem + jp StdBattleTextBox +; 3c93c + +HandleMysteryberry: ; 3c93c + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .DoEnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.DoEnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + callfar GetUserItem + ld a, b + cp HELD_RESTORE_PP + jr nz, .quit + ld hl, PartyMon1PP + ld a, [CurBattleMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, PartyMon1Moves + ld a, [CurBattleMon] + call GetPartyLocation + ld a, [hBattleTurn] + and a + jr z, .wild + ld de, wWildMonPP + ld hl, wWildMonMoves + ld a, [wBattleMode] + dec a + jr z, .wild + ld hl, OTPartyMon1PP + ld a, [CurOTMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, OTPartyMon1Moves + ld a, [CurOTMon] + call GetPartyLocation + +.wild + ld c, $0 +.loop + ld a, [hl] + and a + jr z, .quit + ld a, [de] + and $3f + jr z, .restore + inc hl + inc de + inc c + ld a, c + cp NUM_MOVES + jr nz, .loop + +.quit + ret + +.restore + ; lousy hack + ld a, [hl] + cp SKETCH + ld b, 1 + jr z, .sketch + ld b, 5 +.sketch + ld a, [de] + add b + ld [de], a + push bc + push bc + ld a, [hl] + ld [wd265], a + ld de, BattleMonMoves - 1 + ld hl, BattleMonPP + ld a, [hBattleTurn] + and a + jr z, .player_pp + ld de, EnemyMonMoves - 1 + ld hl, EnemyMonPP +.player_pp + inc de + pop bc + ld b, 0 + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + pop de + pop bc + + ld a, [wd265] + cp [hl] + jr nz, .skip_checks + ld a, [hBattleTurn] + and a + ld a, [PlayerSubStatus5] + jr z, .check_transform + ld a, [EnemySubStatus5] +.check_transform + bit SUBSTATUS_TRANSFORMED, a + jr nz, .skip_checks + ld a, [de] + add b + ld [de], a +.skip_checks + callfar GetUserItem + ld a, [hl] + ld [wd265], a + xor a + ld [hl], a + call GetPartymonItem + ld a, [hBattleTurn] + and a + jr z, .consume_item + ld a, [wBattleMode] + dec a + jr z, .skip_consumption + call GetOTPartymonItem + +.consume_item + xor a + ld [hl], a + +.skip_consumption + call GetItemName + call SwitchTurnCore + call ItemRecoveryAnim + call SwitchTurnCore + ld hl, BattleText_UserRecoveredPPUsing + jp StdBattleTextBox +; 3ca26 + +HandleFutureSight: ; 3ca26 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .enemy_first + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.enemy_first + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, wPlayerFutureSightCount + ld a, [hBattleTurn] + and a + jr z, .okay + ld hl, wEnemyFutureSightCount + +.okay + ld a, [hl] + and a + ret z + dec a + ld [hl], a + cp $1 + ret nz + + ld hl, BattleText_TargetWasHitByFutureSight + call StdBattleTextBox + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + push af + ld a, FUTURE_SIGHT + ld [hl], a + + callfar UpdateMoveData + xor a + ld [AttackMissed], a + ld [AlreadyDisobeyed], a + ld a, 10 + ld [TypeModifier], a + callfar DoMove + xor a + ld [CurDamage], a + ld [CurDamage + 1], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + pop af + ld [hl], a + + call UpdateBattleMonInParty + jp UpdateEnemyMonInParty +; 3ca8f + +HanleDefrost: ; 3ca8f + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .enemy_first + call .do_player_turn + jr .do_enemy_turn + +.enemy_first + call .do_enemy_turn +.do_player_turn + ld a, [BattleMonStatus] + bit FRZ, a + ret z + + ld a, [wPlayerJustGotFrozen] + and a + ret nz + + call BattleRandom + cp 10 percent + ret nc + xor a + ld [BattleMonStatus], a + ld a, [CurBattleMon] + ld hl, PartyMon1Status + call GetPartyLocation + ld [hl], 0 + call UpdateBattleHuds + call SetEnemyTurn + ld hl, DefrostedOpponentText + jp StdBattleTextBox + +.do_enemy_turn + ld a, [EnemyMonStatus] + bit FRZ, a + ret z + ld a, [wEnemyJustGotFrozen] + and a + ret nz + call BattleRandom + cp 10 percent + ret nc + xor a + ld [EnemyMonStatus], a + + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + call GetPartyLocation + ld [hl], 0 +.wild + + call UpdateBattleHuds + call SetPlayerTurn + ld hl, DefrostedOpponentText + jp StdBattleTextBox +; 3cafb + +HandleSafeguard: ; 3cafb + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player1 + call .CheckPlayer + jr .CheckEnemy + +.player1 + call .CheckEnemy +.CheckPlayer: + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, PlayerSafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [PlayerScreens], a + xor a + jr .print + +.CheckEnemy: + ld a, [EnemyScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, EnemySafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [EnemyScreens], a + ld a, $1 + +.print + ld [hBattleTurn], a + ld hl, BattleText_SafeguardFaded + jp StdBattleTextBox + +HandleScreens: ; 3cb36 + ld a, [hLinkPlayerNumber] + cp 1 + jr z, .Both + call .CheckPlayer + jr .CheckEnemy + +.Both: + call .CheckEnemy + +.CheckPlayer: + call SetPlayerTurn + ld de, .Your + call .Copy + ld hl, PlayerScreens + ld de, PlayerLightScreenCount + jr .TickScreens + +.CheckEnemy: + call SetEnemyTurn + ld de, .Enemy + call .Copy + ld hl, EnemyScreens + ld de, EnemyLightScreenCount + +.TickScreens: + bit SCREENS_LIGHT_SCREEN, [hl] + call nz, .LightScreenTick + bit SCREENS_REFLECT, [hl] + call nz, .ReflectTick + ret + +.Copy: + ld hl, StringBuffer1 + jp CopyName2 +; 3cb75 + +.Your: + db "Your@" +.Enemy: + db "Enemy@" +; 3cb80 + +.LightScreenTick: ; 3cb80 + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_LIGHT_SCREEN, [hl] + push hl + push de + ld hl, BattleText_PkmnLightScreenFell + call StdBattleTextBox + pop de + pop hl + ret +; 3cb91 + +.ReflectTick: ; 3cb91 + inc de + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_REFLECT, [hl] + ld hl, BattleText_PkmnReflectFaded + jp StdBattleTextBox +; 3cb9e + +HandleWeather: ; 3cb9e + ld a, [Weather] + cp WEATHER_NONE + ret z + + ld hl, WeatherCount + dec [hl] + jr z, .ended + + ld hl, .WeatherMessages + call .PrintWeatherMessage + + ld a, [Weather] + cp WEATHER_SANDSTORM + ret nz + + ld a, [hLinkPlayerNumber] + cp 1 + jr z, .enemy_first + +.player_first + call SetPlayerTurn + call .SandstormDamage + call SetEnemyTurn + jr .SandstormDamage + +.enemy_first + call SetEnemyTurn + call .SandstormDamage + call SetPlayerTurn + +.SandstormDamage: + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret nz + + ld hl, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonType1 +.ok + ld a, [hli] + cp ROCK + ret z + cp GROUND + ret z + cp STEEL + ret z + + ld a, [hl] + cp ROCK + ret z + cp GROUND + ret z + cp STEEL + ret z + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld de, ANIM_IN_SANDSTORM + call Call_PlayBattleAnim + call SwitchTurnCore + call GetEighthMaxHP + call SubtractHPFromUser + + ld hl, SandstormHitsText + jp StdBattleTextBox + +.ended + ld hl, .WeatherEndedMessages + call .PrintWeatherMessage + xor a + ld [Weather], a + ret + +.PrintWeatherMessage: + ld a, [Weather] + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox +; 3cc2d + +.WeatherMessages: + dw BattleText_RainContinuesToFall + dw BattleText_TheSunlightIsStrong + dw BattleText_TheSandstormRages +.WeatherEndedMessages: + dw BattleText_TheRainStopped + dw BattleText_TheSunlightFaded + dw BattleText_TheSandstormSubsided +; 3cc39 + +SubtractHPFromTarget: ; 3cc39 + call SubtractHP + jp UpdateHPBar +; 3cc3f + +SubtractHPFromUser: ; 3cc3f +; Subtract HP from Pkmn + call SubtractHP + jp UpdateHPBarBattleHuds +; 3cc45 + +SubtractHP: ; 3cc45 + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP +.ok + inc hl + ld a, [hl] + ld [Buffer3], a + sub c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + sbc b + ld [hl], a + ld [Buffer6], a + ret nc + + ld a, [Buffer3] + ld c, a + ld a, [Buffer4] + ld b, a + xor a + ld [hli], a + ld [hl], a + ld [Buffer5], a + ld [Buffer6], a + ret +; 3cc76 + +GetSixteenthMaxHP: ; 3cc76 + call GetQuarterMaxHP + ; quarter result + srl c + srl c + ; round up + ld a, c + and a + jr nz, .ok + inc c +.ok + ret +; 3cc83 + +GetEighthMaxHP: ; 3cc83 +; output: bc + call GetQuarterMaxHP +; assumes nothing can have 1024 or more hp +; halve result + srl c +; round up + ld a, c + and a + jr nz, .end + inc c +.end + ret +; 3cc8e + +GetQuarterMaxHP: ; 3cc8e +; output: bc + call GetMaxHP + +; quarter result + srl b + rr c + srl b + rr c + +; assumes nothing can have 1024 or more hp +; round up + ld a, c + and a + jr nz, .end + inc c +.end + ret +; 3cc9f + +GetHalfMaxHP: ; 3cc9f +; output: bc + call GetMaxHP + +; halve result + srl b + rr c + +; floor = 1 + ld a, c + or b + jr nz, .end + inc c +.end + ret +; 3ccac + +GetMaxHP: ; 3ccac +; output: bc, Buffer1-2 + + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonMaxHP +.ok + ld a, [hli] + ld [Buffer2], a + ld b, a + + ld a, [hl] + ld [Buffer1], a + ld c, a + ret +; 3ccc2 + +GetHalfHP: ; 3ccc2 +; unreferenced + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP +.ok + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + srl b + rr c + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ret +; 3ccde + +CheckUserHasEnoughHP: ; 3ccde + ld hl, BattleMonHP + 1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP + 1 +.ok + ld a, c + sub [hl] + dec hl + ld a, b + sbc [hl] + ret +; 3ccef + +RestoreHP ; 3ccef + ld hl, EnemyMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonMaxHP +.ok + ld a, [hli] + ld [Buffer2], a + ld a, [hld] + ld [Buffer1], a + dec hl + ld a, [hl] + ld [Buffer3], a + add c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + adc b + ld [hli], a + ld [Buffer6], a + + ld a, [Buffer1] + ld c, a + ld a, [hld] + sub c + ld a, [Buffer2] + ld b, a + ld a, [hl] + sbc b + jr c, .asm_3cd2d + ld a, b + ld [hli], a + ld [Buffer6], a + ld a, c + ld [hl], a + ld [Buffer5], a +.asm_3cd2d + + call SwitchTurnCore + call UpdateHPBarBattleHuds + jp SwitchTurnCore +; 3cd36 + +UpdateHPBarBattleHuds: ; 3cd36 + call UpdateHPBar + jp UpdateBattleHuds +; 3cd3c + +UpdateHPBar: ; 3cd3c + hlcoord 10, 9 + ld a, [hBattleTurn] + and a + ld a, 1 + jr z, .ok + hlcoord 2, 2 + xor a +.ok + push bc + ld [wWhichHPBar], a + predef AnimateHPBar + pop bc + ret +; 3cd55 + +HandleEnemyMonFaint: ; 3cd55 + call FaintEnemyPokemon + ld hl, BattleMonHP + ld a, [hli] + or [hl] + call z, FaintYourPokemon + xor a + ld [wWhichMonFaintedFirst], a + call UpdateBattleStateAndExperienceAfterEnemyFaint + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + + ld hl, BattleMonHP + ld a, [hli] + or [hl] + call nz, UpdatePlayerHUD + + ld a, $1 + ld [hBGMapMode], a + ld c, 60 + call DelayFrames + + ld a, [wBattleMode] + dec a + jr nz, .trainer + + ld a, 1 + ld [BattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_not_fainted + + call AskUseNextPokemon + jr nc, .dont_flee + + ld a, 1 + ld [BattleEnded], a + ret + +.dont_flee + call ForcePlayerMonChoice + call CheckMobileBattleError + jp c, WildFled_EnemyFled_LinkBattleCanceled + + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jr DoubleSwitch + +.player_mon_not_fainted + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + xor a + ld [wPlayerAction], a + ret +; 3cdca + +DoubleSwitch: ; 3cdca + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call PlayerPartyMonEntrance + ld a, $1 + call EnemyPartyMonEntrance + jr .done + +.player_1 + ld a, [CurPartyMon] + push af + ld a, $1 + call EnemyPartyMonEntrance + call ClearSprites + call LoadTileMapToTempTileMap + pop af + ld [CurPartyMon], a + call PlayerPartyMonEntrance + +.done + xor a + ld [wPlayerAction], a + ret +; 3ce01 + +UpdateBattleStateAndExperienceAfterEnemyFaint: ; 3ce01 + call UpdateBattleMonInParty + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [CurOTMon] + ld hl, OTPartyMon1HP + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + +.wild + ld hl, PlayerSubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld hl, EnemyDamageTaken + ld [hli], a + ld [hl], a + call NewEnemyMonStatus + call BreakAttraction + ld a, [wBattleMode] + dec a + jr z, .wild2 + jr .trainer + +.wild2 + call StopDangerSound + ld a, $1 + ld [wDanger], a + +.trainer + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_did_not_faint + ld a, [wWhichMonFaintedFirst] + and a + jr nz, .player_mon_did_not_faint + call PlayerMonFaintHappinessMod + +.player_mon_did_not_faint + call CheckPlayerPartyForFitPkmn + ld a, d + and a + ret z + ld a, [wBattleMode] + dec a + call z, PlayVictoryMusic + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + call IsAnyMonHoldingExpShare + jr z, .skip_exp + ld hl, EnemyMonBaseStats + ld b, EnemyMonEnd - EnemyMonBaseStats +.loop + srl [hl] + inc hl + dec b + jr nz, .loop + +.skip_exp + ld hl, EnemyMonBaseStats + ld de, wBackupEnemyMonBaseStats + ld bc, EnemyMonEnd - EnemyMonBaseStats + call CopyBytes + xor a + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + call IsAnyMonHoldingExpShare + ret z + + ld a, [wBattleParticipantsNotFainted] + push af + ld a, d + ld [wBattleParticipantsNotFainted], a + ld hl, wBackupEnemyMonBaseStats + ld de, EnemyMonBaseStats + ld bc, EnemyMonEnd - EnemyMonBaseStats + call CopyBytes + ld a, $1 + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + pop af + ld [wBattleParticipantsNotFainted], a + ret +; 3ceaa + +IsAnyMonHoldingExpShare: ; 3ceaa + ld a, [PartyCount] + ld b, a + ld hl, PartyMon1 + ld c, 1 + ld d, 0 +.loop + push hl + push bc + ld bc, MON_HP + add hl, bc + ld a, [hli] + or [hl] + pop bc + pop hl + jr z, .next + + push hl + push bc + ld bc, MON_ITEM + add hl, bc + pop bc + ld a, [hl] + pop hl + + cp EXP_SHARE + jr nz, .next + ld a, d + or c + ld d, a + +.next + sla c + push de + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + pop de + dec b + jr nz, .loop + + ld a, d + ld e, 0 + ld b, PARTY_LENGTH +.loop2 + srl a + jr nc, .okay + inc e + +.okay + dec b + jr nz, .loop2 + ld a, e + and a + ret +; 3ceec + +StopDangerSound: ; 3ceec + xor a + ld [Danger], a + ret +; 3cef1 + +FaintYourPokemon: ; 3cef1 + call StopDangerSound + call WaitSFX + ld a, $f0 + ld [CryTracks], a + ld a, [BattleMonSpecies] + call PlayStereoCry + call PlayerMonFaintedAnimation + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld hl, BattleText_PkmnFainted + jp StdBattleTextBox +; 3cf14 + +FaintEnemyPokemon: ; 3cf14 + call WaitSFX + ld de, SFX_KINESIS + call PlaySFX + call EnemyMonFaintedAnimation + ld de, SFX_FAINT + call PlaySFX + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld hl, BattleText_EnemyPkmnFainted + jp StdBattleTextBox +; 3cf35 + +CheckEnemyTrainerDefeated: ; 3cf35 + ld a, [OTPartyCount] + ld b, a + xor a + ld hl, OTPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + or [hl] + inc hl + or [hl] + dec hl + add hl, de + dec b + jr nz, .loop + + and a + ret +; 3cf4a + +HandleEnemySwitch: ; 3cf4a + ld hl, EnemyHPPal + ld e, HP_BAR_LENGTH_PX + call UpdateHPPal + call WaitBGMap + farcall EnemySwitch_TrainerHud + ld a, [wLinkMode] + and a + jr z, .not_linked + + call LinkBattleSendReceiveAction + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ret z + + call Call_LoadTempTileMapToTileMap + +.not_linked + ld hl, BattleMonHP + ld a, [hli] + or [hl] + ld a, $0 + jr nz, EnemyPartyMonEntrance + inc a + ret +; 3cf78 + +EnemyPartyMonEntrance: ; 3cf78 + push af + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + pop af + and a + jr nz, .set + call EnemySwitch + jr .done_switch + +.set + call EnemySwitch_SetMode +.done_switch + call ResetBattleParticipants + call SetEnemyTurn + call SpikesDamage + xor a + ld [wEnemyMoveStruct + MOVE_ANIM], a + ld [wPlayerAction], a + inc a + ret +; 3cfa4 + +WinTrainerBattle: ; 3cfa4 +; Player won the battle + call StopDangerSound + ld a, $1 + ld [wDanger], a + ld [BattleEnded], a + ld a, [wLinkMode] + and a + ld a, b + call z, PlayVictoryMusic + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyWasDefeated + call StdBattleTextBox + + call IsMobileBattle + jr z, .mobile + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower + + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld a, [BattleType] + cp BATTLETYPE_CANLOSE + jr nz, .skip_heal + predef HealParty +.skip_heal + ld a, [wMonStatusFlags] + bit 0, a + jr nz, .skip_win_loss_text + call PrintWinLossText + +.skip_win_loss_text + jp .GiveMoney + +.mobile + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld c, $4 ; win + farcall Mobile_PrintOpponentBattleMessage + ret + +.battle_tower + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + call EmptyBattleTextBox + ld c, $3 + farcall BattleTowerText + call WaitPressAorB_BlinkCursor + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + inc hl + or [hl] + ret nz + call ClearTileMap + call ClearBGPalettes + ret + +.GiveMoney: + ld a, [wAmuletCoin] + and a + call nz, .DoubleReward + call .CheckMaxedOutMomMoney + push af + ld a, $0 + jr nc, .okay + ld a, [wMomSavingMoney] + and $7 + cp $3 + jr nz, .okay + inc a + +.okay + ld b, a + ld c, $4 +.loop + ld a, b + and a + jr z, .loop2 + call .SendMoneyToMom + dec c + dec b + jr .loop + +.loop2 + ld a, c + and a + jr z, .done + call .AddMoneyToWallet + dec c + jr .loop2 + +.done + call .DoubleReward + call .DoubleReward + pop af + jr nc, .KeepItAll + ld a, [wMomSavingMoney] + and $7 + jr z, .KeepItAll + ld hl, .SentToMomTexts + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox + +.KeepItAll: + ld hl, GotMoneyForWinningText + jp StdBattleTextBox +; 3d081 + +.SendMoneyToMom: ; 3d081 + push bc + ld hl, wBattleReward + 2 + ld de, wMomsMoney + 2 + call AddBattleMoneyToAccount + pop bc + ret +; 3d08d + +.AddMoneyToWallet: ; 3d08d + push bc + ld hl, wBattleReward + 2 + ld de, Money + 2 + call AddBattleMoneyToAccount + pop bc + ret +; 3d099 + +.DoubleReward: ; 3d099 + ld hl, wBattleReward + 2 + sla [hl] + dec hl + rl [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret +; 3d0ab + +.SentToMomTexts: ; 3d0ab + dw SentSomeToMomText + dw SentHalfToMomText + dw SentAllToMomText +; 3d0b1 + +.CheckMaxedOutMomMoney: ; 3d0b1 + ld hl, wMomsMoney + 2 + ld a, [hld] + cp LOW(MAX_MONEY) + ld a, [hld] + sbc HIGH(MAX_MONEY) ; mid + ld a, [hl] + sbc HIGH(MAX_MONEY >> 8) + ret +; 3d0be + +AddBattleMoneyToAccount: ; 3d0be + ld c, $3 + and a + push de + push hl + push bc + ld b, h + ld c, l + farcall TrainerRankings_AddToBattlePayouts + pop bc + pop hl +.loop + ld a, [de] + adc [hl] + ld [de], a + dec de + dec hl + dec c + jr nz, .loop + pop hl + ld a, [hld] + cp LOW(MAX_MONEY) + ld a, [hld] + sbc HIGH(MAX_MONEY) ; mid + ld a, [hl] + sbc HIGH(MAX_MONEY >> 8) + ret c + ld [hl], HIGH(MAX_MONEY >> 8) + inc hl + ld [hl], HIGH(MAX_MONEY) ; mid + inc hl + ld [hl], LOW(MAX_MONEY) + ret +; 3d0ea + +PlayVictoryMusic: ; 3d0ea + push de + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + ld de, MUSIC_WILD_VICTORY + ld a, [wBattleMode] + dec a + jr nz, .trainer_victory + push de + call IsAnyMonHoldingExpShare + pop de + jr nz, .play_music + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + jr nz, .play_music + ld a, [wBattleParticipantsNotFainted] + and a + jr z, .lost + jr .play_music + +.trainer_victory + ld de, MUSIC_GYM_VICTORY + call IsJohtoGymLeader + jr c, .play_music + ld de, MUSIC_TRAINER_VICTORY + +.play_music + call PlayMusic + +.lost + pop de + ret +; 3d123 + +; These functions check if the current opponent is a gym leader or one of a +; few other special trainers. + +; Note: KantoGymLeaders is a subset of JohtoGymLeaders. If you wish to +; differentiate between the two, call IsKantoGymLeader first. + +; The Lance and Red entries are unused for music checks; those trainers are +; accounted for elsewhere. + +IsKantoGymLeader: ; 0x3d123 + ld hl, KantoGymLeaders + jr IsGymLeaderCommon + +IsJohtoGymLeader: ; 0x3d128 + ld hl, JohtoGymLeaders +IsGymLeaderCommon: + push de + ld a, [OtherTrainerClass] + ld de, $0001 + call IsInArray + pop de + ret +; 0x3d137 + +JohtoGymLeaders: + db FALKNER + db WHITNEY + db BUGSY + db MORTY + db PRYCE + db JASMINE + db CHUCK + db CLAIR + db WILL + db BRUNO + db KAREN + db KOGA +; fallthrough +; these two entries are unused + db CHAMPION + db RED +; fallthrough +KantoGymLeaders: + db BROCK + db MISTY + db LT_SURGE + db ERIKA + db JANINE + db SABRINA + db BLAINE + db BLUE + db -1 + +HandlePlayerMonFaint: ; 3d14e + call FaintYourPokemon + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + call z, FaintEnemyPokemon + ld a, $1 + ld [wWhichMonFaintedFirst], a + call PlayerMonFaintHappinessMod + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .notfainted + call UpdateBattleStateAndExperienceAfterEnemyFaint + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, $1 + ld [BattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + +.notfainted + call AskUseNextPokemon + jr nc, .switch + ld a, $1 + ld [BattleEnded], a + ret + +.switch + call ForcePlayerMonChoice + call CheckMobileBattleError + jp c, WildFled_EnemyFled_LinkBattleCanceled + ld a, c + and a + ret nz + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jp DoubleSwitch +; 3d1aa + +PlayerMonFaintHappinessMod: ; 3d1aa + ld a, [CurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef FlagPredef + ld hl, EnemySubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld [Danger], a + ld hl, PlayerDamageTaken + ld [hli], a + ld [hl], a + ld [BattleMonStatus], a + call UpdateBattleMonInParty + ld c, HAPPINESS_FAINTED + ; If TheirLevel > (YourLevel + 30), use a different parameter + ld a, [BattleMonLevel] + add 30 + ld b, a + ld a, [EnemyMonLevel] + cp b + jr c, .got_param + ld c, HAPPINESS_BEATENBYSTRONGFOE + +.got_param + ld a, [CurBattleMon] + ld [CurPartyMon], a + callfar ChangeHappiness + ld a, [wBattleResult] + and %11000000 + add $1 + ld [wBattleResult], a + ld a, [wWhichMonFaintedFirst] + and a + ret z + ret ; ?????????? +; 3d1f8 + +AskUseNextPokemon: ; 3d1f8 + call EmptyBattleTextBox + call LoadTileMapToTempTileMap +; We don't need to be here if we're in a Trainer battle, +; as that decision is made for us. + ld a, [wBattleMode] + and a + dec a + ret nz + + ld hl, BattleText_UseNextMon + call StdBattleTextBox +.loop + lb bc, 1, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + jr c, .pressed_b + and a + ret + +.pressed_b + ld a, [wMenuCursorY] + cp $1 ; YES + jr z, .loop + ld hl, PartyMon1Speed + ld de, EnemyMonSpeed + jp TryToRunAwayFromBattle +; 3d227 + +ForcePlayerMonChoice: ; 3d227 + call EmptyBattleTextBox + call LoadStandardMenuDataHeader + call SetUpBattlePartyMenu_NoLoop + call ForcePickPartyMonInBattle + ld a, [wLinkMode] + and a + jr z, .skip_link + ld a, $1 + ld [wPlayerAction], a + call LinkBattleSendReceiveAction + +.skip_link + xor a + ld [wPlayerAction], a + call CheckMobileBattleError + jr c, .enemy_fainted_mobile_error + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .send_out_pokemon + +.enemy_fainted_mobile_error + call ClearSprites + call ClearBGPalettes + call _LoadHPBar + call ExitMenu + call LoadTileMapToTempTileMap + call WaitBGMap + call GetMemSGBLayout + call SetPalettes + xor a + ld c, a + ret + +.send_out_pokemon + call ClearSprites + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, $1 + and a + ld c, a + ret +; 3d2b3 + +PlayerPartyMonEntrance: ; 3d2b3 + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + jp SpikesDamage +; 3d2e0 + +CheckMobileBattleError: ; 3d2e0 + ld a, [wLinkMode] + cp LINK_MOBILE + jr nz, .not_mobile ; It's not a mobile battle + + ld a, [wcd2b] + and a + jr z, .not_mobile + +; We have a mobile battle and something else happened + scf + ret + +.not_mobile + xor a + ret +; 3d2f1 + +IsMobileBattle: ; 3d2f1 + ld a, [wLinkMode] + cp LINK_MOBILE + ret +; 3d2f7 + +SetUpBattlePartyMenu_NoLoop: ; 3d2f7 + call ClearBGPalettes +SetUpBattlePartyMenu: ; switch to fullscreen menu? + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuBGPal7 + farcall InitPartyMenuGFX + ret +; 3d313 + +JumpToPartyMenuAndPrintText: ; 3d313 + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + ret +; 3d329 + +SelectBattleMon: ; 3d329 + call IsMobileBattle + jr z, .mobile + farcall PartyMenuSelect + ret + +.mobile + farcall Mobile_PartyMenuSelect + ret +; 3d33c + +PickPartyMonInBattle: ; 3d33c +.loop + ld a, PARTYMENUACTION_SWITCH ; Which PKMN? + ld [PartyMenuActionText], a + call JumpToPartyMenuAndPrintText + call SelectBattleMon + ret c + call CheckIfCurPartyMonIsFitToFight + jr z, .loop + xor a + ret +; 3d34f + +SwitchMonAlreadyOut: ; 3d34f + ld hl, CurBattleMon + ld a, [CurPartyMon] + cp [hl] + jr nz, .notout + + ld hl, BattleText_PkmnIsAlreadyOut + call StdBattleTextBox + scf + ret + +.notout + xor a + ret +; 3d362 + +ForcePickPartyMonInBattle: ; 3d362 +; Can't back out. + +.pick + call PickPartyMonInBattle + ret nc + call CheckMobileBattleError + ret c + + ld de, SFX_WRONG + call PlaySFX + call WaitSFX + jr .pick +; 3d375 + +PickSwitchMonInBattle: ; 3d375 +.pick + call PickPartyMonInBattle + ret c + call SwitchMonAlreadyOut + jr c, .pick + xor a + ret +; 3d380 + +ForcePickSwitchMonInBattle: ; 3d380 +; Can't back out. + +.pick + call ForcePickPartyMonInBattle + call CheckMobileBattleError + ret c + call SwitchMonAlreadyOut + jr c, .pick + + xor a + ret +; 3d38e + +LostBattle: ; 3d38e + ld a, 1 + ld [BattleEnded], a + + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower + + ld a, [BattleType] + cp BATTLETYPE_CANLOSE + jr nz, .not_canlose + +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + ld a, [wMonStatusFlags] + bit 0, a + jr nz, .skip_win_loss_text + call PrintWinLossText +.skip_win_loss_text + ret + +.battle_tower +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + call EmptyBattleTextBox + ld c, 2 + farcall BattleTowerText + call WaitPressAorB_BlinkCursor + call ClearTileMap + call ClearBGPalettes + ret + +.not_canlose + ld a, [wLinkMode] + and a + jr nz, .LostLinkBattle + +; Greyscale + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + call SetPalettes + jr .end + +.LostLinkBattle: + call UpdateEnemyMonInParty + call CheckEnemyTrainerDefeated + jr nz, .not_tied + ld hl, TiedAgainstText + ld a, [wBattleResult] + and $c0 + add 2 + ld [wBattleResult], a + jr .text + +.not_tied + ld hl, LostAgainstText + call IsMobileBattle + jr z, .mobile + +.text + call StdBattleTextBox + +.end + scf + ret + +.mobile +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + ld c, $3 ; lost + farcall Mobile_PrintOpponentBattleMessage + scf + ret +; 3d432 + +EnemyMonFaintedAnimation: ; 3d432 + hlcoord 12, 5 + decoord 12, 6 + jp MonFaintedAnimation +; 3d43b + +PlayerMonFaintedAnimation: ; 3d43b + hlcoord 1, 10 + decoord 1, 11 + jp MonFaintedAnimation +; 3d444 + +MonFaintedAnimation: ; 3d444 + ld a, [wcfbe] + push af + set 6, a + ld [wcfbe], a + ld b, 7 + +.OuterLoop: + push bc + push de + push hl + ld b, 6 + +.InnerLoop: + push bc + push hl + push de + ld bc, 7 + call CopyBytes + pop de + pop hl + ld bc, -SCREEN_WIDTH + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + pop bc + dec b + jr nz, .InnerLoop + + ld bc, 20 + add hl, bc + ld de, .Spaces + call PlaceString + ld c, 2 + call DelayFrames + pop hl + pop de + pop bc + dec b + jr nz, .OuterLoop + + pop af + ld [wcfbe], a + ret +; 3d488 + +.Spaces: + db " @" +; 3d490 + +SlideBattlePicOut: ; 3d490 + ld [hMapObjectIndexBuffer], a + ld c, a +.loop + push bc + push hl + ld b, $7 +.loop2 + push hl + call .DoFrame + pop hl + ld de, SCREEN_WIDTH + add hl, de + dec b + jr nz, .loop2 + ld c, 2 + call DelayFrames + pop hl + pop bc + dec c + jr nz, .loop + ret +; 3d4ae + +.DoFrame: ; 3d4ae + ld a, [hMapObjectIndexBuffer] + ld c, a + cp $8 + jr nz, .back +.forward + ld a, [hli] + ld [hld], a + dec hl + dec c + jr nz, .forward + ret + +.back + ld a, [hld] + ld [hli], a + inc hl + dec c + jr nz, .back + ret +; 3d4c3 + +ForceEnemySwitch: ; 3d4c3 + call ResetEnemyBattleVars + ld a, [wEnemySwitchMonIndex] + dec a + ld b, a + call LoadEnemyPkmnToSwitchTo + call ClearEnemyMonBox + call NewEnemyMonStatus + call ResetEnemyStatLevels + call Function_SetEnemyPkmnAndSendOutAnimation + call BreakAttraction + call ResetBattleParticipants + ret +; 3d4e1 + +EnemySwitch: ; 3d4e1 + call CheckWhetherToAskSwitch + jr nc, EnemySwitch_SetMode + ; Shift Mode + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindPkmnInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + call LoadEnemyPkmnToSwitchTo + call OfferSwitch + push af + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + call Function_SetEnemyPkmnAndSendOutAnimation + pop af + ret c + ; If we're here, then we're switching too + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wPlayerAction], a + inc a + ld [wEnemyIsSwitching], a + call LoadTileMapToTempTileMap + jp PlayerSwitch +; 3d517 + +EnemySwitch_SetMode: ; 3d517 + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindPkmnInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + call LoadEnemyPkmnToSwitchTo + ld a, 1 + ld [wEnemyIsSwitching], a + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + jp Function_SetEnemyPkmnAndSendOutAnimation +; 3d533 + +CheckWhetherSwitchmonIsPredetermined: ; 3d533 +; returns carry if: ??? + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld a, [wBattleAction] + sub BATTLEACTION_SWITCH1 + ld b, a + jr .return_carry + +.not_linked + ld a, [wEnemySwitchMonIndex] + and a + jr z, .check_wBattleHasJustStarted + + dec a + ld b, a + jr .return_carry + +.check_wBattleHasJustStarted + ld a, [wBattleHasJustStarted] + and a + ld b, $0 + jr nz, .return_carry + + and a + ret + +.return_carry + scf + ret +; 3d557 + +ResetEnemyBattleVars: ; 3d557 +; and draw empty TextBox + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastEnemyMove], a + ld [CurEnemyMove], a + dec a + ld [wEnemyItemState], a + xor a + ld [wPlayerWrapCount], a + hlcoord 18, 0 + ld a, 8 + call SlideBattlePicOut + call EmptyBattleTextBox + jp LoadStandardMenuDataHeader +; 3d57a + +ResetBattleParticipants: ; 3d57a + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a +AddBattleParticipant: ; 3d581 + ld a, [CurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, SET_FLAG + push bc + predef FlagPredef + pop bc + ld hl, wBattleParticipantsIncludingFainted + predef_jump FlagPredef +; 3d599 + +FindPkmnInOTPartyToSwitchIntoBattle: ; 3d599 + ld b, $ff + ld a, $1 + ld [Buffer1], a + ld [Buffer2], a +.loop + ld hl, Buffer1 + sla [hl] + inc hl + sla [hl] + inc b + ld a, [OTPartyCount] + cp b + jp z, ScoreMonTypeMatchups + ld a, [CurOTMon] + cp b + jr z, .discourage + ld hl, OTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + ld a, [hli] + ld c, a + ld a, [hl] + or c + pop bc + jr z, .discourage + call LookUpTheEffectivenessOfEveryMove + call IsThePlayerPkmnTypesEffectiveAgainstOTPkmn + jr .loop + +.discourage + ld hl, Buffer2 + set 0, [hl] + jr .loop +; 3d5d7 + +LookUpTheEffectivenessOfEveryMove: ; 3d5d7 + push bc + ld hl, OTPartyMon1Moves + ld a, b + call GetPartyLocation + pop bc + ld e, NUM_MOVES + 1 +.loop + dec e + jr z, .done + ld a, [hli] + and a + jr z, .done + push hl + push de + push bc + dec a + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld de, wEnemyMoveStruct + ld a, BANK(Moves) + call FarCopyBytes + call SetEnemyTurn + callfar BattleCheckTypeMatchup + pop bc + pop de + pop hl + ld a, [wd265] ; Get The Effectiveness Modifier + cp 10 + 1 ; 1.0 + 0.1 + jr c, .loop + ld hl, Buffer1 + set 0, [hl] + ret +.done + ret +; 3d618 + +IsThePlayerPkmnTypesEffectiveAgainstOTPkmn: ; 3d618 +; Calculates the effectiveness of the types of the PlayerPkmn +; against the OTPkmn + push bc + ld hl, OTPartyCount + ld a, b + inc a + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + dec a + ld hl, BaseData + BASE_TYPES + ld bc, BASE_DATA_SIZE + call AddNTimes + ld de, EnemyMonType + ld bc, BASE_CATCH_RATE - BASE_TYPES + ld a, BANK(BaseData) + call FarCopyBytes + ld a, [BattleMonType1] + ld [wPlayerMoveStruct + MOVE_TYPE], a + call SetPlayerTurn + callfar BattleCheckTypeMatchup + ld a, [wd265] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + ld a, [BattleMonType2] + ld [wPlayerMoveStruct + MOVE_TYPE], a + callfar BattleCheckTypeMatchup + ld a, [wd265] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + pop bc + ret + +.super_effective + pop bc + ld hl, Buffer1 + bit 0, [hl] + jr nz, .reset + inc hl + set 0, [hl] + ret + +.reset + res 0, [hl] + ret +; 3d672 + +ScoreMonTypeMatchups: ; 3d672 +.loop1 + ld hl, Buffer1 + sla [hl] + inc hl + sla [hl] + jr nc, .loop1 + ld a, [OTPartyCount] + ld b, a + ld c, [hl] +.loop2 + sla c + jr nc, .okay + dec b + jr z, .loop5 + jr .loop2 + +.okay + ld a, [Buffer1] + and a + jr z, .okay2 + ld b, $ff + ld c, a +.loop3 + inc b + sla c + jr nc, .loop3 + jr .quit + +.okay2 + ld b, $ff + ld a, [Buffer2] + ld c, a +.loop4 + inc b + sla c + jr c, .loop4 + jr .quit + +.loop5 + ld a, [OTPartyCount] + ld b, a + call BattleRandom + and $7 + cp b + jr nc, .loop5 + ld b, a + ld a, [CurOTMon] + cp b + jr z, .loop5 + ld hl, OTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + pop bc + ld a, [hli] + ld c, a + ld a, [hl] + or c + jr z, .loop5 + +.quit + ret +; 3d6ca + +LoadEnemyPkmnToSwitchTo: ; 3d6ca + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + ld a, b + ld [CurPartyMon], a + ld hl, OTPartyMon1Level + call GetPartyLocation + ld a, [hl] + ld [CurPartyLevel], a + ld a, [CurPartyMon] + inc a + ld hl, OTPartyCount + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [TempEnemyMonSpecies], a + ld [CurPartySpecies], a + call LoadEnemyMon + + ld a, [CurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld hl, EnemyMonDVs + predef GetUnownLetter + ld a, [UnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + + ld hl, EnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ret +; 3d714 + +CheckWhetherToAskSwitch: ; 3d714 + ld a, [wBattleHasJustStarted] + dec a + jp z, .return_nc + ld a, [PartyCount] + dec a + jp z, .return_nc + ld a, [wLinkMode] + and a + jp nz, .return_nc + ld a, [Options] + bit BATTLE_SHIFT, a + jr nz, .return_nc + ld a, [CurPartyMon] + push af + ld a, [CurBattleMon] + ld [CurPartyMon], a + farcall CheckCurPartyMonFainted + pop bc + ld a, b + ld [CurPartyMon], a + jr c, .return_nc + scf + ret + +.return_nc + and a + ret +; 3d74b + +OfferSwitch: ; 3d74b + ld a, [CurPartyMon] + push af + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyIsAboutToUseWillPlayerChangePkmn + call StdBattleTextBox + lb bc, 1, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + dec a + jr nz, .said_no + call SetUpBattlePartyMenu_NoLoop + call PickSwitchMonInBattle + jr c, .canceled_switch + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call ClearPalettes + call DelayFrame + call _LoadHPBar + pop af + ld [CurPartyMon], a + xor a + ld [CurEnemyMove], a + ld [CurPlayerMove], a + and a + ret + +.canceled_switch + call ClearPalettes + call DelayFrame + call _LoadHPBar + +.said_no + pop af + ld [CurPartyMon], a + scf + ret +; 3d7a0 + +ClearEnemyMonBox: ; 3d7a0 + xor a + ld [hBGMapMode], a + call ExitMenu + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call WaitBGMap + jp FinishBattleAnim +; 3d7b8 + +Function_BattleTextEnemySentOut: ; 3d7b8 + callfar Battle_GetTrainerName + ld hl, BattleText_EnemySentOut + call StdBattleTextBox + jp WaitBGMap +; 3d7c7 + +Function_SetEnemyPkmnAndSendOutAnimation: ; 3d7c7 + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + ld a, OTPARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + call GetEnemyMonFrontpic + + xor a + ld [wNumHits], a + ld [wBattleAnimParam], a + call SetEnemyTurn + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + + call BattleCheckEnemyShininess + jr nc, .not_shiny + ld a, 1 ; shiny anim + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim +.not_shiny + + ld bc, TempMonSpecies + farcall CheckFaintedFrzSlp + jr c, .skip_cry + farcall CheckBattleScene + jr c, .cry_no_anim + hlcoord 12, 0 + ld d, $0 + ld e, ANIM_MON_SLOW + predef AnimateFrontpic + jr .skip_cry + +.cry_no_anim + ld a, $f + ld [CryTracks], a + ld a, [TempEnemyMonSpecies] + call PlayStereoCry + +.skip_cry + call UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3d834 + +NewEnemyMonStatus: ; 3d834 + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastEnemyMove], a + ld hl, EnemySubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld [EnemyDisableCount], a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + ld [EnemyDisabledMove], a + ld [wEnemyMinimized], a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ld [EnemyTurnsTaken], a + ld hl, PlayerSubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret +; 3d867 + +ResetEnemyStatLevels: ; 3d867 + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, EnemyStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 3d873 + +CheckPlayerPartyForFitPkmn: ; 3d873 +; Has the player any Pkmn in his Party that can fight? + ld a, [PartyCount] + ld e, a + xor a + ld hl, PartyMon1HP + ld bc, PartyMon2 - (PartyMon1 + 1) +.loop + or [hl] + inc hl + or [hl] + add hl, bc + dec e + jr nz, .loop + ld d, a + ret +; 3d887 + +CheckIfCurPartyMonIsFitToFight: ; 3d887 + ld a, [CurPartyMon] + ld hl, PartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + ret nz + + ld a, [wBattleHasJustStarted] + and a + jr nz, .finish_fail + ld hl, PartySpecies + ld a, [CurPartyMon] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp EGG + ld hl, BattleText_AnEGGCantBattle + jr z, .print_textbox + + ld hl, BattleText_TheresNoWillToBattle + +.print_textbox + call StdBattleTextBox + +.finish_fail + xor a + ret +; 3d8b3 + +TryToRunAwayFromBattle: ; 3d8b3 +; Run away from battle, with or without item + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jp z, .can_escape + cp BATTLETYPE_CONTEST + jp z, .can_escape + cp BATTLETYPE_TRAP + jp z, .cant_escape + cp BATTLETYPE_CELEBI + jp z, .cant_escape + cp BATTLETYPE_SHINY + jp z, .cant_escape + cp BATTLETYPE_SUICUNE + jp z, .cant_escape + + ld a, [wLinkMode] + and a + jp nz, .can_escape + + ld a, [wBattleMode] + dec a + jp nz, .cant_run_from_trainer + + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jp nz, .cant_escape + + ld a, [wPlayerWrapCount] + and a + jp nz, .cant_escape + + push hl + push de + ld a, [BattleMonItem] + ld [wd265], a + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_ESCAPE + pop de + pop hl + jr nz, .no_flee_item + + call SetPlayerTurn + call GetItemName + ld hl, BattleText_UserFledUsingAStringBuffer1 + call StdBattleTextBox + jp .can_escape + +.no_flee_item + ld a, [wNumFleeAttempts] + inc a + ld [wNumFleeAttempts], a + ld a, [hli] + ld [hStringCmpString2 + 0], a + ld a, [hl] + ld [hStringCmpString2 + 1], a + ld a, [de] + inc de + ld [hStringCmpString1 + 0], a + ld a, [de] + ld [hStringCmpString1 + 1], a + call Call_LoadTempTileMapToTileMap + ld de, hStringCmpString2 + ld hl, hStringCmpString1 + ld c, $2 + call StringCmp + jr nc, .can_escape + + xor a + ld [hMultiplicand], a + ld a, $20 + ld [hMultiplier], a + call Multiply + ld a, [hProduct + 2] + ld [hDividend + 0], a + ld a, [hProduct + 3] + ld [hDividend + 1], a + ld a, [hStringCmpString1 + 0] + ld b, a + ld a, [hStringCmpString1 + 1] + srl b + rr a + srl b + rr a + and a + jr z, .can_escape + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 1] + and a + jr nz, .can_escape + ld a, [wNumFleeAttempts] + ld c, a +.loop + dec c + jr z, .cant_escape_2 + ld b, 30 + ld a, [hQuotient + 2] + add b + ld [hQuotient + 2], a + jr c, .can_escape + jr .loop + +.cant_escape_2 + call BattleRandom + ld b, a + ld a, [hQuotient + 2] + cp b + jr nc, .can_escape + ld a, $1 + ld [wPlayerAction], a + ld hl, BattleText_CantEscape2 + jr .print_inescapable_text + +.cant_escape + ld hl, BattleText_CantEscape + jr .print_inescapable_text + +.cant_run_from_trainer + ld hl, BattleText_TheresNoEscapeFromTrainerBattle + +.print_inescapable_text + call StdBattleTextBox + ld a, $1 + ld [wFailedToFlee], a + call LoadTileMapToTempTileMap + and a + ret + +.can_escape + ld a, [wLinkMode] + and a + ld a, DRAW + jr z, .fled + call LoadTileMapToTempTileMap + xor a + ld [wPlayerAction], a + ld a, $f + ld [CurMoveNum], a + xor a + ld [CurPlayerMove], a + call LinkBattleSendReceiveAction + call Call_LoadTempTileMapToTileMap + call CheckMobileBattleError + jr c, .mobile + + ; Got away safely + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ld a, DRAW + jr z, .fled + dec a +.fled + ld b, a + ld a, [wBattleResult] + and $c0 + add b + ld [wBattleResult], a + call StopDangerSound + push de + ld de, SFX_RUN + call WaitPlaySFX + pop de + call WaitSFX + ld hl, BattleText_GotAwaySafely + call StdBattleTextBox + call WaitSFX + call LoadTileMapToTempTileMap + scf + ret + +.mobile + call StopDangerSound + ld hl, wcd2a + bit 4, [hl] + jr nz, .skip_link_error + ld hl, BattleText_LinkErrorBattleCanceled + call StdBattleTextBox + +.skip_link_error + call WaitSFX + call LoadTileMapToTempTileMap + scf + ret +; 3da0d + +InitBattleMon: ; 3da0d + ld a, MON_SPECIES + call GetPartyParamLocation + ld de, BattleMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, BattleMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, BattleMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [BattleMonSpecies] + ld [TempBattleMonSpecies], a + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + ld a, [BaseType1] + ld [BattleMonType1], a + ld a, [BaseType2] + ld [BattleMonType2], a + ld hl, PartyMonNicknames + ld a, [CurBattleMon] + call SkipNames + ld de, BattleMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, BattleMonAttack + ld de, PlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnPlayerStats + call BadgeStatBoosts + ret +; 3da74 + +BattleCheckPlayerShininess: ; 3da74 + call GetPartyMonDVs + jr BattleCheckShininess + +BattleCheckEnemyShininess: ; 3da79 + call GetEnemyMonDVs + +BattleCheckShininess: ; 3da7c + ld b, h + ld c, l + callfar CheckShininess + ret +; 3da85 + +GetPartyMonDVs: ; 3da85 + ld hl, BattleMonDVs + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, PartyMon1DVs + ld a, [CurBattleMon] + jp GetPartyLocation +; 3da97 + +GetEnemyMonDVs: ; 3da97 + ld hl, EnemyMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, wEnemyBackupDVs + ld a, [wBattleMode] + dec a + ret z + ld hl, OTPartyMon1DVs + ld a, [CurOTMon] + jp GetPartyLocation +; 3dab1 + +ResetPlayerStatLevels: ; 3dab1 + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, PlayerStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 3dabd + +InitEnemyMon: ; 3dabd + ld a, [CurPartyMon] + ld hl, OTPartyMon1Species + call GetPartyLocation + ld de, EnemyMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, EnemyMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, EnemyMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld hl, OTPartyMonNicknames + ld a, [CurPartyMon] + call SkipNames + ld de, EnemyMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, EnemyMonAttack + ld de, EnemyStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnEnemyStats + ld hl, BaseType1 + ld de, EnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, BaseStats + ld de, EnemyMonBaseStats + ld b, 5 +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + ld a, [CurPartyMon] + ld [CurOTMon], a + ret +; 3db32 + +SwitchPlayerMon: ; 3db32 + call ClearSprites + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + ret +; 3db5f + +SendOutPlayerMon: ; 3db5f + ld hl, BattleMonDVs + predef GetUnownLetter + hlcoord 1, 5 + ld b, 7 + ld c, 8 + call ClearBox + call WaitBGMap + xor a + ld [hBGMapMode], a + call GetBattleMonBackpic + xor a + ld [hGraphicStartTile], a + ld [wBattleMenuCursorBuffer], a + ld [CurMoveNum], a + ld [TypeModifier], a + ld [wPlayerMoveStruct + MOVE_ANIM], a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastPlayerMove], a + call CheckAmuletCoin + call FinishBattleAnim + xor a + ld [wEnemyWrapCount], a + call SetPlayerTurn + xor a + ld [wNumHits], a + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + call BattleCheckPlayerShininess + jr nc, .not_shiny + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + farcall CheckFaintedFrzSlp + jr c, .statused + ld a, $f0 + ld [CryTracks], a + ld a, [CurPartySpecies] + call PlayStereoCry + +.statused + call UpdatePlayerHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3dbde + +NewBattleMonStatus: ; 3dbde + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastPlayerMove], a + ld hl, PlayerSubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld hl, PlayerUsedMoves + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [PlayerDisableCount], a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld [DisabledMove], a + ld [wPlayerMinimized], a + ld [wEnemyWrapCount], a + ld [wPlayerWrapCount], a + ld [PlayerTurnsTaken], a + ld hl, EnemySubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret +; 3dc18 + +BreakAttraction: ; 3dc18 + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, EnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ret +; 3dc23 + +SpikesDamage: ; 3dc23 + ld hl, PlayerScreens + ld de, BattleMonType + ld bc, UpdatePlayerHUD + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyScreens + ld de, EnemyMonType + ld bc, UpdateEnemyHUD +.ok + + bit SCREENS_SPIKES, [hl] + ret z + + ; Flying-types aren't affected by Spikes. + ld a, [de] + cp FLYING + ret z + inc de + ld a, [de] + cp FLYING + ret z + + push bc + + ld hl, BattleText_UserHurtBySpikes ; "hurt by SPIKES!" + call StdBattleTextBox + + call GetEighthMaxHP + call SubtractHPFromTarget + + pop hl + call .hl + + jp WaitBGMap + +.hl + jp hl +; 3dc5b + +PursuitSwitch: ; 3dc5b + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld b, a + call GetMoveEffect + ld a, b + cp EFFECT_PURSUIT + jr nz, .done + + ld a, [CurBattleMon] + push af + + ld hl, DoPlayerTurn + ld a, [hBattleTurn] + and a + jr z, .do_turn + ld hl, DoEnemyTurn + ld a, [LastPlayerMon] + ld [CurBattleMon], a +.do_turn + ld a, BANK(DoPlayerTurn) + rst FarCall + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, $ff + ld [hl], a + + pop af + ld [CurBattleMon], a + + ld a, [hBattleTurn] + and a + jr z, .check_enemy_fainted + + ld a, [LastPlayerMon] + call UpdateBattleMon + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld a, $f0 + ld [CryTracks], a + ld a, [BattleMonSpecies] + call PlayStereoCry + ld a, [LastPlayerMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef FlagPredef + call PlayerMonFaintedAnimation + ld hl, BattleText_PkmnFainted + jr .done_fainted + +.check_enemy_fainted + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld de, SFX_KINESIS + call PlaySFX + call WaitSFX + ld de, SFX_FAINT + call PlaySFX + call WaitSFX + call EnemyMonFaintedAnimation + ld hl, BattleText_EnemyPkmnFainted + +.done_fainted + call StdBattleTextBox + scf + ret + +.done + and a + ret +; 3dce6 + +RecallPlayerMon: ; 3dce6 + ld a, [hBattleTurn] + push af + xor a + ld [hBattleTurn], a + ld [wNumHits], a + ld de, ANIM_RETURN_MON + call Call_PlayBattleAnim + pop af + ld [hBattleTurn], a + ret +; 3dcf9 + +HandleHealingItems: ; 3dcf9 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call SetPlayerTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + call UseConfusionHealingItem + call SetEnemyTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + jp UseConfusionHealingItem + +.player_1 + call SetEnemyTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + call UseConfusionHealingItem + call SetPlayerTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + jp UseConfusionHealingItem +; 3dd2f + +HandleHPHealingItem: ; 3dd2f + callfar GetOpponentItem + ld a, b + cp HELD_BERRY + ret nz + ld de, EnemyMonHP + 1 + ld hl, EnemyMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .go + ld de, BattleMonHP + 1 + ld hl, BattleMonMaxHP + +.go +; If, and only if, Pokemon's HP is less than half max, use the item. +; Store current HP in Buffer 3/4 + push bc + ld a, [de] + ld [Buffer3], a + add a + ld c, a + dec de + ld a, [de] + inc de + ld [Buffer4], a + adc a + ld b, a + ld a, b + cp [hl] + ld a, c + pop bc + jr z, .equal + jr c, .less + ret + +.equal + inc hl + cp [hl] + dec hl + ret nc + +.less + call ItemRecoveryAnim + ; store max HP in Buffer1/2 + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ld a, [de] + add c + ld [Buffer5], a + ld c, a + dec de + ld a, [de] + adc $0 + ld [Buffer6], a + ld b, a + ld a, [hld] + cp c + ld a, [hl] + sbc b + jr nc, .okay + ld a, [hli] + ld [Buffer6], a + ld a, [hl] + ld [Buffer5], a + +.okay + ld a, [Buffer6] + ld [de], a + inc de + ld a, [Buffer5] + ld [de], a + ld a, [hBattleTurn] + ld [wWhichHPBar], a + and a + hlcoord 2, 2 + jr z, .got_hp_bar_coords + hlcoord 10, 9 + +.got_hp_bar_coords + ld [wWhichHPBar], a + predef AnimateHPBar +UseOpponentItem: + call RefreshBattleHuds + callfar GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + callfar ConsumeHeldItem + ld hl, RecoveredUsingText + jp StdBattleTextBox +; 3ddc8 + +ItemRecoveryAnim: ; 3ddc8 + push hl + push de + push bc + call EmptyBattleTextBox + ld a, RECOVER + ld [FXAnimID], a + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + pop bc + pop de + pop hl + ret +; 3dde9 + +UseHeldStatusHealingItem: ; 3dde9 + callfar GetOpponentItem + ld hl, .Statuses +.loop + ld a, [hli] + cp $ff + ret z + inc hl + cp b + jr nz, .loop + dec hl + ld b, [hl] + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and b + ret z + xor a + ld [hl], a + push bc + call UpdateOpponentInParty + pop bc + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + and [hl] + res SUBSTATUS_TOXIC, [hl] + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + and [hl] + res SUBSTATUS_NIGHTMARE, [hl] + ld a, b + cp ALL_STATUS + jr nz, .skip_confuse + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + +.skip_confuse + ld hl, CalcEnemyStats + ld a, [hBattleTurn] + and a + jr z, .got_pointer + ld hl, CalcPlayerStats + +.got_pointer + call SwitchTurnCore + ld a, BANK(CalcEnemyStats) + rst FarCall + call SwitchTurnCore + call ItemRecoveryAnim + call UseOpponentItem + ld a, $1 + and a + ret +; 3de44 + +.Statuses: ; 3de44 + db HELD_HEAL_POISON, 1 << PSN + db HELD_HEAL_FREEZE, 1 << FRZ + db HELD_HEAL_BURN, 1 << BRN + db HELD_HEAL_SLEEP, SLP + db HELD_HEAL_PARALYZE, 1 << PAR + db HELD_HEAL_STATUS, ALL_STATUS + db $ff +; 3de51 + +UseConfusionHealingItem: ; 3de51 + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_CONFUSED, a + ret z + callfar GetOpponentItem + ld a, b + cp HELD_HEAL_CONFUSION + jr z, .heal_status + cp HELD_HEAL_STATUS + ret nz + +.heal_status + ld a, [hl] + ld [wd265], a + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + call GetItemName + call ItemRecoveryAnim + ld hl, BattleText_ItemHealedConfusion + call StdBattleTextBox + ld a, [hBattleTurn] + and a + jr nz, .do_partymon + call GetOTPartymonItem + xor a + ld [bc], a + ld a, [wBattleMode] + dec a + ret z + ld [hl], $0 + ret + +.do_partymon + call GetPartymonItem + xor a + ld [bc], a + ld [hl], a + ret +; 3de97 + +HandleStatBoostingHeldItems: ; 3de97 +; The effects handled here are not used in-game. + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call .DoPlayer + jp .DoEnemy + +.player_1 + call .DoEnemy + jp .DoPlayer +; 3dea9 + +.DoPlayer: ; 3dea9 + call GetPartymonItem + ld a, $0 + jp .HandleItem +; 3deb1 + +.DoEnemy: ; 3deb1 + call GetOTPartymonItem + ld a, $1 +.HandleItem: ; 3deb6 + ld [hBattleTurn], a + ld d, h + ld e, l + push de + push bc + ld a, [bc] + ld b, a + callfar GetItemHeldEffect + ld hl, .StatUpItems +.loop + ld a, [hli] + cp $ff + jr z, .finish + inc hl + inc hl + cp b + jr nz, .loop + pop bc + ld a, [bc] + ld [wd265], a + push bc + dec hl + dec hl + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(BattleCommand_AttackUp) + rst FarCall + pop bc + pop de + ld a, [FailedMessage] + and a + ret nz + xor a + ld [bc], a + ld [de], a + call GetItemName + ld hl, BattleText_UsersStringBuffer1Activated + call StdBattleTextBox + callfar BattleCommand_StatUpMessage + ret + +.finish + pop bc + pop de + ret +; 3defc + +.StatUpItems: + dbw HELD_ATTACK_UP, BattleCommand_AttackUp + dbw HELD_DEFENSE_UP, BattleCommand_DefenseUp + dbw HELD_SPEED_UP, BattleCommand_SpeedUp + dbw HELD_SP_ATTACK_UP, BattleCommand_SpecialAttackUp + dbw HELD_SP_DEFENSE_UP, BattleCommand_SpecialDefenseUp + dbw HELD_ACCURACY_UP, BattleCommand_AccuracyUp + dbw HELD_EVASION_UP, BattleCommand_EvasionUp + db $ff +; 3df12 + +GetPartymonItem: ; 3df12 + ld hl, PartyMon1Item + ld a, [CurBattleMon] + call GetPartyLocation + ld bc, BattleMonItem + ret +; 3df1f + +GetOTPartymonItem: ; 3df1f + ld hl, OTPartyMon1Item + ld a, [CurOTMon] + call GetPartyLocation + ld bc, EnemyMonItem + ret +; 3df2c + +UpdateBattleHUDs: ; 3df2c + push hl + push de + push bc + call DrawPlayerHUD + ld hl, PlayerHPPal + call SetHPPal + call CheckDanger + call DrawEnemyHUD + ld hl, EnemyHPPal + call SetHPPal + pop bc + pop de + pop hl + ret +; 3df48 + +UpdatePlayerHUD:: ; 3df48 + push hl + push de + push bc + call DrawPlayerHUD + call UpdatePlayerHPPal + call CheckDanger + pop bc + pop de + pop hl + ret +; 3df58 + +DrawPlayerHUD: ; 3df58 + xor a + ld [hBGMapMode], a + + ; Clear the area + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + farcall DrawPlayerHUDBorder + + hlcoord 18, 9 + ld [hl], $73 ; vertical bar + call PrintPlayerHUD + + ; HP bar + hlcoord 10, 9 + ld b, 1 + xor a ; PARTYMON + ld [MonType], a + predef DrawPlayerHP + + ; Exp bar + push de + ld a, [CurBattleMon] + ld hl, PartyMon1Exp + 2 + call GetPartyLocation + ld d, h + ld e, l + + hlcoord 10, 11 + ld a, [TempMonLevel] + ld b, a + call FillInExpBar + pop de + ret +; 3df98 + +UpdatePlayerHPPal: ; 3df98 + ld hl, PlayerHPPal + jp UpdateHPPal +; 3df9e + +CheckDanger: ; 3df9e + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr z, .no_danger + ld a, [wDanger] + and a + jr nz, .done + ld a, [PlayerHPPal] + cp HP_RED + jr z, .danger + +.no_danger + ld hl, Danger + res DANGER_ON_F, [hl] + jr .done + +.danger + ld hl, Danger + set DANGER_ON_F, [hl] + +.done + ret +; 3dfbf + +PrintPlayerHUD: ; 3dfbf + ld de, BattleMonNick + hlcoord 10, 7 + call ret_3e138 + call PlaceString + + push bc + + ld a, [CurBattleMon] + ld hl, PartyMon1DVs + call GetPartyLocation + ld de, TempMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, BattleMonLevel + ld de, TempMonLevel + ld bc, $0011 + call CopyBytes + ld a, [CurBattleMon] + ld hl, PartyMon1Species + call GetPartyLocation + ld a, [hl] + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + + pop hl + dec hl + + ld a, TEMPMON + ld [MonType], a + callfar GetGender + ld a, " " + jr c, .got_gender_char + ld a, "♂" + jr nz, .got_gender_char + ld a, "♀" + +.got_gender_char + hlcoord 17, 8 + ld [hl], a + hlcoord 14, 8 + push af ; back up gender + push hl + ld de, BattleMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + ret nz + ld a, b + cp " " + jr nz, .copy_level ; male or female + dec hl ; genderless + +.copy_level + ld a, [BattleMonLevel] + ld [TempMonLevel], a + jp PrintLevel +; 3e036 + +UpdateEnemyHUD:: ; 3e036 + push hl + push de + push bc + call DrawEnemyHUD + call UpdateEnemyHPPal + pop bc + pop de + pop hl + ret +; 3e043 + +DrawEnemyHUD: ; 3e043 + xor a + ld [hBGMapMode], a + + hlcoord 1, 0 + lb bc, 4, 11 + call ClearBox + + farcall DrawEnemyHUDBorder + + ld a, [TempEnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + ld de, EnemyMonNick + hlcoord 1, 0 + call ret_3e138 + call PlaceString + ld h, b + ld l, c + dec hl + + ld hl, EnemyMonDVs + ld de, TempMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .ok + ld hl, wEnemyBackupDVs +.ok + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + + ld a, TEMPMON + ld [MonType], a + callfar GetGender + ld a, " " + jr c, .got_gender + ld a, "♂" + jr nz, .got_gender + ld a, "♀" + +.got_gender + hlcoord 9, 1 + ld [hl], a + + hlcoord 6, 1 + push af + push hl + ld de, EnemyMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + jr nz, .skip_level + ld a, b + cp " " + jr nz, .print_level + dec hl +.print_level + ld a, [EnemyMonLevel] + ld [TempMonLevel], a + call PrintLevel +.skip_level + + ld hl, EnemyMonHP + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hld] + ld [hMultiplicand + 2], a + or [hl] + jr nz, .not_fainted + + ld c, a + ld e, a + ld d, HP_BAR_LENGTH + jp .draw_bar + +.not_fainted + xor a + ld [hMultiplicand], a + ld a, HP_BAR_LENGTH_PX + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, a + ld a, [hl] + ld [hMultiplier], a + ld a, b + and a + jr z, .less_than_256_max + ld a, [hMultiplier] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld a, [hProduct + 2] + ld b, a + srl b + ld a, [hProduct + 3] + rr a + srl b + rr a + ld [hProduct + 3], a + ld a, b + ld [hProduct + 2], a + +.less_than_256_max + ld a, [hProduct + 2] + ld [hDividend + 0], a + ld a, [hProduct + 3] + ld [hDividend + 1], a + ld a, 2 + ld b, a + call Divide + ld a, [hQuotient + 2] + ld e, a + ld a, HP_BAR_LENGTH + ld d, a + ld c, a + +.draw_bar + xor a + ld [wWhichHPBar], a + hlcoord 2, 2 + ld b, 0 + call DrawBattleHPBar + ret +; 3e127 + +UpdateEnemyHPPal: ; 3e127 + ld hl, EnemyHPPal + call UpdateHPPal + ret +; 3e12e + +UpdateHPPal: ; 3e12e + ld b, [hl] + call SetHPPal + ld a, [hl] + cp b + ret z + jp FinishBattleAnim +; 3e138 + +ret_3e138: ; 3e138 + ret +; 3e139 + +BattleMenu: ; 3e139 + xor a + ld [hBGMapMode], a + call LoadTempTileMapToTileMap + + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jr z, .ok + cp BATTLETYPE_TUTORIAL + jr z, .ok + call EmptyBattleTextBox + call UpdateBattleHuds + call EmptyBattleTextBox + call LoadTileMapToTempTileMap +.ok + +.loop + ld a, [BattleType] + cp BATTLETYPE_CONTEST + jr nz, .not_contest + farcall ContestBattleMenu + jr .next +.not_contest + + ; Auto input: choose "ITEM" + ld a, [InputType] + or a + jr z, .skip_dude_pack_select + farcall _DudeAutoInput_DownA +.skip_dude_pack_select + call LoadBattleMenu2 + ret c + +.next + ld a, $1 + ld [hBGMapMode], a + ld a, [wBattleMenuCursorBuffer] + cp $1 + jp z, BattleMenu_Fight + cp $3 + jp z, BattleMenu_Pack + cp $2 + jp z, BattleMenu_PKMN + cp $4 + jp z, BattleMenu_Run + jr .loop +; 3e192 + +BattleMenu_Fight: ; 3e192 + xor a + ld [wNumFleeAttempts], a + call Call_LoadTempTileMapToTileMap + and a + ret +; 3e19b + +LoadBattleMenu2: ; 3e19b + call IsMobileBattle + jr z, .mobile + + farcall LoadBattleMenu + and a + ret + +.mobile + farcall Function100b12 + ld a, [wcd2b] + and a + ret z + + ld hl, wcd2a + bit 4, [hl] + jr nz, .error + ld hl, BattleText_LinkErrorBattleCanceled + call StdBattleTextBox + ld c, 60 + call DelayFrames +.error + scf + ret +; 3e1c7 + +BattleMenu_Pack: ; 3e1c7 + ld a, [wLinkMode] + and a + jp nz, .ItemsCantBeUsed + + ld a, [InBattleTowerBattle] + and a + jp nz, .ItemsCantBeUsed + + call LoadStandardMenuDataHeader + + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial + cp BATTLETYPE_CONTEST + jr z, .contest + + farcall BattlePack + ld a, [wPlayerAction] + and a + jr z, .didnt_use_item + jr .got_item + +.tutorial + farcall TutorialPack + ld a, POKE_BALL + ld [CurItem], a + call DoItemEffect + jr .got_item + +.contest + ld a, PARK_BALL + ld [CurItem], a + call DoItemEffect + +.got_item + call .UseItem + ret + +.didnt_use_item + call ClearPalettes + call DelayFrame + call _LoadBattleFontsHPBar + call GetBattleMonBackpic + call GetEnemyMonFrontpic + call ExitMenu + call WaitBGMap + call FinishBattleAnim + call LoadTileMapToTempTileMap + jp BattleMenu +; 3e22b + +.ItemsCantBeUsed: ; 3e22b + ld hl, BattleText_ItemsCantBeUsedHere + call StdBattleTextBox + jp BattleMenu +; 3e234 + +.UseItem: ; 3e234 + ld a, [wWildMon] + and a + jr nz, .run + callfar CheckItemPocket + ld a, [wItemAttributeParamBuffer] + cp BALL + jr z, .ball + call ClearBGPalettes + +.ball + xor a + ld [hBGMapMode], a + call _LoadBattleFontsHPBar + call ClearSprites + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial2 + call GetBattleMonBackpic + +.tutorial2 + call GetEnemyMonFrontpic + ld a, $1 + ld [wMenuCursorY], a + call ExitMenu + call UpdateBattleHUDs + call WaitBGMap + call LoadTileMapToTempTileMap + call ClearWindowData + call FinishBattleAnim + and a + ret + +.run + xor a + ld [wWildMon], a + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + call ClearWindowData + call SetPalettes + scf + ret +; 3e28d + +BattleMenu_PKMN: ; 3e28d + call LoadStandardMenuDataHeader +BattleMenuPKMN_ReturnFromStats: + call ExitMenu + call LoadStandardMenuDataHeader + call ClearBGPalettes +BattleMenuPKMN_Loop: + call SetUpBattlePartyMenu + xor a + ld [PartyMenuActionText], a + call JumpToPartyMenuAndPrintText + call SelectBattleMon + jr c, .Cancel +.loop + farcall FreezeMonIcons + call .GetMenu + jr c, .PressedB + call PlaceHollowCursor + ld a, [wMenuCursorY] + cp $1 ; SWITCH + jp z, TryPlayerSwitch + cp $2 ; STATS + jr z, .Stats + cp $3 ; CANCEL + jr z, .Cancel + jr .loop + +.PressedB: + call CheckMobileBattleError + jr c, .Cancel + jr BattleMenuPKMN_Loop + +.Stats: + call Battle_StatsScreen + call CheckMobileBattleError + jr c, .Cancel + jp BattleMenuPKMN_ReturnFromStats + +.Cancel: + call ClearSprites + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call LoadTileMapToTempTileMap + call GetMemSGBLayout + call SetPalettes + jp BattleMenu +; 3e2f5 + +.GetMenu: ; 3e2f5 + call IsMobileBattle + jr z, .mobile + farcall BattleMonMenu + ret + +.mobile + farcall MobileBattleMonMenu + ret +; 3e308 + +Battle_StatsScreen: ; 3e308 + call DisableLCD + + ld hl, VTiles2 tile $31 + ld de, VTiles0 + ld bc, $11 tiles + call CopyBytes + + ld hl, VTiles2 + ld de, VTiles0 tile $11 + ld bc, $31 tiles + call CopyBytes + + call EnableLCD + + call ClearSprites + call LowVolume + xor a ; PARTYMON + ld [MonType], a + farcall BattleStatsScreenInit + call MaxVolume + + call DisableLCD + + ld hl, VTiles0 + ld de, VTiles2 tile $31 + ld bc, $11 tiles + call CopyBytes + + ld hl, VTiles0 tile $11 + ld de, VTiles2 + ld bc, $31 tiles + call CopyBytes + + call EnableLCD + ret +; 3e358 + +TryPlayerSwitch: ; 3e358 + ld a, [CurBattleMon] + ld d, a + ld a, [CurPartyMon] + cp d + jr nz, .check_trapped + ld hl, BattleText_PkmnIsAlreadyOut + call StdBattleTextBox + jp BattleMenuPKMN_Loop + +.check_trapped + ld a, [wPlayerWrapCount] + and a + jr nz, .trapped + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr z, .try_switch + +.trapped + ld hl, BattleText_PkmnCantBeRecalled + call StdBattleTextBox + jp BattleMenuPKMN_Loop + +.try_switch + call CheckIfCurPartyMonIsFitToFight + jp z, BattleMenuPKMN_Loop + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, $2 + ld [wPlayerAction], a + call ClearPalettes + call DelayFrame + call ClearSprites + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + ld a, [CurPartyMon] + ld [CurBattleMon], a +PlayerSwitch: ; 3e3ad + ld a, 1 + ld [wPlayerIsSwitching], a + ld a, [wLinkMode] + and a + jr z, .not_linked + call LoadStandardMenuDataHeader + call LinkBattleSendReceiveAction + call CloseWindow + +.not_linked + call ParseEnemyAction + ld a, [wLinkMode] + and a + jr nz, .linked + +.switch + call BattleMonEntrance + and a + ret + +.linked + ld a, [wBattleAction] + cp BATTLEACTION_E + jp z, .switch + cp BATTLEACTION_D + jp z, .switch + cp BATTLEACTION_SWITCH1 + jp c, .switch + cp BATTLEACTION_FORFEIT + jr nz, .dont_run + call WildFled_EnemyFled_LinkBattleCanceled + ret + +.dont_run + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call BattleMonEntrance + call EnemyMonEntrance + and a + ret + +.player_1 + call EnemyMonEntrance + call BattleMonEntrance + and a + ret +; 3e3ff + +EnemyMonEntrance: ; 3e3ff + callfar AI_Switch + call SetEnemyTurn + jp SpikesDamage +; 3e40b + +BattleMonEntrance: ; 3e40b + call WithdrawPkmnText + + ld c, 50 + call DelayFrames + + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + + call SetEnemyTurn + call PursuitSwitch + jr c, .ok + call RecallPlayerMon +.ok + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [CurBattleMon] + ld [CurPartyMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, $2 + ld [wMenuCursorY], a + ret +; 3e459 + +PassedBattleMonEntrance: ; 3e459 + ld c, 50 + call DelayFrames + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + xor a + ld [wd265], a + call ApplyStatLevelMultiplierOnAllStats + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + jp SpikesDamage +; 3e489 + +BattleMenu_Run: ; 3e489 + call Call_LoadTempTileMapToTileMap + ld a, $3 + ld [wMenuCursorY], a + ld hl, BattleMonSpeed + ld de, EnemyMonSpeed + call TryToRunAwayFromBattle + ld a, $0 + ld [wFailedToFlee], a + ret c + ld a, [wPlayerAction] + and a + ret nz + jp BattleMenu +; 3e4a8 + +CheckAmuletCoin: ; 3e4a8 + ld a, [BattleMonItem] + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_AMULET_COIN + ret nz + ld a, 1 + ld [wAmuletCoin], a + ret +; 3e4bc + +MoveSelectionScreen: ; 3e4bc + call IsMobileBattle + jr nz, .not_mobile + farcall MobileMoveSelectionScreen + ret + +.not_mobile + ld hl, EnemyMonMoves + ld a, [wMoveSelectionMenuType] + dec a + jr z, .got_menu_type + dec a + jr z, .ether_elixer_menu + call CheckPlayerHasUsableMoves + ret z ; use Struggle + ld hl, BattleMonMoves + jr .got_menu_type + +.ether_elixer_menu + ld a, MON_MOVES + call GetPartyParamLocation + +.got_menu_type + ld de, wListMoves_MoveIndicesBuffer + ld bc, NUM_MOVES + call CopyBytes + xor a + ld [hBGMapMode], a + + hlcoord 4, 17 - NUM_MOVES - 1 + ld b, 4 + ld c, 14 + ld a, [wMoveSelectionMenuType] + cp $2 + jr nz, .got_dims + hlcoord 4, 17 - NUM_MOVES - 1 - 4 + ld b, 4 + ld c, 14 +.got_dims + call TextBox + + hlcoord 6, 17 - NUM_MOVES + ld a, [wMoveSelectionMenuType] + cp $2 + jr nz, .got_start_coord + hlcoord 6, 17 - NUM_MOVES - 4 +.got_start_coord + ld a, SCREEN_WIDTH + ld [Buffer1], a + predef ListMoves + + ld b, 5 + ld a, [wMoveSelectionMenuType] + cp $2 + ld a, 17 - NUM_MOVES + jr nz, .got_default_coord + ld b, 5 + ld a, 17 - NUM_MOVES - 4 + +.got_default_coord + ld [w2DMenuCursorInitY], a + ld a, b + ld [w2DMenuCursorInitX], a + ld a, [wMoveSelectionMenuType] + cp $1 + jr z, .skip_inc + ld a, [CurMoveNum] + inc a + +.skip_inc + ld [wMenuCursorY], a + ld a, $1 + ld [wMenuCursorX], a + ld a, [wNumMoves] + inc a + ld [w2DMenuNumRows], a + ld a, $1 + ld [w2DMenuNumCols], a + ld c, $2c + ld a, [wMoveSelectionMenuType] + dec a + ld b, D_DOWN | D_UP | A_BUTTON + jr z, .okay + dec a + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON + jr z, .okay + ld a, [wLinkMode] + and a + jr nz, .okay + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON | SELECT + +.okay + ld a, b + ld [wMenuJoypadFilter], a + ld a, c + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + ld a, $10 + ld [w2DMenuCursorOffsets], a +.menu_loop + ld a, [wMoveSelectionMenuType] + and a + jr z, .battle_player_moves + dec a + jr nz, .interpret_joypad + hlcoord 11, 14 + ld de, .string_3e61c + call PlaceString + jr .interpret_joypad + +.battle_player_moves + call MoveInfoBox + ld a, [wMoveSwapBuffer] + and a + jr z, .interpret_joypad + hlcoord 5, 13 + ld bc, SCREEN_WIDTH + dec a + call AddNTimes + ld [hl], "▷" + +.interpret_joypad + ld a, $1 + ld [hBGMapMode], a + call ScrollingMenuJoypad + bit D_UP_F, a + jp nz, .pressed_up + bit D_DOWN_F, a + jp nz, .pressed_down + bit SELECT_F, a + jp nz, .pressed_select + bit B_BUTTON_F, a + ; A button + push af + + xor a + ld [wMoveSwapBuffer], a + ld a, [wMenuCursorY] + dec a + ld [wMenuCursorY], a + ld b, a + ld a, [wMoveSelectionMenuType] + dec a + jr nz, .not_enemy_moves_process_b + + pop af + ret + +.not_enemy_moves_process_b + dec a + ld a, b + ld [CurMoveNum], a + jr nz, .use_move + + pop af + ret + +.use_move + pop af + ret nz + + ld hl, BattleMonPP + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + jr z, .no_pp_left + ld a, [PlayerDisableCount] + swap a + and $f + dec a + cp c + jr z, .move_disabled + ld a, [wUnusedPlayerLockedMove] + and a + jr nz, .skip2 + ld a, [wMenuCursorY] + ld hl, BattleMonMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + +.skip2 + ld [CurPlayerMove], a + xor a + ret + +.move_disabled + ld hl, BattleText_TheMoveIsDisabled + jr .place_textbox_start_over + +.no_pp_left + ld hl, BattleText_TheresNoPPLeftForThisMove + +.place_textbox_start_over + call StdBattleTextBox + call Call_LoadTempTileMapToTileMap + jp MoveSelectionScreen +; 3e61c + +.string_3e61c ; 3e61c + db "@" +; 3e61d + +.pressed_up + ld a, [wMenuCursorY] + and a + jp nz, .menu_loop + ld a, [wNumMoves] + inc a + ld [wMenuCursorY], a + jp .menu_loop +; 3e62e + +.pressed_down ; 3e62e + ld a, [wMenuCursorY] + ld b, a + ld a, [wNumMoves] + inc a + inc a + cp b + jp nz, .menu_loop + ld a, $1 + ld [wMenuCursorY], a + jp .menu_loop +; 3e643 + +.pressed_select ; 3e643 + ld a, [wMoveSwapBuffer] + and a + jr z, .start_swap + ld hl, BattleMonMoves + call .swap_bytes + ld hl, BattleMonPP + call .swap_bytes + ld hl, PlayerDisableCount + ld a, [hl] + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_swapping_disabled_move + ld a, [hl] + and $f + ld b, a + ld a, [wMoveSwapBuffer] + swap a + add b + ld [hl], a + jr .swap_moves_in_party_struct + +.not_swapping_disabled_move + ld a, [wMoveSwapBuffer] + cp b + jr nz, .swap_moves_in_party_struct + ld a, [hl] + and $f + ld b, a + ld a, [wMenuCursorY] + swap a + add b + ld [hl], a + +.swap_moves_in_party_struct +; Fixes the COOLTRAINER glitch + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, PartyMon1Moves + ld a, [CurBattleMon] + call GetPartyLocation + push hl + call .swap_bytes + pop hl + ld bc, MON_PP - MON_MOVES + add hl, bc + call .swap_bytes + +.transformed + xor a + ld [wMoveSwapBuffer], a + jp MoveSelectionScreen + +.swap_bytes + push hl + ld a, [wMoveSwapBuffer] + dec a + ld c, a + ld b, 0 + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, 0 + add hl, bc + ld a, [de] + ld b, [hl] + ld [hl], a + ld a, b + ld [de], a + ret + +.start_swap + ld a, [wMenuCursorY] + ld [wMoveSwapBuffer], a + jp MoveSelectionScreen +; 3e6c8 + +MoveInfoBox: ; 3e6c8 + xor a + ld [hBGMapMode], a + + hlcoord 0, 8 + ld b, 3 + ld c, 9 + call TextBox + call MobileTextBorder + + ld a, [PlayerDisableCount] + and a + jr z, .not_disabled + + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_disabled + + hlcoord 1, 10 + ld de, .Disabled + call PlaceString + jr .done + +.not_disabled + ld hl, wMenuCursorY + dec [hl] + call SetPlayerTurn + ld hl, BattleMonMoves + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [CurPlayerMove], a + + ld a, [CurBattleMon] + ld [CurPartyMon], a + ld a, WILDMON + ld [MonType], a + callfar GetMaxPPOfMove + + ld hl, wMenuCursorY + ld c, [hl] + inc [hl] + ld b, 0 + ld hl, BattleMonPP + add hl, bc + ld a, [hl] + and $3f + ld [StringBuffer1], a + call .PrintPP + + hlcoord 1, 9 + ld de, .Type + call PlaceString + + hlcoord 7, 11 + ld [hl], "/" + + callfar UpdateMoveData + ld a, [wPlayerMoveStruct + MOVE_ANIM] + ld b, a + hlcoord 2, 10 + predef PrintMoveType + +.done + ret +; 3e74f + +.Disabled: + db "Disabled!@" +.Type: + db "TYPE/@" +; 3e75f + +.PrintPP: ; 3e75f + hlcoord 5, 11 + ld a, [wLinkMode] ; What's the point of this check? + cp LINK_MOBILE + jr c, .ok + hlcoord 5, 11 +.ok + push hl + ld de, StringBuffer1 + lb bc, 1, 2 + call PrintNum + pop hl + inc hl + inc hl + ld [hl], "/" + inc hl + ld de, wNamedObjectIndexBuffer + lb bc, 1, 2 + call PrintNum + ret +; 3e786 + +CheckPlayerHasUsableMoves: ; 3e786 + ld a, STRUGGLE + ld [CurPlayerMove], a + ld a, [PlayerDisableCount] + and a + ld hl, BattleMonPP + jr nz, .disabled + + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and $3f + ret nz + jr .force_struggle + +.disabled + swap a + and $f + ld b, a + ld d, NUM_MOVES + 1 + xor a +.loop + dec d + jr z, .done + ld c, [hl] + inc hl + dec b + jr z, .loop + or c + jr .loop + +.done + ; Bug: this will result in a move with PP Up confusing the game. + ; Replace with "and $3f" to fix. + and a + ret nz + +.force_struggle + ld hl, BattleText_PkmnHasNoMovesLeft + call StdBattleTextBox + ld c, 60 + call DelayFrames + xor a + ret +; 3e7c1 + +ParseEnemyAction: ; 3e7c1 + ld a, [wEnemyIsSwitching] + and a + ret nz + ld a, [wLinkMode] + and a + jr z, .not_linked + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, [wPlayerAction] + and a + call z, LinkBattleSendReceiveAction + call Call_LoadTempTileMapToTileMap + ld a, [wBattleAction] + cp BATTLEACTION_E + jp z, .struggle + cp BATTLEACTION_D + jp z, .battle_action_d + cp BATTLEACTION_SWITCH1 + jp nc, ResetVarsForSubstatusRage + ld [CurEnemyMoveNum], a + ld c, a + ld a, [EnemySubStatus1] + bit SUBSTATUS_ROLLOUT, a + jp nz, .skip_load + ld a, [EnemySubStatus3] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + jp nz, .skip_load + + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ld a, [LastEnemyMove] + jp nz, .finish + ld hl, EnemyMonMoves + ld b, 0 + add hl, bc + ld a, [hl] + jp .finish + +.not_linked + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .skip_encore + ld a, [LastEnemyMove] + jp .finish + +.skip_encore + call CheckEnemyLockedIn + jp nz, ResetVarsForSubstatusRage + jr .continue + +.battle_action_d + ld a, $ff + jr .finish + +.continue + ld hl, EnemyMonMoves + ld de, EnemyMonPP + ld b, NUM_MOVES +.loop + ld a, [hl] + and a + jp z, .struggle + ld a, [EnemyDisabledMove] + cp [hl] + jr z, .disabled + ld a, [de] + and $3f + jr nz, .enough_pp + +.disabled + inc hl + inc de + dec b + jr nz, .loop + jr .struggle + +.enough_pp + ld a, [wBattleMode] + dec a + jr nz, .skip_load +; wild +.loop2 + ld hl, EnemyMonMoves + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [EnemyDisableCount] + swap a + and $f + dec a + cp c + jr z, .loop2 + ld a, [hl] + and a + jr z, .loop2 + ld hl, EnemyMonPP + add hl, bc + ld b, a + ld a, [hl] + and $3f + jr z, .loop2 + ld a, c + ld [CurEnemyMoveNum], a + ld a, b + +.finish + ld [CurEnemyMove], a + +.skip_load + call SetEnemyTurn + callfar UpdateMoveData + call CheckEnemyLockedIn + jr nz, .raging + xor a + ld [wEnemyCharging], a + +.raging + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_FURY_CUTTER + jr z, .fury_cutter + xor a + ld [EnemyFuryCutterCount], a + +.fury_cutter + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .no_rage + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [wEnemyRageCounter], a + +.no_rage + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + ret z + cp EFFECT_ENDURE + ret z + xor a + ld [EnemyProtectCount], a + ret + +.struggle + ld a, STRUGGLE + jr .finish +; 3e8c1 + +ResetVarsForSubstatusRage: ; 3e8c1 + xor a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + ret +; 3e8d1 + +CheckEnemyLockedIn: ; 3e8d1 + ld a, [EnemySubStatus4] + and 1 << SUBSTATUS_RECHARGE + ret nz + + ld hl, EnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + ld hl, EnemySubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + ret +; 3e8e4 + +LinkBattleSendReceiveAction: ; 3e8e4 + farcall _LinkBattleSendReceiveAction + ret +; 3e8eb + +LoadEnemyMon: ; 3e8eb +; Initialize enemy monster parameters +; To do this we pull the species from TempEnemyMonSpecies + +; Notes: +; BattleRandom is used to ensure sync between Game Boys + +; Clear the whole EnemyMon struct + xor a + ld hl, EnemyMonSpecies + ld bc, EnemyMonEnd - EnemyMon + call ByteFill + +; We don't need to be here if we're in a link battle + ld a, [wLinkMode] + and a + jp nz, InitEnemyMon + +; and also not in a BattleTower-Battle + ld a, [InBattleTowerBattle] ; ???? + bit 0, a + jp nz, InitEnemyMon + +; Make sure everything knows what species we're working with + ld a, [TempEnemyMonSpecies] + ld [EnemyMonSpecies], a + ld [CurSpecies], a + ld [CurPartySpecies], a + +; Grab the BaseData for this species + call GetBaseData + +; Let's get the item: + +; Is the item predetermined? + ld a, [wBattleMode] + dec a + jr z, .WildItem + +; If we're in a trainer battle, the item is in the party struct + ld a, [CurPartyMon] + ld hl, OTPartyMon1Item + call GetPartyLocation ; bc = PartyMon[CurPartyMon] - PartyMons + ld a, [hl] + jr .UpdateItem + +.WildItem: +; In a wild battle, we pull from the item slots in BaseData + +; Force Item1 +; Used for Ho-Oh, Lugia and Snorlax encounters + ld a, [BattleType] + cp BATTLETYPE_FORCEITEM + ld a, [BaseItems] + jr z, .UpdateItem + +; Failing that, it's all up to chance +; Effective chances: +; 75% None +; 23% Item1 +; 2% Item2 + +; 25% chance of getting an item + call BattleRandom + cp 1 + (75 percent) + ld a, NO_ITEM + jr c, .UpdateItem + +; From there, an 8% chance for Item2 + call BattleRandom + cp 8 percent ; 8% of 25% = 2% Item2 + ld a, [BaseItems] + jr nc, .UpdateItem + ld a, [BaseItems+1] + +.UpdateItem: + ld [EnemyMonItem], a + +; Initialize DVs + +; If we're in a trainer battle, DVs are predetermined + ld a, [wBattleMode] + and a + jr z, .InitDVs + + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .InitDVs + +; Unknown + ld hl, wEnemyBackupDVs + ld de, EnemyMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + jp .Happiness + +.InitDVs: + +; Trainer DVs + +; All trainers have preset DVs, determined by class +; See GetTrainerDVs for more on that + farcall GetTrainerDVs +; These are the DVs we'll use if we're actually in a trainer battle + ld a, [wBattleMode] + dec a + jr nz, .UpdateDVs + +; Wild DVs +; Here's where the fun starts + +; Roaming monsters (Entei, Raikou) work differently +; They have their own structs, which are shorter than normal + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .NotRoaming + +; Grab HP + call GetRoamMonHP + ld a, [hl] +; Check if the HP has been initialized + and a +; We'll do something with the result in a minute + push af + +; Grab DVs + call GetRoamMonDVs + inc hl + ld a, [hld] + ld c, a + ld b, [hl] + +; Get back the result of our check + pop af +; If the RoamMon struct has already been initialized, we're done + jr nz, .UpdateDVs + +; If it hasn't, we need to initialize the DVs +; (HP is initialized at the end of the battle) + call GetRoamMonDVs + inc hl + call BattleRandom + ld [hld], a + ld c, a + call BattleRandom + ld [hl], a + ld b, a +; We're done with DVs + jr .UpdateDVs + +.NotRoaming: +; Register a contains BattleType + +; Forced shiny battle type +; Used by Red Gyarados at Lake of Rage + cp BATTLETYPE_SHINY + jr nz, .GenerateDVs + + ld b, ATKDEFDV_SHINY ; $ea + ld c, SPDSPCDV_SHINY ; $aa + jr .UpdateDVs + +.GenerateDVs: +; Generate new random DVs + call BattleRandom + ld b, a + call BattleRandom + ld c, a + +.UpdateDVs: +; Input DVs in register bc + ld hl, EnemyMonDVs + ld a, b + ld [hli], a + ld [hl], c + +; We've still got more to do if we're dealing with a wild monster + ld a, [wBattleMode] + dec a + jr nz, .Happiness + +; Species-specfic: + +; Unown + ld a, [TempEnemyMonSpecies] + cp UNOWN + jr nz, .Magikarp + +; Get letter based on DVs + ld hl, EnemyMonDVs + predef GetUnownLetter +; Can't use any letters that haven't been unlocked +; If combined with forced shiny battletype, causes an infinite loop + call CheckUnownLetter + jr c, .GenerateDVs ; try again + +.Magikarp: +; Skimming this part recommended + + ld a, [TempEnemyMonSpecies] + cp MAGIKARP + jr nz, .Happiness + +; Get Magikarp's length + ld de, EnemyMonDVs + ld bc, PlayerID + callfar CalcMagikarpLength + +; We're clear if the length is < 1536 + ld a, [wMagikarpLength] + cp HIGH(1536) + jr nz, .CheckMagikarpArea + +; 5% chance of skipping both size checks + call Random + cp 5 percent + jr c, .CheckMagikarpArea +; Try again if > 1614 + ld a, [wMagikarpLength + 1] + cp LOW(1614) + 2 + jr nc, .GenerateDVs + +; 20% chance of skipping this check + call Random + cp 20 percent - 1 + jr c, .CheckMagikarpArea +; Try again if > 1598 + ld a, [wMagikarpLength + 1] + cp LOW(1598) + 2 + jr nc, .GenerateDVs + +.CheckMagikarpArea: +; The z checks are supposed to be nz +; Instead, all maps in GROUP_LAKE_OF_RAGE (mahogany area) +; and routes 20 and 44 are treated as Lake of Rage + +; This also means Lake of Rage Magikarp can be smaller than ones +; caught elsewhere rather than the other way around + +; Intended behavior enforces a minimum size at Lake of Rage +; The real behavior prevents size flooring in the Lake of Rage area + ld a, [MapGroup] + cp GROUP_LAKE_OF_RAGE + jr z, .Happiness + ld a, [MapNumber] + cp MAP_LAKE_OF_RAGE + jr z, .Happiness +; 40% chance of not flooring + call Random + cp 40 percent - 2 + jr c, .Happiness +; Floor at length 1024 + ld a, [wMagikarpLength] + cp HIGH(1024) + jr c, .GenerateDVs ; try again + +; Finally done with DVs + +.Happiness: +; Set happiness + ld a, BASE_HAPPINESS + ld [EnemyMonHappiness], a +; Set level + ld a, [CurPartyLevel] + ld [EnemyMonLevel], a +; Fill stats + ld de, EnemyMonMaxHP + ld b, FALSE + ld hl, EnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1) ; LinkBattleRNs + 7 ; ? + predef CalcPkmnStats + +; If we're in a trainer battle, +; get the rest of the parameters from the party struct + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr z, .OpponentParty + +; If we're in a wild battle, check wild-specific stuff + and a + jr z, .TreeMon + + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jp nz, .Moves + +.TreeMon: +; If we're headbutting trees, some monsters enter battle asleep + call CheckSleepingTreeMon + ld a, TREEMON_SLEEP_TURNS + jr c, .UpdateStatus +; Otherwise, no status + xor a + +.UpdateStatus: + ld hl, EnemyMonStatus + ld [hli], a + +; Unused byte + xor a + ld [hli], a + +; Full HP.. + ld a, [EnemyMonMaxHP] + ld [hli], a + ld a, [EnemyMonMaxHP + 1] + ld [hl], a + +; ..unless it's a RoamMon + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .Moves + +; Grab HP + call GetRoamMonHP + ld a, [hl] +; Check if it's been initialized again + and a + jr z, .InitRoamHP +; Update from the struct if it has + ld a, [hl] + ld [EnemyMonHP + 1], a + jr .Moves + +.InitRoamHP: +; HP only uses the lo byte in the RoamMon struct since +; Raikou/Entei/Suicune will have < 256 hp at level 40 + ld a, [EnemyMonHP + 1] + ld [hl], a + jr .Moves + +.OpponentParty: +; Get HP from the party struct + ld hl, (OTPartyMon1HP + 1) + ld a, [CurPartyMon] + call GetPartyLocation + ld a, [hld] + ld [EnemyMonHP + 1], a + ld a, [hld] + ld [EnemyMonHP], a + +; Make sure everything knows which monster the opponent is using + ld a, [CurPartyMon] + ld [CurOTMon], a + +; Get status from the party struct + dec hl + ld a, [hl] ; OTPartyMonStatus + ld [EnemyMonStatus], a + +.Moves: + ld hl, BaseType1 + ld de, EnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + +; Get moves + ld de, EnemyMonMoves +; Are we in a trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr nz, .WildMoves +; Then copy moves from the party struct + ld hl, OTPartyMon1Moves + ld a, [CurPartyMon] + call GetPartyLocation + ld bc, NUM_MOVES + call CopyBytes + jr .PP + +.WildMoves: +; Clear EnemyMonMoves + xor a + ld h, d + ld l, e + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a +; Make sure the predef knows this isn't a partymon + ld [wEvolutionOldSpecies], a +; Fill moves based on level + predef FillMoves + +.PP: +; Trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr z, .TrainerPP + +; Fill wild PP + ld hl, EnemyMonMoves + ld de, EnemyMonPP + predef FillPP + jr .Finish + +.TrainerPP: +; Copy PP from the party struct + ld hl, OTPartyMon1PP + ld a, [CurPartyMon] + call GetPartyLocation + ld de, EnemyMonPP + ld bc, NUM_MOVES + call CopyBytes + +.Finish: +; Only the first five base stats are copied.. + ld hl, BaseStats + ld de, EnemyMonBaseStats + ld b, BaseSpecialDefense - BaseStats +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + + ld a, [BaseCatchRate] + ld [de], a + inc de + + ld a, [BaseExp] + ld [de], a + + ld a, [TempEnemyMonSpecies] + ld [wd265], a + + call GetPokemonName + +; Did we catch it? + ld a, [wBattleMode] + and a + ret z + +; Update enemy nick + ld hl, StringBuffer1 + ld de, EnemyMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + +; Saw this mon + ld a, [TempEnemyMonSpecies] + dec a + ld c, a + ld b, SET_FLAG + ld hl, PokedexSeen + predef FlagPredef + + ld hl, EnemyMonStats + ld de, EnemyStats + ld bc, EnemyMonStatsEnd - EnemyMonStats + call CopyBytes + + ret +; 3eb38 + +CheckSleepingTreeMon: ; 3eb38 +; Return carry if species is in the list +; for the current time of day + +; Don't do anything if this isn't a tree encounter + ld a, [BattleType] + cp BATTLETYPE_TREE + jr nz, .NotSleeping + +; Get list for the time of day + ld hl, .Morn + ld a, [TimeOfDay] + cp DAY_F + jr c, .Check + ld hl, .Day + jr z, .Check + ld hl, .Nite + +.Check: + ld a, [TempEnemyMonSpecies] + ld de, 1 ; length of species id + call IsInArray +; If it's a match, the opponent is asleep + ret c + +.NotSleeping: + and a + ret + +.Nite: + db CATERPIE + db METAPOD + db BUTTERFREE + db WEEDLE + db KAKUNA + db BEEDRILL + db SPEAROW + db EKANS + db EXEGGCUTE + db LEDYBA + db AIPOM + db -1 ; end + +.Day: + db VENONAT + db HOOTHOOT + db NOCTOWL + db SPINARAK + db HERACROSS + db -1 ; end + +.Morn: + db VENONAT + db HOOTHOOT + db NOCTOWL + db SPINARAK + db HERACROSS + db -1 ; end +; 3eb75 + +CheckUnownLetter: ; 3eb75 +; Return carry if the Unown letter hasn't been unlocked yet + + ld a, [UnlockedUnowns] + ld c, a + ld de, 0 + +.loop + +; Don't check this set unless it's been unlocked + srl c + jr nc, .next + +; Is our letter in the set? + ld hl, .LetterSets + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + push de + ld a, [UnownLetter] + ld de, 1 + push bc + call IsInArray + pop bc + pop de + + jr c, .match + +.next +; Make sure we haven't gone past the end of the table + inc e + inc e + ld a, e + cp .Set1 - .LetterSets + jr c, .loop + +; Hasn't been unlocked, or the letter is invalid + scf + ret + +.match +; Valid letter + and a + ret + +.LetterSets: + dw .Set1 + dw .Set2 + dw .Set3 + dw .Set4 + +.Set1: + ; A B C D E F G H I J K + db 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, $ff +.Set2: + ; L M N O P Q R + db 12, 13, 14, 15, 16, 17, 18, $ff +.Set3: + ; S T U V W + db 19, 20, 21, 22, 23, $ff +.Set4: + ; X Y Z + db 24, 25, 26, $ff + +; 3ebc7 + +SwapBattlerLevels: ; 3ebc7 +; unreferenced + push bc + ld a, [BattleMonLevel] + ld b, a + ld a, [EnemyMonLevel] + ld [BattleMonLevel], a + ld a, b + ld [EnemyMonLevel], a + pop bc + ret +; 3ebd8 + +BattleWinSlideInEnemyTrainerFrontpic: ; 3ebd8 + xor a + ld [TempEnemyMonSpecies], a + call FinishBattleAnim + ld a, [OtherTrainerClass] + ld [TrainerClass], a + ld de, VTiles2 + callfar GetTrainerPic + hlcoord 19, 0 + ld c, 0 + +.outer_loop + inc c + ld a, c + cp 7 + ret z + xor a + ld [hBGMapMode], a + ld [hBGMapThird], a + ld d, $0 + push bc + push hl + +.inner_loop + call .CopyColumn + inc hl + ld a, 7 + add d + ld d, a + dec c + jr nz, .inner_loop + + ld a, $1 + ld [hBGMapMode], a + ld c, 4 + call DelayFrames + pop hl + pop bc + dec hl + jr .outer_loop +; 3ec1a + +.CopyColumn: ; 3ec1a + push hl + push de + push bc + ld e, 7 + +.loop + ld [hl], d + ld bc, SCREEN_WIDTH + add hl, bc + inc d + dec e + jr nz, .loop + + pop bc + pop de + pop hl + ret +; 3ec2c + +ApplyStatusEffectOnPlayerStats: ; 3ec2c + ld a, 1 + jr ApplyStatusEffectOnStats +; 3ec30 + +ApplyStatusEffectOnEnemyStats: ; 3ec30 + xor a +; 3ec31 + +ApplyStatusEffectOnStats: ; 3ec31 + ld [hBattleTurn], a + call ApplyPrzEffectOnSpeed + jp ApplyBrnEffectOnAttack +; 3ec39 + +ApplyPrzEffectOnSpeed: ; 3ec39 + ld a, [hBattleTurn] + and a + jr z, .enemy + ld a, [BattleMonStatus] + and 1 << PAR + ret z + ld hl, BattleMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min speed + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [EnemyMonStatus] + and 1 << PAR + ret z + ld hl, EnemyMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min speed + +.enemy_ok + ld [hl], b + ret +; 3ec76 + +ApplyBrnEffectOnAttack: ; 3ec76 + ld a, [hBattleTurn] + and a + jr z, .enemy + ld a, [BattleMonStatus] + and 1 << BRN + ret z + ld hl, BattleMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min attack + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [EnemyMonStatus] + and 1 << BRN + ret z + ld hl, EnemyMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min attack + +.enemy_ok + ld [hl], b + ret +; 3ecab + +ApplyStatLevelMultiplierOnAllStats: ; 3ecab +; Apply StatLevelMultipliers on all 5 Stats + ld c, 0 +.stat_loop + call ApplyStatLevelMultiplier + inc c + ld a, c + cp 5 + jr nz, .stat_loop + ret +; 3ecb7 + +ApplyStatLevelMultiplier: ; 3ecb7 + push bc + push bc + ld a, [wd265] + and a + ld a, c + ld hl, BattleMonAttack + ld de, PlayerStats + ld bc, PlayerAtkLevel + jr z, .got_pointers + ld hl, EnemyMonAttack + ld de, EnemyStats + ld bc, EnemyAtkLevel + +.got_pointers + add c + ld c, a + jr nc, .okay + inc b +.okay + ld a, [bc] + pop bc + ld b, a + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .okay2 + inc d +.okay2 + pop bc + push hl + ld hl, .StatLevelMultipliers + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + xor a + ld [hMultiplicand + 0], a + ld a, [de] + ld [hMultiplicand + 1], a + inc de + ld a, [de] + ld [hMultiplicand + 2], a + ld a, [hli] + ld [hMultiplier], a + call Multiply + ld a, [hl] + ld [hDivisor], a + ld b, $4 + call Divide + pop hl + +; Cap at 999. + ld a, [hQuotient + 2] + sub LOW(MAX_STAT_VALUE) + ld a, [hQuotient + 1] + sbc HIGH(MAX_STAT_VALUE) + jp c, .okay3 + + ld a, HIGH(MAX_STAT_VALUE) + ld [hQuotient + 1], a + ld a, LOW(MAX_STAT_VALUE) + ld [hQuotient + 2], a + +.okay3 + ld a, [hQuotient + 1] + ld [hli], a + ld b, a + ld a, [hQuotient + 2] + ld [hl], a + or b + jr nz, .okay4 + inc [hl] + +.okay4 + pop bc + ret +; 3ed2b + +.StatLevelMultipliers: +; / + db 25, 100 ; 25% + db 28, 100 ; 28% + db 33, 100 ; 33% + db 40, 100 ; 40% + db 50, 100 ; 50% + db 66, 100 ; 66% + + db 1, 1 ; 100% + + db 15, 10 ; 150% + db 2, 1 ; 200% + db 25, 10 ; 250% + db 3, 1 ; 300% + db 35, 10 ; 350% + db 4, 1 ; 400% +; 3ed45 + +BadgeStatBoosts: ; 3ed45 +; Raise BattleMon stats depending on which badges have been obtained. + +; Every other badge boosts a stat, starting from the first. + +; ZephyrBadge: Attack +; PlainBadge: Speed +; MineralBadge: Defense +; GlacierBadge: Special Attack +; RisingBadge: Special Defense + +; The boosted stats are in order, except PlainBadge and MineralBadge's boosts are swapped. + + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ld a, [JohtoBadges] + +; Swap badges 3 (PlainBadge) and 5 (MineralBadge). + ld d, a + and (1 << PLAINBADGE) + add a + add a + ld b, a + ld a, d + and (1 << MINERALBADGE) + rrca + rrca + ld c, a + ld a, d + and ((1 << ZEPHYRBADGE) | (1 << HIVEBADGE) | (1 << FOGBADGE) | (1 << STORMBADGE) | (1 << GLACIERBADGE) | (1 << RISINGBADGE)) + or b + or c + ld b, a + + ld hl, BattleMonAttack + ld c, 4 +.CheckBadge: + ld a, b + srl b + call c, BoostStat + inc hl + inc hl +; Check every other badge. + srl b + dec c + jr nz, .CheckBadge +; And the last one (RisingBadge) too. + srl a + call c, BoostStat + ret +; 3ed7c + +BoostStat: ; 3ed7c +; Raise stat at hl by 1/8. + + ld a, [hli] + ld d, a + ld e, [hl] + srl d + rr e + srl d + rr e + srl d + rr e + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + +; Cap at 999. + ld a, [hld] + sub LOW(MAX_STAT_VALUE) + ld a, [hl] + sbc HIGH(MAX_STAT_VALUE) + ret c + ld a, HIGH(MAX_STAT_VALUE) + ld [hli], a + ld a, LOW(MAX_STAT_VALUE) + ld [hld], a + ret +; 3ed9f + +_LoadBattleFontsHPBar: ; 3ed9f + callfar LoadBattleFontsHPBar + ret +; 3eda6 + +_LoadHPBar: ; 3eda6 + callfar LoadHPBar + ret +; 3edad + +LoadHPExpBarGFX: ; unreferenced + ld de, EnemyHPBarBorderGFX + ld hl, VTiles2 tile $6c + lb bc, BANK(EnemyHPBarBorderGFX), 4 + call Get1bpp + ld de, HPExpBarBorderGFX + ld hl, VTiles2 tile $73 + lb bc, BANK(HPExpBarBorderGFX), 6 + call Get1bpp + ld de, ExpBarGFX + ld hl, VTiles2 tile $55 + lb bc, BANK(ExpBarGFX), 8 + jp Get2bpp +; 3edd1 + +EmptyBattleTextBox: ; 3edd1 + ld hl, .empty + jp BattleTextBox +.empty + db "@" +; 3edd8 + +_BattleRandom:: ; 3edd8 +; If the normal RNG is used in a link battle it'll desync. +; To circumvent this a shared PRNG is used instead. + +; But if we're in a non-link battle we're safe to use it + ld a, [wLinkMode] + and a + jp z, Random + +; The PRNG operates in streams of 10 values. + +; Which value are we trying to pull? + push hl + push bc + ld a, [LinkBattleRNCount] + ld c, a + ld b, 0 + ld hl, LinkBattleRNs + add hl, bc + inc a + ld [LinkBattleRNCount], a + +; If we haven't hit the end yet, we're good + cp 10 - 1 ; Exclude last value. See the closing comment + ld a, [hl] + pop bc + pop hl + ret c + +; If we have, we have to generate new pseudorandom data +; Instead of having multiple PRNGs, ten seeds are used + push hl + push bc + push af + +; Reset count to 0 + xor a + ld [LinkBattleRNCount], a + ld hl, LinkBattleRNs + ld b, 10 ; number of seeds + +; Generate next number in the sequence for each seed +; a[n+1] = (a[n] * 5 + 1) % 256 +.loop + ; get last # + ld a, [hl] + + ; a * 5 + 1 + ld c, a + add a + add a + add c + inc a + + ; update # + ld [hli], a + dec b + jr nz, .loop + +; This has the side effect of pulling the last value first, +; then wrapping around. As a result, when we check to see if +; we've reached the end, we check the one before it. + + pop af + pop bc + pop hl + ret +; 3ee0f + +Call_PlayBattleAnim_OnlyIfVisible: ; 3ee0f + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz +; 3ee17 + +Call_PlayBattleAnim: ; 3ee17 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + call WaitBGMap + predef_jump PlayBattleAnim +; 3ee27 + +FinishBattleAnim: ; 3ee27 + push af + push bc + push de + push hl + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + call DelayFrame + pop hl + pop de + pop bc + pop af + ret +; 3ee3b + +GiveExperiencePoints: ; 3ee3b +; Give experience. +; Don't give experience if linked or in the Battle Tower. + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + bit 0, a + ret nz + + call .EvenlyDivideExpAmongParticipants + xor a + ld [CurPartyMon], a + ld bc, PartyMon1Species + +.loop + ld hl, MON_HP + add hl, bc + ld a, [hli] + or [hl] + jp z, .skip_stats ; fainted + + push bc + ld hl, wBattleParticipantsNotFainted + ld a, [CurPartyMon] + ld c, a + ld b, CHECK_FLAG + ld d, $0 + predef FlagPredef + ld a, c + and a + pop bc + jp z, .skip_stats + +; give stat exp + ld hl, MON_STAT_EXP + 1 + add hl, bc + ld d, h + ld e, l + ld hl, EnemyMonBaseStats - 1 + push bc + ld c, $5 +.loop1 + inc hl + ld a, [de] + add [hl] + ld [de], a + jr nc, .okay1 + dec de + ld a, [de] + inc a + jr z, .next + ld [de], a + inc de + +.okay1 + push hl + push bc + ld a, MON_PKRUS + call GetPartyParamLocation + ld a, [hl] + and a + pop bc + pop hl + jr z, .skip + ld a, [de] + add [hl] + ld [de], a + jr nc, .skip + dec de + ld a, [de] + inc a + jr z, .next + ld [de], a + inc de + jr .skip + +.next + ld a, $ff + ld [de], a + inc de + ld [de], a + +.skip + inc de + inc de + dec c + jr nz, .loop1 + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [EnemyMonBaseExp] + ld [hMultiplicand + 2], a + ld a, [EnemyMonLevel] + ld [hMultiplier], a + call Multiply + ld a, 7 + ld [hDivisor], a + ld b, 4 + call Divide +; Boost Experience for traded Pokemon + pop bc + ld hl, MON_ID + add hl, bc + ld a, [PlayerID] + cp [hl] + jr nz, .boosted + inc hl + ld a, [PlayerID + 1] + cp [hl] + ld a, $0 + jr z, .no_boost + +.boosted + call BoostExp + ld a, $1 + +.no_boost +; Boost experience for a Trainer Battle + ld [StringBuffer2 + 2], a + ld a, [wBattleMode] + dec a + call nz, BoostExp +; Boost experience for Lucky Egg + push bc + ld a, MON_ITEM + call GetPartyParamLocation + ld a, [hl] + cp LUCKY_EGG + call z, BoostExp + ld a, [hQuotient + 2] + ld [StringBuffer2 + 1], a + ld a, [hQuotient + 1] + ld [StringBuffer2], a + ld a, [CurPartyMon] + ld hl, PartyMonNicknames + call GetNick + ld hl, Text_PkmnGainedExpPoint + call BattleTextBox + ld a, [StringBuffer2 + 1] + ld [hQuotient + 2], a + ld a, [StringBuffer2] + ld [hQuotient + 1], a + pop bc + call AnimateExpBar + push bc + call LoadTileMapToTempTileMap + pop bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + ld d, [hl] + ld a, [hQuotient + 2] + add d + ld [hld], a + ld d, [hl] + ld a, [hQuotient + 1] + adc d + ld [hl], a + jr nc, .skip2 + dec hl + inc [hl] + jr nz, .skip2 + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.skip2 + ld a, [CurPartyMon] + ld e, a + ld d, $0 + ld hl, PartySpecies + add hl, de + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + push bc + ld d, MAX_LEVEL + callfar CalcExpAtLevel + pop bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld a, [hQuotient] + ld b, a + ld a, [hQuotient + 1] + ld c, a + ld a, [hQuotient + 2] + ld d, a + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .not_max_exp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.not_max_exp + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + callfar CalcLevel + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + cp MAX_LEVEL + jp nc, .skip_stats + cp d + jp z, .skip_stats +; <NICKNAME> grew to level ##! + ld [wTempLevel], a + ld a, [CurPartyLevel] + push af + ld a, d + ld [CurPartyLevel], a + ld [hl], a + ld hl, MON_SPECIES + add hl, bc + ld a, [hl] + ld [CurSpecies], a + ld [wd265], a + call GetBaseData + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + ld e, a + ld d, [hl] + push de + ld hl, MON_MAXHP + add hl, bc + ld d, h + ld e, l + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld b, TRUE + predef CalcPkmnStats + pop bc + pop de + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + sub e + ld e, a + ld a, [hl] + sbc d + ld d, a + dec hl + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hl], a + ld a, [CurBattleMon] + ld d, a + ld a, [CurPartyMon] + cp d + jr nz, .skip_animation + ld de, BattleMonHP + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld de, BattleMonMaxHP + push bc + ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP + call CopyBytes + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [BattleMonLevel], a + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, MON_ATK + add hl, bc + ld de, PlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + +.transformed + xor a + ld [wd265], a + call ApplyStatLevelMultiplierOnAllStats + callfar ApplyStatusEffectOnPlayerStats + callfar BadgeStatBoosts + callfar UpdatePlayerHUD + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, $1 + ld [hBGMapMode], a + +.skip_animation + farcall LevelUpHappinessMod + ld a, [CurBattleMon] + ld b, a + ld a, [CurPartyMon] + cp b + jr z, .skip_animation2 + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextBox + call LoadTileMapToTempTileMap + +.skip_animation2 + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + hlcoord 9, 0 + ld b, $a + ld c, $9 + call TextBox + hlcoord 11, 1 + ld bc, 4 + predef PrintTempMonStats + ld c, $1e + call DelayFrames + call WaitPressAorB_BlinkCursor + call Call_LoadTempTileMapToTileMap + xor a ; PARTYMON + ld [MonType], a + ld a, [CurSpecies] + ld [wd265], a + ld a, [CurPartyLevel] + push af + ld c, a + ld a, [wTempLevel] + ld b, a + +.level_loop + inc b + ld a, b + ld [CurPartyLevel], a + push bc + predef LearnLevelMoves + pop bc + ld a, b + cp c + jr nz, .level_loop + pop af + ld [CurPartyLevel], a + ld hl, EvolvableFlags + ld a, [CurPartyMon] + ld c, a + ld b, SET_FLAG + predef FlagPredef + pop af + ld [CurPartyLevel], a + +.skip_stats + ld a, [PartyCount] + ld b, a + ld a, [CurPartyMon] + inc a + cp b + jr z, .done + ld [CurPartyMon], a + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + jp .loop + +.done + jp ResetBattleParticipants +; 3f0d4 + +.EvenlyDivideExpAmongParticipants: +; count number of battle participants + ld a, [wBattleParticipantsNotFainted] + ld b, a + ld c, PARTY_LENGTH + ld d, 0 +.count_loop + xor a + srl b + adc d + ld d, a + dec c + jr nz, .count_loop + cp 2 + ret c + + ld [wd265], a + ld hl, EnemyMonBaseStats + ld c, EnemyMonEnd - EnemyMonBaseStats +.count_loop2 + xor a + ld [hDividend + 0], a + ld a, [hl] + ld [hDividend + 1], a + ld a, [wd265] + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 2] + ld [hli], a + dec c + jr nz, .count_loop2 + ret +; 3f106 + +BoostExp: ; 3f106 +; Multiply experience by 1.5x + push bc +; load experience value + ld a, [hProduct + 2] + ld b, a + ld a, [hProduct + 3] + ld c, a +; halve it + srl b + rr c +; add it back to the whole exp value + add c + ld [hProduct + 3], a + ld a, [hProduct + 2] + adc b + ld [hProduct + 2], a + pop bc + ret +; 3f11b + +Text_PkmnGainedExpPoint: ; 3f11b + text_jump Text_Gained + start_asm + ld hl, TextJump_StringBuffer2ExpPoints + ld a, [StringBuffer2 + 2] ; IsTradedMon + and a + ret z + + ld hl, TextJump_ABoostedStringBuffer2ExpPoints + ret +; 3f12c + +TextJump_ABoostedStringBuffer2ExpPoints: ; 3f12c + text_jump Text_ABoostedStringBuffer2ExpPoints + db "@" +; 3f131 + +TextJump_StringBuffer2ExpPoints: ; 3f131 + text_jump Text_StringBuffer2ExpPoints + db "@" +; 3f136 + +AnimateExpBar: ; 3f136 + push bc + + ld hl, CurPartyMon + ld a, [CurBattleMon] + cp [hl] + jp nz, .finish + + ld a, [BattleMonLevel] + cp MAX_LEVEL + jp nc, .finish + + ld a, [hProduct + 3] + ld [wd004], a + push af + ld a, [hProduct + 2] + ld [wd003], a + push af + xor a + ld [wd002], a + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + ld a, [TempMonLevel] + ld b, a + ld e, a + push de + ld de, TempMonExp + 2 + call CalcExpBar + push bc + ld hl, TempMonExp + 2 + ld a, [wd004] + add [hl] + ld [hld], a + ld a, [wd003] + adc [hl] + ld [hld], a + jr nc, .NoOverflow + inc [hl] + jr nz, .NoOverflow + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.NoOverflow: + ld d, MAX_LEVEL + callfar CalcExpAtLevel + ld a, [hProduct + 1] + ld b, a + ld a, [hProduct + 2] + ld c, a + ld a, [hProduct + 3] + ld d, a + ld hl, TempMonExp + 2 + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .AlreadyAtMaxExp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.AlreadyAtMaxExp: + callfar CalcLevel + ld a, d + pop bc + pop de + ld d, a + cp e + jr nc, .LoopLevels + ld a, e + ld d, a + +.LoopLevels: + ld a, e + cp MAX_LEVEL + jr nc, .FinishExpBar + cp d + jr z, .FinishExpBar + inc a + ld [TempMonLevel], a + ld [CurPartyLevel], a + ld [BattleMonLevel], a + push de + call .PlayExpBarSound + ld c, $40 + call .LoopBarAnimation + call PrintPlayerHUD + ld hl, BattleMonNick + ld de, StringBuffer1 + ld bc, PKMN_NAME_LENGTH + call CopyBytes + call TerminateExpBarSound + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + farcall AnimateEndOfExpBar + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextBox + pop de + inc e + ld b, $0 + jr .LoopLevels + +.FinishExpBar: + push bc + ld b, d + ld de, TempMonExp + 2 + call CalcExpBar + ld a, b + pop bc + ld c, a + call .PlayExpBarSound + call .LoopBarAnimation + call TerminateExpBarSound + pop af + ld [hProduct + 2], a + pop af + ld [hProduct + 3], a + +.finish + pop bc + ret + +.PlayExpBarSound: + push bc + call WaitSFX + ld de, SFX_EXP_BAR + call PlaySFX + ld c, 10 + call DelayFrames + pop bc + ret + +.LoopBarAnimation: + ld d, 3 + dec b +.anim_loop + inc b + push bc + push de + hlcoord 17, 11 + call PlaceExpBar + pop de + ld a, $1 + ld [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ld [hBGMapMode], a + pop bc + ld a, c + cp b + jr z, .end_animation + inc b + push bc + push de + hlcoord 17, 11 + call PlaceExpBar + pop de + ld a, $1 + ld [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ld [hBGMapMode], a + dec d + jr nz, .min_number_of_frames + ld d, 1 +.min_number_of_frames + pop bc + ld a, c + cp b + jr nz, .anim_loop +.end_animation + ld a, $1 + ld [hBGMapMode], a + ret + +SendOutPkmnText: ; 3f26d + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld hl, JumpText_GoPkmn ; If we're in a LinkBattle print just "Go <PlayerMon>" + + ld a, [wBattleHasJustStarted] ; unless this (unidentified) variable is set + and a + jr nz, .skip_to_textbox + +.not_linked +; Depending on the HP of the enemy Pkmn, the game prints a different text + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + ld hl, JumpText_GoPkmn + jr z, .skip_to_textbox + + ; compute enemy helth remaining as a percentage + xor a + ld [hMultiplicand + 0], a + ld hl, EnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ld [hMultiplicand + 2], a + ld a, 25 + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ld [hDivisor], a + call Divide + + ld a, [hQuotient + 2] + ld hl, JumpText_GoPkmn + cp 70 + jr nc, .skip_to_textbox + + ld hl, JumpText_DoItPkmn + cp 40 + jr nc, .skip_to_textbox + + ld hl, JumpText_GoForItPkmn + cp 10 + jr nc, .skip_to_textbox + + ld hl, JumpText_YourFoesWeakGetmPkmn +.skip_to_textbox + jp BattleTextBox +; 3f2d1 + +JumpText_GoPkmn: ; 3f2d1 + text_jump Text_GoPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2d6 + +JumpText_DoItPkmn: ; 3f2d8 + text_jump Text_DoItPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2dd + +JumpText_GoForItPkmn: ; 3f2df + text_jump Text_GoForItPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2e4 + +JumpText_YourFoesWeakGetmPkmn: ; 3f2e6 + text_jump Text_YourFoesWeakGetmPkmn + start_asm +Function_TextJump_BattleMonNick01: ; 3f2eb + ld hl, TextJump_BattleMonNick01 + ret +; 3f2ef + +TextJump_BattleMonNick01: ; 3f2ef + text_jump Text_BattleMonNick01 + db "@" +; 3f2f4 + +WithdrawPkmnText: ; 3f2f4 + ld hl, .WithdrawPkmnText + jp BattleTextBox + +.WithdrawPkmnText: + text_jump Text_BattleMonNickComma + start_asm +; Print text to withdraw Pkmn +; depending on HP the message is different + push de + push bc + ld hl, EnemyMonHP + 1 + ld de, wEnemyHPAtTimeOfPlayerSwitch + 1 + ld b, [hl] + dec hl + ld a, [de] + sub b + ld [hMultiplicand + 2], a + dec de + ld b, [hl] + ld a, [de] + sbc b + ld [hMultiplicand + 1], a + ld a, 25 + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ld [hDivisor], a + call Divide + pop bc + pop de + ld a, [hQuotient + 2] + ld hl, TextJump_ThatsEnoughComeBack + and a + ret z + + ld hl, TextJump_ComeBack + cp 30 + ret c + + ld hl, TextJump_OKComeBack + cp 70 + ret c + + ld hl, TextJump_GoodComeBack + ret +; 3f348 + +TextJump_ThatsEnoughComeBack: ; 3f348 + text_jump Text_ThatsEnoughComeBack + db "@" +; 3f34d + +TextJump_OKComeBack: ; 3f34d + text_jump Text_OKComeBack + db "@" +; 3f352 + +TextJump_GoodComeBack: ; 3f352 + text_jump Text_GoodComeBack + db "@" +; 3f357 + +UnusedFunction_TextJump_ComeBack: ; 3f357 +; this function doesn't seem to be used + ld hl, TextJump_ComeBack + ret +; 3f35b + +TextJump_ComeBack: ; 3f35b + text_jump Text_ComeBack + db "@" +; 3f360 + +HandleSafariAngerEatingStatus: ; unreferenced + ld hl, wSafariMonEating + ld a, [hl] + and a + jr z, .angry + dec [hl] + ld hl, BattleText_WildPkmnIsEating + jr .finish + +.angry + dec hl ; wSafariMonAngerCount + ld a, [hl] + and a + ret z + dec [hl] + ld hl, BattleText_WildPkmnIsAngry + jr nz, .finish + push hl + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseCatchRate] + ld [EnemyMonCatchRate], a + pop hl + +.finish + push hl + call Call_LoadTempTileMapToTileMap + pop hl + jp StdBattleTextBox +; 3f390 + +FillInExpBar: ; 3f390 + push hl + call CalcExpBar + pop hl + ld de, 7 + add hl, de + jp PlaceExpBar +; 3f39c + +CalcExpBar: ; 3f39c +; Calculate the percent exp between this level and the next +; Level in b + push de + ld d, b + push de + callfar CalcExpAtLevel + pop de +; exp at current level gets pushed to the stack + ld hl, hMultiplicand + ld a, [hli] + push af + ld a, [hli] + push af + ld a, [hl] + push af +; next level + inc d + callfar CalcExpAtLevel +; back up the next level exp, and subtract the two levels + ld hl, hMultiplicand + 2 + ld a, [hl] + ld [hMathBuffer + 2], a + pop bc + sub b + ld [hld], a + ld a, [hl] + ld [hMathBuffer + 1], a + pop bc + sbc b + ld [hld], a + ld a, [hl] + ld [hMathBuffer], a + pop bc + sbc b + ld [hl], a + pop de + + ld hl, hMultiplicand + 1 + ld a, [hli] + push af + ld a, [hl] + push af + +; get the amount of exp remaining to the next level + ld a, [de] + dec de + ld c, a + ld a, [hMathBuffer + 2] + sub c + ld [hld], a + ld a, [de] + dec de + ld b, a + ld a, [hMathBuffer + 1] + sbc b + ld [hld], a + ld a, [de] + ld c, a + ld a, [hMathBuffer] + sbc c + ld [hld], a + xor a + ld [hl], a +; multiply by 64 + ld a, $40 + ld [hMultiplier], a + call Multiply + pop af + ld c, a + pop af + ld b, a +.loop + ld a, b + and a + jr z, .done + srl b + rr c + ld hl, hProduct + srl [hl] + inc hl + rr [hl] + inc hl + rr [hl] + inc hl + rr [hl] + jr .loop + +.done + ld a, c + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld b, a + ld a, $40 + sub b + ld b, a + ret +; 3f41c + +PlaceExpBar: ; 3f41c + ld c, $8 ; number of tiles +.loop1 + ld a, b + sub $8 + jr c, .next + ld b, a + ld a, $6a ; full bar + ld [hld], a + dec c + jr z, .finish + jr .loop1 + +.next + add $8 + jr z, .loop2 + add $54 ; tile to the left of small exp bar tile + jr .skip + +.loop2 + ld a, $62 ; empty bar + +.skip + ld [hld], a + ld a, $62 ; empty bar + dec c + jr nz, .loop2 + +.finish + ret +; 3f43d + +GetBattleMonBackpic: ; 3f43d + ld a, [PlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetBattleMonBackpic_DoAnim ; substitute + +DropPlayerSub: ; 3f447 + ld a, [wPlayerMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetBattleMonBackpic_DoAnim + ld a, [CurPartySpecies] + push af + ld a, [BattleMonSpecies] + ld [CurPartySpecies], a + ld hl, BattleMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $31 + predef GetMonBackpic + pop af + ld [CurPartySpecies], a + ret +; 3f46f + +GetBattleMonBackpic_DoAnim: ; 3f46f + ld a, [hBattleTurn] + push af + xor a + ld [hBattleTurn], a + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ld [hBattleTurn], a + ret +; 3f47c + +GetEnemyMonFrontpic: ; 3f47c + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetEnemyMonFrontpic_DoAnim + +DropEnemySub: ; 3f486 + ld a, [wEnemyMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetEnemyMonFrontpic_DoAnim + + ld a, [CurPartySpecies] + push af + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + ld hl, EnemyMonDVs + predef GetUnownLetter + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + pop af + ld [CurPartySpecies], a + ret +; 3f4b4 + +GetEnemyMonFrontpic_DoAnim: ; 3f4b4 + ld a, [hBattleTurn] + push af + call SetEnemyTurn + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ld [hBattleTurn], a + ret +; 3f4c1 + +StartBattle: ; 3f4c1 +; This check prevents you from entering a battle without any Pokemon. +; Those using walk-through-walls to bypass getting a Pokemon experience +; the effects of this check. + ld a, [PartyCount] + and a + ret z + + ld a, [TimeOfDayPal] + push af + call BattleIntro + call DoBattle + call ExitBattle + pop af + ld [TimeOfDayPal], a + scf + ret +; 3f4d9 + +_DoBattle: ; 3f4d9 +; unreferenced + call DoBattle + ret +; 3f4dd + +BattleIntro: ; 3f4dd + farcall TrainerRankings_Battles ; mobile + call LoadTrainerOrWildMonPic + xor a + ld [TempBattleMonSpecies], a + ld [wBattleMenuCursorBuffer], a + xor a + ld [hMapAnims], a + farcall PlayBattleMusic + farcall ShowLinkBattleParticipants + farcall FindFirstAliveMonAndStartBattle + call DisableSpriteUpdates + farcall ClearBattleRAM + call InitEnemy + call BackUpVBGMap2 + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + ld hl, rLCDC + res 6, [hl] + call InitBattleDisplay + call BattleStartMessage + ld hl, rLCDC + set 6, [hl] + xor a + ld [hBGMapMode], a + call EmptyBattleTextBox + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call ClearSprites + ld a, [wBattleMode] + cp WILD_BATTLE + call z, UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3f54e + +LoadTrainerOrWildMonPic: ; 3f54e + ld a, [OtherTrainerClass] + and a + jr nz, .Trainer + ld a, [TempWildMonSpecies] + ld [CurPartySpecies], a + +.Trainer: + ld [TempEnemyMonSpecies], a + ret +; 3f55e + +InitEnemy: ; 3f55e + ld a, [OtherTrainerClass] + and a + jp nz, InitEnemyTrainer ; trainer + jp InitEnemyWildmon ; wild +; 3f568 + +BackUpVBGMap2: ; 3f568 + ld a, [rSVBK] + push af + ld a, $6 ; BANK(wDecompressScratch) + ld [rSVBK], a + ld hl, wDecompressScratch + ld bc, $40 tiles ; VBGMap3 - VBGMap2 + ld a, $2 + call ByteFill + ld a, [rVBK] + push af + ld a, $1 + ld [rVBK], a + ld de, wDecompressScratch + hlbgcoord 0, 0 ; VBGMap2 + lb bc, BANK(BackUpVBGMap2), $40 + call Request2bpp + pop af + ld [rVBK], a + pop af + ld [rSVBK], a + ret +; 3f594 + +InitEnemyTrainer: ; 3f594 + ld [TrainerClass], a + farcall TrainerRankings_TrainerBattles + xor a + ld [TempEnemyMonSpecies], a + callfar GetTrainerAttributes + callfar ReadTrainerParty + + ld a, [TrainerClass] + cp RIVAL1 + jr nz, .ok + xor a + ld [OTPartyMon1Item], a +.ok + + ld de, VTiles2 + callfar GetTrainerPic + xor a + ld [hGraphicStartTile], a + dec a + ld [wEnemyItemState], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ld a, -1 + ld [CurOTMon], a + ld a, TRAINER_BATTLE + ld [wBattleMode], a + + call IsJohtoGymLeader + jr nc, .done + xor a + ld [CurPartyMon], a + ld a, [PartyCount] + ld b, a +.partyloop + push bc + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + or [hl] + jr z, .skipfaintedmon + ld c, HAPPINESS_GYMBATTLE + callfar ChangeHappiness +.skipfaintedmon + pop bc + dec b + jr z, .done + ld hl, CurPartyMon + inc [hl] + jr .partyloop +.done + ret +; 3f607 + +InitEnemyWildmon: ; 3f607 + ld a, WILD_BATTLE + ld [wBattleMode], a + farcall TrainerRankings_WildBattles + call LoadEnemyMon + ld hl, EnemyMonMoves + ld de, wWildMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld hl, EnemyMonPP + ld de, wWildMonPP + ld bc, NUM_MOVES + call CopyBytes + ld hl, EnemyMonDVs + predef GetUnownLetter + ld a, [CurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld a, [UnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + xor a + ld [TrainerClass], a + ld [hGraphicStartTile], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ret +; 3f662 + +Function3f662: ; 3f662 +; XXX + ld hl, EnemyMonMoves + ld de, wListMoves_MoveIndicesBuffer + ld b, NUM_MOVES +.loop + ld a, [de] + inc de + ld [hli], a + and a + jr z, .clearpp + + push bc + push hl + + push hl + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + pop hl + + ld bc, EnemyMonPP - (EnemyMonMoves + 1) + add hl, bc + ld [hl], a + + pop hl + pop bc + + dec b + jr nz, .loop + ret + +.clear + xor a + ld [hli], a + +.clearpp + push bc + push hl + ld bc, EnemyMonPP - (EnemyMonMoves + 1) + add hl, bc + xor a + ld [hl], a + pop hl + pop bc + dec b + jr nz, .clear + ret +; 3f69e + +ExitBattle: ; 3f69e + call .HandleEndOfBattle + call CleanUpBattleRAM + ret +; 3f6a5 + +.HandleEndOfBattle: ; 3f6a5 + ld a, [wLinkMode] + and a + jr z, .not_linked + call ShowLinkBattleParticipantsAfterEnd + ld c, 150 + call DelayFrames + call DisplayLinkBattleResult + ret + +.not_linked + ld a, [wBattleResult] + and $f + ret nz + call CheckPayDay + xor a + ld [wForceEvolution], a + predef EvolveAfterBattle + farcall GivePokerusAndConvertBerries + ret +; 3f6d0 + +CleanUpBattleRAM: ; 3f6d0 + call BattleEnd_HandleRoamMons + xor a + ld [Danger], a + ld [wBattleMode], a + ld [BattleType], a + ld [AttackMissed], a + ld [TempWildMonSpecies], a + ld [OtherTrainerClass], a + ld [wFailedToFlee], a + ld [wNumFleeAttempts], a + ld [wForcedSwitch], a + ld [wPartyMenuCursor], a + ld [wKeyItemsPocketCursor], a + ld [wItemsPocketCursor], a + ld [wBattleMenuCursorBuffer], a + ld [CurMoveNum], a + ld [wBallsPocketCursor], a + ld [wLastPocket], a + ld [wMenuScrollPosition], a + ld [wKeyItemsPocketScrollPosition], a + ld [wItemsPocketScrollPosition], a + ld [wBallsPocketScrollPosition], a + ld hl, PlayerSubStatus1 + ld b, EnemyFuryCutterCount - PlayerSubStatus1 +.loop + ld [hli], a + dec b + jr nz, .loop + call WaitSFX + ret +; 3f71d + +CheckPayDay: ; 3f71d + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + inc hl + or [hl] + ret z + ld a, [wAmuletCoin] + and a + jr z, .okay + ld hl, wPayDayMoney + 2 + sla [hl] + dec hl + rl [hl] + dec hl + rl [hl] + jr nc, .okay + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.okay + ld hl, wPayDayMoney + 2 + ld de, Money + 2 + call AddBattleMoneyToAccount + ld hl, BattleText_PlayerPickedUpPayDayMoney + call StdBattleTextBox + ld a, [InBattleTowerBattle] + bit 0, a + ret z + call ClearTileMap + call ClearBGPalettes + ret +; 3f759 + +ShowLinkBattleParticipantsAfterEnd: ; 3f759 + farcall TrainerRankings_LinkBattles + farcall BackupMobileEventIndex + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + call GetPartyLocation + ld a, [EnemyMonStatus] + ld [hl], a + call ClearTileMap + farcall _ShowLinkBattleParticipants + ret +; 3f77c + +DisplayLinkBattleResult: ; 3f77c + farcall CheckMobileBattleError + jp c, .Mobile_InvalidBattle + call IsMobileBattle2 + jr nz, .proceed + + ld hl, wcd2a + bit 4, [hl] + jr z, .proceed + + farcall DetermineLinkBattleResult + +.proceed + ld a, [wBattleResult] + and $f + cp $1 + jr c, .victory + jr z, .loss + farcall TrainerRankings_ColosseumDraws + ld de, .Draw + jr .store_result + +.victory + farcall TrainerRankings_ColosseumWins + ld de, .Win + jr .store_result + +.loss + farcall TrainerRankings_ColosseumLosses + ld de, .Lose + jr .store_result + +.store_result + hlcoord 6, 8 + call PlaceString + farcall BackupMobileEventIndex + ld c, 200 + call DelayFrames + + ld a, BANK(sLinkBattleStats) + call GetSRAMBank + + call AddLastMobileBattleToLinkRecord + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + + call IsMobileBattle2 + jr z, .mobile + call WaitPressAorB_BlinkCursor + call ClearTileMap + ret + +.mobile + ld c, 200 + call DelayFrames + call ClearTileMap + ret +; 3f7f7 + +.Win: + db "YOU WIN@" +.Lose: + db "YOU LOSE@" +.Draw: + db " DRAW@" +; 3f80f + +.Mobile_InvalidBattle: ; 3f80f + hlcoord 6, 8 + ld de, .Invalid + call PlaceString + ld c, 200 + call DelayFrames + call ClearTileMap + ret +; 3f821 + +.Invalid: + db "INVALID BATTLE@" +; 3f830 + +IsMobileBattle2: ; 3f830 + ld a, [wLinkMode] + cp LINK_MOBILE + ret +; 3f836 + +DisplayLinkRecord: ; 3f836 + ld a, BANK(sLinkBattleStats) + call GetSRAMBank + + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + hlcoord 0, 0, AttrMap + xor a + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call ByteFill + call WaitBGMap2 + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + ld c, 8 + call DelayFrames + call WaitPressAorB_BlinkCursor + ret +; 3f85f + +ReadAndPrintLinkBattleRecord: ; 3f85f + call ClearTileMap + call ClearSprites + call .PrintBattleRecord + hlcoord 0, 8 + ld b, 5 + ld de, sLinkBattleRecord + 2 +.loop + push bc + push hl + push de + ld a, [de] + and a + jr z, .PrintFormatString + ld a, [wSavedAtLeastOnce] + and a + jr z, .PrintFormatString + push hl + push hl + ld h, d + ld l, e + ld de, wd002 + ld bc, 10 + call CopyBytes + ld a, "@" + ld [de], a + inc de + ld bc, 6 + call CopyBytes + ld de, wd002 + pop hl + call PlaceString + pop hl + ld de, 26 + add hl, de + push hl + ld de, wd00d + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + push hl + ld de, wd00f + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + ld de, wd011 + lb bc, 2, 4 + call PrintNum + jr .next + +.PrintFormatString: + ld de, .Format + call PlaceString +.next + pop hl + ld bc, 18 + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .loop + ret + +.PrintBattleRecord: + hlcoord 1, 0 + ld de, .Record + call PlaceString + + hlcoord 0, 6 + ld de, .Result + call PlaceString + + hlcoord 0, 2 + ld de, .Total + call PlaceString + + hlcoord 6, 4 + ld de, sLinkBattleWins + call .PrintZerosIfNoSaveFileExists + jr c, .quit + + lb bc, 2, 4 + call PrintNum + + hlcoord 11, 4 + ld de, sLinkBattleLosses + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + + hlcoord 16, 4 + ld de, sLinkBattleDraws + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + +.quit + ret + +.PrintZerosIfNoSaveFileExists: + ld a, [wSavedAtLeastOnce] + and a + ret nz + ld de, .Scores + call PlaceString + scf + ret +; 3f938 + +.Scores: + db " 0 0 0@" +; 3f947 + +.Format: ; 3f947 + db " --- <LNBRK>" + db " - - -@" +.Record: ; 3f964 + db "<PLAYER>'s RECORD@" +.Result: ; 3f96e + db "RESULT WIN LOSE DRAW@" +.Total: ; 3f983 + db "TOTAL WIN LOSE DRAW@" +; 3f998 + +BattleEnd_HandleRoamMons: ; 3f998 + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .not_roaming + ld a, [wBattleResult] + and $f + jr z, .caught_or_defeated_roam_mon + call GetRoamMonHP + ld a, [EnemyMonHP + 1] + ld [hl], a + jr .update_roam_mons + +.caught_or_defeated_roam_mon + call GetRoamMonHP + ld [hl], $0 + call GetRoamMonMapGroup + ld [hl], $ff + call GetRoamMonMapNumber + ld [hl], $ff + call GetRoamMonSpecies + ld [hl], $0 + ret + +.not_roaming + call BattleRandom + and $f + ret nz + +.update_roam_mons + callfar UpdateRoamMons + ret +; 3f9d1 + +GetRoamMonMapGroup: ; 3f9d1 + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1MapGroup + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2MapGroup + ret z + ld hl, wRoamMon3MapGroup + ret +; 3f9e9 + +GetRoamMonMapNumber: ; 3f9e9 + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1MapNumber + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2MapNumber + ret z + ld hl, wRoamMon3MapNumber + ret +; 3fa01 + +GetRoamMonHP: ; 3fa01 +; output: hl = wRoamMonHP + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1HP + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2HP + ret z + ld hl, wRoamMon3HP + ret +; 3fa19 + +GetRoamMonDVs: ; 3fa19 +; output: hl = wRoamMonDVs + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1DVs + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2DVs + ret z + ld hl, wRoamMon3DVs + ret +; 3fa31 + +GetRoamMonSpecies: ; 3fa31 + ld a, [TempEnemyMonSpecies] + ld hl, wRoamMon1Species + cp [hl] + ret z + ld hl, wRoamMon2Species + cp [hl] + ret z + ld hl, wRoamMon3Species + ret +; 3fa42 + +AddLastMobileBattleToLinkRecord: ; 3fa42 + ld hl, OTPlayerID + ld de, StringBuffer1 + ld bc, 2 + call CopyBytes + ld hl, OTPlayerName + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld hl, sLinkBattleResults + call .StoreResult + ld hl, sLinkBattleRecord + ld d, 5 +.loop + push hl + inc hl + inc hl + ld a, [hl] + dec hl + dec hl + and a + jr z, .copy + push de + ld bc, 12 + ld de, StringBuffer1 + call CompareLong + pop de + pop hl + jr c, .done + ld bc, 18 + add hl, bc + dec d + jr nz, .loop + ld bc, -18 + add hl, bc + push hl + +.copy + ld d, h + ld e, l + ld hl, StringBuffer1 + ld bc, 12 + call CopyBytes + ld b, 6 + xor a +.loop2 + ld [de], a + inc de + dec b + jr nz, .loop2 + pop hl + +.done + call .StoreResult + call .FindOpponentAndAppendRecord + ret +; 3faa0 +.StoreResult: ; 3faa0 + ld a, [wBattleResult] + and $f + cp $1 + ld bc, sLinkBattleWins + 1 - sLinkBattleResults + jr c, .okay + ld bc, sLinkBattleLosses + 1 - sLinkBattleResults + jr z, .okay + ld bc, sLinkBattleDraws + 1 - sLinkBattleResults +.okay + add hl, bc + call .CheckOverflow + ret nc + inc [hl] + ret nz + dec hl + inc [hl] + ret +; 3fabe + +.CheckOverflow: ; 3fabe + dec hl + ld a, [hl] + inc hl + cp HIGH(MAX_LINK_RECORD) + ret c + ld a, [hl] + cp LOW(MAX_LINK_RECORD) + ret +; 3fac8 + +.FindOpponentAndAppendRecord: ; 3fac8 + ld b, 5 + ld hl, sLinkBattleRecord + 17 + ld de, wd002 +.loop3 + push bc + push de + push hl + call .LoadPointer + pop hl + ld a, e + pop de + ld [de], a + inc de + ld a, b + ld [de], a + inc de + ld a, c + ld [de], a + inc de + ld bc, 18 + add hl, bc + pop bc + dec b + jr nz, .loop3 + ld b, $0 + ld c, $1 +.loop4 + ld a, b + add b + add b + ld e, a + ld d, $0 + ld hl, wd002 + add hl, de + push hl + ld a, c + add c + add c + ld e, a + ld d, $0 + ld hl, wd002 + add hl, de + ld d, h + ld e, l + pop hl + push bc + ld c, 3 + call StringCmp + pop bc + jr z, .equal + jr nc, .done2 + +.equal + inc c + ld a, c + cp $5 + jr nz, .loop4 + inc b + ld c, b + inc c + ld a, b + cp $4 + jr nz, .loop4 + ret + +.done2 + push bc + ld a, b + ld bc, 18 + ld hl, sLinkBattleRecord + call AddNTimes + push hl + ld de, wd002 + ld bc, 18 + call CopyBytes + pop hl + pop bc + push hl + ld a, c + ld bc, 18 + ld hl, sLinkBattleRecord + call AddNTimes + pop de + push hl + ld bc, 18 + call CopyBytes + ld hl, wd002 + ld bc, 18 + pop de + call CopyBytes + ret +; 3fb54 + +.LoadPointer: ; 3fb54 + ld e, $0 + ld a, [hld] + ld c, a + ld a, [hld] + ld b, a + ld a, [hld] + add c + ld c, a + ld a, [hld] + adc b + ld b, a + jr nc, .okay2 + inc e + +.okay2 + ld a, [hld] + add c + ld c, a + ld a, [hl] + adc b + ld b, a + ret nc + inc e + ret +; 3fb6c + +InitBattleDisplay: ; 3fb6c + call .InitBackPic + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call TextBox + farcall MobileTextBorder + hlcoord 1, 5 + lb bc, 3, 7 + call ClearBox + call LoadStandardFont + call _LoadBattleFontsHPBar + call .BlankBGMap + xor a + ld [hMapAnims], a + ld [hSCY], a + ld a, $90 + ld [hWY], a + ld [rWY], a + call WaitBGMap + xor a + ld [hBGMapMode], a + farcall BattleIntroSlidingPics + ld a, $1 + ld [hBGMapMode], a + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + xor a + ld [hWY], a + ld [rWY], a + call WaitBGMap + call HideSprites + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + ld a, $90 + ld [hWY], a + xor a + ld [hSCX], a + ret +; 3fbd6 + +.BlankBGMap: ; 3fbd6 + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + + ld hl, wDecompressScratch + ld bc, wScratchAttrMap - wDecompressScratch + ld a, " " + call ByteFill + + ld de, wDecompressScratch + hlbgcoord 0, 0 + lb bc, BANK(.BlankBGMap), $40 + call Request2bpp + + pop af + ld [rSVBK], a + ret +; 3fbf8 + +.InitBackPic: ; 3fbf8 + call GetTrainerBackpic + call CopyBackpic + ret +; 3fbff + +GetTrainerBackpic: ; 3fbff +; Load the player character's backpic (6x6) into VRAM starting from VTiles2 tile $31. + +; Special exception for Dude. + ld b, BANK(DudeBackpic) + ld hl, DudeBackpic + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .Decompress + +; What gender are we? + ld a, [wPlayerSpriteSetupFlags] + bit 2, a ; transformed to male + jr nz, .Chris + ld a, [PlayerGender] + bit 0, a + jr z, .Chris + +; It's a girl. + farcall GetKrisBackpic + ret + +.Chris: +; It's a boy. + ld b, BANK(ChrisBackpic) + ld hl, ChrisBackpic + +.Decompress: + ld de, VTiles2 tile $31 + ld c, $31 + predef DecompressPredef + ret +; 3fc30 + +CopyBackpic: ; 3fc30 + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + ld hl, VTiles0 + ld de, VTiles2 tile $31 + ld a, [hROMBank] + ld b, a + ld c, $31 + call Get2bpp + pop af + ld [rSVBK], a + call .LoadTrainerBackpicAsOAM + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + ret +; 3fc5b + +.LoadTrainerBackpicAsOAM: ; 3fc5b + ld hl, Sprites + xor a + ld [hMapObjectIndexBuffer], a + ld b, $6 + ld e, 21 * 8 +.outer_loop + ld c, $3 + ld d, 8 * 8 +.inner_loop + ld [hl], d + inc hl + ld [hl], e + inc hl + ld a, [hMapObjectIndexBuffer] + ld [hli], a + inc a + ld [hMapObjectIndexBuffer], a + ld a, $1 + ld [hli], a + ld a, d + add $8 + ld d, a + dec c + jr nz, .inner_loop + ld a, [hMapObjectIndexBuffer] + add $3 + ld [hMapObjectIndexBuffer], a + ld a, e + add $8 + ld e, a + dec b + jr nz, .outer_loop + ret +; 3fc8b + +BattleStartMessage: ; 3fc8b + ld a, [wBattleMode] + dec a + jr z, .wild + + ld de, SFX_SHINE + call PlaySFX + call WaitSFX + + ld c, 20 + call DelayFrames + + farcall Battle_GetTrainerName + + ld hl, WantsToBattleText + jr .PlaceBattleStartText + +.wild + call BattleCheckEnemyShininess + jr nc, .not_shiny + + xor a + ld [wNumHits], a + ld a, 1 + ld [hBattleTurn], a + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + farcall CheckSleepingTreeMon + jr c, .skip_cry + + farcall CheckBattleScene + jr c, .cry_no_anim + + hlcoord 12, 0 + ld d, $0 + ld e, ANIM_MON_NORMAL + predef AnimateFrontpic + jr .skip_cry ; cry is played during the animation + +.cry_no_anim + ld a, $0f + ld [CryTracks], a + ld a, [TempEnemyMonSpecies] + call PlayStereoCry + +.skip_cry + ld a, [BattleType] + cp BATTLETYPE_FISH + jr nz, .NotFishing + + farcall TrainerRankings_HookedEncounters + + ld hl, HookedPokemonAttackedText + jr .PlaceBattleStartText + +.NotFishing: + ld hl, PokemonFellFromTreeText + cp BATTLETYPE_TREE + jr z, .PlaceBattleStartText + ld hl, WildCelebiAppearedText + cp BATTLETYPE_CELEBI + jr z, .PlaceBattleStartText + ld hl, WildPokemonAppearedText + +.PlaceBattleStartText: + push hl + farcall BattleStart_TrainerHuds + pop hl + call StdBattleTextBox + + call IsMobileBattle2 + ret nz + + ld c, $2 ; start + farcall Mobile_PrintOpponentBattleMessage + + ret +; 3fd26 diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm new file mode 100644 index 000000000..5922afea3 --- /dev/null +++ b/engine/battle/effect_commands.asm @@ -0,0 +1,10066 @@ +DoPlayerTurn: ; 34000 + call SetPlayerTurn + + ld a, [wPlayerAction] + and a + ret nz + + jr DoTurn + +; 3400a + + +DoEnemyTurn: ; 3400a + call SetEnemyTurn + + ld a, [wLinkMode] + and a + jr z, DoTurn + + ld a, [wBattleAction] + cp BATTLEACTION_E + jr z, DoTurn + cp BATTLEACTION_SWITCH1 + ret nc + + ; fallthrough +; 3401d + + +DoTurn: ; 3401d +; Read in and execute the user's move effects for this turn. + + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData +; 3402c + + +DoMove: ; 3402c +; Get the user's move effect. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + ld c, a + ld b, 0 + ld hl, MoveEffectsPointers + add hl, bc + add hl, bc + ld a, BANK(MoveEffectsPointers) + call GetFarHalfword + + ld de, BattleScriptBuffer + +.GetMoveEffect: + ld a, BANK(MoveEffects) + call GetFarByte + inc hl + ld [de], a + inc de + cp $ff + jr nz, .GetMoveEffect + +; Start at the first command. + ld hl, BattleScriptBuffer + ld a, l + ld [BattleScriptBufferAddress], a + ld a, h + ld [BattleScriptBufferAddress + 1], a + +.ReadMoveEffectCommand: + +; ld a, [BattleScriptBufferAddress++] + ld a, [BattleScriptBufferAddress] + ld l, a + ld a, [BattleScriptBufferAddress + 1] + ld h, a + + ld a, [hli] + + push af + ld a, l + ld [BattleScriptBufferAddress], a + ld a, h + ld [BattleScriptBufferAddress + 1], a + pop af + +; endturn_command (-2) is used to terminate branches without ending the read cycle. + cp endturn_command + ret nc + +; The rest of the commands (01-af) are read from BattleCommandPointers. + push bc + dec a + ld c, a + ld b, 0 + ld hl, BattleCommandPointers + add hl, bc + add hl, bc + pop bc + + ld a, BANK(BattleCommandPointers) + call GetFarHalfword + + call .DoMoveEffectCommand + + jr .ReadMoveEffectCommand + +.DoMoveEffectCommand: + jp hl + +; 34084 + + +CheckTurn: +BattleCommand_CheckTurn: ; 34084 +; checkturn + +; Repurposed as hardcoded turn handling. Useless as a command. + +; Move $ff immediately ends the turn. + ld a, BATTLE_VARS_MOVE + call GetBattleVar + inc a + jp z, EndTurn + + xor a + ld [AttackMissed], a + ld [EffectFailed], a + ld [wKickCounter], a + ld [AlreadyDisobeyed], a + ld [AlreadyFailed], a + ld [wSomeoneIsRampaging], a + + ld a, 10 ; 1.0 + ld [TypeModifier], a + + ld a, [hBattleTurn] + and a + jp nz, CheckEnemyTurn + + +CheckPlayerTurn: + + ld hl, PlayerSubStatus4 + bit SUBSTATUS_RECHARGE, [hl] + jr z, .no_recharge + + res SUBSTATUS_RECHARGE, [hl] + ld hl, MustRechargeText + call StdBattleTextBox + call CantMove + jp EndTurn + +.no_recharge + + + ld hl, BattleMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [BattleMonStatus], a + and SLP + jr z, .woke_up + + xor a + ld [wNumHits], a + ld de, ANIM_SLP + call FarPlayBattleAnimation + jr .fast_asleep + +.woke_up + ld hl, WokeUpText + call StdBattleTextBox + call CantMove + call UpdateBattleMonInParty + ld hl, UpdatePlayerHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld hl, PlayerSubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ld hl, FastAsleepText + call StdBattleTextBox + + ; Snore and Sleep Talk bypass sleep. + ld a, [CurPlayerMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + + call CantMove + jp EndTurn + +.not_asleep + + + ld hl, BattleMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [CurPlayerMove] + cp FLAME_WHEEL + jr z, .not_frozen + cp SACRED_FIRE + jr z, .not_frozen + + ld hl, FrozenSolidText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_frozen + + + ld hl, PlayerSubStatus3 + bit SUBSTATUS_FLINCHED, [hl] + jr z, .not_flinched + + res SUBSTATUS_FLINCHED, [hl] + ld hl, FlinchedText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_flinched + + + ld hl, PlayerDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [DisabledMove], a + ld hl, DisabledNoMoreText + call StdBattleTextBox + +.not_disabled + + + ld a, [PlayerSubStatus3] + add a + jr nc, .not_confused + ld hl, PlayerConfuseCount + dec [hl] + jr nz, .confused + + ld hl, PlayerSubStatus3 + res SUBSTATUS_CONFUSED, [hl] + ld hl, ConfusedNoMoreText + call StdBattleTextBox + jr .not_confused + +.confused + ld hl, IsConfusedText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call FarPlayBattleAnimation + + ; 50% chance of hitting itself + call BattleRandom + cp $80 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, PlayerSubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + call HitConfusion + call CantMove + jp EndTurn + +.not_confused + + + ld a, [PlayerSubStatus1] + add a ; bit SUBSTATUS_ATTRACT + jr nc, .not_infatuated + + ld hl, InLoveWithText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_IN_LOVE + call FarPlayBattleAnimation + + ; 50% chance of infatuation + call BattleRandom + cp $80 + jr c, .not_infatuated + + ld hl, InfatuationText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_infatuated + + + ; We can't disable a move that doesn't exist. + ld a, [DisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, CurPlayerMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + call CantMove + jp EndTurn + +.no_disabled_move + + + ld hl, BattleMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp $3f + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextBox + call CantMove + jp EndTurn + +; 341f0 + + +CantMove: ; 341f0 + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_ROLLOUT, [hl] + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + ld a, [hl] + and $ff ^ (1<<SUBSTATUS_BIDE + 1<<SUBSTATUS_RAMPAGE + 1<<SUBSTATUS_CHARGED) + ld [hl], a + + call ResetFuryCutterCount + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .fly_dig + + cp DIG + ret nz + +.fly_dig + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + jp AppearUserRaiseSub + +; 34216 + + + +OpponentCantMove: ; 34216 + call BattleCommand_SwitchTurn + call CantMove + jp BattleCommand_SwitchTurn + +; 3421f + + + +CheckEnemyTurn: ; 3421f + + ld hl, EnemySubStatus4 + bit SUBSTATUS_RECHARGE, [hl] + jr z, .no_recharge + + res SUBSTATUS_RECHARGE, [hl] + ld hl, MustRechargeText + call StdBattleTextBox + call CantMove + jp EndTurn + +.no_recharge + + + ld hl, EnemyMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [EnemyMonStatus], a + and a + jr z, .woke_up + + ld hl, FastAsleepText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_SLP + call FarPlayBattleAnimation + jr .fast_asleep + +.woke_up + ld hl, WokeUpText + call StdBattleTextBox + call CantMove + call UpdateEnemyMonInParty + ld hl, UpdateEnemyHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld hl, EnemySubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ; Snore and Sleep Talk bypass sleep. + ld a, [CurEnemyMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + call CantMove + jp EndTurn + +.not_asleep + + + ld hl, EnemyMonStatus + bit FRZ, [hl] + jr z, .not_frozen + ld a, [CurEnemyMove] + cp FLAME_WHEEL + jr z, .not_frozen + cp SACRED_FIRE + jr z, .not_frozen + + ld hl, FrozenSolidText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_frozen + + + ld hl, EnemySubStatus3 + bit SUBSTATUS_FLINCHED, [hl] + jr z, .not_flinched + + res SUBSTATUS_FLINCHED, [hl] + ld hl, FlinchedText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_flinched + + + ld hl, EnemyDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [EnemyDisabledMove], a + + ld hl, DisabledNoMoreText + call StdBattleTextBox + +.not_disabled + + + ld a, [EnemySubStatus3] + add a ; bit SUBSTATUS_CONFUSED + jr nc, .not_confused + + ld hl, EnemyConfuseCount + dec [hl] + jr nz, .confused + + ld hl, EnemySubStatus3 + res SUBSTATUS_CONFUSED, [hl] + ld hl, ConfusedNoMoreText + call StdBattleTextBox + jr .not_confused + + +.confused + ld hl, IsConfusedText + call StdBattleTextBox + + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call FarPlayBattleAnimation + + ; 50% chance of hitting itself + call BattleRandom + cp 1 + 50 percent + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, EnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + ld hl, HurtItselfText + call StdBattleTextBox + call HitSelfInConfusion + call BattleCommand_DamageCalc + call BattleCommand_LowerSub + xor a + ld [wNumHits], a + + ; Flicker the monster pic unless flying or underground. + ld de, ANIM_HIT_CONFUSION + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, PlayFXAnimID + + ld c, $1 + call EnemyHurtItself + call BattleCommand_RaiseSub + call CantMove + jp EndTurn + +.not_confused + + + ld a, [EnemySubStatus1] + add a ; bit SUBSTATUS_ATTRACT + jr nc, .not_infatuated + + ld hl, InLoveWithText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_IN_LOVE + call FarPlayBattleAnimation + + ; 50% chance of infatuation + call BattleRandom + cp 1 + 50 percent + jr c, .not_infatuated + + ld hl, InfatuationText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_infatuated + + + ; We can't disable a move that doesn't exist. + ld a, [EnemyDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, CurEnemyMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + + call CantMove + jp EndTurn + +.no_disabled_move + + + ld hl, EnemyMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp $3f + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextBox + call CantMove + + ; fallthrough +; 34385 + + +EndTurn: ; 34385 + ld a, $1 + ld [wTurnEnded], a + jp ResetDamage + +; 3438d + + +MoveDisabled: ; 3438d + + ; Make sure any charged moves fail + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_CHARGED, [hl] + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [wNamedObjectIndexBuffer], a + call GetMoveName + + ld hl, DisabledMoveText + jp StdBattleTextBox + +; 343a5 + + +HitConfusion: ; 343a5 + + ld hl, HurtItselfText + call StdBattleTextBox + + xor a + ld [CriticalHit], a + + call HitSelfInConfusion + call BattleCommand_DamageCalc + call BattleCommand_LowerSub + + xor a + ld [wNumHits], a + + ; Flicker the monster pic unless flying or underground. + ld de, ANIM_HIT_CONFUSION + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, PlayFXAnimID + + ld hl, UpdatePlayerHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld c, $1 + call PlayerHurtItself + jp BattleCommand_RaiseSub + +; 343db + + +BattleCommand_CheckObedience: ; 343db +; checkobedience + + ; Enemy can't disobey + ld a, [hBattleTurn] + and a + ret nz + + call CheckUserIsCharging + ret nz + + ; If we've already checked this turn + ld a, [AlreadyDisobeyed] + and a + ret nz + + xor a + ld [AlreadyDisobeyed], a + + ; No obedience in link battles + ; (since no handling exists for enemy) + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ; If the monster's id doesn't match the player's, + ; some conditions need to be met. + ld a, MON_ID + call BattlePartyAttr + + ld a, [PlayerID] + cp [hl] + jr nz, .obeylevel + inc hl + ld a, [PlayerID + 1] + cp [hl] + ret z + + +.obeylevel + ; The maximum obedience level is constrained by owned badges: + ld hl, JohtoBadges + + ; risingbadge + bit RISINGBADGE, [hl] + ld a, MAX_LEVEL + 1 + jr nz, .getlevel + + ; stormbadge + bit STORMBADGE, [hl] + ld a, 70 + jr nz, .getlevel + + ; fogbadge + bit FOGBADGE, [hl] + ld a, 50 + jr nz, .getlevel + + ; hivebadge + bit HIVEBADGE, [hl] + ld a, 30 + jr nz, .getlevel + + ; no badges + ld a, 10 + + +.getlevel +; c = obedience level +; d = monster level +; b = c + d + + ld b, a + ld c, a + + ld a, [BattleMonLevel] + ld d, a + + add b + ld b, a + +; No overflow (this should never happen) + jr nc, .checklevel + ld b, $ff + + +.checklevel +; If the monster's level is lower than the obedience level, it will obey. + ld a, c + cp d + ret nc + + +; Random number from 0 to obedience level + monster level +.rand1 + call BattleRandom + swap a + cp b + jr nc, .rand1 + +; The higher above the obedience level the monster is, +; the more likely it is to disobey. + cp c + ret c + +; Sleep-only moves have separate handling, and a higher chance of +; being ignored. Lazy monsters like their sleep. + call IgnoreSleepOnly + ret c + + +; Another random number from 0 to obedience level + monster level +.rand2 + call BattleRandom + cp b + jr nc, .rand2 + +; A second chance. + cp c + jr c, .UseInstead + + +; No hope of using a move now. + +; b = number of levels the monster is above the obedience level + ld a, d + sub c + ld b, a + +; The chance of napping is the difference out of 256. + call BattleRandom + swap a + sub b + jr c, .Nap + +; The chance of not hitting itself is the same. + cp b + jr nc, .DoNothing + + ld hl, WontObeyText + call StdBattleTextBox + call HitConfusion + jp .EndDisobedience + + +.Nap: + call BattleRandom + add a + swap a + and SLP + jr z, .Nap + + ld [BattleMonStatus], a + + ld hl, BeganToNapText + jr .Print + + +.DoNothing: + call BattleRandom + and 3 + + ld hl, LoafingAroundText + and a + jr z, .Print + + ld hl, WontObeyText + dec a + jr z, .Print + + ld hl, TurnedAwayText + dec a + jr z, .Print + + ld hl, IgnoredOrdersText + +.Print: + call StdBattleTextBox + jp .EndDisobedience + + +.UseInstead: + +; Can't use another move if the monster only has one! + ld a, [BattleMonMoves + 1] + and a + jr z, .DoNothing + +; Don't bother trying to handle Disable. + ld a, [DisabledMove] + and a + jr nz, .DoNothing + + + ld hl, BattleMonPP + ld de, BattleMonMoves + ld b, 0 + ld c, NUM_MOVES + +.GetTotalPP: + ld a, [hli] + and $3f ; exclude pp up + add b + ld b, a + + dec c + jr z, .CheckMovePP + +; Stop at undefined moves. + inc de + ld a, [de] + and a + jr nz, .GetTotalPP + + +.CheckMovePP: + ld hl, BattleMonPP + ld a, [CurMoveNum] + ld e, a + ld d, 0 + add hl, de + +; Can't use another move if only one move has PP. + ld a, [hl] + and $3f + cp b + jr z, .DoNothing + + +; Make sure we can actually use the move once we get there. + ld a, 1 + ld [AlreadyDisobeyed], a + + ld a, [w2DMenuNumRows] + ld b, a + +; Save the move we originally picked for afterward. + ld a, [CurMoveNum] + ld c, a + push af + + +.RandomMove: + call BattleRandom + and 3 ; TODO NUM_MOVES + + cp b + jr nc, .RandomMove + +; Not the move we were trying to use. + cp c + jr z, .RandomMove + +; Make sure it has PP. + ld [CurMoveNum], a + ld hl, BattleMonPP + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + and $3f + jr z, .RandomMove + + +; Use it. + ld a, [CurMoveNum] + ld c, a + ld b, 0 + ld hl, BattleMonMoves + add hl, bc + ld a, [hl] + ld [CurPlayerMove], a + + call SetPlayerTurn + call UpdateMoveData + call DoMove + + +; Restore original move choice. + pop af + ld [CurMoveNum], a + + +.EndDisobedience: + xor a + ld [LastPlayerMove], a + ld [LastPlayerCounterMove], a + + ; Break Encore too. + ld hl, PlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + xor a + ld [PlayerEncoreCount], a + + jp EndMoveEffect + +; 3451f + + +IgnoreSleepOnly: ; 3451f + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp SNORE + jr z, .CheckSleep + cp SLEEP_TALK + jr z, .CheckSleep + and a + ret + +.CheckSleep: + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret z + +; 'ignored orders…sleeping!' + ld hl, IgnoredSleepingText + call StdBattleTextBox + + call EndMoveEffect + + scf + ret + +; 34541 + + +BattleCommand_UsedMoveText: ; 34541 +; usedmovetext + farcall DisplayUsedMoveText + ret + +; 34548 + + +CheckUserIsCharging: ; 34548 + + ld a, [hBattleTurn] + and a + ld a, [wPlayerCharging] ; player + jr z, .end + ld a, [wEnemyCharging] ; enemy +.end + and a + ret + +; 34555 + + +BattleCommand_DoTurn: ; 34555 + call CheckUserIsCharging + ret nz + + ld hl, BattleMonPP + ld de, PlayerSubStatus3 + ld bc, PlayerTurnsTaken + + ld a, [hBattleTurn] + and a + jr z, .proceed + + ld hl, EnemyMonPP + ld de, EnemySubStatus3 + ld bc, EnemyTurnsTaken + +.proceed + +; If we've gotten this far, this counts as a turn. + ld a, [bc] + inc a + ld [bc], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + cp STRUGGLE + ret z + + ld a, [de] + and 1 << SUBSTATUS_IN_LOOP | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + call .consume_pp + ld a, b + and a + jp nz, EndMoveEffect + + ; SubStatus5 + inc de + inc de + + ld a, [de] + bit SUBSTATUS_TRANSFORMED, a + ret nz + + ld a, [hBattleTurn] + and a + + ld hl, PartyMon1PP + ld a, [CurBattleMon] + jr z, .player + +; mimic this part entirely if wildbattle + ld a, [wBattleMode] + dec a + jr z, .wild + + ld hl, OTPartyMon1PP + ld a, [CurOTMon] + +.player + call GetPartyLocation + push hl + call CheckMimicUsed + pop hl + ret c + +.consume_pp + ld a, [hBattleTurn] + and a + ld a, [CurMoveNum] + jr z, .okay + ld a, [CurEnemyMoveNum] + +.okay + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + jr z, .out_of_pp + dec [hl] + ld b, 0 + ret + +.wild + ld hl, EnemyMonMoves + ld a, [CurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp MIMIC + jr z, .mimic + ld hl, wWildMonMoves + add hl, bc + ld a, [hl] + cp MIMIC + ret z + +.mimic + ld hl, wWildMonPP + call .consume_pp + ret + +.out_of_pp + call BattleCommand_MoveDelay +; get move effect + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar +; continuous? + ld hl, .continuousmoves + ld de, 1 + call IsInArray + +; 'has no pp left for [move]' + ld hl, HasNoPPLeftText + jr c, .print +; 'but no pp is left for the move' + ld hl, NoPPLeftText +.print + call StdBattleTextBox + ld b, 1 + ret + +; 34602 + +.continuousmoves ; 34602 + db EFFECT_RAZOR_WIND + db EFFECT_SKY_ATTACK + db EFFECT_SKULL_BASH + db EFFECT_SOLARBEAM + db EFFECT_FLY + db EFFECT_ROLLOUT + db EFFECT_BIDE + db EFFECT_RAMPAGE + db $ff +; 3460b + +CheckMimicUsed: ; 3460b + ld a, [hBattleTurn] + and a + ld a, [CurMoveNum] + jr z, .player + ld a, [CurEnemyMoveNum] + +.player + ld c, a + ld a, MON_MOVES + call UserPartyAttr + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + cp MIMIC + jr z, .mimic +; + ld b, 0 + add hl, bc + ld a, [hl] + cp MIMIC + jr nz, .mimic + + scf + ret + +.mimic + and a + ret + +; 34631 + + +BattleCommand_Critical: ; 34631 +; critical + +; Determine whether this attack's hit will be critical. + + xor a + ld [CriticalHit], a + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + and a + ret z + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonItem + ld a, [EnemyMonSpecies] + jr nz, .Item + ld hl, BattleMonItem + ld a, [BattleMonSpecies] + +.Item: + ld c, 0 + + cp CHANSEY + jr nz, .Farfetchd + ld a, [hl] + cp LUCKY_PUNCH + jr nz, .FocusEnergy + +; +2 critical level + ld c, 2 + jr .Tally + +.Farfetchd: + cp FARFETCH_D + jr nz, .FocusEnergy + ld a, [hl] + cp STICK + jr nz, .FocusEnergy + +; +2 critical level + ld c, 2 + jr .Tally + +.FocusEnergy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_FOCUS_ENERGY, a + jr z, .CheckCritical + +; +1 critical level + inc c + +.CheckCritical: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld de, 1 + ld hl, .Criticals + push bc + call IsInArray + pop bc + jr nc, .ScopeLens + +; +2 critical level + inc c + inc c + +.ScopeLens: + push bc + call GetUserItem + ld a, b + cp HELD_CRITICAL_UP ; Increased critical chance. Only Scope Lens has this. + pop bc + jr nz, .Tally + +; +1 critical level + inc c + +.Tally: + ld hl, .Chances + ld b, 0 + add hl, bc + call BattleRandom + cp [hl] + ret nc + ld a, 1 + ld [CriticalHit], a + ret + +.Criticals: + db KARATE_CHOP, RAZOR_WIND, RAZOR_LEAF, CRABHAMMER, SLASH, AEROBLAST, CROSS_CHOP, $ff +.Chances: + ; 6.25% 12.1% 24.6% 33.2% 49.6% 49.6% 49.6% + db $11, $20, $40, $55, $80, $80, $80 + ; 0 1 2 3 4 5 6 +; 346b2 + + +BattleCommand_TripleKick: ; 346b2 +; triplekick + + ld a, [wKickCounter] + ld b, a + inc b + ld hl, CurDamage + 1 + ld a, [hld] + ld e, a + ld a, [hli] + ld d, a +.next_kick + dec b + ret z + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + +; No overflow. + jr nc, .next_kick + ld a, $ff + ld [hld], a + ld [hl], a + ret + +; 346cd + + +BattleCommand_KickCounter: ; 346cd +; kickcounter + + ld hl, wKickCounter + inc [hl] + ret + +; 346d2 + + +BattleCommand_Stab: ; 346d2 +; STAB = Same Type Attack Bonus + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp STRUGGLE + ret z + + ld hl, BattleMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemyMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + + ld a, [hBattleTurn] + and a + jr z, .go ; Who Attacks and who Defends + + ld hl, EnemyMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, BattleMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + +.go + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + ld [wTypeMatchup], a + + push hl + push de + push bc + farcall DoWeatherModifiers + pop bc + pop de + pop hl + + push de + push bc + farcall DoBadgeTypeBoosts + pop bc + pop de + + ld a, [wTypeMatchup] + cp b + jr z, .stab + cp c + jr z, .stab + + jr .SkipStab + +.stab + ld hl, CurDamage + 1 + ld a, [hld] + ld h, [hl] + ld l, a + + ld b, h + ld c, l + srl b + rr c + add hl, bc + + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + + ld hl, TypeModifier + set 7, [hl] + +.SkipStab: + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld b, a + ld hl, TypeMatchups + +.TypesLoop: + ld a, [hli] + + cp $ff + jr z, .end + + ; foresight + cp $fe + jr nz, .SkipForesightCheck + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_IDENTIFIED, a + jr nz, .end + + jr .TypesLoop + +.SkipForesightCheck: + cp b + jr nz, .SkipType + ld a, [hl] + cp d + jr z, .GotMatchup + cp e + jr z, .GotMatchup + jr .SkipType + +.GotMatchup: + push hl + push bc + inc hl + ld a, [TypeModifier] + and %10000000 + ld b, a +; If the target is immune to the move, treat it as a miss and calculate the damage as 0 + ld a, [hl] + and a + jr nz, .NotImmune + inc a + ld [AttackMissed], a + xor a +.NotImmune: + ld [hMultiplier], a + add b + ld [TypeModifier], a + + xor a + ld [hMultiplicand + 0], a + + ld hl, CurDamage + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hld] + ld [hMultiplicand + 2], a + + call Multiply + + ld a, [hProduct + 1] + ld b, a + ld a, [hProduct + 2] + or b + ld b, a + ld a, [hProduct + 3] + or b + jr z, .ok ; This is a very convoluted way to get back that we've essentially dealt no damage. + +; Take the product and divide it by 10. + ld a, 10 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + or b + jr nz, .ok + + ld a, 1 + ld [hMultiplicand + 2], a + +.ok + ld a, [hMultiplicand + 1] + ld [hli], a + ld a, [hMultiplicand + 2] + ld [hl], a + pop bc + pop hl + +.SkipType: + inc hl + inc hl + jr .TypesLoop + +.end + call BattleCheckTypeMatchup + ld a, [wTypeMatchup] + ld b, a + ld a, [TypeModifier] + and %10000000 + or b + ld [TypeModifier], a + ret + +; 347c8 + + +BattleCheckTypeMatchup: ; 347c8 + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, CheckTypeMatchup + ld hl, BattleMonType1 +CheckTypeMatchup: ; 347d3 +; There is an incorrect assumption about this function made in the AI related code: when +; the AI calls CheckTypeMatchup (not BattleCheckTypeMatchup), it assumes that placing the +; offensive type in a will make this function do the right thing. Since a is overwritten, +; this assumption is incorrect. A simple fix would be to load the move type for the +; current move into a in BattleCheckTypeMatchup, before falling through, which is +; consistent with how the rest of the code assumes this code works like. + push hl + push de + push bc + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld d, a + ld b, [hl] + inc hl + ld c, [hl] + ld a, 10 ; 1.0 + ld [wTypeMatchup], a + ld hl, TypeMatchups +.TypesLoop: + ld a, [hli] + cp $ff + jr z, .End + cp $fe + jr nz, .Next + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_IDENTIFIED, a + jr nz, .End + jr .TypesLoop + +.Next: + cp d + jr nz, .Nope + ld a, [hli] + cp b + jr z, .Yup + cp c + jr z, .Yup + jr .Nope2 + +.Nope: + inc hl +.Nope2: + inc hl + jr .TypesLoop + +.Yup: + xor a + ld [hDividend + 0], a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hli] + ld [hMultiplicand + 2], a + ld a, [wTypeMatchup] + ld [hMultiplier], a + call Multiply + ld a, 10 + ld [hDivisor], a + push bc + ld b, 4 + call Divide + pop bc + ld a, [hQuotient + 2] + ld [wTypeMatchup], a + jr .TypesLoop + +.End: + pop bc + pop de + pop hl + ret + +; 34833 + + +BattleCommand_ResetTypeMatchup: ; 34833 +; Reset the type matchup multiplier to 1.0, if the type matchup is not 0. +; If there is immunity in play, the move automatically misses. + call BattleCheckTypeMatchup + ld a, [wTypeMatchup] + and a + ld a, 10 ; 1.0 + jr nz, .reset + call ResetDamage + xor a + ld [TypeModifier], a + inc a + ld [AttackMissed], a + ret + +.reset + ld [wTypeMatchup], a + ret + +; 3484e + +INCLUDE "engine/battle/ai/switch.asm" + +INCLUDE "data/type_matchups.asm" + +BattleCommand_DamageVariation: ; 34cfd +; damagevariation + +; Modify the damage spread between 85% and 100%. + +; Because of the method of division the probability distribution +; is not consistent. This makes the highest damage multipliers +; rarer than normal. + + +; No point in reducing 1 or 0 damage. + ld hl, CurDamage + ld a, [hli] + and a + jr nz, .go + ld a, [hl] + cp 2 + ret c + +.go +; Start with the maximum damage. + xor a + ld [hMultiplicand + 0], a + dec hl + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + +; Multiply by 85-100%... +.loop + call BattleRandom + rrca + cp $d9 ; 85% + jr c, .loop + + ld [hMultiplier], a + call Multiply + +; ...divide by 100%... + ld a, $ff ; 100% + ld [hDivisor], a + ld b, $4 + call Divide + +; ...to get .85-1.00x damage. + ld a, [hQuotient + 1] + ld hl, CurDamage + ld [hli], a + ld a, [hQuotient + 2] + ld [hl], a + ret + +; 34d32 + + +BattleCommand_CheckHit: ; 34d32 +; checkhit + + call .DreamEater + jp z, .Miss + + call .Protect + jp nz, .Miss + + call .DrainSub + jp z, .Miss + + call .LockOn + ret nz + + call .FlyDigMoves + jp nz, .Miss + + call .ThunderRain + ret z + + call .XAccuracy + ret nz + + ; Perfect-accuracy moves + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ALWAYS_HIT + ret z + + call .StatModifiers + + ld a, [wPlayerMoveStruct + MOVE_ACC] + ld b, a + ld a, [hBattleTurn] + and a + jr z, .BrightPowder + ld a, [wEnemyMoveStruct + MOVE_ACC] + ld b, a + +.BrightPowder: + push bc + call GetOpponentItem + ld a, b + cp HELD_BRIGHTPOWDER + ld a, c ; % miss + pop bc + jr nz, .skip_brightpowder + + ld c, a + ld a, b + sub c + ld b, a + jr nc, .skip_brightpowder + ld b, 0 + +.skip_brightpowder + ld a, b + cp $ff + jr z, .Hit + + call BattleRandom + cp b + jr nc, .Miss + +.Hit: + ret + + +.Miss: +; Keep the damage value intact if we're using (Hi) Jump Kick. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_JUMP_KICK + jr z, .Missed + call ResetDamage + +.Missed: + ld a, 1 + ld [AttackMissed], a + ret + + +.DreamEater: +; Return z if we're trying to eat the dream of +; a monster that isn't sleeping. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_DREAM_EATER + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and SLP + ret + + +.Protect: +; Return nz if the opponent is protected. + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_PROTECT, a + ret z + + ld c, 40 + call DelayFrames + +; 'protecting itself!' + ld hl, ProtectingItselfText + call StdBattleTextBox + + ld c, 40 + call DelayFrames + + ld a, 1 + and a + ret + + +.LockOn: +; Return nz if we are locked-on and aren't trying to use Earthquake, +; Fissure or Magnitude on a monster that is flying. + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_LOCK_ON, [hl] + res SUBSTATUS_LOCK_ON, [hl] + ret z + + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + jr z, .LockedOn + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp EARTHQUAKE + ret z + cp FISSURE + ret z + cp MAGNITUDE + ret z + +.LockedOn: + ld a, 1 + and a + ret + + +.DrainSub: +; Return z if using an HP drain move on a substitute. + call CheckSubstituteOpp + jr z, .not_draining_sub + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + + cp EFFECT_LEECH_HIT + ret z + cp EFFECT_DREAM_EATER + ret z + +.not_draining_sub + ld a, 1 + and a + ret + + +.FlyDigMoves: +; Check for moves that can hit underground/flying opponents. +; Return z if the current move can hit the opponent. + + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + bit SUBSTATUS_FLYING, a + jr z, .DigMoves + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp GUST + ret z + cp WHIRLWIND + ret z + cp THUNDER + ret z + cp TWISTER + ret + +.DigMoves: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp EARTHQUAKE + ret z + cp FISSURE + ret z + cp MAGNITUDE + ret + + +.ThunderRain: +; Return z if the current move always hits in rain, and it is raining. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_THUNDER + ret nz + + ld a, [Weather] + cp WEATHER_RAIN + ret + + +.XAccuracy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_X_ACCURACY, a + ret + + +.StatModifiers: + + ld a, [hBattleTurn] + and a + + ; load the user's accuracy into b and the opponent's evasion into c. + ld hl, wPlayerMoveStruct + MOVE_ACC + ld a, [PlayerAccLevel] + ld b, a + ld a, [EnemyEvaLevel] + ld c, a + + jr z, .got_acc_eva + + ld hl, wEnemyMoveStruct + MOVE_ACC + ld a, [EnemyAccLevel] + ld b, a + ld a, [PlayerEvaLevel] + ld c, a + +.got_acc_eva + cp b + jr c, .skip_foresight_check + + ; if the target's evasion is greater than the user's accuracy, + ; check the target's foresight status + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_IDENTIFIED, a + ret nz + +.skip_foresight_check + ; subtract evasion from 14 + ld a, 14 + sub c + ld c, a + ; store the base move accuracy for math ops + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + push hl + ld d, 2 ; do this twice, once for the user's accuracy and once for the target's evasion + +.accuracy_loop + ; look up the multiplier from the table + push bc + ld hl, .AccProb + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + pop bc + ; multiply by the first byte in that row... + ld a, [hli] + ld [hMultiplier], a + call Multiply + ; ... and divide by the second byte + ld a, [hl] + ld [hDivisor], a + ld b, 4 + call Divide + ; minimum accuracy is $0001 + ld a, [hQuotient + 2] + ld b, a + ld a, [hQuotient + 1] + or b + jr nz, .min_accuracy + ld [hQuotient + 1], a + ld a, 1 + ld [hQuotient + 2], a + +.min_accuracy + ; do the same thing to the target's evasion + ld b, c + dec d + jr nz, .accuracy_loop + + ; if the result is more than 2 bytes, max out at 100% + ld a, [hQuotient + 1] + and a + ld a, [hQuotient + 2] + jr z, .finish_accuracy + ld a, $ff + +.finish_accuracy + pop hl + ld [hl], a + ret + +.AccProb: + db 33, 100 ; 33% -6 + db 36, 100 ; 36% -5 + db 43, 100 ; 43% -4 + db 50, 100 ; 50% -3 + db 60, 100 ; 60% -2 + db 75, 100 ; 75% -1 + db 1, 1 ; 100% 0 + db 133, 100 ; 133% +1 + db 166, 100 ; 166% +2 + db 2, 1 ; 200% +3 + db 233, 100 ; 233% +4 + db 133, 50 ; 266% +5 + db 3, 1 ; 300% +6 + +; 34ecc + + +BattleCommand_EffectChance: ; 34ecc +; effectchance + + xor a + ld [EffectFailed], a + call CheckSubstituteOpp + jr nz, .failed + + push hl + ld hl, wPlayerMoveStruct + MOVE_CHANCE + ld a, [hBattleTurn] + and a + jr z, .got_move_chance + ld hl, wEnemyMoveStruct + MOVE_CHANCE +.got_move_chance + + call BattleRandom + cp [hl] + pop hl + ret c + +.failed + ld a, 1 + ld [EffectFailed], a + and a + ret + +; 34eee + + +BattleCommand_LowerSub: ; 34eee +; lowersub + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret z + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_CHARGED, a + jr nz, .already_charged + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_RAZOR_WIND + jr z, .charge_turn + cp EFFECT_SKY_ATTACK + jr z, .charge_turn + cp EFFECT_SKULL_BASH + jr z, .charge_turn + cp EFFECT_SOLARBEAM + jr z, .charge_turn + cp EFFECT_FLY + jr z, .charge_turn + +.already_charged + call .Rampage + jr z, .charge_turn + + call CheckUserIsCharging + ret nz + +.charge_turn + call _CheckBattleScene + jr c, .mimic_anims + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + inc a + ld [wKickCounter], a + ld a, SUBSTITUTE + jp LoadAnim + +.mimic_anims + call BattleCommand_LowerSubNoAnim + jp BattleCommand_MoveDelay + +.Rampage: + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ROLLOUT + jr z, .rollout_rampage + cp EFFECT_RAMPAGE + jr z, .rollout_rampage + + ld a, 1 + and a + ret + +.rollout_rampage + ld a, [wSomeoneIsRampaging] + and a + ld a, 0 + ld [wSomeoneIsRampaging], a + ret + +; 34f57 + + +BattleCommand_HitTarget: ; 34f57 +; hittarget + call BattleCommand_LowerSub + call BattleCommand_HitTargetNoSub + jp BattleCommand_RaiseSub + +; 34f60 + + +BattleCommand_HitTargetNoSub: ; 34f60 + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ld a, [hBattleTurn] + and a + ld de, PlayerRolloutCount + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .got_rollout_count + ld de, EnemyRolloutCount + ld a, BATTLEANIM_PLAYER_DAMAGE + +.got_rollout_count + ld [wNumHits], a + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_MULTI_HIT + jr z, .multihit + cp EFFECT_CONVERSION + jr z, .conversion + cp EFFECT_DOUBLE_HIT + jr z, .doublehit + cp EFFECT_POISON_MULTI_HIT + jr z, .twineedle + cp EFFECT_TRIPLE_KICK + jr z, .triplekick + xor a + ld [wKickCounter], a + +.triplekick + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + call PlayFXAnimID + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .fly_dig + cp DIG + ret nz + +.fly_dig +; clear sprite + jp AppearUserLowerSub + +.multihit +.conversion +.doublehit +.twineedle + ld a, [wKickCounter] + and 1 + xor 1 + ld [wKickCounter], a + ld a, [de] + cp $1 + push af + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + pop af + jp z, PlayFXAnimID + xor a + ld [wNumHits], a + jp PlayFXAnimID + +; 34fd1 + + +BattleCommand_StatUpAnim: ; 34fd1 + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + xor a + jr BattleCommand_StatUpDownAnim + +; 34fdb + + +BattleCommand_StatDownAnim: ; 34fdb + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ld a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_STAT_DOWN + jr z, BattleCommand_StatUpDownAnim + ld a, BATTLEANIM_WOBBLE + + ; fallthrough +; 34feb + + +BattleCommand_StatUpDownAnim: ; 34feb + ld [wNumHits], a + xor a + ld [wKickCounter], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + jp PlayFXAnimID + +; 34ffd + + +BattleCommand_SwitchTurn: ; 34ffd +; switchturn + + ld a, [hBattleTurn] + xor 1 + ld [hBattleTurn], a + ret + +; 35004 + + +BattleCommand_RaiseSub: ; 35004 +; raisesub + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret z + + call _CheckBattleScene + jp c, BattleCommand_RaiseSubNoAnim + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + ld a, SUBSTITUTE + jp LoadAnim + +; 35023 + + +BattleCommand_FailureText: ; 35023 +; failuretext +; If the move missed or failed, load the appropriate +; text, and end the effects of multi-turn or multi- +; hit moves. + ld a, [AttackMissed] + and a + ret z + + call GetFailureResultText + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + + cp FLY + jr z, .fly_dig + cp DIG + jr z, .fly_dig + +; Move effect: + inc hl + ld a, [hl] + + cp EFFECT_MULTI_HIT + jr z, .multihit + cp EFFECT_DOUBLE_HIT + jr z, .multihit + cp EFFECT_POISON_MULTI_HIT + jr z, .multihit + jp EndMoveEffect + +.multihit + call BattleCommand_RaiseSub + jp EndMoveEffect + +.fly_dig + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + call AppearUserRaiseSub + jp EndMoveEffect + +; 3505e + + +BattleCommand_CheckFaint: ; 3505e +; checkfaint + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_ENDURE, a + jr z, .not_enduring + call BattleCommand_FalseSwipe + ld b, $0 + jr nc, .okay + ld b, $1 + jr .okay + +.not_enduring + call GetOpponentItem + ld a, b + cp HELD_FOCUS_BAND + ld b, $0 + jr nz, .okay + call BattleRandom + cp c + jr nc, .okay + call BattleCommand_FalseSwipe + ld b, $0 + jr nc, .okay + ld b, $2 +.okay + push bc + call .check_sub + ld c, $0 + ld a, [hBattleTurn] + and a + jr nz, .damage_player + call EnemyHurtItself + jr .done_damage + +.damage_player + call PlayerHurtItself + +.done_damage + pop bc + ld a, b + and a + ret z + dec a + jr nz, .not_enduring2 + ld hl, EnduredText + jp StdBattleTextBox + +.not_enduring2 + call GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + + ld hl, HungOnText + jp StdBattleTextBox + +.check_sub + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld de, PlayerDamageTaken + 1 + ld a, [hBattleTurn] + and a + jr nz, .damage_taken + ld de, EnemyDamageTaken + 1 + +.damage_taken + ld a, [CurDamage + 1] + ld b, a + ld a, [de] + add b + ld [de], a + dec de + ld a, [CurDamage] + ld b, a + ld a, [de] + adc b + ld [de], a + ret nc + ld a, $ff + ld [de], a + inc de + ld [de], a + ret + +; 350e4 + + +GetFailureResultText: ; 350e4 + ld hl, DoesntAffectText + ld de, DoesntAffectText + ld a, [TypeModifier] + and $7f + jr z, .got_text + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_FUTURE_SIGHT + ld hl, ButItFailedText + ld de, ItFailedText + jr z, .got_text + ld hl, AttackMissedText + ld de, AttackMissed2Text + ld a, [CriticalHit] + cp $ff + jr nz, .got_text + ld hl, UnaffectedText +.got_text + call FailText_CheckOpponentProtect + xor a + ld [CriticalHit], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_JUMP_KICK + ret nz + + ld a, [TypeModifier] + and $7f + ret z + + ld hl, CurDamage + ld a, [hli] + ld b, [hl] + rept 3 + srl a + rr b + endr + ld [hl], b + dec hl + ld [hli], a + or b + jr nz, .do_at_least_1_damage + inc a + ld [hl], a +.do_at_least_1_damage + ld hl, CrashedText + call StdBattleTextBox + ld a, $1 + ld [wKickCounter], a + call LoadMoveAnim + ld c, $1 + ld a, [hBattleTurn] + and a + jp nz, EnemyHurtItself + jp PlayerHurtItself + +FailText_CheckOpponentProtect: ; 35157 + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_PROTECT, a + jr z, .not_protected + ld h, d + ld l, e +.not_protected + jp StdBattleTextBox + +; 35165 + + +BattleCommanda5: ; 35165 + ld a, [AttackMissed] + and a + ret z + + ld a, [TypeModifier] + and $7f + jp z, PrintDoesntAffect + jp PrintButItFailed + +; 35175 + + +BattleCommand_CriticalText: ; 35175 +; criticaltext +; Prints the message for critical hits or one-hit KOs. + +; If there is no message to be printed, wait 20 frames. + ld a, [CriticalHit] + and a + jr z, .wait + + dec a + add a + ld hl, .texts + ld b, 0 + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call StdBattleTextBox + + xor a + ld [CriticalHit], a + +.wait + ld c, 20 + jp DelayFrames + +.texts + dw CriticalHitText + dw OneHitKOText +; 35197 + + +BattleCommand_StartLoop: ; 35197 +; startloop + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyRolloutCount +.ok + xor a + ld [hl], a + ret + +; 351a5 + + +BattleCommand_SuperEffectiveLoopText: ; 351a5 +; supereffectivelooptext + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, a + ret nz + + ; fallthrough +; 351ad + + +BattleCommand_SuperEffectiveText: ; 351ad +; supereffectivetext + + ld a, [TypeModifier] + and $7f + cp 10 ; 1.0 + ret z + ld hl, SuperEffectiveText + jr nc, .print + ld hl, NotVeryEffectiveText +.print + jp StdBattleTextBox + +; 351c0 + + +BattleCommand_CheckDestinyBond: ; 351c0 +; checkdestinybond + +; Faint the user if it fainted an opponent using Destiny Bond. + + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP + +.got_hp + ld a, [hli] + or [hl] + ret nz + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_DESTINY_BOND, a + jr z, .no_dbond + + ld hl, TookDownWithItText + call StdBattleTextBox + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonMaxHP + 1 + bccoord 2, 2 ; hp bar + ld a, 0 + jr nz, .got_max_hp + ld hl, BattleMonMaxHP + 1 + bccoord 10, 9 ; hp bar + ld a, 1 + +.got_max_hp + ld [wWhichHPBar], a + ld a, [hld] + ld [Buffer1], a + ld a, [hld] + ld [Buffer2], a + ld a, [hl] + ld [Buffer3], a + xor a + ld [hld], a + ld a, [hl] + ld [Buffer4], a + xor a + ld [hl], a + ld [Buffer5], a + ld [Buffer6], a + ld h, b + ld l, c + predef AnimateHPBar + call RefreshBattleHuds + + call BattleCommand_SwitchTurn + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + inc a + ld [wKickCounter], a + ld a, DESTINY_BOND + call LoadAnim + call BattleCommand_SwitchTurn + + jr .finish + +.no_dbond + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_MULTI_HIT + jr z, .multiple_hit_raise_sub + cp EFFECT_DOUBLE_HIT + jr z, .multiple_hit_raise_sub + cp EFFECT_POISON_MULTI_HIT + jr z, .multiple_hit_raise_sub + cp EFFECT_TRIPLE_KICK + jr z, .multiple_hit_raise_sub + cp EFFECT_BEAT_UP + jr nz, .finish + +.multiple_hit_raise_sub + call BattleCommand_RaiseSub + +.finish + jp EndMoveEffect + +; 35250 + + +BattleCommand_BuildOpponentRage: ; 35250 +; buildopponentrage + + jp .start + +.start + ld a, [AttackMissed] + and a + ret nz + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_RAGE, a + ret z + + ld de, wEnemyRageCounter + ld a, [hBattleTurn] + and a + jr z, .player + ld de, wPlayerRageCounter +.player + ld a, [de] + inc a + ret z + ld [de], a + + call BattleCommand_SwitchTurn + ld hl, RageBuildingText + call StdBattleTextBox + jp BattleCommand_SwitchTurn + +; 3527b + + +BattleCommand_RageDamage: ; 3527b +; ragedamage + + ld a, [CurDamage] + ld h, a + ld b, a + ld a, [CurDamage + 1] + ld l, a + ld c, a + ld a, [hBattleTurn] + and a + ld a, [wPlayerRageCounter] + jr z, .rage_loop + ld a, [wEnemyRageCounter] +.rage_loop + and a + jr z, .done + dec a + add hl, bc + jr nc, .rage_loop + ld hl, -1 +.done + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + ret + +; 352a3 + + +EndMoveEffect: ; 352a3 + ld a, [BattleScriptBufferAddress] + ld l, a + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret + +; 352b1 + + +DittoMetalPowder: ; 352b1 + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .Ditto + ld a, [TempEnemyMonSpecies] + +.Ditto: + cp DITTO + ret nz + + push bc + call GetOpponentItem + ld a, [hl] + cp METAL_POWDER + pop bc + ret nz + + ld a, c + srl a + add c + ld c, a + ret nc + + srl b + ld a, b + and a + jr nz, .done + inc b +.done + scf + rr c + ret + +; 352dc + + +BattleCommand_DamageStats: ; 352dc +; damagestats + + ld a, [hBattleTurn] + and a + jp nz, EnemyAttackDamage + + ; fallthrough +; 352e2 + + +PlayerAttackDamage: ; 352e2 +; Return move power d, player level e, enemy defense c and player attack b. + + call ResetDamage + + ld hl, wPlayerMoveStructPower + ld a, [hli] + and a + ld d, a + ret z + + ld a, [hl] + cp SPECIAL + jr nc, .special + +.physical + ld hl, EnemyMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [EnemyScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, BattleMonAttack + call GetDamageStatsCritical + jr c, .thickclub + + ld hl, EnemyDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, PlayerAttack + jr .thickclub + +.special + ld hl, EnemyMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [EnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, BattleMonSpclAtk + call GetDamageStatsCritical + jr c, .lightball + + ld hl, EnemySpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, PlayerSpAtk + +.lightball +; Note: Returns player special attack at hl in hl. + call LightBallBoost + jr .done + +.thickclub +; Note: Returns player attack at hl in hl. + call ThickClubBoost + +.done + call TruncateHL_BC + + ld a, [BattleMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +; 3534d + + +TruncateHL_BC: ; 3534d +.loop +; Truncate 16-bit values hl and bc to 8-bit values b and c respectively. +; b = hl, c = bc + + ld a, h + or b + jr z, .finish + + srl b + rr c + srl b + rr c + + ld a, c + or b + jr nz, .done_bc + inc c + +.done_bc + srl h + rr l + srl h + rr l + + ld a, l + or h + jr nz, .finish + inc l + +.finish + ld a, [wLinkMode] + cp 3 + jr z, .done +; If we go back to the loop point, +; it's the same as doing this exact +; same check twice. + ld a, h + or b + jr nz, .loop + +.done + ld b, l + ret + +; 35378 + + +GetDamageStatsCritical: ; 35378 +; Return carry if non-critical. + + ld a, [CriticalHit] + and a + scf + ret z + + ; fallthrough +; 3537e + + +GetDamageStats: ; 3537e +; Return the attacker's offensive stat and the defender's defensive +; stat based on whether the attacking type is physical or special. + + push hl + push bc + ld a, [hBattleTurn] + and a + jr nz, .enemy + ld a, [wPlayerMoveStructType] + cp SPECIAL +; special + ld a, [PlayerSAtkLevel] + ld b, a + ld a, [EnemySDefLevel] + jr nc, .end +; physical + ld a, [PlayerAtkLevel] + ld b, a + ld a, [EnemyDefLevel] + jr .end + +.enemy + ld a, [wEnemyMoveStructType] + cp SPECIAL +; special + ld a, [EnemySAtkLevel] + ld b, a + ld a, [PlayerSDefLevel] + jr nc, .end +; physical + ld a, [EnemyAtkLevel] + ld b, a + ld a, [PlayerDefLevel] +.end + cp b + pop bc + pop hl + ret + +; 353b5 + + +ThickClubBoost: ; 353b5 +; Return in hl the stat value at hl. + +; If the attacking monster is Cubone or Marowak and +; it's holding a Thick Club, double it. + push bc + push de + ld b, CUBONE + ld c, MAROWAK + ld d, THICK_CLUB + call SpeciesItemBoost + pop de + pop bc + ret + +; 353c3 + + +LightBallBoost: ; 353c3 +; Return in hl the stat value at hl. + +; If the attacking monster is Pikachu and it's +; holding a Light Ball, double it. + push bc + push de + ld b, PIKACHU + ld c, PIKACHU + ld d, LIGHT_BALL + call SpeciesItemBoost + pop de + pop bc + ret + +; 353d1 + + +SpeciesItemBoost: ; 353d1 +; Return in hl the stat value at hl. + +; If the attacking monster is species b or c and +; it's holding item d, double it. + + ld a, [hli] + ld l, [hl] + ld h, a + + push hl + ld a, MON_SPECIES + call BattlePartyAttr + + ld a, [hBattleTurn] + and a + ld a, [hl] + jr z, .CompareSpecies + ld a, [TempEnemyMonSpecies] +.CompareSpecies: + pop hl + + cp b + jr z, .GetItemHeldEffect + cp c + ret nz + +.GetItemHeldEffect: + push hl + call GetUserItem + ld a, [hl] + pop hl + cp d + ret nz + +; Double the stat + sla l + rl h + ret + +; 353f6 + + +EnemyAttackDamage: ; 353f6 + call ResetDamage + +; No damage dealt with 0 power. + ld hl, wEnemyMoveStructPower + ld a, [hli] ; hl = wEnemyMoveStructType + ld d, a + and a + ret z + + ld a, [hl] + cp SPECIAL + jr nc, .Special + +.physical + ld hl, BattleMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [PlayerScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, EnemyMonAttack + call GetDamageStatsCritical + jr c, .thickclub + + ld hl, PlayerDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemyAttack + jr .thickclub + +.Special: + ld hl, BattleMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [PlayerScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, EnemyMonSpclAtk + call GetDamageStatsCritical + jr c, .lightball + ld hl, PlayerSpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemySpAtk + +.lightball + call LightBallBoost + jr .done + +.thickclub + call ThickClubBoost + +.done + call TruncateHL_BC + + ld a, [EnemyMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +; 35461 + + +BattleCommand_BeatUp: ; 35461 +; beatup + + call ResetDamage + ld a, [hBattleTurn] + and a + jp nz, .enemy_beats_up + ld a, [PlayerSubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .next_mon + ld c, 20 + call DelayFrames + xor a + ld [PlayerRolloutCount], a + ld [wd002], a + ld [wBeatUpHitAtLeastOnce], a + jr .got_mon + +.next_mon + ld a, [PlayerRolloutCount] + ld b, a + ld a, [PartyCount] + sub b + ld [wd002], a + +.got_mon + ld a, [wd002] + ld hl, PartyMonNicknames + call GetNick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail ; fainted + ld a, [wd002] + ld c, a + ld a, [CurBattleMon] + ; BUG: this can desynchronize link battles + ; Change "cp [hl]" to "cp c" to fix + cp [hl] + ld hl, BattleMonStatus + jr z, .active_mon + ld a, MON_STATUS + call GetBeatupMonLocation +.active_mon + ld a, [hl] + and a + jp nz, .beatup_fail + + ld a, $1 + ld [wBeatUpHitAtLeastOnce], a + ld hl, BeatUpAttackText + call StdBattleTextBox + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseDefense] + ld c, a + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseAttack] + pop bc + ld b, a + push bc + ld a, MON_LEVEL + call GetBeatupMonLocation + ld a, [hl] + ld e, a + pop bc + ld a, [wPlayerMoveStructPower] + ld d, a + ret + +.enemy_beats_up + ld a, [EnemySubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .not_first_enemy_beatup + + xor a + ld [EnemyRolloutCount], a + ld [wd002], a + ld [wBeatUpHitAtLeastOnce], a + jr .enemy_continue + +.not_first_enemy_beatup + ld a, [EnemyRolloutCount] + ld b, a + ld a, [OTPartyCount] + sub b + ld [wd002], a +.enemy_continue + ld a, [wBattleMode] + dec a + jr z, .wild + + ld a, [wLinkMode] + and a + jr nz, .link_or_tower + + ld a, [InBattleTowerBattle] + and a + jr nz, .link_or_tower + + ld a, [wd002] + ld c, a + ld b, 0 + ld hl, OTPartySpecies + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + jr .got_enemy_nick + +.link_or_tower + ld a, [wd002] + ld hl, OTPartyMonNicknames + ld bc, NAME_LENGTH + call AddNTimes + ld de, StringBuffer1 + call CopyBytes +.got_enemy_nick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail + ld a, [wd002] + ld b, a + ld a, [CurOTMon] + cp b + ld hl, EnemyMonStatus + jr z, .active_enemy + + ld a, MON_STATUS + call GetBeatupMonLocation +.active_enemy + ld a, [hl] + and a + jr nz, .beatup_fail + + ld a, $1 + ld [wBeatUpHitAtLeastOnce], a + jr .finish_beatup + +.wild + ld a, [EnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BeatUpAttackText + call StdBattleTextBox + jp EnemyAttackDamage + +.finish_beatup + ld hl, BeatUpAttackText + call StdBattleTextBox + ld a, [BattleMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseDefense] + ld c, a + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseAttack] + pop bc + ld b, a + push bc + ld a, MON_LEVEL + call GetBeatupMonLocation + ld a, [hl] + ld e, a + pop bc + ld a, [wEnemyMoveStructPower] + ld d, a + ret + +; 355b0 + + +.beatup_fail ; 355b0 + ld b, buildopponentrage_command + jp SkipToBattleCommand + +; 355b5 + + +BattleCommanda8: ; 355b5 + ld a, [wBeatUpHitAtLeastOnce] + and a + ret nz + + jp PrintButItFailed + +; 355bd + + +GetBeatupMonLocation: ; 355bd + push bc + ld c, a + ld b, 0 + ld a, [hBattleTurn] + and a + ld hl, PartyMon1Species + jr z, .got_species + ld hl, OTPartyMon1Species + +.got_species + ld a, [wd002] + add hl, bc + call GetPartyLocation + pop bc + ret + + +BattleCommand_ClearMissDamage: ; 355d5 +; clearmissdamage + ld a, [AttackMissed] + and a + ret z + + jp ResetDamage + +; 355dd + + +HitSelfInConfusion: ; 355dd + call ResetDamage + ld a, [hBattleTurn] + and a + ld hl, BattleMonDefense + ld de, PlayerScreens + ld a, [BattleMonLevel] + jr z, .got_it + + ld hl, EnemyMonDefense + ld de, EnemyScreens + ld a, [EnemyMonLevel] +.got_it + push af + ld a, [hli] + ld b, a + ld c, [hl] + ld a, [de] + bit SCREENS_REFLECT, a + jr z, .mimic_screen + + sla c + rl b +.mimic_screen + dec hl + dec hl + dec hl + ld a, [hli] + ld l, [hl] + ld h, a + call TruncateHL_BC + ld d, 40 + pop af + ld e, a + ret + +; 35612 + + +BattleCommand_DamageCalc: ; 35612 +; damagecalc + +; Return a damage value for move power d, player level e, enemy defense c and player attack b. + +; Return 1 if successful, else 0. + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + +; Selfdestruct and Explosion halve defense. + cp EFFECT_SELFDESTRUCT + jr nz, .dont_selfdestruct + + srl c + jr nz, .dont_selfdestruct + inc c + +.dont_selfdestruct + +; Variable-hit moves and Conversion can have a power of 0. + cp EFFECT_MULTI_HIT + jr z, .skip_zero_damage_check + + cp EFFECT_CONVERSION + jr z, .skip_zero_damage_check + +; No damage if move power is 0. + ld a, d + and a + ret z + +.skip_zero_damage_check +; Minimum defense value is 1. + ld a, c + and a + jr nz, .not_dividing_by_zero + ld c, 1 +.not_dividing_by_zero + + xor a + ld hl, hDividend + ld [hli], a + ld [hli], a + ld [hl], a + +; Level * 2 + ld a, e + add a + jr nc, .level_not_overflowing + ld [hl], $1 +.level_not_overflowing + inc hl + ld [hli], a + +; / 5 + ld a, 5 + ld [hld], a + push bc + ld b, $4 + call Divide + pop bc + +; + 2 + inc [hl] + inc [hl] + +; * bp + inc hl + ld [hl], d + call Multiply + +; * Attack + ld [hl], b + call Multiply + +; / Defense + ld [hl], c + ld b, $4 + call Divide + +; / 50 + ld [hl], 50 + ld b, $4 + call Divide + +; Item boosts + call GetUserItem + + ld a, b + and a + jr z, .DoneItem + + ld hl, TypeBoostItems + +.NextItem: + ld a, [hli] + cp $ff + jr z, .DoneItem + +; Item effect + cp b + ld a, [hli] + jr nz, .NextItem + +; Type + ld b, a + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + cp b + jr nz, .DoneItem + +; * 100 + item effect amount + ld a, c + add 100 + ld [hMultiplier], a + call Multiply + +; / 100 + ld a, 100 + ld [hDivisor], a + ld b, 4 + call Divide +.DoneItem: + +; Critical hits + call .CriticalMultiplier + + +; Update CurDamage (capped at 997). + ld hl, CurDamage + ld b, [hl] + ld a, [hProduct + 3] + add b + ld [hProduct + 3], a + jr nc, .dont_cap_1 + + ld a, [hProduct + 2] + inc a + ld [hProduct + 2], a + and a + jr z, .Cap + +.dont_cap_1 + ld a, [hProduct] + ld b, a + ld a, [hProduct + 1] + or a + jr nz, .Cap + + ld a, [hProduct + 2] + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr c, .dont_cap_2 + + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1 + jr nc, .Cap + + ld a, [hProduct + 3] + cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr nc, .Cap + +.dont_cap_2 + inc hl + + ld a, [hProduct + 3] + ld b, [hl] + add b + ld [hld], a + + ld a, [hProduct + 2] + ld b, [hl] + adc b + ld [hl], a + jr c, .Cap + + ld a, [hl] + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr c, .dont_cap_3 + + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1 + jr nc, .Cap + + inc hl + ld a, [hld] + cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr c, .dont_cap_3 + +.Cap: + ld a, HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE) + ld [hli], a + ld a, LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE) + ld [hld], a + + +.dont_cap_3 +; Minimum neutral damage is 2 (bringing the cap to 999). + inc hl + ld a, [hl] + add MIN_NEUTRAL_DAMAGE + ld [hld], a + jr nc, .dont_floor + inc [hl] +.dont_floor + + ld a, 1 + and a + ret + + +.CriticalMultiplier: + ld a, [CriticalHit] + and a + ret z + +; x2 + ld a, [hQuotient + 2] + add a + ld [hProduct + 3], a + + ld a, [hQuotient + 1] + rl a + ld [hProduct + 2], a + +; Cap at $ffff. + ret nc + + ld a, $ff + ld [hProduct + 2], a + ld [hProduct + 3], a + + ret + +; 35703 + + +TypeBoostItems: ; 35703 + db HELD_NORMAL_BOOST, NORMAL ; Pink/Polkadot Bow + db HELD_FIGHTING_BOOST, FIGHTING ; Blackbelt + db HELD_FLYING_BOOST, FLYING ; Sharp Beak + db HELD_POISON_BOOST, POISON ; Poison Barb + db HELD_GROUND_BOOST, GROUND ; Soft Sand + db HELD_ROCK_BOOST, ROCK ; Hard Stone + db HELD_BUG_BOOST, BUG ; Silverpowder + db HELD_GHOST_BOOST, GHOST ; Spell Tag + db HELD_FIRE_BOOST, FIRE ; Charcoal + db HELD_WATER_BOOST, WATER ; Mystic Water + db HELD_GRASS_BOOST, GRASS ; Miracle Seed + db HELD_ELECTRIC_BOOST, ELECTRIC ; Magnet + db HELD_PSYCHIC_BOOST, PSYCHIC ; Twistedspoon + db HELD_ICE_BOOST, ICE ; Nevermeltice + db HELD_DRAGON_BOOST, DRAGON ; Dragon Scale + db HELD_DARK_BOOST, DARK ; Blackglasses + db HELD_STEEL_BOOST, STEEL ; Metal Coat + db $ff +; 35726 + + +BattleCommand_ConstantDamage: ; 35726 +; constantdamage + + ld hl, BattleMonLevel + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, EnemyMonLevel + +.got_turn + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_LEVEL_DAMAGE + ld b, [hl] + ld a, 0 + jr z, .got_power + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_PSYWAVE + jr z, .psywave + + cp EFFECT_SUPER_FANG + jr z, .super_fang + + cp EFFECT_REVERSAL + jr z, .reversal + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + ld b, a + ld a, $0 + jr .got_power + +.psywave + ld a, b + srl a + add b + ld b, a +.psywave_loop + call BattleRandom + and a + jr z, .psywave_loop + cp b + jr nc, .psywave_loop + ld b, a + ld a, $0 + jr .got_power + +.super_fang + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP +.got_hp + ld a, [hli] + srl a + ld b, a + ld a, [hl] + rr a + push af + ld a, b + pop bc + and a + jr nz, .got_power + or b + ld a, $0 + jr nz, .got_power + ld b, $1 + jr .got_power + +.got_power + ld hl, CurDamage + ld [hli], a + ld [hl], b + ret + +.reversal + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .reversal_got_hp + ld hl, EnemyMonHP +.reversal_got_hp + xor a + ld [hDividend], a + ld [hMultiplicand + 0], a + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hli] + ld [hMultiplicand + 2], a + ld a, $30 + ld [hMultiplier], a + call Multiply + ld a, [hli] + ld b, a + ld a, [hl] + ld [hDivisor], a + ld a, b + and a + jr z, .skip_to_divide + + ld a, [hProduct + 4] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld a, [hProduct + 2] + ld b, a + srl b + ld a, [hProduct + 3] + rr a + srl b + rr a + ld [hDividend + 3], a + ld a, b + ld [hDividend + 2], a + +.skip_to_divide + ld b, $4 + call Divide + ld a, [hQuotient + 2] + ld b, a + ld hl, .FlailPower + +.reversal_loop + ld a, [hli] + cp b + jr nc, .break_loop + inc hl + jr .reversal_loop + +.break_loop + ld a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .notPlayersTurn + + ld hl, wPlayerMoveStructPower + ld [hl], a + push hl + call PlayerAttackDamage + jr .notEnemysTurn + +.notPlayersTurn + ld hl, wEnemyMoveStructPower + ld [hl], a + push hl + call EnemyAttackDamage + +.notEnemysTurn + call BattleCommand_DamageCalc + pop hl + ld [hl], 1 + ret + +.FlailPower: + ; px, bp + db 1, 200 + db 4, 150 + db 9, 100 + db 16, 80 + db 32, 40 + db 48, 20 +; 35813 + + +BattleCommand_Counter: ; 35813 +; counter + + ld a, 1 + ld [AttackMissed], a + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + ret z + + ld b, a + callfar GetMoveEffect + ld a, b + cp EFFECT_COUNTER + ret z + + call BattleCommand_ResetTypeMatchup + ld a, [wTypeMatchup] + and a + ret z + + call CheckOpponentWentFirst + ret z + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + dec a + ld de, StringBuffer1 + call GetMoveData + + ld a, [StringBuffer1 + MOVE_POWER] + and a + ret z + + ld a, [StringBuffer1 + MOVE_TYPE] + cp SPECIAL + ret nc + + ld hl, CurDamage + ld a, [hli] + or [hl] + ret z + + ld a, [hl] + add a + ld [hld], a + ld a, [hl] + adc a + ld [hl], a + jr nc, .capped + ld a, $ff + ld [hli], a + ld [hl], a +.capped + + xor a + ld [AttackMissed], a + ret + +; 35864 + + +BattleCommand_Encore: ; 35864 +; encore + + ld hl, EnemyMonMoves + ld de, EnemyEncoreCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonMoves + ld de, PlayerEncoreCount +.ok + ld a, BATTLE_VARS_LAST_MOVE_OPP + call GetBattleVar + and a + jp z, .failed + cp STRUGGLE + jp z, .failed + cp ENCORE + jp z, .failed + cp MIRROR_MOVE + jp z, .failed + ld b, a + +.got_move + ld a, [hli] + cp b + jr nz, .got_move + + ld bc, BattleMonPP - BattleMonMoves - 1 + add hl, bc + ld a, [hl] + and $3f + jp z, .failed + ld a, [AttackMissed] + and a + jp nz, .failed + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_ENCORED, [hl] + jp nz, .failed + set SUBSTATUS_ENCORED, [hl] + call BattleRandom + and $3 + inc a + inc a + inc a + ld [de], a + call CheckOpponentWentFirst + jr nz, .finish_move + ld a, [hBattleTurn] + and a + jr z, .force_last_enemy_move + + push hl + ld a, [LastPlayerMove] + ld b, a + ld c, 0 + ld hl, BattleMonMoves +.find_player_move + ld a, [hli] + cp b + jr z, .got_player_move + inc c + ld a, c + cp NUM_MOVES + jr c, .find_player_move + pop hl + res SUBSTATUS_ENCORED, [hl] + xor a + ld [de], a + jr .failed + +.got_player_move + pop hl + ld a, c + ld [CurMoveNum], a + ld a, b + ld [CurPlayerMove], a + dec a + ld de, wPlayerMoveStruct + call GetMoveData + jr .finish_move + +.force_last_enemy_move + push hl + ld a, [LastEnemyMove] + ld b, a + ld c, 0 + ld hl, EnemyMonMoves +.find_enemy_move + ld a, [hli] + cp b + jr z, .got_enemy_move + inc c + ld a, c + cp NUM_MOVES + jr c, .find_enemy_move + pop hl + res SUBSTATUS_ENCORED, [hl] + xor a + ld [de], a + jr .failed + +.got_enemy_move + pop hl + ld a, c + ld [CurEnemyMoveNum], a + ld a, b + ld [CurEnemyMove], a + dec a + ld de, wEnemyMoveStruct + call GetMoveData + +.finish_move + call AnimateCurrentMove + ld hl, GotAnEncoreText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +; 35926 + + +BattleCommand_PainSplit: ; 35926 +; painsplit + + ld a, [AttackMissed] + and a + jp nz, .ButItFailed + call CheckSubstituteOpp + jp nz, .ButItFailed + call AnimateCurrentMove + ld hl, BattleMonMaxHP + 1 + ld de, EnemyMonMaxHP + 1 + call .PlayerShareHP + ld a, $1 + ld [wWhichHPBar], a + hlcoord 10, 9 + predef AnimateHPBar + ld hl, EnemyMonHP + ld a, [hli] + ld [Buffer4], a + ld a, [hli] + ld [Buffer3], a + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + call .EnemyShareHP + xor a + ld [wWhichHPBar], a + call ResetDamage + hlcoord 2, 2 + predef AnimateHPBar + farcall _UpdateBattleHUDs + + ld hl, SharedPainText + jp StdBattleTextBox + +.PlayerShareHP: + ld a, [hld] + ld [Buffer1], a + ld a, [hld] + ld [Buffer2], a + ld a, [hld] + ld b, a + ld [Buffer3], a + ld a, [hl] + ld [Buffer4], a + dec de + dec de + ld a, [de] + dec de + add b + ld [CurDamage + 1], a + ld b, [hl] + ld a, [de] + adc b + srl a + ld [CurDamage], a + ld a, [CurDamage + 1] + rr a + ld [CurDamage + 1], a + inc hl + inc hl + inc hl + inc de + inc de + inc de + +.EnemyShareHP: ; 359ac + ld c, [hl] + dec hl + ld a, [CurDamage + 1] + sub c + ld b, [hl] + dec hl + ld a, [CurDamage] + sbc b + jr nc, .skip + + ld a, [CurDamage] + ld b, a + ld a, [CurDamage + 1] + ld c, a +.skip + ld a, c + ld [hld], a + ld [Buffer5], a + ld a, b + ld [hli], a + ld [Buffer6], a + ret + +; 359cd + +.ButItFailed: + jp PrintDidntAffect2 + +; 359d0 + + +BattleCommand_Snore: ; 359d0 +; snore + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + call ResetDamage + ld a, $1 + ld [AttackMissed], a + call FailSnore + jp EndMoveEffect + +; 359e6 + + +BattleCommand_Conversion2: ; 359e6 +; conversion2 + + ld a, [AttackMissed] + and a + jr nz, .failed + ld hl, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .got_type + ld hl, EnemyMonType1 +.got_type + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + push hl + dec a + ld hl, Moves + MOVE_TYPE + call GetMoveAttr + ld d, a + pop hl + cp CURSE_T + jr z, .failed + call AnimateCurrentMove + call BattleCommand_SwitchTurn + +.loop + call BattleRandom + and $1f + cp UNUSED_TYPES + jr c, .okay + cp UNUSED_TYPES_END + jr c, .loop + cp TYPES_END + jr nc, .loop +.okay + ld [hli], a + ld [hld], a + push hl + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + push af + push hl + ld a, d + ld [hl], a + call BattleCheckTypeMatchup + pop hl + pop af + ld [hl], a + pop hl + ld a, [wTypeMatchup] + cp 10 + jr nc, .loop + call BattleCommand_SwitchTurn + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + predef GetTypeName + ld hl, TransformedTypeText + jp StdBattleTextBox + +.failed + jp FailConversion2 + +; 35a53 + + +BattleCommand_LockOn: ; 35a53 +; lockon + + call CheckSubstituteOpp + jr nz, .fail + + ld a, [AttackMissed] + and a + jr nz, .fail + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + set SUBSTATUS_LOCK_ON, [hl] + call AnimateCurrentMove + + ld hl, TookAimText + jp StdBattleTextBox + +.fail + call AnimateFailedMove + jp PrintDidntAffect + +; 35a74 + + +BattleCommand_Sketch: ; 35a74 +; sketch + + call ClearLastMove +; Don't sketch during a link battle + ld a, [wLinkMode] + and a + jr z, .not_linked + call AnimateFailedMove + jp PrintNothingHappened + +.not_linked +; If the opponent has a substitute up, fail. + call CheckSubstituteOpp + jp nz, .fail +; If the opponent is transformed, fail. + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_TRANSFORMED, [hl] + jp nz, .fail +; Get the user's moveset in its party struct. +; This move replacement shall be permanent. +; Pointer will be in de. + ld a, MON_MOVES + call UserPartyAttr + ld d, h + ld e, l +; Get the battle move structs. + ld hl, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .get_last_move + ld hl, EnemyMonMoves +.get_last_move + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [wTypeMatchup], a + ld b, a +; Fail if move is invalid or is Struggle. + and a + jr z, .fail + cp STRUGGLE + jr z, .fail +; Fail if user already knows that move + ld c, NUM_MOVES +.does_user_already_know_move + ld a, [hli] + cp b + jr z, .fail + dec c + jr nz, .does_user_already_know_move +; Find Sketch in the user's moveset. +; Pointer in hl, and index in c. + dec hl + ld c, NUM_MOVES +.find_sketch + dec c + ld a, [hld] + cp SKETCH + jr nz, .find_sketch + inc hl +; The Sketched move is loaded to that slot. + ld a, b + ld [hl], a +; Copy the base PP from that move. + push bc + push hl + dec a + ld hl, Moves + MOVE_PP + call GetMoveAttr + pop hl + ld bc, BattleMonPP - BattleMonMoves + add hl, bc + ld [hl], a + pop bc + + ld a, [hBattleTurn] + and a + jr z, .user_trainer + ld a, [wBattleMode] + dec a + jr nz, .user_trainer +; wildmon + ld a, [hl] + push bc + ld hl, wWildMonPP + ld b, 0 + add hl, bc + ld [hl], a + ld hl, wWildMonMoves + add hl, bc + pop bc + ld [hl], b + jr .done_copy + +.user_trainer + ld a, [hl] + push af + ld l, c + ld h, 0 + add hl, de + ld a, b + ld [hl], a + pop af + ld de, MON_PP - MON_MOVES + add hl, de + ld [hl], a +.done_copy + call GetMoveName + call AnimateCurrentMove + + ld hl, SketchedText + jp StdBattleTextBox + +.fail + call AnimateFailedMove + jp PrintDidntAffect + +; 35b16 + + +BattleCommand_DefrostOpponent: ; 35b16 +; defrostopponent +; Thaw the opponent if frozen, and +; raise the user's Attack one stage. + + call AnimateCurrentMove + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + call Defrost + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld a, [hl] + push hl + push af + + ld a, EFFECT_ATTACK_UP + ld [hl], a + call BattleCommand_StatUp + + pop af + pop hl + ld [hl], a + ret + +; 35b33 + + +BattleCommand_SleepTalk: ; 35b33 +; sleeptalk + + call ClearLastMove + ld a, [AttackMissed] + and a + jr nz, .fail + ld a, [hBattleTurn] + and a + ld hl, BattleMonMoves + 1 + ld a, [DisabledMove] + ld d, a + jr z, .got_moves + ld hl, EnemyMonMoves + 1 + ld a, [EnemyDisabledMove] + ld d, a +.got_moves + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr z, .fail + ld a, [hl] + and a + jr z, .fail + call .safely_check_has_usable_move + jr c, .fail + dec hl +.sample_move + push hl + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .sample_move + ld e, a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp e + jr z, .sample_move + ld a, e + cp d + jr z, .sample_move + call .check_two_turn_move + jr z, .sample_move + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, e + ld [hl], a + call CheckUserIsCharging + jr nz, .charging + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a +.charging + call LoadMoveAnim + call UpdateMoveData + jp ResetTurn + +.fail + call AnimateFailedMove + jp TryPrintButItFailed + +.safely_check_has_usable_move + push hl + push de + push bc + call .check_has_usable_move + pop bc + pop de + pop hl + ret + +.check_has_usable_move + ld a, [hBattleTurn] + and a + ld a, [DisabledMove] + jr z, .got_move_2 + + ld a, [EnemyDisabledMove] +.got_move_2 + ld b, a + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld c, a + dec hl + ld d, NUM_MOVES +.loop2 + ld a, [hl] + and a + jr z, .carry + + cp c + jr z, .nope + cp b + jr z, .nope + + call .check_two_turn_move + jr nz, .no_carry + +.nope + inc hl + dec d + jr nz, .loop2 + +.carry + scf + ret + +.no_carry + and a + ret + +.check_two_turn_move + push hl + push de + push bc + + ld b, a + callfar GetMoveEffect + ld a, b + + pop bc + pop de + pop hl + + cp EFFECT_SKULL_BASH + ret z + cp EFFECT_RAZOR_WIND + ret z + cp EFFECT_SKY_ATTACK + ret z + cp EFFECT_SOLARBEAM + ret z + cp EFFECT_FLY + ret z + cp EFFECT_BIDE + ret + +; 35bff + + +BattleCommand_DestinyBond: ; 35bff +; destinybond + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_DESTINY_BOND, [hl] + call AnimateCurrentMove + ld hl, DestinyBondEffectText + jp StdBattleTextBox + +; 35c0f + + +BattleCommand_Spite: ; 35c0f +; spite + + ld a, [AttackMissed] + and a + jp nz, .failed + ld bc, PARTYMON_STRUCT_LENGTH ; ???? + ld hl, EnemyMonMoves + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, BattleMonMoves +.got_moves + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + cp STRUGGLE + jr z, .failed + ld b, a + ld c, -1 +.loop + inc c + ld a, [hli] + cp b + jr nz, .loop + ld [wTypeMatchup], a + dec hl + ld b, 0 + push bc + ld c, BattleMonPP - BattleMonMoves + add hl, bc + pop bc + ld a, [hl] + and $3f + jr z, .failed + push bc + call GetMoveName + call BattleRandom + and 3 + inc a + inc a + ld b, a + ld a, [hl] + and $3f + cp b + jr nc, .deplete_pp + ld b, a +.deplete_pp + ld a, [hl] + sub b + ld [hl], a + push af + ld a, MON_PP + call OpponentPartyAttr + ld d, b + pop af + pop bc + add hl, bc + ld e, a + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld a, [hBattleTurn] + and a + jr nz, .not_wildmon + ld a, [wBattleMode] + dec a + jr nz, .not_wildmon + ld hl, wWildMonPP + add hl, bc +.not_wildmon + ld [hl], e +.transformed + push de + call AnimateCurrentMove + pop de + ld a, d + ld [wTypeMatchup], a + ld hl, SpiteEffectText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +; 35c94 + + +BattleCommand_FalseSwipe: ; 35c94 +; falseswipe + + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP +.got_hp + ld de, CurDamage + ld c, 2 + push hl + push de + call StringCmp + pop de + pop hl + jr c, .done + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + dec a + ld [de], a + inc a + jr nz, .okay + dec de + ld a, [de] + dec a + ld [de], a +.okay + ld a, [CriticalHit] + cp $2 + jr nz, .carry + xor a + ld [CriticalHit], a +.carry + scf + ret + +.done + and a + ret + +; 35cc9 + + +BattleCommand_HealBell: ; 35cc9 +; healbell + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] + ld de, PartyMon1Status + ld a, [hBattleTurn] + and a + jr z, .got_status + ld de, OTPartyMon1Status +.got_status + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + xor a + ld [hl], a + ld h, d + ld l, e + ld bc, PARTYMON_STRUCT_LENGTH + ld d, PARTY_LENGTH +.loop + ld [hl], a + add hl, bc + dec d + jr nz, .loop + call AnimateCurrentMove + + ld hl, BellChimedText + call StdBattleTextBox + + ld a, [hBattleTurn] + and a + jp z, CalcPlayerStats + jp CalcEnemyStats + +; 35d00 + + +FarPlayBattleAnimation: ; 35d00 +; play animation de + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz + + ; fallthrough +; 35d08 + +PlayFXAnimID: ; 35d08 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + + ld c, 3 + call DelayFrames + + callfar PlayBattleAnim + + ret + +; 35d1c + + +EnemyHurtItself: ; 35d1c + ld hl, CurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .mimic_sub_check + + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, SelfInflictDamageToSubstitute + +.mimic_sub_check + ld a, [hld] + ld b, a + ld a, [EnemyMonHP + 1] + ld [Buffer3], a + sub b + ld [EnemyMonHP + 1], a + ld a, [hl] + ld b, a + ld a, [EnemyMonHP] + ld [Buffer4], a + sbc b + ld [EnemyMonHP], a + jr nc, .mimic_faint + + ld a, [Buffer4] + ld [hli], a + ld a, [Buffer3] + ld [hl], a + + xor a + ld hl, EnemyMonHP + ld [hli], a + ld [hl], a + +.mimic_faint + ld hl, EnemyMonMaxHP + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ld hl, EnemyMonHP + ld a, [hli] + ld [Buffer6], a + ld a, [hl] + ld [Buffer5], a + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +; 35d7e + + +PlayerHurtItself: ; 35d7e + ld hl, CurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .mimic_sub_check + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, SelfInflictDamageToSubstitute +.mimic_sub_check + ld a, [hld] + ld b, a + ld a, [BattleMonHP + 1] + ld [Buffer3], a + sub b + ld [BattleMonHP + 1], a + ld [Buffer5], a + ld b, [hl] + ld a, [BattleMonHP] + ld [Buffer4], a + sbc b + ld [BattleMonHP], a + ld [Buffer6], a + jr nc, .mimic_faint + + ld a, [Buffer4] + ld [hli], a + ld a, [Buffer3] + ld [hl], a + xor a + + ld hl, BattleMonHP + ld [hli], a + ld [hl], a + ld hl, Buffer5 + ld [hli], a + ld [hl], a + +.mimic_faint + ld hl, BattleMonMaxHP + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + hlcoord 10, 9 + ld a, $1 + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +; 35de0 + + +SelfInflictDamageToSubstitute: ; 35de0 + + ld hl, SubTookDamageText + call StdBattleTextBox + + ld de, EnemySubstituteHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld de, PlayerSubstituteHP +.got_hp + + ld hl, CurDamage + ld a, [hli] + and a + jr nz, .broke + + ld a, [de] + sub [hl] + ld [de], a + jr z, .broke + jr nc, .done + +.broke + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_SUBSTITUTE, [hl] + + ld hl, SubFadedText + call StdBattleTextBox + + call BattleCommand_SwitchTurn + call BattleCommand_LowerSubNoAnim + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, AppearUserLowerSub + call BattleCommand_SwitchTurn + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + cp EFFECT_MULTI_HIT + jr z, .ok + cp EFFECT_DOUBLE_HIT + jr z, .ok + cp EFFECT_POISON_MULTI_HIT + jr z, .ok + cp EFFECT_TRIPLE_KICK + jr z, .ok + cp EFFECT_BEAT_UP + jr z, .ok + xor a + ld [hl], a +.ok + call RefreshBattleHuds +.done + jp ResetDamage + +; 35e40 + + +UpdateMoveData: ; 35e40 + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [CurMove], a + ld [wNamedObjectIndexBuffer], a + + dec a + call GetMoveData + call GetMoveName + jp CopyName1 + +; 35e5c + + +BattleCommand_SleepTarget: ; 35e5c +; sleeptarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_SLEEP + jr nz, .not_protected_by_item + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, ProtectedByText + jr .fail + +.not_protected_by_item + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + ld d, h + ld e, l + ld a, [de] + and SLP + ld hl, AlreadyAsleepText + jr nz, .fail + + ld a, [AttackMissed] + and a + jp nz, PrintDidntAffect2 + + ld hl, DidntAffect1Text + call .CheckAIRandomFail + jr c, .fail + + ld a, [de] + and a + jr nz, .fail + + call CheckSubstituteOpp + jr nz, .fail + + call AnimateCurrentMove + ld b, $7 + ld a, [InBattleTowerBattle] + and a + jr z, .random_loop + ld b, $3 + +.random_loop + call BattleRandom + and b + jr z, .random_loop + cp 7 + jr z, .random_loop + inc a + ld [de], a + call UpdateOpponentInParty + call RefreshBattleHuds + + ld hl, FellAsleepText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + + jp z, OpponentCantMove + ret + +.fail + push hl + call AnimateFailedMove + pop hl + jp StdBattleTextBox + +; 35ece + + +.CheckAIRandomFail: ; 35ece + ; Enemy turn + ld a, [hBattleTurn] + and a + jr z, .dont_fail + + ; Not in link battle + ld a, [wLinkMode] + and a + jr nz, .dont_fail + + ld a, [InBattleTowerBattle] + and a + jr nz, .dont_fail + + ; Not locked-on by the enemy + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_fail + + call BattleRandom + cp $40 ; 25% + ret c + +.dont_fail + xor a + ret + +; 35eee + + +BattleCommand_PoisonTarget: ; 35eee +; poisontarget + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + call CheckIfTargetIsPoisonType + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + + call PoisonOpponent + ld de, ANIM_PSN + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasPoisonedText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret + +; 35f2c + + +BattleCommand_Poison: ; 35f2c +; poison + + ld hl, DoesntAffectText + ld a, [TypeModifier] + and $7f + jp z, .failed + + call CheckIfTargetIsPoisonType + jp z, .failed + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + ld b, a + ld hl, AlreadyPoisonedText + and 1 << PSN + jp nz, .failed + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + jr nz, .do_poison + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, ProtectedByText + jr .failed + +.do_poison + ld hl, DidntAffect1Text + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and a + jr nz, .failed + + ld a, [hBattleTurn] + and a + jr z, .mimic_random + + ld a, [wLinkMode] + and a + jr nz, .mimic_random + + ld a, [InBattleTowerBattle] + and a + jr nz, .mimic_random + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .mimic_random + + call BattleRandom + cp $40 ; 25% chance AI fails + jr c, .failed + +.mimic_random + call CheckSubstituteOpp + jr nz, .failed + ld a, [AttackMissed] + and a + jr nz, .failed + call .check_toxic + jr z, .toxic + + call .apply_poison + ld hl, WasPoisonedText + call StdBattleTextBox + jr .finished + +.toxic + set SUBSTATUS_TOXIC, [hl] + xor a + ld [de], a + call .apply_poison + + ld hl, BadlyPoisonedText + call StdBattleTextBox + +.finished + farcall UseHeldStatusHealingItem + ret + +.failed + push hl + call AnimateFailedMove + pop hl + jp StdBattleTextBox + +; 35fc0 + + +.apply_poison ; 35fc0 + call AnimateCurrentMove + call PoisonOpponent + jp RefreshBattleHuds + +; 35fc9 + + +.check_toxic ; 35fc9 + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + ld a, [hBattleTurn] + and a + ld de, EnemyToxicCount + jr z, .ok + ld de, PlayerToxicCount +.ok + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_TOXIC + ret + +; 35fe1 + + +CheckIfTargetIsPoisonType: ; 35fe1 + ld de, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, BattleMonType1 +.ok + ld a, [de] + inc de + cp POISON + ret z + ld a, [de] + cp POISON + ret + +; 35ff5 + + +PoisonOpponent: ; 35ff5 + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PSN, [hl] + jp UpdateOpponentInParty + +; 35fff + + +BattleCommand_DrainTarget: ; 35fff +; draintarget + call SapHealth + ld hl, SuckedHealthText + jp StdBattleTextBox + +; 36008 + + +BattleCommand_EatDream: ; 36008 +; eatdream + call SapHealth + ld hl, DreamEatenText + jp StdBattleTextBox + +; 36011 + + +SapHealth: ; 36011 + ld hl, CurDamage + ld a, [hli] + srl a + ld [hDividend], a + ld b, a + ld a, [hl] + rr a + ld [hDividend + 1], a + or b + jr nz, .ok1 + ld a, $1 + ld [hDividend + 1], a +.ok1 + ld hl, BattleMonHP + ld de, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .battlemonhp + ld hl, EnemyMonHP + ld de, EnemyMonMaxHP +.battlemonhp + ld bc, Buffer4 + ld a, [hli] + ld [bc], a + ld a, [hl] + dec bc + ld [bc], a + ld a, [de] + dec bc + ld [bc], a + inc de + ld a, [de] + dec bc + ld [bc], a + ld a, [hDividend + 1] + ld b, [hl] + add b + ld [hld], a + ld [Buffer5], a + ld a, [hDividend] + ld b, [hl] + adc b + ld [hli], a + ld [Buffer6], a + jr c, .okay2 + ld a, [hld] + ld b, a + ld a, [de] + dec de + sub b + ld a, [hli] + ld b, a + ld a, [de] + inc de + sbc b + jr nc, .okay3 +.okay2 + ld a, [de] + ld [hld], a + ld [Buffer5], a + dec de + ld a, [de] + ld [hli], a + ld [Buffer6], a + inc de +.okay3 + ld a, [hBattleTurn] + and a + hlcoord 10, 9 + ld a, $1 + jr z, .hp_bar + hlcoord 2, 2 + xor a +.hp_bar + ld [wWhichHPBar], a + predef AnimateHPBar + call RefreshBattleHuds + jp UpdateBattleMonInParty + +; 3608c + + +BattleCommand_BurnTarget: ; 3608c +; burntarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jp nz, Defrost + ld a, [TypeModifier] + and $7f + ret z + call CheckMoveTypeMatchesTarget ; Don't burn a Fire-type + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_BURN + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set BRN, [hl] + call UpdateOpponentInParty + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + ld de, ANIM_BRN + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasBurnedText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret + +; 360dd + + +Defrost: ; 360dd + ld a, [hl] + and 1 << FRZ + ret z + + xor a + ld [hl], a + + ld a, [hBattleTurn] + and a + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + jr z, .ok + ld hl, PartyMon1Status + ld a, [CurBattleMon] +.ok + + call GetPartyLocation + xor a + ld [hl], a + call UpdateOpponentInParty + + ld hl, DefrostedOpponentText + jp StdBattleTextBox + +; 36102 + + +BattleCommand_FreezeTarget: ; 36102 +; freezetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + ld a, [Weather] + cp WEATHER_SUN + ret z + call CheckMoveTypeMatchesTarget ; Don't freeze an Ice-type + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_FREEZE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set FRZ, [hl] + call UpdateOpponentInParty + ld de, ANIM_FRZ + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasFrozenText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret nz + + call OpponentCantMove + call EndRechargeOpp + ld hl, wEnemyJustGotFrozen + ld a, [hBattleTurn] + and a + jr z, .finish + ld hl, wPlayerJustGotFrozen +.finish + ld [hl], $1 + ret + +; 36165 + + +BattleCommand_ParalyzeTarget: ; 36165 +; paralyzetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PAR, [hl] + call UpdateOpponentInParty + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + ld de, ANIM_PAR + call PlayOpponentBattleAnim + call RefreshBattleHuds + call PrintParalyze + ld hl, UseHeldStatusHealingItem + jp CallBattleCore + +; 361ac + + +BattleCommand_AttackUp: ; 361ac +; attackup + ld b, ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp: ; 361b0 +; defenseup + ld b, DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp: ; 361b4 +; speedup + ld b, SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp: ; 361b8 +; specialattackup + ld b, SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp: ; 361bc +; specialdefenseup + ld b, SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp: ; 361c0 +; accuracyup + ld b, ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp: ; 361c4 +; evasionup + ld b, EVASION + jr BattleCommand_StatUp + +BattleCommand_AttackUp2: ; 361c8 +; attackup2 + ld b, $10 | ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp2: ; 361cc +; defenseup2 + ld b, $10 | DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp2: ; 361d0 +; speedup2 + ld b, $10 | SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp2: ; 361d4 +; specialattackup2 + ld b, $10 | SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp2: ; 361d8 +; specialdefenseup2 + ld b, $10 | SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp2: ; 361dc +; accuracyup2 + ld b, $10 | ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp2: ; 361e0 +; evasionup2 + ld b, $10 | EVASION + jr BattleCommand_StatUp + +BattleCommand_StatUp: ; 361e4 +; statup + call CheckIfStatCanBeRaised + ld a, [FailedMessage] + and a + ret nz + jp StatUpAnimation + +; 361ef + + +CheckIfStatCanBeRaised: ; 361ef + ld a, b + ld [LoweredStat], a + ld hl, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .got_stat_levels + ld hl, EnemyStatLevels +.got_stat_levels + ld a, [AttackMissed] + and a + jp nz, .stat_raise_failed + ld a, [EffectFailed] + and a + jp nz, .stat_raise_failed + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + inc b + ld a, $d + cp b + jp c, .cant_raise_stat + ld a, [LoweredStat] + and $f0 + jr z, .got_num_stages + inc b + ld a, $d + cp b + jr nc, .got_num_stages + ld b, a +.got_num_stages + ld [hl], b + push hl + ld a, c + cp $5 + jr nc, .done_calcing_stats + ld hl, BattleMonStats + 1 + ld de, PlayerStats + ld a, [hBattleTurn] + and a + jr z, .got_stats_pointer + ld hl, EnemyMonStats + 1 + ld de, EnemyStats +.got_stats_pointer + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .no_carry + inc d +.no_carry + pop bc + ld a, [hld] + sub LOW(MAX_STAT_VALUE) + jr nz, .not_already_max + ld a, [hl] + sbc HIGH(MAX_STAT_VALUE) + jp z, .stats_already_max +.not_already_max + ld a, [hBattleTurn] + and a + jr z, .calc_player_stats + call CalcEnemyStats + jr .done_calcing_stats + +.calc_player_stats + call CalcPlayerStats +.done_calcing_stats + pop hl + xor a + ld [FailedMessage], a + ret + +; 3626e + + +.stats_already_max ; 3626e + pop hl + dec [hl] + ; fallthrough +; 36270 + + +.cant_raise_stat ; 36270 + ld a, $2 + ld [FailedMessage], a + ld a, $1 + ld [AttackMissed], a + ret + +; 3627b + + +.stat_raise_failed ; 3627b + ld a, $1 + ld [FailedMessage], a + ret + +; 36281 + + +StatUpAnimation: ; 36281 + ld bc, wPlayerMinimized + ld hl, DropPlayerSub + ld a, [hBattleTurn] + and a + jr z, .do_player + ld bc, wEnemyMinimized + ld hl, DropEnemySub +.do_player + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp MINIMIZE + ret nz + + ld a, $1 + ld [bc], a + call _CheckBattleScene + ret nc + + xor a + ld [hBGMapMode], a + call CallBattleCore + call WaitBGMap + jp BattleCommand_MoveDelay + +; 362ad + + +BattleCommand_AttackDown: ; 362ad +; attackdown + ld a, ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown: ; 362b1 +; defensedown + ld a, DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown: ; 362b5 +; speeddown + ld a, SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown: ; 362b9 +; specialattackdown + ld a, SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown: ; 362bd +; specialdefensedown + ld a, SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown: ; 362c1 +; accuracydown + ld a, ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown: ; 362c5 +; evasiondown + ld a, EVASION + jr BattleCommand_StatDown + +BattleCommand_AttackDown2: ; 362c9 +; attackdown2 + ld a, $10 | ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown2: ; 362cd +; defensedown2 + ld a, $10 | DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown2: ; 362d1 +; speeddown2 + ld a, $10 | SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown2: ; 362d5 +; specialattackdown2 + ld a, $10 | SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown2: ; 362d9 +; specialdefensedown2 + ld a, $10 | SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown2: ; 362dd +; accuracydown2 + ld a, $10 | ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown2: ; 362e1 +; evasiondown2 + ld a, $10 | EVASION + +BattleCommand_StatDown: ; 362e3 +; statdown + + ld [LoweredStat], a + + call CheckMist + jp nz, .Mist + + ld hl, EnemyStatLevels + ld a, [hBattleTurn] + and a + jr z, .GetStatLevel + ld hl, PlayerStatLevels + +.GetStatLevel: +; Attempt to lower the stat. + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jp z, .CantLower + +; Sharply lower the stat if applicable. + ld a, [LoweredStat] + and $f0 + jr z, .ComputerMiss + dec b + jr nz, .ComputerMiss + inc b + +.ComputerMiss: +; Computer opponents have a 1/4 chance of failing. + ld a, [hBattleTurn] + and a + jr z, .DidntMiss + + ld a, [wLinkMode] + and a + jr nz, .DidntMiss + + ld a, [InBattleTowerBattle] + and a + jr nz, .DidntMiss + +; Lock-On still always works. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .DidntMiss + +; Attacking moves that also lower accuracy are unaffected. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ACCURACY_DOWN_HIT + jr z, .DidntMiss + + call BattleRandom + cp $40 + jr c, .Failed + +.DidntMiss: + call CheckSubstituteOpp + jr nz, .Failed + + ld a, [AttackMissed] + and a + jr nz, .Failed + + ld a, [EffectFailed] + and a + jr nz, .Failed + + call CheckHiddenOpponent + jr nz, .Failed + +; Accuracy/Evasion reduction don't involve stats. + ld [hl], b + ld a, c + cp ACCURACY + jr nc, .Hit + + push hl + ld hl, EnemyMonAttack + 1 + ld de, EnemyStats + ld a, [hBattleTurn] + and a + jr z, .do_enemy + ld hl, BattleMonAttack + 1 + ld de, PlayerStats +.do_enemy + call TryLowerStat + pop hl + jr z, .CouldntLower + +.Hit: + xor a + ld [FailedMessage], a + ret + +.CouldntLower: + inc [hl] +.CantLower: + ld a, 3 + ld [FailedMessage], a + ld a, 1 + ld [AttackMissed], a + ret + +.Failed: + ld a, 1 + ld [FailedMessage], a + ld [AttackMissed], a + ret + +.Mist: + ld a, 2 + ld [FailedMessage], a + ld a, 1 + ld [AttackMissed], a + ret + +; 36391 + + +CheckMist: ; 36391 + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ATTACK_DOWN + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN + 1 + jr c, .check_mist + cp EFFECT_ATTACK_DOWN_2 + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN_2 + 1 + jr c, .check_mist + cp EFFECT_ATTACK_DOWN_HIT + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN_HIT + 1 + jr c, .check_mist +.dont_check_mist + xor a + ret + +.check_mist + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_MIST, a + ret + +; 363b8 + + +BattleCommand_StatUpMessage: ; 363b8 + ld a, [FailedMessage] + and a + ret nz + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp BattleTextBox + +.stat + text_jump UnknownText_0x1c0cc6 + start_asm + ld hl, .up + ld a, [LoweredStat] + and $f0 + ret z + ld hl, .wayup + ret + +.wayup + text_jump UnknownText_0x1c0cd0 + db "@" + +.up + text_jump UnknownText_0x1c0ce0 + db "@" + +; 363e9 + + +BattleCommand_StatDownMessage: ; 363e9 + ld a, [FailedMessage] + and a + ret nz + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp BattleTextBox + +.stat + text_jump UnknownText_0x1c0ceb + start_asm + ld hl, .fell + ld a, [LoweredStat] + and $f0 + ret z + ld hl, .sharplyfell + ret + +.sharplyfell + text_jump UnknownText_0x1c0cf5 + db "@" +.fell + text_jump UnknownText_0x1c0d06 + db "@" + +; 3641a + + +TryLowerStat: ; 3641a +; Lower stat c from stat struct hl (buffer de). + + push bc + sla c + ld b, 0 + add hl, bc + ; add de, c + ld a, c + add e + ld e, a + jr nc, .no_carry + inc d +.no_carry + pop bc + +; The lowest possible stat is 1. + ld a, [hld] + sub 1 + jr nz, .not_min + ld a, [hl] + and a + ret z + +.not_min + ld a, [hBattleTurn] + and a + jr z, .Player + + call BattleCommand_SwitchTurn + call CalcPlayerStats + call BattleCommand_SwitchTurn + jr .end + +.Player: + call BattleCommand_SwitchTurn + call CalcEnemyStats + call BattleCommand_SwitchTurn +.end + ld a, 1 + and a + ret + +; 3644c + + +BattleCommand_StatUpFailText: ; 3644c +; statupfailtext + ld a, [FailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontRiseAnymoreText + jp StdBattleTextBox + +; 3646a + + +BattleCommand_StatDownFailText: ; 3646a +; statdownfailtext + ld a, [FailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + dec a + ld hl, ProtectedByMistText + jp z, StdBattleTextBox + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontDropAnymoreText + jp StdBattleTextBox + +; 3648f + + +GetStatName: ; 3648f + ld hl, .names + ld c, "@" +.CheckName: + dec b + jr z, .Copy +.GetName: + ld a, [hli] + cp c + jr z, .CheckName + jr .GetName + +.Copy: + ld de, StringBuffer2 + ld bc, StringBuffer3 - StringBuffer2 + jp CopyBytes + +.names + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPCL.ATK@" + db "SPCL.DEF@" + db "ACCURACY@" + db "EVASION@" + db "ABILITY@" +; 364e6 + + +StatLevelMultipliers: ; 364e6 + db 25, 100 ; 0.25x + db 28, 100 ; 0.28x + db 33, 100 ; 0.33x + db 40, 100 ; 0.40x + db 50, 100 ; 0.50x + db 66, 100 ; 0.66x + db 1, 1 ; 1.00x + db 15, 10 ; 1.50x + db 2, 1 ; 2.00x + db 25, 10 ; 2.50x + db 3, 1 ; 3.00x + db 35, 10 ; 3.50x + db 4, 1 ; 4.00x +; 36500 + + +BattleCommand_AllStatsUp: ; 36500 +; allstatsup + +; Attack + call ResetMiss + call BattleCommand_AttackUp + call BattleCommand_StatUpMessage + +; Defense + call ResetMiss + call BattleCommand_DefenseUp + call BattleCommand_StatUpMessage + +; Speed + call ResetMiss + call BattleCommand_SpeedUp + call BattleCommand_StatUpMessage + +; Special Attack + call ResetMiss + call BattleCommand_SpecialAttackUp + call BattleCommand_StatUpMessage + +; Special Defense + call ResetMiss + call BattleCommand_SpecialDefenseUp + jp BattleCommand_StatUpMessage +; 3652d + + +ResetMiss: ; 3652d + xor a + ld [AttackMissed], a + ret + +; 36532 + + +LowerStat: ; 36532 + ld [LoweredStat], a + + ld hl, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .got_target + ld hl, EnemyStatLevels + +.got_target + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jr z, .cant_lower_anymore + + ld a, [LoweredStat] + and $f0 + jr z, .got_num_stages + dec b + jr nz, .got_num_stages + inc b + +.got_num_stages + ld [hl], b + ld a, c + cp 5 + jr nc, .accuracy_evasion + + push hl + ld hl, BattleMonStats + 1 + ld de, PlayerStats + ld a, [hBattleTurn] + and a + jr z, .got_target_2 + ld hl, EnemyMonStats + 1 + ld de, EnemyStats + +.got_target_2 + call TryLowerStat + pop hl + jr z, .failed + +.accuracy_evasion + ld a, [hBattleTurn] + and a + jr z, .player + + call CalcEnemyStats + + jr .finish + +.player + call CalcPlayerStats + +.finish + xor a + ld [FailedMessage], a + ret + +.failed + inc [hl] + +.cant_lower_anymore + ld a, 2 + ld [FailedMessage], a + ret + +; 3658f + + +BattleCommand_TriStatusChance: ; 3658f +; tristatuschance + + call BattleCommand_EffectChance + +; 1/3 chance of each status +.loop + call BattleRandom + swap a + and 3 + jr z, .loop +; jump + dec a + ld hl, .ptrs + rst JumpTable + ret + +.ptrs + dw BattleCommand_ParalyzeTarget ; paralyze + dw BattleCommand_FreezeTarget ; freeze + dw BattleCommand_BurnTarget ; burn +; 365a7 + + +BattleCommand_Curl: ; 365a7 +; curl + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVarAddr + set SUBSTATUS_CURLED, [hl] + ret + +; 365af + + +BattleCommand_RaiseSubNoAnim: ; 365af + ld hl, GetBattleMonBackpic + ld a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, GetEnemyMonFrontpic +.PlayerTurn: + xor a + ld [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +; 365c3 + + +BattleCommand_LowerSubNoAnim: ; 365c3 + ld hl, DropPlayerSub + ld a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, DropEnemySub +.PlayerTurn: + xor a + ld [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +; 365d7 + + +CalcPlayerStats: ; 365d7 + ld hl, PlayerAtkLevel + ld de, PlayerStats + ld bc, BattleMonAttack + + ld a, 5 + call CalcStats + + ld hl, BadgeStatBoosts + call CallBattleCore + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +; 365fd + + +CalcEnemyStats: ; 365fd + ld hl, EnemyAtkLevel + ld de, EnemyStats + ld bc, EnemyMonAttack + + ld a, 5 + call CalcStats + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +; 3661d + + +CalcStats: ; 3661d +.loop + push af + ld a, [hli] + push hl + push bc + + ld c, a + dec c + ld b, 0 + ld hl, StatLevelMultipliers + add hl, bc + add hl, bc + + xor a + ld [hMultiplicand + 0], a + ld a, [de] + ld [hMultiplicand + 1], a + inc de + ld a, [de] + ld [hMultiplicand + 2], a + inc de + + ld a, [hli] + ld [hMultiplier], a + call Multiply + + ld a, [hl] + ld [hDivisor], a + ld b, 4 + call Divide + + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + or b + jr nz, .check_maxed_out + + ld a, 1 + ld [hQuotient + 2], a + jr .not_maxed_out + +.check_maxed_out + ld a, [hQuotient + 2] + cp LOW(MAX_STAT_VALUE) + ld a, b + sbc HIGH(MAX_STAT_VALUE) + jr c, .not_maxed_out + + ld a, LOW(MAX_STAT_VALUE) + ld [hQuotient + 2], a + ld a, HIGH(MAX_STAT_VALUE) + ld [hQuotient + 1], a + +.not_maxed_out + pop bc + ld a, [hQuotient + 1] + ld [bc], a + inc bc + ld a, [hQuotient + 2] + ld [bc], a + inc bc + pop hl + pop af + dec a + jr nz, .loop + + ret + +; 36671 + + +BattleCommand_StoreEnergy: ; 36671 +; storeenergy + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_BIDE, a + ret z + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .check_still_storing_energy + ld hl, EnemyRolloutCount +.check_still_storing_energy + dec [hl] + jr nz, .still_storing + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_BIDE, [hl] + + ld hl, UnleashedEnergyText + call StdBattleTextBox + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVarAddr + ld a, 1 + ld [hl], a + ld hl, PlayerDamageTaken + 1 + ld de, wPlayerCharging ; player + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, EnemyDamageTaken + 1 + ld de, wEnemyCharging ; enemy +.player + ld a, [hld] + add a + ld b, a + ld [CurDamage + 1], a + ld a, [hl] + rl a + ld [CurDamage], a + jr nc, .not_maxed + ld a, $ff + ld [CurDamage], a + ld [CurDamage + 1], a +.not_maxed + or b + jr nz, .built_up_something + ld a, 1 + ld [AttackMissed], a +.built_up_something + xor a + ld [hli], a + ld [hl], a + ld [de], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld a, BIDE + ld [hl], a + + ld b, unleashenergy_command + jp SkipToBattleCommand + +.still_storing + ld hl, StoringEnergyText + call StdBattleTextBox + jp EndMoveEffect + +; 366e5 + + +BattleCommand_UnleashEnergy: ; 366e5 +; unleashenergy + + ld de, PlayerDamageTaken + ld bc, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .got_damage + ld de, EnemyDamageTaken + ld bc, EnemyRolloutCount +.got_damage + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_BIDE, [hl] + xor a + ld [de], a + inc de + ld [de], a + ld [wPlayerMoveStructEffect], a + ld [wEnemyMoveStructEffect], a + call BattleRandom + and 1 + inc a + inc a + ld [bc], a + ld a, 1 + ld [wKickCounter], a + call AnimateCurrentMove + jp EndMoveEffect + +; 3671a + + +BattleCommand_CheckRampage: ; 3671a +; checkrampage + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .player + ld de, EnemyRolloutCount +.player + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_RAMPAGE, [hl] + ret z + ld a, [de] + dec a + ld [de], a + jr nz, .continue_rampage + + res SUBSTATUS_RAMPAGE, [hl] + call BattleCommand_SwitchTurn + call SafeCheckSafeguard + push af + call BattleCommand_SwitchTurn + pop af + jr nz, .continue_rampage + + set SUBSTATUS_CONFUSED, [hl] + call BattleRandom + and %00000001 + inc a + inc a + inc de ; ConfuseCount + ld [de], a +.continue_rampage + ld b, rampage_command + jp SkipToBattleCommand + +; 36751 + + +BattleCommand_Rampage: ; 36751 +; rampage + +; No rampage during Sleep Talk. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyRolloutCount +.ok + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_RAMPAGE, [hl] +; Rampage for 1 or 2 more turns + call BattleRandom + and %00000001 + inc a + ld [de], a + ld a, 1 + ld [wSomeoneIsRampaging], a + ret + +; 36778 + + +BattleCommand_Teleport: ; 36778 +; teleport + + ld a, [BattleType] + cp BATTLETYPE_SHINY + jr z, .failed + cp BATTLETYPE_TRAP + jr z, .failed + cp BATTLETYPE_CELEBI + jr z, .failed + cp BATTLETYPE_SUICUNE + jr z, .failed + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_CANT_RUN, a + jr nz, .failed +; Only need to check these next things if it's your turn + ld a, [hBattleTurn] + and a + jr nz, .enemy_turn +; Can't teleport from a trainer battle + ld a, [wBattleMode] + dec a + jr nz, .failed +; If your level is greater than the opponent's, you run without fail. + ld a, [CurPartyLevel] + ld b, a + ld a, [BattleMonLevel] + cp b + jr nc, .run_away +; Generate a number between 0 and (YourLevel + TheirLevel). + add b + ld c, a + inc c +.loop_player + call BattleRandom + cp c + jr nc, .loop_player +; If that number is greater than 4 times your level, run away. + srl b + srl b + cp b + jr nc, .run_away + +.failed + call AnimateFailedMove + jp PrintButItFailed + +.enemy_turn + ld a, [wBattleMode] + dec a + jr nz, .failed + ld a, [BattleMonLevel] + ld b, a + ld a, [CurPartyLevel] + cp b + jr nc, .run_away + add b + ld c, a + inc c +.loop_enemy + call BattleRandom + cp c + jr nc, .loop_enemy + srl b + srl b + cp b + ; This does the wrong thing. What was + ; probably intended was jr c, .failed + ; The way this is made makes enemy use + ; of Teleport always succeed if able + jr nc, .run_away +.run_away + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + ld [wKickCounter], a + call SetBattleDraw + call BattleCommand_LowerSub + call LoadMoveAnim + ld c, 20 + call DelayFrames + call SetBattleDraw + + ld hl, FledFromBattleText + jp StdBattleTextBox + +; 36804 + + +SetBattleDraw: ; 36804 + ld a, [wBattleResult] + and $c0 + or $2 + ld [wBattleResult], a + ret + +; 3680f + + +BattleCommand_ForceSwitch: ; 3680f +; forceswitch + + ld a, [BattleType] + cp BATTLETYPE_SHINY + jp z, .fail + cp BATTLETYPE_TRAP + jp z, .fail + cp BATTLETYPE_CELEBI + jp z, .fail + cp BATTLETYPE_SUICUNE + jp z, .fail + ld a, [hBattleTurn] + and a + jp nz, .force_player_switch + ld a, [AttackMissed] + and a + jr nz, .missed + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, [CurPartyLevel] + ld b, a + ld a, [BattleMonLevel] + cp b + jr nc, .wild_force_flee + add b + ld c, a + inc c +.random_loop_wild + call BattleRandom + cp c + jr nc, .random_loop_wild + srl b + srl b + cp b + jr nc, .wild_force_flee +.missed + jp .fail + +.wild_force_flee + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + call SetBattleDraw + ld a, [wPlayerMoveStructAnimation] + jp .succeed + +.trainer + call FindAliveEnemyMons + jr c, .switch_fail + ld a, [wEnemyGoesFirst] + and a + jr z, .switch_fail + call UpdateEnemyMonInParty + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, $14 + call DelayFrames + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld c, 20 + call DelayFrames + ld a, [OTPartyCount] + ld b, a + ld a, [CurOTMon] + ld c, a +; select a random enemy mon to switch to +.random_loop_trainer + call BattleRandom + and $7 + cp b + jr nc, .random_loop_trainer + cp c + jr z, .random_loop_trainer + push af + push bc + ld hl, OTPartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer + ld a, d + inc a + ld [wEnemySwitchMonIndex], a + callfar ForceEnemySwitch + + ld hl, DraggedOutText + call StdBattleTextBox + + ld hl, SpikesDamage + jp CallBattleCore + +.switch_fail + jp .fail + +.force_player_switch + ld a, [AttackMissed] + and a + jr nz, .player_miss + + ld a, [wBattleMode] + dec a + jr nz, .vs_trainer + + ld a, [BattleMonLevel] + ld b, a + ld a, [CurPartyLevel] + cp b + jr nc, .wild_succeed_playeristarget + + add b + ld c, a + inc c +.wild_random_loop_playeristarget + call BattleRandom + cp c + jr nc, .wild_random_loop_playeristarget + + srl b + srl b + cp b + jr nc, .wild_succeed_playeristarget + +.player_miss + jr .fail + +.wild_succeed_playeristarget + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + call SetBattleDraw + ld a, [wEnemyMoveStructAnimation] + jr .succeed + +.vs_trainer + call CheckPlayerHasMonToSwitchTo + jr c, .fail + + ld a, [wEnemyGoesFirst] + cp $1 + jr z, .switch_fail + + call UpdateBattleMonInParty + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, 20 + call DelayFrames + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld c, 20 + call DelayFrames + ld a, [PartyCount] + ld b, a + ld a, [CurBattleMon] + ld c, a +.random_loop_trainer_playeristarget + call BattleRandom + and $7 + cp b + jr nc, .random_loop_trainer_playeristarget + + cp c + jr z, .random_loop_trainer_playeristarget + + push af + push bc + ld hl, PartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer_playeristarget + + ld a, d + ld [CurPartyMon], a + ld hl, SwitchPlayerMon + call CallBattleCore + + ld hl, DraggedOutText + call StdBattleTextBox + + ld hl, SpikesDamage + jp CallBattleCore + +.fail + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + jp PrintButItFailed + +.succeed + push af + call SetBattleDraw + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, 20 + call DelayFrames + pop af + + ld hl, FledInFearText + cp ROAR + jr z, .do_text + ld hl, BlownAwayText +.do_text + jp StdBattleTextBox + +; 36994 + + +CheckPlayerHasMonToSwitchTo: ; 36994 + ld a, [PartyCount] + ld d, a + ld e, 0 + ld bc, PARTYMON_STRUCT_LENGTH +.loop + ld a, [CurBattleMon] + cp e + jr z, .next + + ld a, e + ld hl, PartyMon1HP + call AddNTimes + ld a, [hli] + or [hl] + jr nz, .not_fainted + +.next + inc e + dec d + jr nz, .loop + + scf + ret + +.not_fainted + and a + ret + +; 369b6 + + +BattleCommand_EndLoop: ; 369b6 +; endloop + +; Loop back to the command before 'critical'. + + ld de, PlayerRolloutCount + ld bc, PlayerDamageTaken + ld a, [hBattleTurn] + and a + jr z, .got_addrs + ld de, EnemyRolloutCount + ld bc, EnemyDamageTaken +.got_addrs + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, [hl] + jp nz, .in_loop + set SUBSTATUS_IN_LOOP, [hl] + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld a, [hl] + cp EFFECT_POISON_MULTI_HIT + jr z, .twineedle + cp EFFECT_DOUBLE_HIT + ld a, 1 + jr z, .double_hit + ld a, [hl] + cp EFFECT_BEAT_UP + jr z, .beat_up + cp EFFECT_TRIPLE_KICK + jr nz, .not_triple_kick +.reject_triple_kick_sample + call BattleRandom + and $3 + jr z, .reject_triple_kick_sample + dec a + jr nz, .double_hit + ld a, 1 + ld [bc], a + jr .done_loop + +.beat_up + ld a, [hBattleTurn] + and a + jr nz, .check_ot_beat_up + ld a, [PartyCount] + cp 1 + jp z, .only_one_beatup + dec a + jr .double_hit + +.check_ot_beat_up + ld a, [wBattleMode] + cp WILD_BATTLE + jp z, .only_one_beatup + ld a, [OTPartyCount] + cp 1 + jp z, .only_one_beatup + dec a + jr .double_hit + +.only_one_beatup + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_IN_LOOP, [hl] + call BattleCommanda8 + jp EndMoveEffect + +.not_triple_kick + call BattleRandom + and $3 + cp 2 + jr c, .got_number_hits + call BattleRandom + and $3 +.got_number_hits + inc a +.double_hit + ld [de], a + inc a + ld [bc], a + jr .loop_back_to_critical + +.twineedle + ld a, 1 + jr .double_hit + +.in_loop + ld a, [de] + dec a + ld [de], a + jr nz, .loop_back_to_critical +.done_loop + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_IN_LOOP, [hl] + + ld hl, PlayerHitTimesText + ld a, [hBattleTurn] + and a + jr z, .got_hit_n_times_text + ld hl, EnemyHitTimesText +.got_hit_n_times_text + + push bc + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_BEAT_UP + jr z, .beat_up_2 + call StdBattleTextBox +.beat_up_2 + + pop bc + xor a + ld [bc], a + ret + +; Loop back to the command before 'critical'. +.loop_back_to_critical + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, [BattleScriptBufferAddress] + ld l, a +.not_critical + ld a, [hld] + cp critical_command + jr nz, .not_critical + inc hl + ld a, h + ld [BattleScriptBufferAddress + 1], a + ld a, l + ld [BattleScriptBufferAddress], a + ret + +; 36a82 + + +BattleCommand_FakeOut: ; 36a82 + ld a, [AttackMissed] + and a + ret nz + + call CheckSubstituteOpp + jr nz, .fail + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + jr nz, .fail + + call CheckOpponentWentFirst + jr z, FlinchTarget + +.fail + ld a, 1 + ld [AttackMissed], a + ret + +; 36aa0 + + +BattleCommand_FlinchTarget: ; 36aa0 + call CheckSubstituteOpp + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + ret nz + + call CheckOpponentWentFirst + ret nz + + ld a, [EffectFailed] + and a + ret nz + + ; fallthrough +; 36ab5 + + +FlinchTarget: ; 36ab5 + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + jp EndRechargeOpp + +; 36abf + + +CheckOpponentWentFirst: ; 36abf +; Returns a=0, z if user went first +; Returns a=1, nz if opponent went first + push bc + ld a, [wEnemyGoesFirst] ; 0 if player went first + ld b, a + ld a, [hBattleTurn] ; 0 if it's the player's turn + xor b ; 1 if opponent went first + pop bc + ret + +; 36ac9 + + +BattleCommand_HeldFlinch: ; 36ac9 +; kingsrock + + ld a, [AttackMissed] + and a + ret nz + + call GetUserItem + ld a, b + cp HELD_FLINCH + ret nz + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld d, h + ld e, l + call GetUserItem + call BattleRandom + cp c + ret nc + call EndRechargeOpp + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + ret + +; 36af3 + + +BattleCommand_OHKO: ; 36af3 +; ohko + + call ResetDamage + ld a, [TypeModifier] + and $7f + jr z, .no_effect + ld hl, EnemyMonLevel + ld de, BattleMonLevel + ld bc, wPlayerMoveStruct + MOVE_ACC + ld a, [hBattleTurn] + and a + jr z, .got_move_accuracy + push hl + ld h, d + ld l, e + pop de + ld bc, wEnemyMoveStruct + MOVE_ACC +.got_move_accuracy + ld a, [de] + sub [hl] + jr c, .no_effect + add a + ld e, a + ld a, [bc] + add e + jr nc, .finish_ohko + ld a, $ff +.finish_ohko + ld [bc], a + call BattleCommand_CheckHit + ld hl, CurDamage + ld a, $ff + ld [hli], a + ld [hl], a + ld a, $2 + ld [CriticalHit], a + ret + +.no_effect + ld a, $ff + ld [CriticalHit], a + ld a, $1 + ld [AttackMissed], a + ret + +; 36b3a + + +BattleCommand_CheckCharge: ; 36b3a +; checkcharge + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_CHARGED, [hl] + ret z + res SUBSTATUS_CHARGED, [hl] + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + ld b, charge_command + jp SkipToBattleCommand + +; 36b4d + + +BattleCommand_Charge: ; 36b4d +; charge + + call BattleCommand_ClearText + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr z, .awake + + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + call PrintButItFailed + jp EndMoveEffect + +.awake + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_CHARGED, [hl] + + ld hl, IgnoredOrders2Text + ld a, [AlreadyDisobeyed] + and a + call nz, StdBattleTextBox + + call BattleCommand_LowerSub + xor a + ld [wNumHits], a + inc a + ld [wKickCounter], a + call LoadMoveAnim + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .flying + cp DIG + jr z, .flying + call BattleCommand_RaiseSub + jr .not_flying + +.flying + call DisappearUser +.not_flying + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + cp FLY + jr z, .set_flying + cp DIG + jr nz, .dont_set_digging + set SUBSTATUS_UNDERGROUND, [hl] + jr .dont_set_digging + +.set_flying + set SUBSTATUS_FLYING, [hl] + +.dont_set_digging + call CheckUserIsCharging + jr nz, .mimic + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + ld [hl], b + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], b + +.mimic + call ResetDamage + + ld hl, .UsedText + call BattleTextBox + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_SKULL_BASH + ld b, endturn_command + jp z, SkipToBattleCommand + jp EndMoveEffect + +.UsedText: + text_jump UnknownText_0x1c0d0e ; "[USER]" + start_asm + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp RAZOR_WIND + ld hl, .RazorWind + jr z, .done + + cp SOLARBEAM + ld hl, .Solarbeam + jr z, .done + + cp SKULL_BASH + ld hl, .SkullBash + jr z, .done + + cp SKY_ATTACK + ld hl, .SkyAttack + jr z, .done + + cp FLY + ld hl, .Fly + jr z, .done + + cp DIG + ld hl, .Dig + +.done + ret + +.RazorWind: +; 'made a whirlwind!' + text_jump UnknownText_0x1c0d12 + db "@" + +.Solarbeam: +; 'took in sunlight!' + text_jump UnknownText_0x1c0d26 + db "@" + +.SkullBash: +; 'lowered its head!' + text_jump UnknownText_0x1c0d3a + db "@" + +.SkyAttack: +; 'is glowing!' + text_jump UnknownText_0x1c0d4e + db "@" + +.Fly: +; 'flew up high!' + text_jump UnknownText_0x1c0d5c + db "@" + +.Dig: +; 'dug a hole!' + text_jump UnknownText_0x1c0d6c + db "@" +; 36c2c + + +BattleCommand3c: ; 36c2c +; unused + ret + +; 36c2d + + +BattleCommand_TrapTarget: ; 36c2d +; traptarget + + ld a, [AttackMissed] + and a + ret nz + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + ld a, [hBattleTurn] + and a + jr z, .got_trap + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + +.got_trap + ld a, [hl] + and a + ret nz + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + call BattleRandom + and 3 + inc a + inc a + inc a + ld [hl], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld [de], a + ld b, a + ld hl, .Traps + +.find_trap_text + ld a, [hli] + cp b + jr z, .found_trap_text + inc hl + inc hl + jr .find_trap_text + +.found_trap_text + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox + +.Traps: + dbw BIND, UsedBindText ; 'used BIND on' + dbw WRAP, WrappedByText ; 'was WRAPPED by' + dbw FIRE_SPIN, FireSpinTrapText ; 'was trapped!' + dbw CLAMP, ClampedByText ; 'was CLAMPED by' + dbw WHIRLPOOL, WhirlpoolTrapText ; 'was trapped!' +; 36c7e + + +BattleCommand_Mist: ; 36c7e +; mist + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_MIST, [hl] + jr nz, .already_mist + set SUBSTATUS_MIST, [hl] + call AnimateCurrentMove + ld hl, MistText + jp StdBattleTextBox + +.already_mist + call AnimateFailedMove + jp PrintButItFailed + +; 36c98 + + +BattleCommand_FocusEnergy: ; 36c98 +; focusenergy + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_FOCUS_ENERGY, [hl] + jr nz, .already_pumped + set SUBSTATUS_FOCUS_ENERGY, [hl] + call AnimateCurrentMove + ld hl, GettingPumpedText + jp StdBattleTextBox + +.already_pumped + call AnimateFailedMove + jp PrintButItFailed + +; 36cb2 + + +BattleCommand_Recoil: ; 36cb2 +; recoil + + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld d, a +; get 1/4 damage or 1 HP, whichever is higher + ld a, [CurDamage] + ld b, a + ld a, [CurDamage + 1] + ld c, a + srl b + rr c + srl b + rr c + ld a, b + or c + jr nz, .min_damage + inc c +.min_damage + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + dec hl + dec hl + ld a, [hl] + ld [Buffer3], a + sub c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + sbc b + ld [hl], a + ld [Buffer6], a + jr nc, .dont_ko + xor a + ld [hli], a + ld [hl], a + ld hl, Buffer5 + ld [hli], a + ld [hl], a +.dont_ko + hlcoord 10, 9 + ld a, [hBattleTurn] + and a + ld a, 1 + jr z, .animate_hp_bar + hlcoord 2, 2 + xor a +.animate_hp_bar + ld [wWhichHPBar], a + predef AnimateHPBar + call RefreshBattleHuds + ld hl, RecoilText + jp StdBattleTextBox + +; 36d1d + + +BattleCommand_ConfuseTarget: ; 36d1d +; confusetarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + bit SUBSTATUS_CONFUSED, [hl] + ret nz + jr BattleCommand_FinishConfusingTarget + + +BattleCommand_Confuse: ; 36d3b +; confuse + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + jr nz, .no_item_protection + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call AnimateFailedMove + ld hl, ProtectedByText + jp StdBattleTextBox + +.no_item_protection + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + bit SUBSTATUS_CONFUSED, [hl] + jr z, .not_already_confused + call AnimateFailedMove + ld hl, AlreadyConfusedText + jp StdBattleTextBox + +.not_already_confused + call CheckSubstituteOpp + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit + ld a, [AttackMissed] + and a + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit +BattleCommand_FinishConfusingTarget: ; 36d70 + ld bc, EnemyConfuseCount + ld a, [hBattleTurn] + and a + jr z, .got_confuse_count + ld bc, PlayerConfuseCount + +.got_confuse_count + set SUBSTATUS_CONFUSED, [hl] + call BattleRandom + and 3 + inc a + inc a + ld [bc], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_CONFUSE_HIT + jr z, .got_effect + cp EFFECT_SNORE + jr z, .got_effect + cp EFFECT_SWAGGER + jr z, .got_effect + call AnimateCurrentMove + +.got_effect + ld de, ANIM_CONFUSED + call PlayOpponentBattleAnim + + ld hl, BecameConfusedText + call StdBattleTextBox + + call GetOpponentItem + ld a, b + cp HELD_HEAL_STATUS + jr z, .heal_confusion + cp HELD_HEAL_CONFUSION + ret nz +.heal_confusion + ld hl, UseConfusionHealingItem + jp CallBattleCore + +; 36db6 + +BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit: ; 36db6 + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_CONFUSE_HIT + ret z + cp EFFECT_SNORE + ret z + cp EFFECT_SWAGGER + ret z + jp PrintDidntAffect2 + +; 36dc7 + + +BattleCommand_Paralyze: ; 36dc7 +; paralyze + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + bit PAR, a + jr nz, .paralyzed + ld a, [TypeModifier] + and $7f + jr z, .didnt_affect + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + jr nz, .no_item_protection + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call AnimateFailedMove + ld hl, ProtectedByText + jp StdBattleTextBox + +.no_item_protection + ld a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [InBattleTowerBattle] + and a + jr nz, .dont_sample_failure + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 1 + 25 percent + jr c, .failed + +.dont_sample_failure + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jr nz, .failed + ld a, [AttackMissed] + and a + jr nz, .failed + call CheckSubstituteOpp + jr nz, .failed + ld c, 30 + call DelayFrames + call AnimateCurrentMove + ld a, $1 + ld [hBGMapMode], a + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PAR, [hl] + call UpdateOpponentInParty + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + call UpdateBattleHuds + call PrintParalyze + ld hl, UseHeldStatusHealingItem + jp CallBattleCore + +.paralyzed + call AnimateFailedMove + ld hl, AlreadyParalyzedText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +.didnt_affect + call AnimateFailedMove + jp PrintDoesntAffect + +; 36e5b + + +CheckMoveTypeMatchesTarget: ; 36e5b +; Compare move type to opponent type. +; Return z if matching the opponent type, +; unless the move is Normal (Tri Attack). + + push hl + + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonType1 +.ok + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + cp NORMAL + jr z, .normal + + cp [hl] + jr z, .return + + inc hl + cp [hl] + +.return + pop hl + ret + +.normal + ld a, 1 + and a + pop hl + ret + +; 36e7c + + +BattleCommand_Substitute: ; 36e7c +; substitute + + call BattleCommand_MoveDelay + ld hl, BattleMonMaxHP + ld de, PlayerSubstituteHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonMaxHP + ld de, EnemySubstituteHP +.got_hp + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + jr nz, .already_has_sub + + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + dec hl + dec hl + ld a, b + ld [de], a + ld a, [hld] + sub b + ld e, a + ld a, [hl] + sbc 0 + ld d, a + jr c, .too_weak_to_sub + ld a, d + or e + jr z, .too_weak_to_sub + ld [hl], d + inc hl + ld [hl], e + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_SUBSTITUTE, [hl] + + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove +.player + + xor a + ld [hl], a + ld [de], a + call _CheckBattleScene + jr c, .no_anim + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld [wKickCounter], a + ld a, SUBSTITUTE + call LoadAnim + jr .finish + +.no_anim + call BattleCommand_RaiseSubNoAnim +.finish + ld hl, MadeSubstituteText + call StdBattleTextBox + jp RefreshBattleHuds + +.already_has_sub + call CheckUserIsCharging + call nz, BattleCommand_RaiseSub + ld hl, HasSubstituteText + jr .jp_stdbattletextbox + +.too_weak_to_sub + call CheckUserIsCharging + call nz, BattleCommand_RaiseSub + ld hl, TooWeakSubText +.jp_stdbattletextbox + jp StdBattleTextBox + +; 36f0b + +BattleCommand_RechargeNextTurn: ; 36f0b +; rechargenextturn + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RECHARGE, [hl] + ret + +; 36f13 + + +EndRechargeOpp: ; 36f13 + push hl + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_RECHARGE, [hl] + pop hl + ret + +; 36f1d + + +BattleCommand_Rage: ; 36f1d +; rage + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RAGE, [hl] + ret + +; 36f25 + + +BattleCommand_DoubleFlyingDamage: ; 36f25 +; doubleflyingdamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + ret z + jr DoubleDamage + +; 36f2f + + +BattleCommand_DoubleUndergroundDamage: ; 36f2f +; doubleundergrounddamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret z + + ; fallthrough +; 36f37 + + +DoubleDamage: ; 36f37 + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .quit + + ld a, $ff + ld [hli], a + ld [hl], a +.quit + ret + +; 36f46 + + +BattleCommand_Mimic: ; 36f46 +; mimic + + call ClearLastMove + call BattleCommand_MoveDelay + ld a, [AttackMissed] + and a + jr nz, .fail + ld hl, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .player_turn + ld hl, EnemyMonMoves +.player_turn + call CheckHiddenOpponent + jr nz, .fail + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .fail + cp STRUGGLE + jr z, .fail + ld b, a + ld c, NUM_MOVES +.check_already_knows_move + ld a, [hli] + cp b + jr z, .fail + dec c + jr nz, .check_already_knows_move + dec hl +.find_mimic + ld a, [hld] + cp MIMIC + jr nz, .find_mimic + inc hl + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [hl], a + ld [wNamedObjectIndexBuffer], a + ld bc, BattleMonPP - BattleMonMoves + add hl, bc + ld [hl], 5 + call GetMoveName + call AnimateCurrentMove + ld hl, LearnedMoveText + jp StdBattleTextBox + +.fail + jp FailMimic + +; 36f9d + + +BattleCommand_LeechSeed: ; 36f9d +; leechseed + ld a, [AttackMissed] + and a + jr nz, .evaded + call CheckSubstituteOpp + jr nz, .evaded + + ld de, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, BattleMonType1 +.ok + + ld a, [de] + cp GRASS + jr z, .grass + inc de + ld a, [de] + cp GRASS + jr z, .grass + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr nz, .evaded + set SUBSTATUS_LEECH_SEED, [hl] + call AnimateCurrentMove + ld hl, WasSeededText + jp StdBattleTextBox + +.grass + call AnimateFailedMove + jp PrintDoesntAffect + +.evaded + call AnimateFailedMove + ld hl, EvadedText + jp StdBattleTextBox + +; 36fe1 + + +BattleCommand_Splash: ; 36fe1 + call AnimateCurrentMove + farcall TrainerRankings_Splash + jp PrintNothingHappened + +; 36fed + + +BattleCommand_Disable: ; 36fed +; disable + + ld a, [AttackMissed] + and a + jr nz, .failed + + ld de, EnemyDisableCount + ld hl, EnemyMonMoves + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld de, PlayerDisableCount + ld hl, BattleMonMoves +.got_moves + + ld a, [de] + and a + jr nz, .failed + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + cp STRUGGLE + jr z, .failed + + ld b, a + ld c, $ff +.loop + inc c + ld a, [hli] + cp b + jr nz, .loop + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonPP + jr z, .got_pp + ld hl, BattleMonPP +.got_pp + ld b, 0 + add hl, bc + ld a, [hl] + and a + jr z, .failed +.loop2 + call BattleRandom + and 7 + jr z, .loop2 + inc a + inc c + swap c + add c + ld [de], a + call AnimateCurrentMove + ld hl, DisabledMove + ld a, [hBattleTurn] + and a + jr nz, .got_disabled_move_pointer + inc hl +.got_disabled_move_pointer + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [hl], a + ld [wNamedObjectIndexBuffer], a + call GetMoveName + ld hl, WasDisabledText + jp StdBattleTextBox + +.failed + jp FailDisable + +; 3705c + + +BattleCommand_PayDay: ; 3705c +; payday + + xor a + ld hl, StringBuffer1 + ld [hli], a + + ld a, [hBattleTurn] + and a + ld a, [BattleMonLevel] + jr z, .ok + ld a, [EnemyMonLevel] +.ok + + add a + ld hl, wPayDayMoney + 2 + add [hl] + ld [hld], a + jr nc, .done + inc [hl] + dec hl + jr nz, .done + inc [hl] +.done + ld hl, CoinsScatteredText + jp StdBattleTextBox + +; 3707f + + +BattleCommand_Conversion: ; 3707f +; conversion + + ld hl, BattleMonMoves + ld de, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, EnemyMonMoves + ld de, EnemyMonType1 +.got_moves + push de + ld c, 0 + ld de, StringBuffer1 +.loop + push hl + ld b, 0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .okay + push hl + push bc + dec a + ld hl, Moves + MOVE_TYPE + call GetMoveAttr + ld [de], a + inc de + pop bc + pop hl + inc c + ld a, c + cp NUM_MOVES + jr c, .loop +.okay + ld a, $ff + ld [de], a + inc de + ld [de], a + inc de + ld [de], a + pop de + ld hl, StringBuffer1 +.loop2 + ld a, [hl] + cp -1 + jr z, .fail + cp CURSE_T + jr z, .next + ld a, [de] + cp [hl] + jr z, .next + inc de + ld a, [de] + dec de + cp [hl] + jr nz, .done +.next + inc hl + jr .loop2 + +.fail + call AnimateFailedMove + jp PrintButItFailed + +.done +.loop3 + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + ld hl, StringBuffer1 + add hl, bc + ld a, [hl] + cp -1 + jr z, .loop3 + cp CURSE_T + jr z, .loop3 + ld a, [de] + cp [hl] + jr z, .loop3 + inc de + ld a, [de] + dec de + cp [hl] + jr z, .loop3 + ld a, [hl] + ld [de], a + inc de + ld [de], a + ld [wNamedObjectIndexBuffer], a + farcall GetTypeName + call AnimateCurrentMove + ld hl, TransformedTypeText + jp StdBattleTextBox + +; 3710e + + +BattleCommand_ResetStats: ; 3710e +; resetstats + + ld a, 7 ; neutral + ld hl, PlayerStatLevels + call .Fill + ld hl, EnemyStatLevels + call .Fill + + ld a, [hBattleTurn] + push af + + call SetPlayerTurn + call CalcPlayerStats + call SetEnemyTurn + call CalcEnemyStats + + pop af + ld [hBattleTurn], a + + call AnimateCurrentMove + + ld hl, EliminatedStatsText + jp StdBattleTextBox + +.Fill: + ld b, PlayerStatLevelsEnd - PlayerStatLevels +.next + ld [hli], a + dec b + jr nz, .next + ret + +; 3713e + + +BattleCommand_Heal: ; 3713e +; heal + + ld de, BattleMonHP + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld de, EnemyMonHP + ld hl, EnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + push hl + push de + push bc + ld c, 2 + call StringCmp + pop bc + pop de + pop hl + jp z, .hp_full + ld a, b + cp REST + jr nz, .not_rest + + push hl + push de + push af + call BattleCommand_MoveDelay + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_TOXIC, [hl] + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + ld a, [hl] + and a + ld [hl], REST_SLEEP_TURNS + 1 + ld hl, WentToSleepText + jr z, .no_status_to_heal + ld hl, RestedText +.no_status_to_heal + call StdBattleTextBox + ld a, [hBattleTurn] + and a + jr nz, .calc_enemy_stats + call CalcPlayerStats + jr .got_stats + +.calc_enemy_stats + call CalcEnemyStats +.got_stats + pop af + pop de + pop hl + +.not_rest + jr z, .restore_full_hp + ld hl, GetHalfMaxHP + call CallBattleCore + jr .finish + +.restore_full_hp + ld hl, GetMaxHP + call CallBattleCore +.finish + call AnimateCurrentMove + call BattleCommand_SwitchTurn + ld hl, RestoreHP + call CallBattleCore + call BattleCommand_SwitchTurn + call UpdateUserInParty + call RefreshBattleHuds + ld hl, RegainedHealthText + jp StdBattleTextBox + +.hp_full + call AnimateFailedMove + ld hl, HPIsFullText + jp StdBattleTextBox + +; 371cd + +INCLUDE "engine/battle/effect_commands/transform.asm" + +BattleSideCopy: ; 372c6 +; Copy bc bytes from hl to de if it's the player's turn. +; Copy bc bytes from de to hl if it's the enemy's turn. + ld a, [hBattleTurn] + and a + jr z, .copy + +; Swap hl and de + push hl + ld h, d + ld l, e + pop de +.copy + jp CopyBytes + +; 372d2 + + +BattleEffect_ButItFailed: ; 372d2 + call AnimateFailedMove + jp PrintButItFailed + +; 372d8 + + +ClearLastMove: ; 372d8 + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + xor a + ld [hl], a + + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + xor a + ld [hl], a + ret + +; 372e7 + + +ResetActorDisable: ; 372e7 + ld a, [hBattleTurn] + and a + jr z, .player + + xor a + ld [EnemyDisableCount], a + ld [EnemyDisabledMove], a + ret + +.player + xor a + ld [PlayerDisableCount], a + ld [DisabledMove], a + ret + +; 372fc + + +BattleCommand_Screen: ; 372fc +; screen + + ld hl, PlayerScreens + ld bc, PlayerLightScreenCount + ld a, [hBattleTurn] + and a + jr z, .got_screens_pointer + ld hl, EnemyScreens + ld bc, EnemyLightScreenCount + +.got_screens_pointer + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_LIGHT_SCREEN + jr nz, .Reflect + + bit SCREENS_LIGHT_SCREEN, [hl] + jr nz, .failed + set SCREENS_LIGHT_SCREEN, [hl] + ld a, 5 + ld [bc], a + ld hl, LightScreenEffectText + jr .good + +.Reflect: + bit SCREENS_REFLECT, [hl] + jr nz, .failed + set SCREENS_REFLECT, [hl] + + ; LightScreenCount -> ReflectCount + inc bc + + ld a, 5 + ld [bc], a + ld hl, ReflectEffectText + +.good + call AnimateCurrentMove + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 3733d + + +PrintDoesntAffect: ; 3733d +; 'it doesn't affect' + ld hl, DoesntAffectText + jp StdBattleTextBox + +; 37343 + + +PrintNothingHappened: ; 37343 +; 'but nothing happened!' + ld hl, NothingHappenedText + jp StdBattleTextBox + +; 37349 + + +TryPrintButItFailed: ; 37349 + ld a, [AlreadyFailed] + and a + ret nz + + ; fallthrough +; 3734e + + +PrintButItFailed: ; 3734e +; 'but it failed!' + ld hl, ButItFailedText + jp StdBattleTextBox + +; 37354 + + +FailSnore: +FailDisable: +FailConversion2: +FailAttract: +FailForesight: +FailSpikes: + call AnimateFailedMove + ; fallthrough +; 37357 + +FailMimic: ; 37357 + ld hl, ButItFailedText ; 'but it failed!' + ld de, ItFailedText ; 'it failed!' + jp FailText_CheckOpponentProtect + +; 37360 + + +PrintDidntAffect: ; 37360 +; 'it didn't affect' + ld hl, DidntAffect1Text + jp StdBattleTextBox + +; 37366 + + +PrintDidntAffect2: ; 37366 + call AnimateFailedMove + ld hl, DidntAffect1Text ; 'it didn't affect' + ld de, DidntAffect2Text ; 'it didn't affect' + jp FailText_CheckOpponentProtect + +; 37372 + + +PrintParalyze: ; 37372 +; 'paralyzed! maybe it can't attack!' + ld hl, ParalyzedText + jp StdBattleTextBox + +; 37378 + + +CheckSubstituteOpp: ; 37378 + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret + +; 37380 + + +BattleCommand_Selfdestruct: ; 37380 + farcall TrainerRankings_Selfdestruct + ld a, BATTLEANIM_PLAYER_DAMAGE + ld [wNumHits], a + ld c, 3 + call DelayFrames + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + xor a + ld [hli], a + inc hl + ld [hli], a + ld [hl], a + ld a, $1 + ld [wKickCounter], a + call BattleCommand_LowerSub + call LoadMoveAnim + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + res SUBSTATUS_LEECH_SEED, [hl] + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + call _CheckBattleScene + ret nc + farcall DrawPlayerHUD + farcall DrawEnemyHUD + call WaitBGMap + jp RefreshBattleHuds + +; 373c9 + + +INCLUDE "engine/battle/effect_commands/mirror_move.asm" + +INCLUDE "engine/battle/effect_commands/metronome.asm" + + +CheckUserMove: ; 37462 +; Return z if the user has move a. + ld b, a + ld de, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyMonMoves +.ok + + ld c, NUM_MOVES +.loop + ld a, [de] + inc de + cp b + ret z + + dec c + jr nz, .loop + + ld a, 1 + and a + ret + +; 3747b + + +ResetTurn: ; 3747b + ld hl, wPlayerCharging + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyCharging + +.player + ld [hl], 1 + xor a + ld [AlreadyDisobeyed], a + call DoMove + jp EndMoveEffect + +; 37492 + + +INCLUDE "engine/battle/effect_commands/thief.asm" + + +BattleCommand_ArenaTrap: ; 37517 +; arenatrap + +; Doesn't work on an absent opponent. + + call CheckHiddenOpponent + jr nz, .failed + +; Don't trap if the opponent is already trapped. + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + bit SUBSTATUS_CANT_RUN, [hl] + jr nz, .failed + +; Otherwise trap the opponent. + + set SUBSTATUS_CANT_RUN, [hl] + call AnimateCurrentMove + ld hl, CantEscapeNowText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37536 + + +INCLUDE "engine/battle/effect_commands/nightmare.asm" + + +BattleCommand_Defrost: ; 37563 +; defrost + +; Thaw the user. + + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + bit FRZ, [hl] + ret z + res FRZ, [hl] + +; Don't update the enemy's party struct in a wild battle. + + ld a, [hBattleTurn] + and a + jr z, .party + + ld a, [wBattleMode] + dec a + jr z, .done + +.party + ld a, MON_STATUS + call UserPartyAttr + res FRZ, [hl] + +.done + call RefreshBattleHuds + ld hl, WasDefrostedText + jp StdBattleTextBox + +; 37588 + + +INCLUDE "engine/battle/effect_commands/curse.asm" + +INCLUDE "engine/battle/effect_commands/protect.asm" + +INCLUDE "engine/battle/effect_commands/endure.asm" + +INCLUDE "engine/battle/effect_commands/spikes.asm" + +INCLUDE "engine/battle/effect_commands/foresight.asm" + +INCLUDE "engine/battle/effect_commands/perish_song.asm" + +INCLUDE "engine/battle/effect_commands/sandstorm.asm" + +INCLUDE "engine/battle/effect_commands/rollout.asm" + + +BattleCommand5d: ; 37791 +; unused + ret + +; 37792 + + +BattleCommand_FuryCutter: ; 37792 +; furycutter + + ld hl, PlayerFuryCutterCount + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, EnemyFuryCutterCount + +.go + ld a, [AttackMissed] + and a + jp nz, ResetFuryCutterCount + + inc [hl] + +; Damage capped at 5 turns' worth (16x). + ld a, [hl] + ld b, a + cp 6 + jr c, .checkdouble + ld b, 5 + +.checkdouble + dec b + ret z + +; Double the damage + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .checkdouble + +; No overflow + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 377be + + +ResetFuryCutterCount: ; 377be + + push hl + + ld hl, PlayerFuryCutterCount + ld a, [hBattleTurn] + and a + jr z, .reset + ld hl, EnemyFuryCutterCount + +.reset + xor a + ld [hl], a + + pop hl + ret + +; 377ce + + +INCLUDE "engine/battle/effect_commands/attract.asm" + +BattleCommand_HappinessPower: ; 3784b +; happinesspower + push bc + ld hl, BattleMonHappiness + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHappiness +.ok + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + ld a, 10 + ld [hMultiplier], a + call Multiply + ld a, 25 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld d, a + pop bc + ret + +; 37874 + + +INCLUDE "engine/battle/effect_commands/present.asm" + +BattleCommand_FrustrationPower: ; 3790e +; frustrationpower + + push bc + ld hl, BattleMonHappiness + ld a, [hBattleTurn] + and a + jr z, .got_happiness + ld hl, EnemyMonHappiness +.got_happiness + ld a, $ff + sub [hl] + ld [hMultiplicand + 2], a + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, 10 + ld [hMultiplier], a + call Multiply + ld a, 25 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld d, a + pop bc + ret + +; 37939 + + +BattleCommand_Safeguard: ; 37939 +; safeguard + + ld hl, PlayerScreens + ld de, PlayerSafeguardCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyScreens + ld de, EnemySafeguardCount +.ok + bit SCREENS_SAFEGUARD, [hl] + jr nz, .failed + set SCREENS_SAFEGUARD, [hl] + ld a, 5 + ld [de], a + call AnimateCurrentMove + ld hl, CoveredByVeilText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37962 + + +SafeCheckSafeguard: ; 37962 + push hl + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, PlayerScreens + +.got_turn + bit SCREENS_SAFEGUARD, [hl] + pop hl + ret + +; 37972 + + +BattleCommand_CheckSafeguard: ; 37972 +; checksafeguard + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, PlayerScreens +.got_turn + bit SCREENS_SAFEGUARD, [hl] + ret z + ld a, 1 + ld [AttackMissed], a + call BattleCommand_MoveDelay + ld hl, SafeguardProtectText + call StdBattleTextBox + jp EndMoveEffect + +; 37991 + + +BattleCommand_GetMagnitude: ; 37991 +; getmagnitude + + push bc + call BattleRandom + ld b, a + ld hl, .Magnitudes +.loop + ld a, [hli] + cp b + jr nc, .ok + inc hl + inc hl + jr .loop + +.ok + ld d, [hl] + push de + inc hl + ld a, [hl] + ld [wTypeMatchup], a + call BattleCommand_MoveDelay + ld hl, MagnitudeText + call StdBattleTextBox + pop de + pop bc + ret + +.Magnitudes: + ; /255, BP, magnitude + db 13, 10, 4 + db 38, 30, 5 + db 89, 50, 6 + db 166, 70, 7 + db 217, 90, 8 + db 242, 110, 9 + db 255, 150, 10 +; 379c9 + + +BattleCommand_BatonPass: ; 379c9 +; batonpass + + ld a, [hBattleTurn] + and a + jp nz, .Enemy + + +; Need something to switch to + call CheckAnyOtherAlivePartyMons + jp z, FailedBatonPass + + call UpdateBattleMonInParty + call AnimateCurrentMove + + ld c, 50 + call DelayFrames + +; Transition into switchmon menu + call LoadStandardMenuDataHeader + farcall SetUpBattlePartyMenu_NoLoop + + farcall ForcePickSwitchMonInBattle + +; Return to battle scene + call ClearPalettes + farcall _LoadBattleFontsHPBar + call CloseWindow + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + call BatonPass_LinkPlayerSwitch + +; Mobile link battles handle entrances differently + farcall CheckMobileBattleError + jp c, EndMoveEffect + + ld hl, PassedBattleMonEntrance + call CallBattleCore + + call ResetBatonPassStatus + ret + + +.Enemy: + +; Wildmons don't have anything to switch to + ld a, [wBattleMode] + dec a ; WILDMON + jp z, FailedBatonPass + + call CheckAnyOtherAliveEnemyMons + jp z, FailedBatonPass + + call UpdateEnemyMonInParty + call AnimateCurrentMove + call BatonPass_LinkEnemySwitch + +; Mobile link battles handle entrances differently + farcall CheckMobileBattleError + jp c, EndMoveEffect + +; Passed enemy PartyMon entrance + xor a + ld [wEnemySwitchMonIndex], a + ld hl, EnemySwitch_SetMode + call CallBattleCore + ld hl, ResetBattleParticipants + call CallBattleCore + ld a, 1 + ld [wTypeMatchup], a + ld hl, ApplyStatLevelMultiplierOnAllStats + call CallBattleCore + + ld hl, SpikesDamage + call CallBattleCore + + jr ResetBatonPassStatus + +; 37a67 + + +BatonPass_LinkPlayerSwitch: ; 37a67 + ld a, [wLinkMode] + and a + ret z + + ld a, 1 + ld [wPlayerAction], a + + call LoadStandardMenuDataHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + call CloseWindow + + xor a + ld [wPlayerAction], a + ret + +; 37a82 + + +BatonPass_LinkEnemySwitch: ; 37a82 + ld a, [wLinkMode] + and a + ret z + + call LoadStandardMenuDataHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + + ld a, [OTPartyCount] + add BATTLEACTION_SWITCH1 + ld b, a + ld a, [wBattleAction] + cp BATTLEACTION_SWITCH1 + jr c, .baton_pass + cp b + jr c, .switch + +.baton_pass + ld a, [CurOTMon] + add BATTLEACTION_SWITCH1 + ld [wBattleAction], a +.switch + jp CloseWindow + +; 37aab + + +FailedBatonPass: ; 37aab + call AnimateFailedMove + jp PrintButItFailed + +; 37ab1 + + +ResetBatonPassStatus: ; 37ab1 +; Reset status changes that aren't passed by Baton Pass. + + ; Nightmare isn't passed. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr nz, .ok + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] +.ok + + ; Disable isn't passed. + call ResetActorDisable + + ; Attraction isn't passed. + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, EnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, PlayerSubStatus5 + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_TRANSFORMED, [hl] + res SUBSTATUS_ENCORED, [hl] + + ; New mon hasn't used a move yet. + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], 0 + + xor a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ret + +; 37ae9 + + +CheckAnyOtherAlivePartyMons: ; 37ae9 + ld hl, PartyMon1HP + ld a, [PartyCount] + ld d, a + ld a, [CurBattleMon] + ld e, a + jr CheckAnyOtherAliveMons + +; 37af6 + + +CheckAnyOtherAliveEnemyMons: ; 37af6 + ld hl, OTPartyMon1HP + ld a, [OTPartyCount] + ld d, a + ld a, [CurOTMon] + ld e, a + + ; fallthrough +; 37b01 + +CheckAnyOtherAliveMons: ; 37b01 +; Check for nonzero HP starting from partymon +; HP at hl for d partymons, besides current mon e. + +; Return nz if any are alive. + + xor a + ld b, a + ld c, a +.loop + ld a, c + cp d + jr z, .done + cp e + jr z, .next + + ld a, [hli] + or b + ld b, a + ld a, [hld] + or b + ld b, a + +.next + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + inc c + jr .loop + +.done + ld a, b + and a + ret + +; 37b1d + + +BattleCommand_Pursuit: ; 37b1d +; pursuit +; Double damage if the opponent is switching. + + ld hl, wEnemyIsSwitching + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerIsSwitching +.ok + ld a, [hl] + and a + ret z + + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 37b39 + + +BattleCommand_ClearHazards: ; 37b39 +; clearhazards + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr z, .not_leeched + res SUBSTATUS_LEECH_SEED, [hl] + ld hl, ShedLeechSeedText + call StdBattleTextBox +.not_leeched + + ld hl, PlayerScreens + ld de, wPlayerWrapCount + ld a, [hBattleTurn] + and a + jr z, .got_screens_wrap + ld hl, EnemyScreens + ld de, wEnemyWrapCount +.got_screens_wrap + bit SCREENS_SPIKES, [hl] + jr z, .no_spikes + res SCREENS_SPIKES, [hl] + ld hl, BlewSpikesText + push de + call StdBattleTextBox + pop de +.no_spikes + + ld a, [de] + and a + ret z + xor a + ld [de], a + ld hl, ReleasedByText + jp StdBattleTextBox + +; 37b74 + + +BattleCommand_HealMorn: ; 37b74 +; healmorn + ld b, MORN_F + jr BattleCommand_TimeBasedHealContinue + +; 37b78 + +BattleCommand_HealDay: ; 37b78 +; healday + ld b, DAY_F + jr BattleCommand_TimeBasedHealContinue + +; 37b7c + +BattleCommand_HealNite: ; 37b7c +; healnite + ld b, NITE_F + ; fallthrough +; 37b7e + +BattleCommand_TimeBasedHealContinue: ; 37b7e +; Time- and weather-sensitive heal. + + ld hl, BattleMonMaxHP + ld de, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .start + ld hl, EnemyMonMaxHP + ld de, EnemyMonHP + +.start +; Index for .Multipliers +; Default restores half max HP. + ld c, 2 + +; Don't bother healing if HP is already full. + push bc + call StringCmp + pop bc + jr z, .Full + +; Don't factor in time of day in link battles. + ld a, [wLinkMode] + and a + jr nz, .Weather + + ld a, [TimeOfDay] + cp b + jr z, .Weather + dec c ; double + +.Weather: + ld a, [Weather] + and a + jr z, .Heal + +; x2 in sun +; /2 in rain/sandstorm + inc c + cp WEATHER_SUN + jr z, .Heal + dec c + dec c + +.Heal: + ld b, 0 + ld hl, .Multipliers + add hl, bc + add hl, bc + + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(GetMaxHP) + rst FarCall + + call AnimateCurrentMove + call BattleCommand_SwitchTurn + + callfar RestoreHP + + call BattleCommand_SwitchTurn + call UpdateUserInParty + +; 'regained health!' + ld hl, RegainedHealthText + jp StdBattleTextBox + +.Full: + call AnimateFailedMove + +; 'hp is full!' + ld hl, HPIsFullText + jp StdBattleTextBox + +.Multipliers: + dw GetEighthMaxHP + dw GetQuarterMaxHP + dw GetHalfMaxHP + dw GetMaxHP +; 37be8 + + +BattleCommand_HiddenPower: ; 37be8 +; hiddenpower + + ld a, [AttackMissed] + and a + ret nz + farcall HiddenPowerDamage + ret + +; 37bf4 + + +BattleCommand_StartRain: ; 37bf4 +; startrain + ld a, WEATHER_RAIN + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, DownpourText + jp StdBattleTextBox + +; 37c07 + + +BattleCommand_StartSun: ; 37c07 +; startsun + ld a, WEATHER_SUN + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, SunGotBrightText + jp StdBattleTextBox + +; 37c1a + + +BattleCommand_BellyDrum: ; 37c1a +; bellydrum +; This command is buggy because it raises the user's attack +; before checking that it has enough HP to use the move. +; Swap the order of these two blocks to fix. + call BattleCommand_AttackUp2 + ld a, [AttackMissed] + and a + jr nz, .failed + + callfar GetHalfMaxHP + callfar CheckUserHasEnoughHP + jr nc, .failed + + push bc + call AnimateCurrentMove + pop bc + callfar SubtractHPFromUser + call UpdateUserInParty + ld a, 5 + +.max_attack_loop + push af + call BattleCommand_AttackUp2 + pop af + dec a + jr nz, .max_attack_loop + + ld hl, BellyDrumText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37c55 + + +BattleCommand_PsychUp: ; 37c55 +; psychup + + ld hl, EnemyStatLevels + ld de, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .pointers_correct +; It's the enemy's turn, so swap the pointers. + push hl + ld h, d + ld l, e + pop de +.pointers_correct + push hl + ld b, NUM_LEVEL_STATS +; If any of the enemy's stats is modified from its base level, +; the move succeeds. Otherwise, it fails. +.loop + ld a, [hli] + cp BASE_STAT_LEVEL + jr nz, .break + dec b + jr nz, .loop + pop hl + call AnimateFailedMove + jp PrintButItFailed + +.break + pop hl + ld b, NUM_LEVEL_STATS +.loop2 + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop2 + ld a, [hBattleTurn] + and a + jr nz, .calc_enemy_stats + call CalcPlayerStats + jr .merge + +.calc_enemy_stats + call CalcEnemyStats +.merge + call AnimateCurrentMove + ld hl, CopiedStatsText + jp StdBattleTextBox + +; 37c95 + + +BattleCommand_MirrorCoat: ; 37c95 +; mirrorcoat + + ld a, 1 + ld [AttackMissed], a + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + ret z + + ld b, a + callfar GetMoveEffect + ld a, b + cp EFFECT_MIRROR_COAT + ret z + + call BattleCommand_ResetTypeMatchup + ld a, [wTypeMatchup] + and a + ret z + + call CheckOpponentWentFirst + ret z + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + dec a + ld de, StringBuffer1 + call GetMoveData + + ld a, [StringBuffer1 + 2] + and a + ret z + + ld a, [StringBuffer1 + 3] + cp SPECIAL + ret c + + ld hl, CurDamage + ld a, [hli] + or [hl] + ret z + + ld a, [hl] + add a + ld [hld], a + ld a, [hl] + adc a + ld [hl], a + jr nc, .capped + ld a, $ff + ld [hli], a + ld [hl], a +.capped + + xor a + ld [AttackMissed], a + ret + +; 37ce6 + + +BattleCommand_DoubleMinimizeDamage: ; 37ce6 +; doubleminimizedamage + + ld hl, wEnemyMinimized + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerMinimized +.ok + ld a, [hl] + and a + ret z + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 37d02 + + +BattleCommand_SkipSunCharge: ; 37d02 +; mimicsuncharge + ld a, [Weather] + cp WEATHER_SUN + ret nz + ld b, charge_command + jp SkipToBattleCommand + +; 37d0d + + +BattleCommand_CheckFutureSight: ; 37d0d +; checkfuturesight + + ld hl, wPlayerFutureSightCount + ld de, wPlayerFutureSightDamage + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyFutureSightCount + ld de, wEnemyFutureSightDamage +.ok + + ld a, [hl] + and a + ret z + cp 1 + ret nz + + ld [hl], 0 + ld a, [de] + inc de + ld [CurDamage], a + ld a, [de] + ld [CurDamage + 1], a + ld b, futuresight_command + jp SkipToBattleCommand + +; 37d34 + +BattleCommand_FutureSight: ; 37d34 +; futuresight + + call CheckUserIsCharging + jr nz, .AlreadyChargingFutureSight + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + ld [hl], b + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], b +.AlreadyChargingFutureSight: + ld hl, wPlayerFutureSightCount + ld a, [hBattleTurn] + and a + jr z, .GotFutureSightCount + ld hl, wEnemyFutureSightCount +.GotFutureSightCount: + ld a, [hl] + and a + jr nz, .failed + ld a, 4 + ld [hl], a + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + ld hl, ForesawAttackText + call StdBattleTextBox + call BattleCommand_RaiseSub + ld de, wPlayerFutureSightDamage + ld a, [hBattleTurn] + and a + jr z, .StoreDamage + ld de, wEnemyFutureSightDamage +.StoreDamage: + ld hl, CurDamage + ld a, [hl] + ld [de], a + ld [hl], 0 + inc hl + inc de + ld a, [hl] + ld [de], a + ld [hl], 0 + jp EndMoveEffect + +.failed + pop bc + call ResetDamage + call AnimateFailedMove + call PrintButItFailed + jp EndMoveEffect + +; 37d94 + + +BattleCommand_ThunderAccuracy: ; 37d94 +; thunderaccuracy + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + inc hl + ld a, [Weather] + cp WEATHER_RAIN + jr z, .rain + cp WEATHER_SUN + ret nz + ld [hl], 50 percent + 1 + ret + +.rain + ; Redundant with CheckHit guranteeing hit + ld [hl], 100 percent + ret + +; 37daa + + +CheckHiddenOpponent: ; 37daa +; BUG: This routine should account for Lock-On and Mind Reader. + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +; 37db2 + + +GetUserItem: ; 37db2 +; Return the effect of the user's item in bc, and its id at hl. + ld hl, BattleMonItem + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, EnemyMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +; 37dc1 + + +GetOpponentItem: ; 37dc1 +; Return the effect of the opponent's item in bc, and its id at hl. + ld hl, EnemyMonItem + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, BattleMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +; 37dd0 + + +GetItemHeldEffect: ; 37dd0 +; Return the effect of item b in bc. + ld a, b + and a + ret z + + push hl + ld hl, ItemAttributes + ITEMATTR_EFFECT + dec a + ld c, a + ld b, 0 + ld a, ITEMATTR_STRUCT_LENGTH + call AddNTimes + ld a, BANK(ItemAttributes) + call GetFarHalfword + ld b, l + ld c, h + pop hl + ret + +; 37de9 + + +AnimateCurrentMoveEitherSide: ; 37de9 + push hl + push de + push bc + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + call PlayDamageAnim + call BattleCommand_RaiseSub + pop bc + pop de + pop hl + ret + +; 37e01 + + +AnimateCurrentMove: ; 37e01 + push hl + push de + push bc + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + call LoadMoveAnim + call BattleCommand_RaiseSub + pop bc + pop de + pop hl + ret + +; 37e19 + + +PlayDamageAnim: ; 37e19 + xor a + ld [FXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ld [FXAnimID], a + + ld a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .player + ld a, BATTLEANIM_PLAYER_DAMAGE + +.player + ld [wNumHits], a + + jp PlayUserBattleAnim + +; 37e36 + + +LoadMoveAnim: ; 37e36 + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ; fallthrough +; 37e44 + + +LoadAnim: ; 37e44 + + ld [FXAnimID], a + + ; fallthrough +; 37e47 + + +PlayUserBattleAnim: ; 37e47 + push hl + push de + push bc + callfar PlayBattleAnim + pop bc + pop de + pop hl + ret + +; 37e54 + + +PlayOpponentBattleAnim: ; 37e54 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + xor a + ld [wNumHits], a + + push hl + push de + push bc + call BattleCommand_SwitchTurn + + callfar PlayBattleAnim + + call BattleCommand_SwitchTurn + pop bc + pop de + pop hl + ret + +; 37e73 + + +CallBattleCore: ; 37e73 + ld a, BANK(BattleCore) + rst FarCall + ret + +; 37e77 + + +AnimateFailedMove: ; 37e77 + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + jp BattleCommand_RaiseSub + +; 37e80 + + +BattleCommand_MoveDelay: ; 37e80 +; movedelay +; Wait 40 frames. + ld c, 40 + jp DelayFrames + +; 37e85 + + +BattleCommand_ClearText: ; 37e85 +; cleartext + +; Used in multi-hit moves. + ld hl, .text + jp BattleTextBox + +.text + db "@" +; 37e8c + + +SkipToBattleCommand: ; 37e8c +; Skip over commands until reaching command b. + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, [BattleScriptBufferAddress] + ld l, a +.loop + ld a, [hli] + cp b + jr nz, .loop + + ld a, h + ld [BattleScriptBufferAddress + 1], a + ld a, l + ld [BattleScriptBufferAddress], a + ret + +; 37ea1 + + +GetMoveAttr: ; 37ea1 +; Assuming hl = Moves + x, return attribute x of move a. + push bc + ld bc, MOVE_LENGTH + call AddNTimes + call GetMoveByte + pop bc + ret + +; 37ead + + +GetMoveData: ; 37ead +; Copy move struct a to de. + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld a, Bank(Moves) + jp FarCopyBytes + +; 37ebb + + +GetMoveByte: ; 37ebb + ld a, BANK(Moves) + jp GetFarByte + +; 37ec0 + + +DisappearUser: ; 37ec0 + farcall _DisappearUser + ret + +; 37ec7 + + +AppearUserLowerSub: ; 37ec7 + farcall _AppearUserLowerSub + ret + +; 37ece + + +AppearUserRaiseSub: ; 37ece + farcall _AppearUserRaiseSub + ret + +; 37ed5 + + +_CheckBattleScene: ; 37ed5 +; Checks the options. Returns carry if battle animations are disabled. + push hl + push de + push bc + farcall CheckBattleScene + pop bc + pop de + pop hl + ret + +; 37ee2 diff --git a/engine/battle/effect_commands/attract.asm b/engine/battle/effect_commands/attract.asm new file mode 100755 index 000000000..0a6d7c975 --- /dev/null +++ b/engine/battle/effect_commands/attract.asm @@ -0,0 +1,79 @@ +BattleCommand_Attract: ; 377ce +; attract + ld a, [AttackMissed] + and a + jr nz, .failed + call CheckOppositeGender + jr c, .failed + call CheckHiddenOpponent + jr nz, .failed + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_IN_LOVE, [hl] + jr nz, .failed + + set SUBSTATUS_IN_LOVE, [hl] + call AnimateCurrentMove + +; 'fell in love!' + ld hl, FellInLoveText + jp StdBattleTextBox + +.failed + jp FailAttract +; 377f5 + + +CheckOppositeGender: ; 377f5 + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hl] + ld [CurPartySpecies], a + + ld a, [CurBattleMon] + ld [CurPartyMon], a + xor a + ld [MonType], a + + farcall GetGender + jr c, .genderless_samegender + + ld b, 1 + jr nz, .got_gender + dec b + +.got_gender + push bc + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld hl, EnemyMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .not_transformed + ld hl, wEnemyBackupDVs +.not_transformed + ld a, [hli] + ld [TempMonDVs], a + ld a, [hl] + ld [TempMonDVs + 1], a + ld a, 3 + ld [MonType], a + farcall GetGender + pop bc + jr c, .genderless_samegender + + ld a, 1 + jr nz, .got_enemy_gender + dec a + +.got_enemy_gender + xor b + jr z, .genderless_samegender + + and a + ret + +.genderless_samegender + scf + ret +; 3784b diff --git a/engine/battle/effect_commands/curse.asm b/engine/battle/effect_commands/curse.asm new file mode 100644 index 000000000..dceb3b8d5 --- /dev/null +++ b/engine/battle/effect_commands/curse.asm @@ -0,0 +1,97 @@ +BattleCommand_Curse: ; 37588 +; curse + + ld de, BattleMonType1 + ld bc, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .go + ld de, EnemyMonType1 + ld bc, EnemyStatLevels + +.go + +; Curse is different for Ghost-types. + + ld a, [de] + cp GHOST + jr z, .ghost + inc de + ld a, [de] + cp GHOST + jr z, .ghost + + +; If no stats can be increased, don't. + +; Attack + ld a, [bc] + cp MAX_STAT_LEVEL + jr c, .raise + +; Defense + inc bc + ld a, [bc] + cp MAX_STAT_LEVEL + jr nc, .cantraise + +.raise + +; Raise Attack and Defense, and lower Speed. + + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld a, SPEED + call LowerStat + call BattleCommand_SwitchTurn + call BattleCommand_StatDownMessage + call ResetMiss + call BattleCommand_SwitchTurn + call BattleCommand_AttackUp + call BattleCommand_StatUpMessage + call ResetMiss + call BattleCommand_DefenseUp + jp BattleCommand_StatUpMessage + + +.ghost + +; Cut HP in half and put a curse on the opponent. + + call CheckHiddenOpponent + jr nz, .failed + + call CheckSubstituteOpp + jr nz, .failed + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_CURSE, [hl] + jr nz, .failed + + set SUBSTATUS_CURSE, [hl] + call AnimateCurrentMove + ld hl, GetHalfMaxHP + call CallBattleCore + ld hl, SubtractHPFromUser + call CallBattleCore + call UpdateUserInParty + ld hl, PutACurseText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + + +.cantraise + +; Can't raise either stat. + + ld b, ABILITY + 1 + call GetStatName + call AnimateFailedMove + ld hl, WontRiseAnymoreText + jp StdBattleTextBox +; 37618 diff --git a/engine/battle/effect_commands/endure.asm b/engine/battle/effect_commands/endure.asm new file mode 100644 index 000000000..ed4329ff5 --- /dev/null +++ b/engine/battle/effect_commands/endure.asm @@ -0,0 +1,17 @@ +BattleCommand_Endure: ; 3766f +; endure + +; Endure shares code with Protect. See protect.asm. + + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_ENDURE, [hl] + + call AnimateCurrentMove + + ld hl, BracedItselfText + jp StdBattleTextBox +; 37683 diff --git a/engine/battle/effect_commands/foresight.asm b/engine/battle/effect_commands/foresight.asm new file mode 100644 index 000000000..6f4f97cd2 --- /dev/null +++ b/engine/battle/effect_commands/foresight.asm @@ -0,0 +1,23 @@ +BattleCommand_Foresight: ; 376a0 +; foresight + + ld a, [AttackMissed] + and a + jr nz, .failed + + call CheckHiddenOpponent + jr nz, .failed + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_IDENTIFIED, [hl] + jr nz, .failed + + set SUBSTATUS_IDENTIFIED, [hl] + call AnimateCurrentMove + ld hl, IdentifiedText + jp StdBattleTextBox + +.failed + jp FailForesight +; 376c2 diff --git a/engine/battle/effect_commands/metronome.asm b/engine/battle/effect_commands/metronome.asm new file mode 100644 index 000000000..1908df84d --- /dev/null +++ b/engine/battle/effect_commands/metronome.asm @@ -0,0 +1,61 @@ +BattleCommand_Metronome: ; 37418 +; metronome + + call ClearLastMove + call CheckUserIsCharging + jr nz, .asm_3742b + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.asm_3742b + call LoadMoveAnim + +.GetMove: + call BattleRandom + +; No invalid moves. + cp NUM_ATTACKS + 1 + jr nc, .GetMove + +; None of the moves in MetronomeExcepts. + push af + ld de, 1 + ld hl, MetronomeExcepts + call IsInArray + pop bc + jr c, .GetMove + +; No moves the user already has. + ld a, b + call CheckUserMove + jr z, .GetMove + + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld [hl], b + call UpdateMoveData + jp ResetTurn +; 37454 + + +MetronomeExcepts: ; 37454 + db NO_MOVE + db METRONOME + db STRUGGLE + db SKETCH + db MIMIC + db COUNTER + db MIRROR_COAT + db PROTECT + db DETECT + db ENDURE + db DESTINY_BOND + db SLEEP_TALK + db THIEF + db -1 +; 37462 diff --git a/engine/battle/effect_commands/mirror_move.asm b/engine/battle/effect_commands/mirror_move.asm new file mode 100644 index 000000000..c4f208d77 --- /dev/null +++ b/engine/battle/effect_commands/mirror_move.asm @@ -0,0 +1,52 @@ +BattleCommand_MirrorMove: ; 373c9 +; mirrormove + + call ClearLastMove + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + + call CheckUserMove + jr nz, .use + +.failed + call AnimateFailedMove + + ld hl, MirrorMoveFailedText + call StdBattleTextBox + jp EndMoveEffect + +.use + ld a, b + ld [hl], a + ld [wd265], a + + push af + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + pop af + + dec a + call GetMoveData + call GetMoveName + call CopyName1 + call CheckUserIsCharging + jr nz, .done + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.done + call BattleCommand_MoveDelay + jp ResetTurn +; 37418 diff --git a/engine/battle/effect_commands/nightmare.asm b/engine/battle/effect_commands/nightmare.asm new file mode 100644 index 000000000..788e3de41 --- /dev/null +++ b/engine/battle/effect_commands/nightmare.asm @@ -0,0 +1,38 @@ +BattleCommand_Nightmare: ; 37536 +; nightmare + +; Can't hit an absent opponent. + + call CheckHiddenOpponent + jr nz, .failed + +; Can't hit a substitute. + + call CheckSubstituteOpp + jr nz, .failed + +; Only works on a sleeping opponent. + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and SLP + jr z, .failed + +; Bail if the opponent is already having a nightmare. + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_NIGHTMARE, [hl] + jr nz, .failed + +; Otherwise give the opponent a nightmare. + + set SUBSTATUS_NIGHTMARE, [hl] + call AnimateCurrentMove + ld hl, StartedNightmareText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed +; 37563 diff --git a/engine/battle/effect_commands/perish_song.asm b/engine/battle/effect_commands/perish_song.asm new file mode 100644 index 000000000..ac491ef6b --- /dev/null +++ b/engine/battle/effect_commands/perish_song.asm @@ -0,0 +1,40 @@ +BattleCommand_PerishSong: ; 376c2 +; perishsong + + + ld hl, PlayerSubStatus1 + ld de, EnemySubStatus1 + bit SUBSTATUS_PERISH, [hl] + jr z, .ok + + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .failed + +.ok + bit SUBSTATUS_PERISH, [hl] + jr nz, .enemy + + set SUBSTATUS_PERISH, [hl] + ld a, 4 + ld [PlayerPerishCount], a + +.enemy + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .done + + set SUBSTATUS_PERISH, a + ld [de], a + ld a, 4 + ld [EnemyPerishCount], a + +.done + call AnimateCurrentMove + ld hl, StartPerishText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed +; 376f8 diff --git a/engine/battle/effect_commands/present.asm b/engine/battle/effect_commands/present.asm new file mode 100755 index 000000000..819294f8c --- /dev/null +++ b/engine/battle/effect_commands/present.asm @@ -0,0 +1,93 @@ +BattleCommand_Present: ; 37874 +; present + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .colosseum_skippush + push bc + push de +.colosseum_skippush + + call BattleCommand_Stab + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .colosseum_skippop + pop de + pop bc +.colosseum_skippop + + ld a, [wTypeMatchup] + and a + jp z, AnimateFailedMove + ld a, [AttackMissed] + and a + jp nz, AnimateFailedMove + + push bc + call BattleRandom + ld b, a + ld hl, .PresentPower + ld c, 0 +.next + ld a, [hli] + cp $ff + jr z, .heal_effect ; 378a4 $11 + cp b + jr nc, .got_power ; 378a7 $4 + inc c + inc hl + jr .next ; 378ab $f4 + +.got_power + ld a, c + ld [wPresentPower], a + call AnimateCurrentMoveEitherSide + ld d, [hl] + pop bc + ret + +.heal_effect + pop bc + ld a, $3 + ld [wPresentPower], a + call AnimateCurrentMove + call BattleCommand_SwitchTurn + ld hl, AICheckPlayerMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp_fn_pointer ; 378c9 $3 + ld hl, AICheckEnemyMaxHP +.got_hp_fn_pointer + ld a, BANK(AICheckPlayerMaxHP) + rst FarCall + jr c, .already_fully_healed ; 378d1 $20 + + ld hl, GetQuarterMaxHP + call CallBattleCore + call BattleCommand_SwitchTurn + ld hl, RestoreHP + call CallBattleCore + call BattleCommand_SwitchTurn + ld hl, RegainedHealthText + call StdBattleTextBox + call BattleCommand_SwitchTurn + call UpdateOpponentInParty + jr .do_animation ; 378f1 $11 + +.already_fully_healed + call BattleCommand_SwitchTurn + call _CheckBattleScene + jr nc, .do_animation ; 378f9 $9 + call AnimateFailedMove + ld hl, RefusedGiftText + call StdBattleTextBox +.do_animation + jp EndMoveEffect + +.PresentPower: + db 40 percent, 40 + db 70 percent + 1, 80 + db 80 percent, 120 + db $ff +; 3790e diff --git a/engine/battle/effect_commands/protect.asm b/engine/battle/effect_commands/protect.asm new file mode 100644 index 000000000..568ac00f8 --- /dev/null +++ b/engine/battle/effect_commands/protect.asm @@ -0,0 +1,80 @@ +BattleCommand_Protect: ; 37618 +; protect + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_PROTECT, [hl] + + call AnimateCurrentMove + + ld hl, ProtectedItselfText + jp StdBattleTextBox +; 3762c + + +ProtectChance: ; 3762c + + ld de, PlayerProtectCount + ld a, [hBattleTurn] + and a + jr z, .asm_37637 + ld de, EnemyProtectCount +.asm_37637 + + call CheckOpponentWentFirst + jr nz, .failed + +; Can't have a substitute. + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + jr nz, .failed + +; Halve the chance of a successful Protect for each consecutive use. + + ld b, $ff + ld a, [de] + ld c, a +.loop + ld a, c + and a + jr z, .done + dec c + + srl b + ld a, b + and a + jr nz, .loop + jr .failed +.done + +.rand + call BattleRandom + and a + jr z, .rand + + dec a + cp b + jr nc, .failed + +; Another consecutive Protect use. + + ld a, [de] + inc a + ld [de], a + + and a + ret + + +.failed + xor a + ld [de], a + call AnimateFailedMove + call PrintButItFailed + scf + ret +; 3766f diff --git a/engine/battle/effect_commands/rollout.asm b/engine/battle/effect_commands/rollout.asm new file mode 100644 index 000000000..4ce9ab3d8 --- /dev/null +++ b/engine/battle/effect_commands/rollout.asm @@ -0,0 +1,99 @@ +MAX_ROLLOUT_COUNT EQU 5 + + +BattleCommand_CheckCurl: ; 37718 +; checkcurl + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyRolloutCount +.ok + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_ROLLOUT, a + jr z, .reset + + ld b, $4 ; doturn + jp SkipToBattleCommand + +.reset + xor a + ld [de], a + ret +; 37734 + + +BattleCommand_RolloutPower: ; 37734 +; rolloutpower + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .got_rollout_count + ld hl, EnemyRolloutCount + +.got_rollout_count + ld a, [hl] + and a + jr nz, .skip_set_rampage + ld a, 1 + ld [wSomeoneIsRampaging], a + +.skip_set_rampage + ld a, [AttackMissed] + and a + jr z, .hit + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res 6, [hl] + ret + +.hit + inc [hl] + ld a, [hl] + ld b, a + cp MAX_ROLLOUT_COUNT + jr c, .not_done_with_rollout + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_ROLLOUT, [hl] + jr .done_with_substatus_flag + +.not_done_with_rollout + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_ROLLOUT, [hl] + +.done_with_substatus_flag + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVar + bit SUBSTATUS_CURLED, a + jr z, .not_curled + inc b +.not_curled +.loop + dec b + jr z, .done_damage + + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .loop + + ld a, $ff + ld [hli], a + ld [hl], a + +.done_damage + ret +; 37791 diff --git a/engine/battle/effect_commands/sandstorm.asm b/engine/battle/effect_commands/sandstorm.asm new file mode 100644 index 000000000..27b8e8e2c --- /dev/null +++ b/engine/battle/effect_commands/sandstorm.asm @@ -0,0 +1,19 @@ +BattleCommand_StartSandstorm: ; 376f8 +; startsandstorm + + ld a, [Weather] + cp WEATHER_SANDSTORM + jr z, .failed + + ld a, WEATHER_SANDSTORM + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, SandstormBrewedText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed +; 37718 diff --git a/engine/battle/effect_commands/spikes.asm b/engine/battle/effect_commands/spikes.asm new file mode 100644 index 000000000..3d15e4cfd --- /dev/null +++ b/engine/battle/effect_commands/spikes.asm @@ -0,0 +1,27 @@ +BattleCommand_Spikes: ; 37683 +; spikes + + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .asm_3768e + ld hl, PlayerScreens +.asm_3768e + +; Fails if spikes are already down! + + bit SCREENS_SPIKES, [hl] + jr nz, .failed + +; Nothing else stops it from working. + + set SCREENS_SPIKES, [hl] + + call AnimateCurrentMove + + ld hl, SpikesText + jp StdBattleTextBox + +.failed + jp FailSpikes +; 376a0 diff --git a/engine/battle/effect_commands/thief.asm b/engine/battle/effect_commands/thief.asm new file mode 100644 index 000000000..6d32d68d4 --- /dev/null +++ b/engine/battle/effect_commands/thief.asm @@ -0,0 +1,116 @@ +BattleCommand_Thief: ; 37492 +; thief + + ld a, [hBattleTurn] + and a + jr nz, .enemy + +; The player needs to be able to steal an item. + + call .playeritem + ld a, [hl] + and a + ret nz + +; The enemy needs to have an item to steal. + + call .enemyitem + ld a, [hl] + and a + ret z + +; Can't steal mail. + + ld [wd265], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [EffectFailed] + and a + ret nz + + ld a, [wLinkMode] + and a + jr z, .stealenemyitem + + ld a, [wBattleMode] + dec a + ret z + +.stealenemyitem + call .enemyitem + xor a + ld [hl], a + ld [de], a + + call .playeritem + ld a, [wd265] + ld [hl], a + ld [de], a + jr .stole + + +.enemy + +; The enemy can't already have an item. + + call .enemyitem + ld a, [hl] + and a + ret nz + +; The player must have an item to steal. + + call .playeritem + ld a, [hl] + and a + ret z + +; Can't steal mail! + + ld [wd265], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [EffectFailed] + and a + ret nz + +; If the enemy steals your item, +; it's gone for good if you don't get it back. + + call .playeritem + xor a + ld [hl], a + ld [de], a + + call .enemyitem + ld a, [wd265] + ld [hl], a + ld [de], a + + +.stole + call GetItemName + ld hl, StoleText + jp StdBattleTextBox + + +.playeritem + ld a, 1 + call BattlePartyAttr + ld d, h + ld e, l + ld hl, BattleMonItem + ret + +.enemyitem + ld a, 1 + call OTPartyAttr + ld d, h + ld e, l + ld hl, EnemyMonItem + ret +; 37517 diff --git a/engine/battle/effect_commands/transform.asm b/engine/battle/effect_commands/transform.asm new file mode 100755 index 000000000..65c3f3e60 --- /dev/null +++ b/engine/battle/effect_commands/transform.asm @@ -0,0 +1,141 @@ + +BattleCommand_Transform: ; 371cd +; transform + + call ClearLastMove + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_TRANSFORMED, [hl] + jp nz, BattleEffect_ButItFailed + call CheckHiddenOpponent + jp nz, BattleEffect_ButItFailed + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $1 + ld [wKickCounter], a + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_SUBSTITUTE, [hl] + push af + jr z, .mimic_substitute + call CheckUserIsCharging + jr nz, .mimic_substitute + ld a, SUBSTITUTE + call LoadAnim +.mimic_substitute + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_TRANSFORMED, [hl] + call ResetActorDisable + ld hl, BattleMonSpecies + ld de, EnemyMonSpecies + ld a, [hBattleTurn] + and a + jr nz, .got_mon_species + ld hl, EnemyMonSpecies + ld de, BattleMonSpecies + xor a + ld [CurMoveNum], a +.got_mon_species + push hl + ld a, [hli] + ld [de], a + inc hl + inc de + inc de + ld bc, NUM_MOVES + call CopyBytes + ld a, [hBattleTurn] + and a + jr z, .mimic_enemy_backup + ld a, [de] + ld [wEnemyBackupDVs], a + inc de + ld a, [de] + ld [wEnemyBackupDVs + 1], a + dec de +.mimic_enemy_backup +; copy DVs + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de +; move pointer to stats + ld bc, BattleMonStats - BattleMonPP + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, BattleMonStructEnd - BattleMonStats + call CopyBytes +; init the power points + ld bc, BattleMonMoves - BattleMonStructEnd + add hl, bc + push de + ld d, h + ld e, l + pop hl + ld bc, BattleMonPP - BattleMonStructEnd + add hl, bc + ld b, NUM_MOVES +.pp_loop + ld a, [de] + inc de + and a + jr z, .done_move + cp SKETCH + ld a, 1 + jr z, .done_move + ld a, 5 +.done_move + ld [hli], a + dec b + jr nz, .pp_loop + pop hl + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, EnemyStats + ld de, PlayerStats + ld bc, 2 * 5 + call BattleSideCopy + ld hl, EnemyStatLevels + ld de, PlayerStatLevels + ld bc, 8 + call BattleSideCopy + call _CheckBattleScene + jr c, .mimic_anims + ld a, [hBattleTurn] + and a + ld a, [wPlayerMinimized] + jr z, .got_byte + ld a, [wEnemyMinimized] +.got_byte + and a + jr nz, .mimic_anims + call LoadMoveAnim + jr .after_anim + +.mimic_anims + call BattleCommand_MoveDelay + call BattleCommand_RaiseSubNoAnim +.after_anim + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + pop af + ld a, SUBSTITUTE + call nz, LoadAnim + ld hl, TransformedText + jp StdBattleTextBox + +; 372c6 diff --git a/engine/battle/hidden_power.asm b/engine/battle/hidden_power.asm new file mode 100644 index 000000000..c75a67ab3 --- /dev/null +++ b/engine/battle/hidden_power.asm @@ -0,0 +1,111 @@ +HiddenPowerDamage: ; fbced +; Override Hidden Power's type and power based on the user's DVs. + + ld hl, BattleMonDVs + ld a, [hBattleTurn] + and a + jr z, .got_dvs + ld hl, EnemyMonDVs +.got_dvs + + +; Power: + +; Take the top bit from each stat + + ; Attack + ld a, [hl] + swap a + and 8 + + ; Defense + ld b, a + ld a, [hli] + and 8 + srl a + or b + + ; Speed + ld b, a + ld a, [hl] + swap a + and 8 + srl a + srl a + or b + + ; Special + ld b, a + ld a, [hl] + and 8 + srl a + srl a + srl a + or b + +; Multiply by 5 + ld b, a + add a + add a + add b + +; Add Special & 3 + ld b, a + ld a, [hld] + and 3 + add b + +; Divide by 2 and add 30 + 1 + srl a + add 30 + inc a + + ld d, a + + +; Type: + + ; Def & 3 + ld a, [hl] + and 3 + ld b, a + + ; + (Atk & 3) << 2 + ld a, [hl] + and 3 << 4 + swap a + add a + add a + or b + +; Skip Normal + inc a + +; Skip Bird + cp BIRD + jr c, .done + inc a + +; Skip unused types + cp UNUSED_TYPES + jr c, .done + add SPECIAL - UNUSED_TYPES + +.done + +; Overwrite the current move type. + push af + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + pop af + ld [hl], a + +; Get the rest of the damage formula variables +; based on the new type, but keep base power. + ld a, d + push af + farcall BattleCommand_DamageStats ; damagestats + pop af + ld d, a + ret +; fbd54 diff --git a/engine/battle/link_result.asm b/engine/battle/link_result.asm new file mode 100755 index 000000000..cf6102acc --- /dev/null +++ b/engine/battle/link_result.asm @@ -0,0 +1,162 @@ +DetermineLinkBattleResult: ; 2b930 + farcall UpdateEnemyMonInParty + ld hl, PartyMon1HP + call .CountMonsRemaining + push bc + ld hl, OTPartyMon1HP + call .CountMonsRemaining + ld a, c + pop bc + cp c + jr z, .even_number_of_mons_remaining + jr c, .defeat + jr .victory + +.even_number_of_mons_remaining + call .BothSides_CheckNumberMonsAtFullHealth + jr z, .drawn + ld a, e + cp $1 + jr z, .victory + cp $2 + jr z, .defeat + ld hl, PartyMon1HP + call .CalcPercentHPRemaining + push de + ld hl, OTPartyMon1HP + call .CalcPercentHPRemaining + pop hl + ld a, d + cp h + jr c, .victory + jr z, .compare_lo + jr .defeat + +.compare_lo + ld a, e + cp l + jr z, .drawn + jr nc, .defeat + +.victory + ld a, [wBattleResult] + and $f0 + ld [wBattleResult], a + ret + +.defeat + ld a, [wBattleResult] + and $f0 + add $1 + ld [wBattleResult], a + ret + +.drawn + ld a, [wBattleResult] + and $f0 + add $2 + ld [wBattleResult], a + ret + +.CountMonsRemaining: ; 2b995 + ld c, 0 + ld b, 3 + ld de, PARTYMON_STRUCT_LENGTH - 1 +.loop + ld a, [hli] + or [hl] + jr nz, .not_fainted + inc c + +.not_fainted + add hl, de + dec b + jr nz, .loop + ret + +.CalcPercentHPRemaining: ; 2b9a6 + ld de, 0 + ld c, $3 +.loop2 + ld a, [hli] + or [hl] + jr z, .next + dec hl + xor a + ld [hDividend + 0], a + ld a, [hli] + ld [hDividend + 1], a + ld a, [hli] + ld [hDividend + 2], a + xor a + ld [hDividend + 3], a + ld a, [hli] + ld b, a + ld a, [hld] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld b, $4 + call Divide + ld a, [hQuotient + 2] + add e + ld e, a + ld a, [hQuotient + 1] + adc d + ld d, a + dec hl + +.next + push de + ld de, $2f + add hl, de + pop de + dec c + jr nz, .loop2 + ret + +.BothSides_CheckNumberMonsAtFullHealth: ; 2b9e1 + ld hl, PartyMon1HP + call .CheckFaintedOrFullHealth + jr nz, .finish ; we have a pokemon that's neither fainted nor at full health + ld hl, OTPartyMon1HP + call .CheckFaintedOrFullHealth + ld e, $1 + ret + +.finish + ld hl, OTPartyMon1HP + call .CheckFaintedOrFullHealth + ld e, $0 + ret nz ; we both have pokemon that are neither fainted nor at full health + ld e, $2 + ld a, $1 + and a + ret + +.CheckFaintedOrFullHealth: ; 2ba01 + ld d, 3 +.loop3 + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + or b + jr z, .fainted_or_full_health + ld a, [hli] + cp b + ret nz + ld a, [hld] + cp c + ret nz + +.fainted_or_full_health + push de + ld de, PARTYMON_STRUCT_LENGTH - 2 + add hl, de + pop de + dec d + jr nz, .loop3 + ret diff --git a/engine/battle/menu.asm b/engine/battle/menu.asm new file mode 100755 index 000000000..07d3e6081 --- /dev/null +++ b/engine/battle/menu.asm @@ -0,0 +1,118 @@ +LoadBattleMenu: ; 24ef2 + ld hl, BattleMenuDataHeader + call LoadMenuDataHeader + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + call InterpretBattleMenu + ld a, [wMenuCursorBuffer] + ld [wBattleMenuCursorBuffer], a + call ExitMenu + ret +; 24f0b + +SafariBattleMenu: ; 24f0b +; untranslated + ld hl, MenuDataHeader_0x24f4e + call LoadMenuDataHeader + jr Function24f19 +; 24f13 + +ContestBattleMenu: ; 24f13 + ld hl, MenuDataHeader_0x24f89 + call LoadMenuDataHeader +; 24f19 + +Function24f19: ; 24f19 + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + call _2DMenu + ld a, [wMenuCursorBuffer] + ld [wBattleMenuCursorBuffer], a + call ExitMenu + ret +; 24f2c + +BattleMenuDataHeader: ; 24f2c + db $40 ; flags + db 12, 08 ; start coords + db 17, 19 ; end coords + dw MenuData_0x24f34 + db 1 ; default option +; 24f34 + +MenuData_0x24f34: ; 0x24f34 + db $81 ; flags + dn 2, 2 ; rows, columns + db 6 ; spacing + dba Strings24f3d + dbw BANK(MenuData_0x24f34), 0 +; 0x24f3d + +Strings24f3d: ; 0x24f3d + db "FIGHT@" + db "<PKMN>@" + db "PACK@" + db "RUN@" +; 24f4e + +MenuDataHeader_0x24f4e: ; 24f4e + db $40 ; flags + db 12, 00 ; start coords + db 17, 19 ; end coords + dw MenuData_0x24f56 + db 1 ; default option +; 24f56 + +MenuData_0x24f56: ; 24f56 + db $81 ; flags + dn 2, 2 ; rows, columns + db 11 ; spacing + dba Strings24f5f + dba Function24f7c +; 24f5f + +Strings24f5f: ; 24f5f + db "サファりボール× @" ; "SAFARI BALL× @" + db "エサをなげる@" ; "THROW BAIT" + db "いしをなげる@" ; "THROW ROCK" + db "にげる@" ; "RUN" +; 24f7c + +Function24f7c: ; 24f7c + hlcoord 17, 13 + ld de, wSafariBallsRemaining + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret +; 24f89 + +MenuDataHeader_0x24f89: ; 24f89 + db $40 ; flags + db 12, 02 ; start coords + db 17, 19 ; end coords + dw MenuData_0x24f91 + db 1 ; default option +; 24f91 + +MenuData_0x24f91: ; 24f91 + db $81 ; flags + dn 2, 2 ; rows, columns + db 12 ; spacing + dba Strings24f9a + dba Function24fb2 +; 24f9a + +Strings24f9a: ; 24f9a + db "FIGHT@" + db "<PKMN>", "@" + db "PARKBALL× @" + db "RUN@" +; 24fb2 + +Function24fb2: ; 24fb2 + hlcoord 13, 16 + ld de, wParkBallsRemaining + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret +; 24fbf diff --git a/engine/battle/misc.asm b/engine/battle/misc.asm new file mode 100644 index 000000000..b05dc8071 --- /dev/null +++ b/engine/battle/misc.asm @@ -0,0 +1,257 @@ +_DisappearUser: ; fbd54 + xor a + ld [hBGMapMode], a + ld a, [hBattleTurn] + and a + jr z, .player + call GetEnemyFrontpicCoords + jr .okay +.player + call GetPlayerBackpicCoords +.okay + call ClearBox + jr FinishAppearDisappearUser + +_AppearUserRaiseSub: ; fbd69 (3e:7d69) + farcall BattleCommand_RaiseSubNoAnim + jr AppearUser + +_AppearUserLowerSub: ; fbd71 (3e:7d71) + farcall BattleCommand_LowerSubNoAnim + +AppearUser: ; fbd77 (3e:7d77) + xor a + ld [hBGMapMode], a + ld a, [hBattleTurn] + and a + jr z, .player + call GetEnemyFrontpicCoords + xor a + jr .okay +.player + call GetPlayerBackpicCoords + ld a, $31 +.okay + ld [hGraphicStartTile], a + predef PlaceGraphic +FinishAppearDisappearUser: ; fbd91 (3e:7d91) + ld a, $1 + ld [hBGMapMode], a + ret + +GetEnemyFrontpicCoords: ; fbd96 (3e:7d96) + hlcoord 12, 0 + lb bc, 7, 7 + ret + +GetPlayerBackpicCoords: ; fbd9d (3e:7d9d) + hlcoord 2, 6 + lb bc, 6, 6 + ret + + +DoWeatherModifiers: ; fbda4 + + ld de, .WeatherTypeModifiers + ld a, [Weather] + ld b, a + ld a, [wd265] ; move type + ld c, a + +.CheckWeatherType: + ld a, [de] + inc de + cp $ff + jr z, .done_weather_types + + cp b + jr nz, .NextWeatherType + + ld a, [de] + cp c + jr z, .ApplyModifier + +.NextWeatherType: + inc de + inc de + jr .CheckWeatherType + + +.done_weather_types + ld de, .WeatherMoveModifiers + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + ld c, a + +.CheckWeatherMove: + ld a, [de] + inc de + cp $ff + jr z, .done + + cp b + jr nz, .NextWeatherMove + + ld a, [de] + cp c + jr z, .ApplyModifier + +.NextWeatherMove: + inc de + inc de + jr .CheckWeatherMove + +.ApplyModifier: + xor a + ld [hMultiplicand + 0], a + ld hl, CurDamage + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + + inc de + ld a, [de] + ld [hMultiplier], a + + call Multiply + + ld a, 10 + ld [hDivisor], a + ld b, $4 + call Divide + + ld a, [hQuotient + 0] + and a + ld bc, -1 + jr nz, .Update + + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + ld c, a + or b + jr nz, .Update + + ld bc, 1 + +.Update: + ld a, b + ld [CurDamage], a + ld a, c + ld [CurDamage + 1], a + +.done + ret + +.WeatherTypeModifiers: + db WEATHER_RAIN, WATER, 15 + db WEATHER_RAIN, FIRE, 05 + db WEATHER_SUN, FIRE, 15 + db WEATHER_SUN, WATER, 05 + db $ff + +.WeatherMoveModifiers: + db WEATHER_RAIN, EFFECT_SOLARBEAM, 05 + db $ff +; fbe24 + + +DoBadgeTypeBoosts: ; fbe24 + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ld a, [hBattleTurn] + and a + ret nz + + push de + push bc + + ld hl, .BadgeTypes + + ld a, [KantoBadges] + ld b, a + ld a, [JohtoBadges] + ld c, a + +.CheckBadge: + ld a, [hl] + cp $ff + jr z, .done + + srl b + rr c + jr nc, .NextBadge + + ld a, [wd265] ; move type + cp [hl] + jr z, .ApplyBoost + +.NextBadge: + inc hl + jr .CheckBadge + +.ApplyBoost: + ld a, [CurDamage] + ld h, a + ld d, a + ld a, [CurDamage + 1] + ld l, a + ld e, a + + srl d + rr e + srl d + rr e + srl d + rr e + + ld a, e + or d + jr nz, .done_min + ld e, 1 + +.done_min + add hl, de + jr nc, .Update + + ld hl, $ffff + +.Update: + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + +.done + pop bc + pop de + ret + +.BadgeTypes: + db FLYING ; zephyrbadge + db BUG ; hivebadge + db NORMAL ; plainbadge + db GHOST ; fogbadge + db STEEL ; mineralbadge + db FIGHTING ; stormbadge + db ICE ; glacierbadge + db DRAGON ; risingbadge + + db ROCK ; boulderbadge + db WATER ; cascadebadge + db ELECTRIC ; thunderbadge + db GRASS ; rainbowbadge + db POISON ; soulbadge + db PSYCHIC ; marshbadge + db FIRE ; volcanobadge + db GROUND ; earthbadge + db $ff +; fbe91 diff --git a/engine/read_trainer_attributes.asm b/engine/battle/read_trainer_attributes.asm index dfb8d3682..dfb8d3682 100644 --- a/engine/read_trainer_attributes.asm +++ b/engine/battle/read_trainer_attributes.asm diff --git a/engine/battle/read_trainer_dvs.asm b/engine/battle/read_trainer_dvs.asm new file mode 100644 index 000000000..d7c0ff50b --- /dev/null +++ b/engine/battle/read_trainer_dvs.asm @@ -0,0 +1,20 @@ +GetTrainerDVs: ; 270c4 +; Return the DVs of OtherTrainerClass in bc + + push hl + ld a, [OtherTrainerClass] + dec a + ld c, a + ld b, 0 + + ld hl, TrainerClassDVs + add hl, bc + add hl, bc + + ld a, [hli] + ld b, a + ld c, [hl] + + pop hl + ret +; 270d6 diff --git a/engine/read_trainer_party.asm b/engine/battle/read_trainer_party.asm index 9b7727a84..a09c6dd08 100755 --- a/engine/read_trainer_party.asm +++ b/engine/battle/read_trainer_party.asm @@ -1,4 +1,3 @@ - ReadTrainerParty: ; 39771 ld a, [InBattleTowerBattle] bit 0, a diff --git a/engine/routines/returntobattle_useball.asm b/engine/battle/returntobattle_useball.asm index e6e33f900..e6e33f900 100644 --- a/engine/routines/returntobattle_useball.asm +++ b/engine/battle/returntobattle_useball.asm diff --git a/engine/battle/sliding_intro.asm b/engine/battle/sliding_intro.asm new file mode 100755 index 000000000..ed78add8e --- /dev/null +++ b/engine/battle/sliding_intro.asm @@ -0,0 +1,104 @@ +BattleIntroSlidingPics: ; 4e980 + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + call .subfunction1 + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + call .subfunction2 + xor a + ld [hLCDCPointer], a + pop af + ld [rSVBK], a + ret +; 4e998 + +.subfunction1 ; 4e998 + call .subfunction4 + ld a, $90 + ld [hSCX], a + ld a, %11100100 + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + ret +; 4e9ab + +.subfunction2 ; 4e9ab + ld d, $90 + ld e, $72 + ld a, $48 + inc a +.loop1 + push af +.loop2 + ld a, [rLY] + cp $60 + jr c, .loop2 + ld a, d + ld [hSCX], a + call .subfunction5 + inc e + inc e + dec d + dec d + pop af + push af + cp $1 + jr z, .skip1 + push de + call .subfunction3 + pop de + +.skip1 + call DelayFrame + pop af + dec a + jr nz, .loop1 + ret +; 4e9d6 + +.subfunction3 ; 4e9d6 + ld hl, Sprites + 1 ; x pixel + ld c, $12 ; 18 + ld de, $4 +.loop3 + dec [hl] + dec [hl] + add hl, de + dec c + jr nz, .loop3 + ret +; 4e9e5 + +.subfunction4 ; 4e9e5 + ld hl, LYOverrides + ld a, $90 + ld bc, SCREEN_HEIGHT_PX + call ByteFill + ret +; 4e9f1 + +.subfunction5 ; 4e9f1 + ld hl, LYOverrides + ld a, d + ld c, $3e ; 62 +.loop4 + ld [hli], a + dec c + jr nz, .loop4 + ld a, e + ld c, $22 ; 34 +.loop5 + ld [hli], a + dec c + jr nz, .loop5 + xor a + ld c, $30 ; 48 +.loop6 + ld [hli], a + dec c + jr nz, .loop6 + ret +; 4ea0a diff --git a/engine/start_battle.asm b/engine/battle/start_battle.asm index 8d510b72e..8d510b72e 100644 --- a/engine/start_battle.asm +++ b/engine/battle/start_battle.asm diff --git a/engine/battle/trainer_huds.asm b/engine/battle/trainer_huds.asm new file mode 100755 index 000000000..9efe08414 --- /dev/null +++ b/engine/battle/trainer_huds.asm @@ -0,0 +1,269 @@ +BattleStart_TrainerHuds: ; 2c000 + ld a, $e4 + ld [rOBP0], a + call LoadBallIconGFX + call ShowPlayerMonsRemaining + ld a, [wBattleMode] + dec a + ret z + jp ShowOTTrainerMonsRemaining +; 2c012 + +EnemySwitch_TrainerHud: ; 2c012 + ld a, $e4 + ld [rOBP0], a + call LoadBallIconGFX + jp ShowOTTrainerMonsRemaining +; 2c01c + +ShowPlayerMonsRemaining: ; 2c01c + call DrawPlayerPartyIconHUDBorder + ld hl, PartyMon1HP + ld de, PartyCount + call StageBallTilesData + ; ldpixel wPlaceBallsX, 12, 12 + ld a, 12 * 8 + ld hl, wPlaceBallsX + ld [hli], a + ld [hl], a + ld a, 8 + ld [wPlaceBallsDirection], a + ld hl, Sprites + jp LoadTrainerHudOAM +; 2c03a + +ShowOTTrainerMonsRemaining: ; 2c03a + call DrawEnemyHUDBorder + ld hl, OTPartyMon1HP + ld de, OTPartyCount + call StageBallTilesData + ; ldpixel wPlaceBallsX, 9, 4 + ld hl, wPlaceBallsX + ld a, 9 * 8 + ld [hli], a + ld [hl], 4 * 8 + ld a, -8 + ld [wPlaceBallsDirection], a + ld hl, Sprites + PARTY_LENGTH * 4 + jp LoadTrainerHudOAM +; 2c059 + +StageBallTilesData: ; 2c059 + ld a, [de] + push af + ld de, Buffer1 + ld c, PARTY_LENGTH + ld a, $34 ; empty slot +.loop1 + ld [de], a + inc de + dec c + jr nz, .loop1 + pop af + ld de, Buffer1 +.loop2 + push af + call .GetHUDTile + inc de + pop af + dec a + jr nz, .loop2 + ret +; 2c075 + +.GetHUDTile: ; 2c075 + ld a, [hli] + and a + jr nz, .got_hp + ld a, [hl] + and a + ld b, $33 ; fainted + jr z, .fainted + +.got_hp + dec hl + dec hl + dec hl + ld a, [hl] + and a + ld b, $32 ; statused + jr nz, .load + dec b ; normal + jr .load + +.fainted + dec hl + dec hl + dec hl + +.load + ld a, b + ld [de], a + ld bc, PARTYMON_STRUCT_LENGTH + MON_HP - MON_STATUS + add hl, bc + ret +; 2c095 + +DrawPlayerHUDBorder: ; 2c095 + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, 4 + call CopyBytes + hlcoord 18, 10 + ld de, -1 ; start on right + jr PlaceHUDBorderTiles + +.tiles + db $73 ; right side + db $77 ; bottom right + db $6f ; bottom left + db $76 ; bottom side +; 2c0ad + +DrawPlayerPartyIconHUDBorder: ; 2c0ad + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, 4 + call CopyBytes + hlcoord 18, 10 + ld de, -1 ; start on right + jr PlaceHUDBorderTiles + +.tiles + db $73 ; right side + db $5c ; bottom right + db $6f ; bottom left + db $76 ; bottom side +; 2c0c5 + +DrawEnemyHUDBorder: ; 2c0c5 + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, 4 + call CopyBytes + hlcoord 1, 2 + ld de, 1 ; start on left + call PlaceHUDBorderTiles + ld a, [wBattleMode] + dec a + ret nz + ld a, [TempEnemyMonSpecies] + dec a + call CheckCaughtMon + ret z + hlcoord 1, 1 + ld [hl], $5d + ret + +.tiles + db $6d ; left side + db $74 ; bottom left + db $78 ; bottom right + db $76 ; bottom side +; 2c0f1 + +PlaceHUDBorderTiles: ; 2c0f1 + ld a, [wTrainerHUDTiles] + ld [hl], a + ld bc, SCREEN_WIDTH + add hl, bc + ld a, [StartFlypoint] + ld [hl], a + ld b, $8 +.loop + add hl, de + ld a, [MovementBuffer] + ld [hl], a + dec b + jr nz, .loop + add hl, de + ld a, [EndFlypoint] + ld [hl], a + ret +; 2c10d + +LinkBattle_TrainerHuds: ; 2c10d + call LoadBallIconGFX + ld hl, PartyMon1HP + ld de, PartyCount + call StageBallTilesData + ld hl, wPlaceBallsX + ld a, 10 * 8 + ld [hli], a + ld [hl], 8 * 8 + ld a, $8 + ld [wPlaceBallsDirection], a + ld hl, Sprites + call LoadTrainerHudOAM + + ld hl, OTPartyMon1HP + ld de, OTPartyCount + call StageBallTilesData + ld hl, wPlaceBallsX + ld a, 10 * 8 + ld [hli], a + ld [hl], 13 * 8 + ld hl, Sprites + PARTY_LENGTH * 4 + jp LoadTrainerHudOAM +; 2c143 + +LoadTrainerHudOAM: ; 2c143 + ld de, Buffer1 + ld c, PARTY_LENGTH +.loop + ld a, [wPlaceBallsY] + ld [hli], a + ld a, [wPlaceBallsX] + ld [hli], a + ld a, [de] + ld [hli], a + ld a, $3 + ld [hli], a + ld a, [wPlaceBallsX] + ld b, a + ld a, [wPlaceBallsDirection] + add b + ld [wPlaceBallsX], a + inc de + dec c + jr nz, .loop + ret +; 2c165 + +LoadBallIconGFX: ; 2c165 + ld de, .gfx + ld hl, VTiles0 tile $31 + lb bc, BANK(LoadBallIconGFX), 4 + call Get2bpp_2 + ret +; 2c172 + +.gfx ; 2c172 +INCBIN "gfx/battle/balls.2bpp" +; 2c1b2 + +_ShowLinkBattleParticipants: ; 2c1b2 + call ClearBGPalettes + call LoadFontsExtra + hlcoord 2, 3 + ld b, 9 + ld c, 14 + call TextBox + hlcoord 4, 5 + ld de, PlayerName + call PlaceString + hlcoord 4, 10 + ld de, OTPlayerName + call PlaceString + hlcoord 9, 8 + ld a, "<BOLD_V>" + ld [hli], a + ld [hl], "<BOLD_S>" + farcall LinkBattle_TrainerHuds ; no need to farcall + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + ld a, $e4 + ld [rOBP0], a + ret +; 2c1ef diff --git a/engine/routines/updatebattlehuds.asm b/engine/battle/updatebattlehuds.asm index ec7f662e8..ec7f662e8 100644 --- a/engine/routines/updatebattlehuds.asm +++ b/engine/battle/updatebattlehuds.asm diff --git a/engine/battle/used_move_text.asm b/engine/battle/used_move_text.asm new file mode 100755 index 000000000..ce9e51359 --- /dev/null +++ b/engine/battle/used_move_text.asm @@ -0,0 +1,338 @@ +DisplayUsedMoveText: ; 105db0 +; battle command 03 + ld hl, UsedMoveText + call BattleTextBox + jp WaitBGMap +; 105db9 + +UsedMoveText: ; 105db9 +; this is a stream of text and asm from 105db9 to 105ef6 + text_jump _ActorNameText + start_asm + ld a, [hBattleTurn] + and a + jr nz, .start + + ld a, [wPlayerMoveStruct + MOVE_ANIM] + call UpdateUsedMoves + +.start + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld [wd265], a + + push hl + farcall CheckUserIsCharging + pop hl + jr nz, .grammar + + ; update last move + ld a, [wd265] + ld [hl], a + ld [de], a + +.grammar + call GetMoveGrammar +; wd265 now contains MoveGrammar + +; everything except 'instead' made redundant in localization + + ; check obedience + ld a, [AlreadyDisobeyed] + and a + ld hl, UsedMove2Text + ret nz + + ; check move grammar + ld a, [wd265] + cp $3 + ld hl, UsedMove2Text + ret c + ld hl, UsedMove1Text + ret +; 105e04 + +UsedMove1Text: ; 105e04 + text_jump _UsedMove1Text + start_asm + jr UsedMoveText_CheckObedience +; 105e0b + +UsedMove2Text: ; 105e0b + text_jump _UsedMove2Text + start_asm +UsedMoveText_CheckObedience: ; 105e10 +; check obedience + ld a, [AlreadyDisobeyed] + and a + jr z, .GetMoveNameText +; print "instead," + ld hl, .UsedInsteadText + ret +; 105e1a + +.UsedInsteadText: + text_jump _UsedInsteadText + start_asm +.GetMoveNameText: + ld hl, MoveNameText + ret +; 105e23 + +MoveNameText: ; 105e23 + text_jump _MoveNameText + start_asm +; get start address + ld hl, .endusedmovetexts + +; get move id + ld a, [wd265] + +; 2-byte pointer + add a + +; seek + push bc + ld b, $0 + ld c, a + add hl, bc + pop bc + +; get pointer to usedmovetext ender + ld a, [hli] + ld h, [hl] + ld l, a + ret +; 105e39 + +.endusedmovetexts ; 105e39 + dw EndUsedMove1Text + dw EndUsedMove2Text + dw EndUsedMove3Text + dw EndUsedMove4Text + dw EndUsedMove5Text +; 105e43 + +EndUsedMove1Text: ; 105e43 + text_jump _EndUsedMove1Text + db "@" +; 105e48 +EndUsedMove2Text: ; 105e48 + text_jump _EndUsedMove2Text + db "@" +; 105e4d +EndUsedMove3Text: ; 105e4d + text_jump _EndUsedMove3Text + db "@" +; 105e52 +EndUsedMove4Text: ; 105e52 + text_jump _EndUsedMove4Text + db "@" +; 105e57 +EndUsedMove5Text: ; 105e57 + text_jump _EndUsedMove5Text + db "@" +; 105e5c + + +GetMoveGrammar: ; 105e5c +; store move grammar type in wd265 + + push bc +; c = move id + ld a, [wd265] + ld c, a + ld b, $0 + +; read grammar table + ld hl, MoveGrammar +.loop + ld a, [hli] +; end of table? + cp $ff + jr z, .end +; match? + cp c + jr z, .end +; advance grammar type at $00 + and a + jr nz, .loop +; next grammar type + inc b + jr .loop + +.end +; wd265 now contains move grammar + ld a, b + ld [wd265], a + +; we're done + pop bc + ret +; 105e7a + +MoveGrammar: ; 105e7a +; made redundant in localization +; each move is given an identifier for what usedmovetext to use (0-4): + +; 0 + db SWORDS_DANCE + db GROWTH + db STRENGTH + db HARDEN + db MINIMIZE + db SMOKESCREEN + db WITHDRAW + db DEFENSE_CURL + db EGG_BOMB + db SMOG + db BONE_CLUB + db FLASH + db SPLASH + db ACID_ARMOR + db BONEMERANG + db REST + db SHARPEN + db SUBSTITUTE + db MIND_READER + db SNORE + db PROTECT + db SPIKES + db ENDURE + db ROLLOUT + db SWAGGER + db SLEEP_TALK + db HIDDEN_POWER + db PSYCH_UP + db EXTREMESPEED + db 0 ; end set + +; 1 + db RECOVER + db TELEPORT + db BIDE + db SELFDESTRUCT + db AMNESIA + db FLAIL + db 0 ; end set + +; 2 + db MEDITATE + db AGILITY + db MIMIC + db DOUBLE_TEAM + db BARRAGE + db TRANSFORM + db STRUGGLE + db SCARY_FACE + db 0 ; end set + +; 3 + db POUND + db SCRATCH + db VICEGRIP + db WING_ATTACK + db FLY + db BIND + db SLAM + db HORN_ATTACK + db WRAP + db THRASH + db TAIL_WHIP + db LEER + db BITE + db GROWL + db ROAR + db SING + db PECK + db ABSORB + db STRING_SHOT + db EARTHQUAKE + db FISSURE + db DIG + db TOXIC + db SCREECH + db METRONOME + db LICK + db CLAMP + db CONSTRICT + db POISON_GAS + db BUBBLE + db SLASH + db SPIDER_WEB + db NIGHTMARE + db CURSE + db FORESIGHT + db CHARM + db ATTRACT + db ROCK_SMASH + db 0 ; end set + +; all other moves = 4 + db $ff ; end +; 105ed0 + + +UpdateUsedMoves: ; 105ed0 +; append move a to PlayerUsedMoves unless it has already been used + + push bc +; start of list + ld hl, PlayerUsedMoves +; get move id + ld b, a +; next count + ld c, NUM_MOVES + +.loop +; get move from the list + ld a, [hli] +; not used yet? + and a + jr z, .add +; already used? + cp b + jr z, .quit +; next byte + dec c + jr nz, .loop + +; if the list is full and the move hasn't already been used +; shift the list back one byte, deleting the first move used +; this can occur with struggle or a new learned move + ld hl, PlayerUsedMoves + 1 +; 1 = 2 + ld a, [hld] + ld [hli], a +; 2 = 3 + inc hl + ld a, [hld] + ld [hli], a +; 3 = 4 + inc hl + ld a, [hld] + ld [hl], a +; 4 = new move + ld a, b + ld [PlayerUsedMoves + 3], a + jr .quit + +.add +; go back to the byte we just inced from + dec hl +; add the new move + ld [hl], b + +.quit +; list updated + pop bc + ret +; 105ef6 diff --git a/engine/battle_anims/anim_commands.asm b/engine/battle_anims/anim_commands.asm new file mode 100644 index 000000000..875849ce3 --- /dev/null +++ b/engine/battle_anims/anim_commands.asm @@ -0,0 +1,1514 @@ +; Battle animation command interpreter. + +PlayBattleAnim: ; cc0d6 + + ld a, [rSVBK] + push af + + ld a, 5 + ld [rSVBK], a + + call _PlayBattleAnim + + pop af + ld [rSVBK], a + ret +; cc0e4 + +_PlayBattleAnim: ; cc0e4 + + ld c, 6 +.wait + call BattleAnimDelayFrame + dec c + jr nz, .wait + + call BattleAnimAssignPals + call BattleAnimRequestPals + call BattleAnimDelayFrame + + ld c, 1 + ld a, [rKEY1] + bit 7, a + jr nz, .asm_cc0ff + ld c, 3 + +.asm_cc0ff + ld hl, hVBlank + ld a, [hl] + push af + + ld [hl], c + call BattleAnimRunScript + + pop af + ld [hVBlank], a + + ld a, $1 + ld [hBGMapMode], a + + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call WaitSFX + ret +; cc11c + +BattleAnimRunScript: ; cc11c + + ld a, [FXAnimID + 1] + and a + jr nz, .hi_byte + + farcall CheckBattleScene + jr c, .disabled + + call BattleAnimClearHud + call RunBattleAnimScript + + call BattleAnimAssignPals + call BattleAnimRequestPals + + xor a + ld [hSCX], a + ld [hSCY], a + call BattleAnimDelayFrame + call BattleAnimRestoreHuds + +.disabled + ld a, [wNumHits] + and a + jr z, .done + + ld l, a + ld h, 0 + ld de, ANIM_MISS + add hl, de + ld a, l + ld [FXAnimID], a + ld a, h + ld [FXAnimID + 1], a + +.hi_byte + call WaitSFX + call PlayHitSound + call RunBattleAnimScript + +.done + call BattleAnim_RevertPals + ret +; cc163 + +RunBattleAnimScript: ; cc163 + + call ClearBattleAnims + +.playframe + call RunBattleAnimCommand + call _ExecuteBGEffects + call BattleAnim_UpdateOAM_All + call PushLYOverrides + call BattleAnimRequestPals + +; Speed up Rollout's animation. + ld a, [FXAnimID + 1] + or a + jr nz, .not_rollout + + ld a, [FXAnimID] + cp ROLLOUT + jr nz, .not_rollout + + ld a, $2e + ld b, 5 + ld de, 4 + ld hl, ActiveBGEffects +.find + cp [hl] + jr z, .done + add hl, de + dec b + jr nz, .find + +.not_rollout + call BattleAnimDelayFrame + +.done + ld a, [BattleAnimFlags] + bit 0, a + jr z, .playframe + + call BattleAnim_ClearCGB_OAMFlags + ret +; cc1a1 + +BattleAnimClearHud: ; cc1a1 + + call BattleAnimDelayFrame + call WaitTop + call ClearActorHud + ld a, $1 + ld [hBGMapMode], a + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call WaitTop + ret +; cc1bb + +BattleAnimRestoreHuds: ; cc1bb + + call BattleAnimDelayFrame + call WaitTop + + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + + ld hl, UpdateBattleHuds + ld a, BANK(UpdatePlayerHUD) + rst FarCall ; Why not "call UpdateBattleHuds"? + + pop af + ld [rSVBK], a + + ld a, $1 + ld [hBGMapMode], a + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call WaitTop + ret +; cc1e2 + +BattleAnimRequestPals: ; cc1e2 + + ld a, [hCGB] + and a + ret z + + ld a, [rBGP] + ld b, a + ld a, [wBGP] + cp b + call nz, BattleAnim_SetBGPals + + ld a, [rOBP0] + ld b, a + ld a, [wOBP0] + cp b + call nz, BattleAnim_SetOBPals + ret +; cc1fb + +BattleAnimDelayFrame: ; cc1fb +; Like DelayFrame but wastes battery life. + + ld a, 1 + ld [VBlankOccurred], a +.wait + ld a, [VBlankOccurred] + and a + jr nz, .wait + ret +; cc207 + +ClearActorHud: ; cc207 + + ld a, [hBattleTurn] + and a + jr z, .player + + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ret + +.player + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ret +; cc220 + +Functioncc220: ; cc220 +; Appears to be unused. + xor a + ld [hBGMapMode], a + ld a, LOW(VBGMap0 tile $28) + ld [hBGMapAddress], a + ld a, HIGH(VBGMap0 tile $28) + ld [hBGMapAddress + 1], a + call WaitBGMap2 + ld a, $60 + ld [hWY], a + xor a ; LOW(VBGMap0) + ld [hBGMapAddress], a + ld a, HIGH(VBGMap0) + ld [hBGMapAddress + 1], a + call BattleAnimDelayFrame + ret +; cc23d + + +BattleAnim_ClearCGB_OAMFlags: ; cc23d + + ld a, [BattleAnimFlags] + bit 3, a + jr z, .delete + + ld hl, Sprites + 3 + ld c, (SpritesEnd - Sprites) / 4 +.loop + ld a, [hl] + and $f0 + ld [hli], a + inc hl + inc hl + inc hl + dec c + jr nz, .loop + ret + +.delete + ld hl, Sprites + ld c, SpritesEnd - Sprites + xor a +.loop2 + ld [hli], a + dec c + jr nz, .loop2 + ret +; cc25f + +RunBattleAnimCommand: ; cc25f + call .CheckTimer + ret nc + call .RunScript + ret +; cc267 + +.CheckTimer: ; cc267 + ld a, [BattleAnimDuration] + and a + jr z, .done + + dec a + ld [BattleAnimDuration], a + and a + ret + +.done + scf + ret +; cc275 + +.RunScript: ; cc275 +.loop + call GetBattleAnimByte + + cp $ff + jr nz, .not_done_with_anim + +; Return from a subroutine. + ld hl, BattleAnimFlags + bit 1, [hl] + jr nz, .do_anim + + set 0, [hl] + ret + +.not_done_with_anim + cp $d0 + jr nc, .do_anim + + ld [BattleAnimDuration], a + ret + +.do_anim + call .DoCommand + + jr .loop +; cc293 + +.DoCommand: ; cc293 +; Execute battle animation command in [BattleAnimByte]. + ld a, [BattleAnimByte] + sub $d0 + + ld e, a + ld d, 0 + ld hl, BattleAnimCommands + add hl, de + add hl, de + + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; cc2a4 + + +BattleAnimCommands:: ; cc2a4 (33:42a4) +; entries correspond to macros/scripts/battle_anims.asm enumeration + dw BattleAnimCmd_Obj + dw BattleAnimCmd_1GFX + dw BattleAnimCmd_2GFX + dw BattleAnimCmd_3GFX + dw BattleAnimCmd_4GFX + dw BattleAnimCmd_5GFX + dw BattleAnimCmd_IncObj + dw BattleAnimCmd_SetObj + dw BattleAnimCmd_IncBGEffect + dw BattleAnimCmd_EnemyFeetObj + dw BattleAnimCmd_PlayerHeadObj + dw BattleAnimCmd_CheckPokeball + dw BattleAnimCmd_Transform + dw BattleAnimCmd_RaiseSub + dw BattleAnimCmd_DropSub + dw BattleAnimCmd_ResetObp0 + dw BattleAnimCmd_Sound + dw BattleAnimCmd_Cry + dw BattleAnimCmd_MinimizeOpp + dw BattleAnimCmd_OAMOn + dw BattleAnimCmd_OAMOff + dw BattleAnimCmd_ClearObjs + dw BattleAnimCmd_BeatUp + dw BattleAnimCmd_E7 + dw BattleAnimCmd_UpdateActorPic + dw BattleAnimCmd_Minimize + dw BattleAnimCmd_EA ; dummy + dw BattleAnimCmd_EB ; dummy + dw BattleAnimCmd_EC ; dummy + dw BattleAnimCmd_ED ; dummy + dw BattleAnimCmd_IfParamAnd + dw BattleAnimCmd_JumpUntil + dw BattleAnimCmd_BGEffect + dw BattleAnimCmd_BGP + dw BattleAnimCmd_OBP0 + dw BattleAnimCmd_OBP1 + dw BattleAnimCmd_ClearSprites + dw BattleAnimCmd_F5 + dw BattleAnimCmd_F6 + dw BattleAnimCmd_F7 + dw BattleAnimCmd_IfParamEqual + dw BattleAnimCmd_SetVar + dw BattleAnimCmd_IncVar + dw BattleAnimCmd_IfVarEqual + dw BattleAnimCmd_Jump + dw BattleAnimCmd_Loop + dw BattleAnimCmd_Call + dw BattleAnimCmd_Ret + + +BattleAnimCmd_EA: +BattleAnimCmd_EB: +BattleAnimCmd_EC: +BattleAnimCmd_ED: ; cc304 (33:4304) + ret + +BattleAnimCmd_Ret: ; cc305 (33:4305) + ld hl, BattleAnimFlags + res 1, [hl] + ld hl, BattleAnimParent + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_Call: ; cc317 (33:4317) + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + push de + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BattleAnimParent + ld [hl], e + inc hl + ld [hl], d + pop de + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ld hl, BattleAnimFlags + set 1, [hl] + ret + +BattleAnimCmd_Jump: ; cc339 (33:4339) + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_Loop: ; cc348 (33:4348) + call GetBattleAnimByte + ld hl, BattleAnimFlags + bit 2, [hl] + jr nz, .continue_loop + and a + jr z, .perpetual + dec a + set 2, [hl] + ld [BattleAnimLoops], a +.continue_loop + ld hl, BattleAnimLoops + ld a, [hl] + and a + jr z, .return_from_loop + dec [hl] +.perpetual + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +.return_from_loop + ld hl, BattleAnimFlags + res 2, [hl] + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +BattleAnimCmd_JumpUntil: ; cc383 (33:4383) + ld hl, wBattleAnimParam + ld a, [hl] + and a + jr z, .dont_jump + + dec [hl] + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +.dont_jump + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +BattleAnimCmd_SetVar: ; cc3a6 (33:43a6) + call GetBattleAnimByte + ld [BattleAnimVar], a + ret + +BattleAnimCmd_IncVar: ; cc3ad (33:43ad) + ld hl, BattleAnimVar + inc [hl] + ret + +BattleAnimCmd_IfVarEqual: ; cc3b2 (33:43b2) + call GetBattleAnimByte + ld hl, BattleAnimVar + cp [hl] + jr z, .jump + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +.jump + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_IfParamEqual: ; cc3d6 (33:43d6) + call GetBattleAnimByte + ld hl, wBattleAnimParam + cp [hl] + jr z, .jump + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +.jump + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_IfParamAnd: ; cc3fa (33:43fa) + call GetBattleAnimByte + ld e, a + ld a, [wBattleAnimParam] + and e + jr nz, .jump + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +.jump + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_Obj: ; cc41f (33:441f) +; index, x, y, param + call GetBattleAnimByte + ld [wBattleAnimTemp0], a + call GetBattleAnimByte + ld [wBattleAnimTemp1], a + call GetBattleAnimByte + ld [wBattleAnimTemp2], a + call GetBattleAnimByte + ld [wBattleAnimTemp3], a + call QueueBattleAnimation + ret + +BattleAnimCmd_BGEffect: ; cc43b (33:443b) + call GetBattleAnimByte + ld [wBattleAnimTemp0], a + call GetBattleAnimByte + ld [wBattleAnimTemp1], a + call GetBattleAnimByte + ld [wBattleAnimTemp2], a + call GetBattleAnimByte + ld [wBattleAnimTemp3], a + call _QueueBGEffect + ret + +BattleAnimCmd_BGP: ; cc457 (33:4457) + call GetBattleAnimByte + ld [wBGP], a + ret + +BattleAnimCmd_OBP0: ; cc45e (33:445e) + call GetBattleAnimByte + ld [wOBP0], a + ret + +BattleAnimCmd_OBP1: ; cc465 (33:4465) + call GetBattleAnimByte + ld [wOBP1], a + ret + +BattleAnimCmd_ResetObp0: ; cc46c (33:446c) + ld a, [hSGB] + and a + ld a, $e0 + jr z, .not_sgb + ld a, $f0 +.not_sgb + ld [wOBP0], a + ret + +BattleAnimCmd_ClearObjs: ; cc479 (33:4479) + ld hl, ActiveAnimObjects + ld a, $a0 +.loop + ld [hl], $0 + inc hl + dec a + jr nz, .loop + ret + +BattleAnimCmd_1GFX: +BattleAnimCmd_2GFX: +BattleAnimCmd_3GFX: +BattleAnimCmd_4GFX: +BattleAnimCmd_5GFX: ; cc485 (33:4485) + ld a, [BattleAnimByte] + and $f + ld c, a + ld hl, wBattleAnimTileDict + xor a + ld [wBattleAnimTemp0], a +.loop + ld a, [wBattleAnimTemp0] + cp (VTiles1 - VTiles0) / $10 - $31 + ret nc + call GetBattleAnimByte + ld [hli], a + ld a, [wBattleAnimTemp0] + ld [hli], a + push bc + push hl + ld l, a + ld h, $0 +rept 4 + add hl, hl +endr + ld de, VTiles0 tile $31 + add hl, de + ld a, [BattleAnimByte] + call LoadBattleAnimObj + ld a, [wBattleAnimTemp0] + add c + ld [wBattleAnimTemp0], a + pop hl + pop bc + dec c + jr nz, .loop + ret + +BattleAnimCmd_IncObj: ; cc4c0 (33:44c0) + call GetBattleAnimByte + ld e, 10 + ld bc, ActiveAnimObjects +.loop + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld d, [hl] + ld a, [BattleAnimByte] + cp d + jr z, .found + ld hl, BATTLEANIMSTRUCT_LENGTH + add hl, bc + ld c, l + ld b, h + dec e + jr nz, .loop + ret + +.found + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleAnimCmd_IncBGEffect: ; cc4e3 (33:44e3) + call GetBattleAnimByte + ld e, 5 + ld bc, ActiveBGEffects +.loop + ld hl, $0 + add hl, bc + ld d, [hl] + ld a, [BattleAnimByte] + cp d + jr z, .found + ld hl, 4 + add hl, bc + ld c, l + ld b, h + dec e + jr nz, .loop + ret + +.found + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleAnimCmd_SetObj: ; cc506 (33:4506) + call GetBattleAnimByte + ld e, 10 + ld bc, ActiveAnimObjects +.loop + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld d, [hl] + ld a, [BattleAnimByte] + cp d + jr z, .found + ld hl, BATTLEANIMSTRUCT_LENGTH + add hl, bc + ld c, l + ld b, h + dec e + jr nz, .loop + ret + +.found + call GetBattleAnimByte + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +BattleAnimCmd_EnemyFeetObj: ; cc52c (33:452c) + + ld hl, wBattleAnimTileDict +.loop + ld a, [hl] + and a + jr z, .okay + inc hl + inc hl + jr .loop + +.okay + ld a, $28 + ld [hli], a + ld a, $42 + ld [hli], a + ld a, $29 + ld [hli], a + ld a, $49 + ld [hl], a + + ld hl, VTiles0 tile $73 + ld de, VTiles2 tile $06 + ld a, $70 + ld [wBattleAnimTemp0], a + ld a, $7 + call .LoadFootprint + ld de, VTiles2 tile $31 + ld a, $60 + ld [wBattleAnimTemp0], a + ld a, $6 + call .LoadFootprint + ret + +.LoadFootprint: ; cc561 (33:4561) + push af + push hl + push de + lb bc, BANK(BattleAnimCmd_EnemyFeetObj), 1 + call Request2bpp + pop de + ld a, [wBattleAnimTemp0] + ld l, a + ld h, 0 + add hl, de + ld e, l + ld d, h + pop hl + ld bc, 1 tiles + add hl, bc + pop af + dec a + jr nz, .LoadFootprint + ret + +BattleAnimCmd_PlayerHeadObj: ; cc57e (33:457e) + + ld hl, wBattleAnimTileDict +.loop + ld a, [hl] + and a + jr z, .okay + inc hl + inc hl + jr .loop + +.okay + ld a, $28 + ld [hli], a + ld a, $35 + ld [hli], a + ld a, $29 + ld [hli], a + ld a, $43 + ld [hl], a + + ld hl, VTiles0 tile $66 + ld de, VTiles2 tile $05 + ld a, $70 + ld [wBattleAnimTemp0], a + ld a, $7 + call .LoadHead + ld de, VTiles2 tile $31 + ld a, $60 + ld [wBattleAnimTemp0], a + ld a, $6 + call .LoadHead + ret + +.LoadHead: ; cc5b3 (33:45b3) + push af + push hl + push de + lb bc, BANK(BattleAnimCmd_EnemyFeetObj), 2 + call Request2bpp + pop de + ld a, [wBattleAnimTemp0] + ld l, a + ld h, 0 + add hl, de + ld e, l + ld d, h + pop hl + ld bc, 2 tiles + add hl, bc + pop af + dec a + jr nz, .LoadHead + ret + +BattleAnimCmd_CheckPokeball: ; cc5d0 (33:45d0) + callfar GetPokeBallWobble + ld a, c + ld [BattleAnimVar], a + ret + +BattleAnimCmd_E7: ; cc5db (33:45db) + ret + +BattleAnimCmd_Transform: ; cc5dc (33:45dc) + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + ld a, [CurPartySpecies] ; CurPartySpecies + push af + + ld a, [hBattleTurn] + and a + jr z, .player + + ld a, [TempBattleMonSpecies] ; TempBattleMonSpecies + ld [CurPartySpecies], a ; CurPartySpecies + ld hl, BattleMonDVs ; BattleMonDVs + predef GetUnownLetter + ld de, VTiles0 tile $00 + predef GetMonFrontpic + jr .done + +.player + ld a, [TempEnemyMonSpecies] ; TempEnemyMonSpecies + ld [CurPartySpecies], a ; CurPartySpecies + ld hl, EnemyMonDVs ; EnemyMonDVs + predef GetUnownLetter + ld de, VTiles0 tile $00 + predef GetMonBackpic + +.done + pop af + ld [CurPartySpecies], a ; CurPartySpecies + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_UpdateActorPic: ; cc622 (33:4622) + + ld de, VTiles0 tile $00 + ld a, [hBattleTurn] + and a + jr z, .player + + ld hl, VTiles2 tile $00 + ld b, 0 + ld c, $31 + call Request2bpp + ret + +.player + ld hl, VTiles2 tile $31 + ld b, 0 + ld c, $24 + call Request2bpp + ret + +BattleAnimCmd_RaiseSub: ; cc640 (33:4640) + + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + xor a + call GetSRAMBank + +GetSubstitutePic: ; cc64c + + ld hl, sScratch + ld bc, (7 * 7) tiles +.loop + xor a + ld [hli], a + dec bc + ld a, c + or b + jr nz, .loop + + ld a, [hBattleTurn] + and a + jr z, .player + + ld hl, MonsterSpriteGFX + 0 tiles + ld de, sScratch + (2 * 7 + 5) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 1 tiles + ld de, sScratch + (3 * 7 + 5) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 2 tiles + ld de, sScratch + (2 * 7 + 6) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 3 tiles + ld de, sScratch + (3 * 7 + 6) tiles + call .CopyTile + + ld hl, VTiles2 tile $00 + ld de, sScratch + lb bc, BANK(GetSubstitutePic), 7 * 7 + call Request2bpp + jr .done + +.player + ld hl, MonsterSpriteGFX + 4 tiles + ld de, sScratch + (2 * 6 + 4) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 5 tiles + ld de, sScratch + (3 * 6 + 4) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 6 tiles + ld de, sScratch + (2 * 6 + 5) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 7 tiles + ld de, sScratch + (3 * 6 + 5) tiles + call .CopyTile + + ld hl, VTiles2 tile $31 + ld de, sScratch + lb bc, BANK(GetSubstitutePic), 6 * 6 + call Request2bpp + +.done + call CloseSRAM + pop af + ld [rSVBK], a + ret + +.CopyTile: ; cc6c6 (33:46c6) + ld bc, 1 tiles + ld a, BANK(MonsterSpriteGFX) + call FarCopyBytes + ret + +BattleAnimCmd_MinimizeOpp: ; cc6cf (33:46cf) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + xor a + call GetSRAMBank + call GetMinimizePic + call Request2bpp + call CloseSRAM + pop af + ld [rSVBK], a + ret + +GetMinimizePic: ; cc6e7 (33:46e7) + ld hl, sScratch + ld bc, $31 tiles +.loop + xor a + ld [hli], a + dec bc + ld a, c + or b + jr nz, .loop + + ld a, [hBattleTurn] + and a + jr z, .player + + ld de, sScratch + $1a tiles + call CopyMinimizePic + ld hl, VTiles2 tile $00 + ld de, sScratch + lb bc, BANK(GetMinimizePic), $31 + ret + +.player + ld de, sScratch + $160 + call CopyMinimizePic + ld hl, VTiles2 tile $31 + ld de, sScratch + lb bc, BANK(GetMinimizePic), $24 + ret + +CopyMinimizePic: ; cc719 (33:4719) + ld hl, MinimizePic + ld bc, $10 + ld a, BANK(MinimizePic) + call FarCopyBytes + ret +; cc725 (33:4725) + +MinimizePic: ; cc725 +INCBIN "gfx/battle/minimize.2bpp" +; cc735 + +BattleAnimCmd_Minimize: ; cc735 (33:4735) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + xor a + call GetSRAMBank + call GetMinimizePic + ld hl, VTiles0 tile $00 + call Request2bpp + call CloseSRAM + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_DropSub: ; cc750 (33:4750) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + + ld a, [CurPartySpecies] ; CurPartySpecies + push af + ld a, [hBattleTurn] + and a + jr z, .player + + callfar DropEnemySub + jr .done + +.player + callfar DropPlayerSub + +.done + pop af + ld [CurPartySpecies], a ; CurPartySpecies + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_BeatUp: ; cc776 (33:4776) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + ld a, [CurPartySpecies] ; CurPartySpecies + push af + + ld a, [wBattleAnimParam] + ld [CurPartySpecies], a ; CurPartySpecies + + ld a, [hBattleTurn] + and a + jr z, .player + + ld hl, BattleMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $00 + predef GetMonFrontpic + jr .done + +.player + ld hl, EnemyMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $31 + predef GetMonBackpic + +.done + pop af + ld [CurPartySpecies], a ; CurPartySpecies + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_OAMOn: ; cc7bb (33:47bb) + xor a + ld [hOAMUpdate], a + ret + +BattleAnimCmd_OAMOff: ; cc7bf (33:47bf) + ld a, $1 + ld [hOAMUpdate], a + ret + +BattleAnimCmd_ClearSprites: ; cc7c4 (33:47c4) + ld hl, BattleAnimFlags + set 3, [hl] + ret + +BattleAnimCmd_F5: ; cc7ca (33:47ca) + ret + +BattleAnimCmd_F6: ; cc7cb (33:47cb) + ret + +BattleAnimCmd_F7: ; cc7cc (33:47cc) + ret + +BattleAnimCmd_Sound: ; cc7cd (33:47cd) + call GetBattleAnimByte + ld e, a + srl a + srl a + ld [wSFXDuration], a + call .GetCryTrack + and 3 + ld [CryTracks], a ; CryTracks + + ld e, a + ld d, 0 + ld hl, .GetPanning + add hl, de + ld a, [hl] + ld [wStereoPanningMask], a + + call GetBattleAnimByte + ld e, a + ld d, 0 + callfar PlayStereoSFX + + ret +; cc7f8 (33:47f8) + +.GetPanning: ; cc7f8 + db $f0, $0f, $f0, $0f +; cc7fc + +.GetCryTrack: ; cc7fc (33:47fc) + ld a, [hBattleTurn] + and a + jr nz, .enemy + + ld a, e + ret + +.enemy + ld a, e + xor 1 + ret + +BattleAnimCmd_Cry: ; cc807 (33:4807) + call GetBattleAnimByte + and 3 + ld e, a + ld d, 0 + ld hl, .CryData +rept 4 + add hl, de +endr + + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + + ld a, [hBattleTurn] + and a + jr nz, .enemy + + ld a, $f0 + ld [CryTracks], a ; CryTracks + ld a, [BattleMonSpecies] ; BattleMonSpecies + jr .done_cry_tracks + +.enemy + ld a, $0f + ld [CryTracks], a ; CryTracks + ld a, [EnemyMonSpecies] ; EnemyMon + +.done_cry_tracks + push hl + call LoadCryHeader + pop hl + jr c, .done + + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + + push hl + ld hl, CryPitch + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + ld a, l + ld [CryPitch], a + ld a, h + ld [CryPitch + 1], a + pop hl + + ld a, [hli] + ld c, a + ld b, [hl] + ld hl, CryLength ; CryLength + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + + ld a, l + ld [CryLength], a ; CryLength + ld a, h + ld [CryLength + 1], a + ld a, 1 + ld [wStereoPanningMask], a + + callfar _PlayCryHeader + +.done + pop af + ld [rSVBK], a + ret +; cc871 (33:4871) + +.CryData: ; cc871 +; +pitch, +length + dw $0000, $00c0 + dw $0000, $0040 + dw $0000, $0000 + dw $0000, $0000 +; cc881 + + +PlayHitSound: ; cc881 + ld a, [wNumHits] + cp $1 + jr z, .okay + cp $4 + ret nz + +.okay + ld a, [TypeModifier] + and $7f + ret z + + cp 10 + ld de, SFX_DAMAGE + jr z, .play + + ld de, SFX_SUPER_EFFECTIVE + jr nc, .play + + ld de, SFX_NOT_VERY_EFFECTIVE + +.play + call PlaySFX + ret +; cc8a4 + +BattleAnimAssignPals: ; cc8a4 + ld a, [hCGB] + and a + jr nz, .cgb + ld a, [hSGB] + and a + ld a, %11100000 + jr z, .sgb + ld a, %11110000 + +.sgb + ld [wOBP0], a + ld a, %11100100 + ld [wBGP], a + ld [wOBP1], a + ret + +.cgb + ld a, %11100100 + ld [wBGP], a + ld [wOBP0], a + ld [wOBP1], a + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + ret +; cc8d3 + +ClearBattleAnims: ; cc8d3 +; Clear animation block + ld hl, LYOverrides + ld bc, wBattleAnimEnd - LYOverrides +.loop + ld [hl], $0 + inc hl + dec bc + ld a, c + or b + jr nz, .loop + + ld hl, FXAnimID + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BattleAnimations + add hl, de + add hl, de + call GetBattleAnimPointer + call BattleAnimAssignPals + call BattleAnimDelayFrame + ret +; cc8f6 + +BattleAnim_RevertPals: ; cc8f6 + call WaitTop + ld a, %11100100 + ld [wBGP], a + ld [wOBP0], a + ld [wOBP1], a + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + xor a + ld [hSCX], a + ld [hSCY], a + call BattleAnimDelayFrame + ld a, $1 + ld [hBGMapMode], a + ret +; cc91a + +BattleAnim_SetBGPals: ; cc91a + ld [rBGP], a + ld a, [hCGB] + and a + ret z + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld hl, BGPals + ld de, UnknBGPals + ld a, [rBGP] + ld b, a + ld c, 7 + call CopyPals + ld hl, OBPals + ld de, UnknOBPals + ld a, [rBGP] + ld b, a + ld c, 2 + call CopyPals + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret +; cc94b + +BattleAnim_SetOBPals: ; cc94b + ld [rOBP0], a + ld a, [hCGB] + and a + ret z + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld hl, OBPals palette PAL_BATTLE_OB_GRAY + ld de, UnknOBPals palette PAL_BATTLE_OB_GRAY + ld a, [rOBP0] + ld b, a + ld c, 2 + call CopyPals + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret +; cc96e + +BattleAnim_UpdateOAM_All: ; cc96e + ld a, $0 + ld [wBattleAnimOAMPointerLo], a + ld hl, ActiveAnimObjects + ld e, 10 +.loop + ld a, [hl] + and a + jr z, .next + ld c, l + ld b, h + push hl + push de + call DoBattleAnimFrame + call BattleAnimOAMUpdate + pop de + pop hl + jr c, .done + +.next + ld bc, BATTLEANIMSTRUCT_LENGTH + add hl, bc + dec e + jr nz, .loop + ld a, [wBattleAnimOAMPointerLo] + ld l, a + ld h, HIGH(Sprites) +.loop2 + ld a, l + cp LOW(SpritesEnd) + jr nc, .done + xor a + ld [hli], a + jr .loop2 + +.done + ret +; cc9a1 diff --git a/engine/battle_anims/bg_effects.asm b/engine/battle_anims/bg_effects.asm new file mode 100644 index 000000000..ab4a8036b --- /dev/null +++ b/engine/battle_anims/bg_effects.asm @@ -0,0 +1,2958 @@ + const_def + const BGSQUARE_SIX + const BGSQUARE_FOUR + const BGSQUARE_TWO + const BGSQUARE_SEVEN + const BGSQUARE_FIVE + const BGSQUARE_THREE + +; BG effects for use in battle animations. + +ExecuteBGEffects: ; c8000 (32:4000) + ld hl, ActiveBGEffects + ld e, 5 +.loop + ld a, [hl] + and a + jr z, .next + ld c, l + ld b, h + push hl + push de + call DoBattleBGEffectFunction + pop de + pop hl +.next + ld bc, 4 + add hl, bc + dec e + jr nz, .loop + ret + +QueueBGEffect: ; c801a (32:401a) + ld hl, ActiveBGEffects + ld e, 5 +.loop + ld a, [hl] + and a + jr z, .load + ld bc, 4 + add hl, bc + dec e + jr nz, .loop + scf + ret + +.load + ld c, l + ld b, h + ld hl, BG_EFFECT_STRUCT_FUNCTION + add hl, bc + ld a, [wBattleAnimTemp0] + ld [hli], a + ld a, [wBattleAnimTemp1] + ld [hli], a + ld a, [wBattleAnimTemp2] + ld [hli], a + ld a, [wBattleAnimTemp3] + ld [hl], a + ret + +EndBattleBGEffect: ; c8043 (32:4043) + ld hl, BG_EFFECT_STRUCT_FUNCTION + add hl, bc + ld [hl], 0 + ret + +DoBattleBGEffectFunction: ; c804a (32:404a) + ld hl, BG_EFFECT_STRUCT_FUNCTION + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, BattleBGEffects + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +BattleBGEffects: ; c805a (32:405a) +; entries correspond to ANIM_BG_* constants + dw BattleBGEffect_End + dw BattleBGEffect_FlashInverted + dw BattleBGEffect_FlashWhite + dw BattleBGEffect_WhiteHues + dw BattleBGEffect_BlackHues + dw BattleBGEffect_AlternateHues + dw BattleBGEffect_06 + dw BattleBGEffect_07 + dw BattleBGEffect_08 + dw BattleBGEffect_HideMon + dw BattleBGEffect_ShowMon + dw BattleBGEffect_EnterMon + dw BattleBGEffect_ReturnMon + dw BattleBGEffect_Surf + dw BattleBGEffect_Whirlpool + dw BattleBGEffect_Teleport + dw BattleBGEffect_NightShade + dw BattleBGEffect_FeetFollow + dw BattleBGEffect_HeadFollow + dw BattleBGEffect_DoubleTeam + dw BattleBGEffect_AcidArmor + dw BattleBGEffect_RapidFlash + dw BattleBGEffect_16 + dw BattleBGEffect_17 + dw BattleBGEffect_18 + dw BattleBGEffect_19 + dw BattleBGEffect_1a + dw BattleBGEffect_1b + dw BattleBGEffect_1c + dw BattleBGEffect_1d + dw BattleBGEffect_1e + dw BattleBGEffect_1f + dw BattleBGEffect_20 + dw BattleBGEffect_Withdraw + dw BattleBGEffect_BounceDown + dw BattleBGEffect_Dig + dw BattleBGEffect_Tackle + dw BattleBGEffect_25 + dw BattleBGEffect_26 + dw BattleBGEffect_27 + dw BattleBGEffect_28 + dw BattleBGEffect_Psychic + dw BattleBGEffect_2a + dw BattleBGEffect_2b + dw BattleBGEffect_2c + dw BattleBGEffect_2d + dw BattleBGEffect_2e + dw BattleBGEffect_2f + dw BattleBGEffect_30 + dw BattleBGEffect_31 + dw BattleBGEffect_32 + dw BattleBGEffect_VibrateMon + dw BattleBGEffect_WobbleMon + dw BattleBGEffect_35 + + +BattleBGEffect_End: ; c80c6 (32:40c6) + call EndBattleBGEffect + ret + +BatttleBGEffects_GetNamedJumptablePointer: ; c80ca (32:40ca) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld l, [hl] + ld h, 0 + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ret + +BattleBGEffects_AnonJumptable: ; c80d7 (32:40d7) + pop de + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld l, [hl] + ld h, 0 + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +BattleBGEffects_IncrementJumptable: ; c80e5 (32:40e5) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleBGEffect_FlashInverted: ; c80eb (32:40eb) + ld de, .inverted + jp BattleBGEffect_FlashContinue + +.inverted + db %11100100 ; 3210 + db %00011011 ; 0123 +; c80f3 + +BattleBGEffect_FlashWhite: ; c80f3 (32:40f3) + ld de, .white + jp BattleBGEffect_FlashContinue + +.white + db %11100100 ; 3210 + db %00000000 ; 0000 +; c80fb + +BattleBGEffect_FlashContinue: ; c80fb (32:40fb) +; current timer, flash duration, number of flashes + ld a, $1 + ld [wBattleAnimTemp0], a + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + and a + jr z, .init + dec [hl] + ret + +.init + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr nz, .apply_pal + call EndBattleBGEffect + ret + +.apply_pal + dec a + ld [hl], a + and 1 + ld l, a + ld h, 0 + add hl, de + ld a, [hl] + ld [wBGP], a + ret + +BattleBGEffect_WhiteHues: ; c812d (32:412d) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + jr c, .quit + ld [wBGP], a + ret + +.quit + call EndBattleBGEffect + ret + +.Pals: + db %11100100 + db %11100000 + db %11010000 + db -1 +; c8141 + +BattleBGEffect_BlackHues: ; c8141 (32:4141) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + jr c, .quit + ld [wBGP], a + ret + +.quit + call EndBattleBGEffect + ret + +.Pals: + db %11100100 + db %11110100 + db %11111000 + db -1 +; c8155 + +BattleBGEffect_AlternateHues: ; c8155 (32:4155) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + jr c, .quit + ld [wBGP], a + ld [wOBP1], a + ret + +.quit + call EndBattleBGEffect + ret + +.Pals: + db %11100100 + db %11111000 + db %11111100 + db %11111000 + db %11100100 + db %10010000 + db %01000000 + db %10010000 + db -2 +; c8171 + +BattleBGEffect_06: ; c8171 (32:4171) + call BattleBGEffects_CheckSGB + jr nz, .sgb + ld de, .PalsCGB + jr .okay + +.sgb + ld de, .PalsSGB +.okay + call BattleBGEffect_GetNthDMGPal + ld [wOBP0], a + ret + +.PalsCGB: + db %11100100 + db %10010000 + db -2 + +.PalsSGB: + db %11110000 + db %11000000 + db -2 +; c818b + +BattleBGEffect_07: ; c818b (32:418b) + call BattleBGEffects_CheckSGB + jr nz, .sgb + ld de, .PalsCGB + jr .okay + +.sgb + ld de, .PalsSGB +.okay + call BattleBGEffect_GetNthDMGPal + ld [wOBP0], a + ret + +.PalsCGB: + db %11100100 + db %11011000 + db -2 + +.PalsSGB: + db %11110000 + db %11001100 + db -2 +; c81a5 + +BattleBGEffect_08: ; c81a5 (32:41a5) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + ld [wBGP], a + ret + +.Pals: + db %00011011 + db %01100011 + db %10000111 + db -2 +; c81b3 + +BattleBGEffect_HideMon: ; c81b3 (32:41b3) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .four + + +.zero + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_side + hlcoord 12, 0 + lb bc, 7, 7 + jr .got_pointer + +.player_side + hlcoord 2, 6 + lb bc, 6, 6 +.got_pointer + call ClearBox + pop bc + xor a + ld [hBGMapThird], a + ld a, $1 + ld [hBGMapMode], a + ret + +.four + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +BattleBGEffect_ShowMon: ; c81ea (32:41ea) + call BGEffect_CheckFlyDigStatus + jr z, .not_flying + call EndBattleBGEffect + ret + +.not_flying + call BGEffect_CheckBattleTurn + jr nz, .player_side + ld de, .EnemyData + jr .got_pointer + +.player_side + ld de, .PlayerData +.got_pointer + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call BattleBGEffect_RunPicResizeScript + ret + +.PlayerData: + db 0, $31, 0 + db -1 +.EnemyData: + db 3, $00, 3 + db -1 +; c8214 + +BattleBGEffect_FeetFollow: ; c8214 (32:4214) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .five + + +.zero + call BGEffect_CheckFlyDigStatus + jr z, .not_flying_digging + ld hl, wNumActiveBattleAnims + inc [hl] + call EndBattleBGEffect + ret + +.not_flying_digging + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld a, ANIM_OBJ_PLAYERFEETFOLLOW + ld [wBattleAnimTemp0], a + ld a, 16 * 8 + 4 + jr .okay + +.player_turn + ld a, ANIM_OBJ_ENEMYFEETFOLLOW + ld [wBattleAnimTemp0], a + ld a, 6 * 8 +.okay + ld [wBattleAnimTemp1], a + ld a, 8 * 8 + ld [wBattleAnimTemp2], a + xor a + ld [wBattleAnimTemp3], a + call _QueueBattleAnimation + pop bc + ret + +.one + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn_2 + hlcoord 12, 6 + lb bc, 1, 7 + jr .okay2 + +.player_turn_2 + hlcoord 2, 6 + lb bc, 1, 6 +.okay2 + call ClearBox + ld a, $1 + ld [hBGMapMode], a + pop bc + ret + +.five + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +BattleBGEffect_HeadFollow: ; c8281 (32:4281) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .five + + +.zero + call BGEffect_CheckFlyDigStatus + jr z, .not_flying_digging + ld hl, wNumActiveBattleAnims + inc [hl] + call EndBattleBGEffect + ret + +.not_flying_digging + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld a, ANIM_OBJ_BA + ld [wBattleAnimTemp0], a + ld a, 16 * 8 + 4 + jr .okay + +.player_turn + ld a, ANIM_OBJ_BB + ld [wBattleAnimTemp0], a + ld a, 6 * 8 +.okay + ld [wBattleAnimTemp1], a + ld a, 8 * 8 + ld [wBattleAnimTemp2], a + xor a + ld [wBattleAnimTemp3], a + call _QueueBattleAnimation + pop bc + ret + +.one + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn_2 + hlcoord 12, 5 + lb bc, 2, 7 + jr .okay2 + +.player_turn_2 + hlcoord 2, 6 + lb bc, 2, 6 +.okay2 + call ClearBox + ld a, $1 + ld [hBGMapMode], a + pop bc + ret + +.five + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +_QueueBattleAnimation: ; c82ee (32:42ee) + callfar QueueBattleAnimation + ret + +BattleBGEffect_27: ; c82f5 (32:42f5) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .four + + +.zero + call BattleBGEffects_IncrementJumptable + call BGEffect_CheckBattleTurn + ld [hl], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + jr z, .user + ld a, $9 + jr .okay + +.user + ld a, $8 +.okay + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], a + ret + +.one + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + jr z, .user_2 + hlcoord 0, 6 + lb de, 8, 6 +.row1 + push de + push hl +.col1 + inc hl + ld a, [hld] + ld [hli], a + dec d + jr nz, .col1 + pop hl + ld de, SCREEN_WIDTH + add hl, de + pop de + dec e + jr nz, .row1 + jr .okay2 + +.user_2 + hlcoord 19, 0 + lb de, 8, 7 +.row2 + push de + push hl +.col2 + dec hl + ld a, [hli] + ld [hld], a + dec d + jr nz, .col2 + pop hl + ld de, SCREEN_WIDTH + add hl, de + pop de + dec e + jr nz, .row2 +.okay2 + xor a + ld [hBGMapThird], a + ld a, $1 + ld [hBGMapMode], a + call BattleBGEffects_IncrementJumptable + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.four + xor a + ld [hBGMapMode], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .done + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], $1 + ret + +.done + call EndBattleBGEffect + ret + +BattleBGEffect_EnterMon: ; c837b (32:437b) + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld de, .EnemyData + jr .okay + +.player_turn + ld de, .PlayerData +.okay + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call BattleBGEffect_RunPicResizeScript + ret + +.PlayerData: + db 2, $31, 2 + db 1, $31, 1 + db 0, $31, 0 + db -1 +.EnemyData: + db 5, $00, 5 + db 4, $00, 4 + db 3, $00, 3 + db -1 +; c83a8 + +BattleBGEffect_ReturnMon: ; c83a8 (32:43a8) + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld de, .EnemyData + jr .okay + +.player_turn + ld de, .PlayerData +.okay + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call BattleBGEffect_RunPicResizeScript + ret + +.PlayerData: + db 0, $31, 0 + db -2, $66, 0 + db 1, $31, 1 + db -2, $44, 1 + db 2, $31, 2 + db -2, $22, 2 + db -3, $00, 0 + db -1 +.EnemyData: + db 3, $00, 3 + db -2, $77, 3 + db 4, $00, 4 + db -2, $55, 4 + db 5, $00, 5 + db -2, $33, 5 + db -3, $00, 0 + db -1 +; c83ed + +BattleBGEffect_RunPicResizeScript: ; c83ed (32:43ed) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .restart + dw .end + + +.zero + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld e, [hl] + ld d, $0 + inc [hl] + ld a, [wBattleAnimTemp1] + ld l, a + ld a, [wBattleAnimTemp2] + ld h, a + add hl, de + add hl, de + add hl, de + ld a, [hl] + cp -1 + jr z, .end + cp -2 + jr z, .clear + cp -3 + jr z, .skip + call .PlaceGraphic +.skip + call BattleBGEffects_IncrementJumptable + ld a, $1 + ld [hBGMapMode], a + ret + +.clear + call .ClearBox + jr .zero + +.restart + xor a + ld [hBGMapMode], a + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], $0 + ret + +.end + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +.ClearBox: +; get dims + push bc + inc hl + ld a, [hli] + ld b, a + and $f + ld c, a + ld a, b + swap a + and $f + ld b, a +; get coords + ld e, [hl] + ld d, 0 + ld hl, .Coords + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call ClearBox + pop bc + ret + +.PlaceGraphic: +; get dims + push bc + push hl + ld e, [hl] + ld d, 0 + ld hl, .BGSquares + add hl, de + add hl, de + add hl, de + ld a, [hli] + ld b, a + and $f + ld c, a + ld a, b + swap a + and $f + ld b, a +; store pointer + ld e, [hl] + inc hl + ld d, [hl] +; get byte + pop hl + inc hl + ld a, [hli] + ld [wBattleAnimTemp0], a +; get coord + push de + ld e, [hl] + ld d, 0 + ld hl, .Coords + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + pop de +; fill box +.row + push bc + push hl + ld a, [wBattleAnimTemp0] + ld b, a +.col + ld a, [de] + add b + ld [hli], a + inc de + dec c + jr nz, .col + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + pop bc + ret + +.Coords: + dwcoord 2, 6 + dwcoord 3, 8 + dwcoord 4, 10 + dwcoord 12, 0 + dwcoord 13, 2 + dwcoord 14, 4 + +.BGSquares: +bgsquare: MACRO + dn \1, \2 + dw \3 +endm + + bgsquare 6, 6, .SixBySix + bgsquare 4, 4, .FourByFour + bgsquare 2, 2, .TwoByTwo + bgsquare 7, 7, .SevenBySeven + bgsquare 5, 5, .FiveByFive + bgsquare 3, 3, .ThreeByThree + +.SixBySix: + db $00, $06, $0c, $12, $18, $1e + db $01, $07, $0d, $13, $19, $1f + db $02, $08, $0e, $14, $1a, $20 + db $03, $09, $0f, $15, $1b, $21 + db $04, $0a, $10, $16, $1c, $22 + db $05, $0b, $11, $17, $1d, $23 + +.FourByFour: + db $00, $0c, $12, $1e + db $02, $0e, $14, $20 + db $03, $0f, $15, $21 + db $05, $11, $17, $23 + +.TwoByTwo: + db $00, $1e + db $05, $23 + +.SevenBySeven: + db $00, $07, $0e, $15, $1c, $23, $2a + db $01, $08, $0f, $16, $1d, $24, $2b + db $02, $09, $10, $17, $1e, $25, $2c + db $03, $0a, $11, $18, $1f, $26, $2d + db $04, $0b, $12, $19, $20, $27, $2e + db $05, $0c, $13, $1a, $21, $28, $2f + db $06, $0d, $14, $1b, $22, $29, $30 + +.FiveByFive: + db $00, $07, $15, $23, $2a + db $01, $08, $16, $24, $2b + db $03, $0a, $18, $26, $2d + db $05, $0c, $1a, $28, $2f + db $06, $0d, $1b, $29, $30 + +.ThreeByThree: + db $00, $15, $2a + db $03, $18, $2d + db $06, $1b, $30 +; c8545 + +BattleBGEffect_Surf: ; c8545 (32:4545) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + lb de, 2, 2 + call InitSurfWaves + +.one + ld a, [hLCDCPointer] + and a + ret z + push bc + call .RotatewSurfWaveBGEffect + pop bc + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +.RotatewSurfWaveBGEffect: + ld hl, wSurfWaveBGEffect + ld de, wSurfWaveBGEffect + 1 + ld c, wSurfWaveBGEffectEnd - wSurfWaveBGEffect - 1 + ld a, [hl] + push af +.loop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + pop af + ld [hl], a + ld de, LYOverridesBackup + ld hl, wSurfWaveBGEffect + ld bc, $0 +.loop2 + ld a, [hLYOverrideStart] + cp e + jr nc, .load_zero + push hl + add hl, bc + ld a, [hl] + pop hl + jr .okay + +.load_zero + xor a +.okay + ld [de], a + ld a, c + inc a + and $3f + ld c, a + inc de + ld a, e + cp $5f + jr c, .loop2 + ret + +BattleBGEffect_Whirlpool: ; c8599 (32:4599) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $5e + ld [hLYOverrideEnd], a + lb de, 2, 2 + call Functionc8f2e + ret + +.one + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_30: ; c85c2 (32:45c2) + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + call EndBattleBGEffect + ret + +BattleBGEffect_31: ; c85ce (32:45ce) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld e, a + add $4 + ld [hl], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f0 + swap a + xor $ff + add $4 + ld d, a + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + ld [wBattleAnimTemp0], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + cp $20 + jr nc, .done + inc [hl] + inc [hl] + call Functionc8f9a + ret + +.done + call BattleBGEffects_ClearLYOverrides + call EndBattleBGEffect + ret + +BattleBGEffect_32: ; c8603 (32:4603) + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Psychic: ; c8607 (32:4607) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $5f + ld [hLYOverrideEnd], a + lb de, 6, 5 + call Functionc8f2e + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + and $3 + ret nz + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Teleport: ; c863f (32:463f) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + lb de, 6, 5 + call Functionc8f2e + ret + +.one + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_NightShade: ; c8662 (32:4662) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld e, [hl] + ld d, 2 + call Functionc8f2e + ret + +.one + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_DoubleTeam: ; c8689 (32:4689) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $10 + jr nc, .next + inc [hl] + call .UpdateLYOverrides + ret + +.three + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $ff + jr z, .next + dec [hl] + call .UpdateLYOverrides + ret + +.next + call BattleBGEffects_IncrementJumptable + ret + +.two + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld d, $2 + call BattleBGEffects_Sine + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + add [hl] + call .UpdateLYOverrides + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + add $4 + ld [hl], a + +.four + ret + +.UpdateLYOverrides: + ld e, a + xor $ff + inc a + ld d, a + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + srl a + push af +.loop + ld [hl], e + inc hl + ld [hl], d + inc hl + dec a + jr nz, .loop + pop af + ret nc + ld [hl], e + ret + +.five + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_AcidArmor: ; c8709 (32:4709) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld e, [hl] + ld d, 2 + call Functionc8f2e + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideEnd] + ld l, a + ld [hl], $0 + dec l + ld [hl], $0 + ret + +.one + ld a, [hLYOverrideEnd] + ld l, a + ld h, HIGH(LYOverridesBackup) + ld e, l + ld d, h + dec de +.loop + ld a, [de] + dec de + ld [hld], a + ld a, [hLYOverrideStart] + cp l + jr nz, .loop + ld [hl], $90 + ld a, [hLYOverrideEnd] + ld l, a + ld a, [hl] + cp $1 + jr c, .okay + cp $90 + jr z, .okay + ld [hl], $0 +.okay + dec l + ld a, [hl] + cp $2 + ret c + cp $90 + ret z + ld [hl], $0 + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Withdraw: ; c8761 (32:4761) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $1 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and $3f + ld d, a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + cp d + ret nc + call BGEffect_DisplaceLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + rlca + rlca + and $3 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + add [hl] + ld [hl], a + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Dig: ; c87a7 (32:47a7) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $2 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .next + dec [hl] + ret + +.next + ld [hl], $10 + call BattleBGEffects_IncrementJumptable +.two + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + dec a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + cp [hl] + ret c + ld a, [hl] + push af + and $7 + jr nz, .skip + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + dec [hl] +.skip + pop af + call BGEffect_DisplaceLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + inc [hl] + inc [hl] + ret + +.three + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Tackle: ; c8805 (32:4805) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw Tackle_BGEffect25_2d_one + dw Tackle_BGEffect25_2d_two + dw .three + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + call BGEffect_CheckBattleTurn + jr nz, .player_side + ld a, 2 + jr .okay + +.player_side + ld a, -2 +.okay + ld [hl], a + ret + +.three + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_25: ; c8837 (32:4837) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw Tackle_BGEffect25_2d_one + dw Tackle_BGEffect25_2d_two + dw .three + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms2 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + call BGEffect_CheckBattleTurn + jr nz, .player_side + ld a, 2 + jr .okay + +.player_side + ld a, -2 +.okay + ld [hl], a + ret + +.three + call BattleAnim_ResetLCDStatCustom + ret + +Tackle_BGEffect25_2d_one: + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp -8 + jr z, .reached_limit + cp 8 + jr nz, .finish +.reached_limit + call BattleBGEffects_IncrementJumptable +.finish + call Functionc88a5 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + add [hl] + ld [hl], a + ret + +Tackle_BGEffect25_2d_two: + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr nz, .asm_c8893 + call BattleBGEffects_IncrementJumptable +.asm_c8893 + call Functionc88a5 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + xor $ff + inc a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + add [hl] + ld [hl], a + ret + +Functionc88a5: ; c88a5 (32:48a5) + push af + ld a, [FXAnimID + 1] ; FXAnimID + 1 + or a + jr nz, .not_rollout + ld a, [FXAnimID] ; FXAnimID + cp ROLLOUT + jr z, .rollout +.not_rollout + pop af + jp BGEffect_FillLYOverridesBackup + +.rollout + ld a, [hLYOverrideStart] + ld d, a + ld a, [hLYOverrideEnd] + sub d + ld d, a + ld h, HIGH(LYOverridesBackup) + ld a, [hSCY] + or a + jr nz, .skip1 + ld a, [hLYOverrideStart] + or a + jr z, .skip2 + dec a + ld l, a + ld [hl], $0 + jr .skip2 + +.skip1 + ld a, [hLYOverrideEnd] + dec a + ld l, a + ld [hl], $0 +.skip2 + ld a, [hSCY] + ld l, a + ld a, [hLYOverrideStart] + sub l + jr nc, .skip3 + xor a + dec d +.skip3 + ld l, a + pop af +.loop + ld [hli], a + dec d + jr nz, .loop + ret + +BattleBGEffect_2d: ; c88e7 (32:48e7) + call BattleBGEffects_AnonJumptable +.anon_dw + dw BGEffect2d_2f_zero + dw Tackle_BGEffect25_2d_one + dw Tackle_BGEffect25_2d_two + dw .three + + +.three + call BattleAnim_ResetLCDStatCustom + ret + +BGEffect2d_2f_zero: + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld a, -2 + jr .okay + +.player_turn + ld a, 2 +.okay + ld [hl], a + ret + +BattleBGEffect_2f: ; c8919 (32:4919) + call BattleBGEffects_AnonJumptable +.anon_dw + dw BGEffect2d_2f_zero + dw Tackle_BGEffect25_2d_one + dw .two + dw Tackle_BGEffect25_2d_two + dw .four + +.four + call BattleAnim_ResetLCDStatCustom +.two + ret + +BattleBGEffect_26: ; c892a (32:492a) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld d, $8 + call BattleBGEffects_Sine + call BGEffect_FillLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $4 + ld [hl], a + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_2c: ; c8964 (32:4964) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + xor a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hli], a + ld [hl], a + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld d, $6 + call BattleBGEffects_Sine + push af + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld d, $2 + call BattleBGEffects_Sine + ld e, a + pop af + add e + call BGEffect_FillLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + add $8 + ld [hl], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_28: ; c89b5 (32:49b5) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $20 + ret nc + inc [hl] + ld d, a + ld e, 4 + call Functionc8f2e + ret + +.two + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .reset + dec [hl] + ld d, a + ld e, 4 + call Functionc8f2e + ret + +.reset + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_BounceDown: ; c89ee (32:49ee) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms2 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $20 + ret + +.one + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + cp $38 + ret nc + push af + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld d, $10 + call BattleBGEffects_Cosine + add $10 + ld d, a + pop af + add d + call BGEffect_DisplaceLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + inc [hl] + inc [hl] + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_2a: ; c8a3a (32:4a3a) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + +.zero + call BattleBGEffects_IncrementJumptable + ld a, $e4 + call BattleBGEffects_SetLYOverrides + ld a, $47 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld a, [hLYOverrideStart] + ld l, a + ld h, HIGH(LYOverridesBackup) +.loop + ld a, [hLYOverrideEnd] + cp l + jr z, .done + xor a + ld [hli], a + jr .loop + +.done + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 +.one +.four + ret + +.two + call .GetLYOverride + jr nc, .next + call .SetLYOverridesBackup + ret + +.next + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ld a, [hLYOverrideStart] + inc a + ld [hLYOverrideStart], a + call BattleBGEffects_IncrementJumptable + ret + +.three + call .GetLYOverride + jr nc, .finish + call .SetLYOverridesBackup + ld a, [hLYOverrideEnd] + dec a + ld l, a + ld [hl], e + ret + +.finish + call BattleBGEffects_IncrementJumptable + ret + +.SetLYOverridesBackup: + ld e, a + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + srl a + ld h, HIGH(LYOverridesBackup) +.loop2 + ld [hl], e + inc hl + inc hl + dec a + jr nz, .loop2 + ret + +.five + call BattleBGEffects_ResetVideoHRAM + ret + +.GetLYOverride: + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + srl a + srl a + srl a + ld e, a + ld d, 0 + ld hl, .data + add hl, de + ld a, [hl] + cp $ff + ret + +.data + db $00, $40, $90, $e4 + db -1 +; c8acc + +BattleBGEffect_2b: ; c8acc (32:4acc) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $40 + ret + +.one + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + jr z, .done + dec [hl] + srl a + srl a + srl a + and $f + ld d, a + ld e, a + call Functionc8f2e + ret + +.done + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_1c: ; c8b00 (32:4b00) + ld a, [hCGB] + and a + jr nz, .cgb + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + ld a, $e4 + call BattleBGEffects_SetLYOverrides + ld a, rBGP - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $60 + ld [hLYOverrideEnd], a + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + ld e, a + and $7 + ret nz + ld a, e + and $18 + sla a + swap a + sla a + ld e, a + ld d, $0 + push bc + call BGEffect_CheckBattleTurn + jr nz, .player + ld hl, .CGB_DMGEnemyData + add hl, de + ld a, [hli] + ld [wOBP1], a + ld d, a + ld e, [hl] + lb bc, $2f, $30 + jr .okay + +.player + ld hl, .DMG_PlayerData + add hl, de + ld d, [hl] + inc hl + ld a, [hl] + ld [wOBP1], a + ld e, a + lb bc, $37, $28 +.okay + call .DMG_LYOverrideLoads + pop bc + ret + +.two + call BattleBGEffects_ResetVideoHRAM + ld a, $e4 + ld [wBGP], a + ld [wOBP1], a + ret + +.DMG_LYOverrideLoads: + ld hl, LYOverridesBackup +.loop1 + ld [hl], d + inc hl + dec b + jr nz, .loop1 +.loop2 + ld [hl], e + inc hl + dec c + jr nz, .loop2 + ret + +.cgb + ld de, .Jumptable + call BatttleBGEffects_GetNamedJumptablePointer + jp hl + +.Jumptable: + dw .cgb_zero + dw .cgb_one + dw .cgb_two +.cgb_zero + call BattleBGEffects_IncrementJumptable + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.cgb_one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + ld e, a + and $7 + ret nz + ld a, e + and $18 + sla a + swap a + sla a + ld e, a + ld d, 0 + call BGEffect_CheckBattleTurn + jr nz, .player_2 + ld hl, .CGB_DMGEnemyData + add hl, de + ld a, [hli] + push hl + call BGEffects_LoadBGPal1_OBPal0 + pop hl + ld a, [hl] + call BGEffects_LoadBGPal0_OBPal1 + ret + +.player_2 + ld hl, .CGB_DMGEnemyData + add hl, de + ld a, [hli] + push hl + call BGEffects_LoadBGPal0_OBPal1 + pop hl + ld a, [hl] + call BGEffects_LoadBGPal1_OBPal0 + ret + +.cgb_two + ld a, $e4 + call BGEffects_LoadBGPal0_OBPal1 + ld a, $e4 + call BGEffects_LoadBGPal1_OBPal0 + call EndBattleBGEffect + ret + +.CGB_DMGEnemyData: + db $e4, $e4 + db $f8, $90 + db $fc, $40 + db $f8, $90 +.DMG_PlayerData: + db $e4, $e4 + db $90, $f8 + db $40, $fc + db $90, $f8 +; c8be8 + +BattleBGEffect_RapidFlash: ; c8be8 (32:4be8) + ld de, .FlashPals + call BGEffect_RapidCyclePals + ret + +.FlashPals: + db $e4, $6c, $fe +; c8bf2 + +BattleBGEffect_16: ; c8bf2 (32:4bf2) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $90, $40, $ff +; c8bfd + +BattleBGEffect_17: ; c8bfd (32:4bfd) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $f8, $fc, $ff +; c8c08 + +BattleBGEffect_18: ; c8c08 (32:4c08) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $90, $40, $90, $fe +; c8c14 + +BattleBGEffect_19: ; c8c14 (32:4c14) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $f8, $fc, $f8, $fe +; c8c20 + +BattleBGEffect_1a: ; c8c20 (32:4c20) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $f8, $fc, $f8, $e4, $90, $40, $90, $fe +; c8c30 + +BattleBGEffect_1b: ; c8c30 (32:4c30) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $fc, $e4, $00, $fe +; c8c3c + +BattleBGEffect_1d: ; c8c3c (32:4c3c) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $90, $40, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $40, $90, $e4, $ff +; c8c55 + +BattleBGEffect_1e: ; c8c55 (32:4c55) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $00, $40, $90, $e4, $ff +; c8c61 + +BattleBGEffect_VibrateMon: ; c8c61 (32:4c61) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + + +.zero ; c8c68 (32:4c68) + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $20 + ret + +.one ; c8c85 (32:4c85) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .finish + dec [hl] + and $1 + ret nz + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + call BGEffect_FillLYOverridesBackup + ret + +.finish + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_WobbleMon: ; c8ca2 (32:4ca2) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero ; c8cab (32:4cab) + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $37 + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one ; c8cc3 (32:4cc3) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $40 + jr nc, .two + ld d, $6 + call BattleBGEffects_Sine + call BGEffect_FillLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ret + +.two ; c8cdd (32:4cdd) + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_2e: ; c8ce1 (32:4ce1) + call Functionc8d0b + jr c, .xor_a + bit 7, a + jr z, .okay +.xor_a + xor a +.okay + push af + call DelayFrame + pop af + ld [hSCY], a + xor $ff + inc a + ld [AnimObject01_YOffset], a + ret + +BattleBGEffect_1f: ; c8cf9 (32:4cf9) + call Functionc8d0b + jr nc, .skip + xor a +.skip + ld [hSCX], a + ret + +BattleBGEffect_20: ; c8d02 (32:4d02) + call Functionc8d0b + jr nc, .skip + xor a +.skip + ld [hSCY], a + ret + +Functionc8d0b: ; c8d0b (32:4d0b) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + and a + jr nz, .okay + call EndBattleBGEffect + scf + ret + +.okay + dec [hl] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and $f + jr z, .every_16_frames + dec [hl] + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + ret + +.every_16_frames + ld a, [hl] + swap a + or [hl] + ld [hl], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + and a + ret + +BattleBGEffect_35: ; c8d3a (32:4d3a) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $40 + jr nc, .finish + ld d, $6 + call BattleBGEffects_Sine + ld [hSCX], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ret + +.finish + xor a + ld [hSCX], a + ret + +BattleBGEffect_GetNthDMGPal: ; c8d57 (32:4d57) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + and a + jr z, .zero + dec [hl] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + call BattleBGEffect_GetNextDMGPal + ret + +.zero + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + ret + +BGEffect_RapidCyclePals: ; c8d77 (32:4d77) + ld a, [hCGB] + and a + jr nz, .cgb + push de + ld de, .Jumptable_DMG + call BatttleBGEffects_GetNamedJumptablePointer + pop de + jp hl + +.Jumptable_DMG: + dw .zero_dmg + dw .one_dmg + dw .two_dmg + + +.zero_dmg ; c8d8b (32:4d8b) + call BattleBGEffects_IncrementJumptable + ld a, $e4 + call BattleBGEffects_SetLYOverrides + ld a, $47 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld [hl], $0 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], a + ret + +.one_dmg ; c8daa (32:4daa) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f + jr z, .okay_1_dmg + dec [hl] + ret + +.okay_1_dmg + ld a, [hl] + swap a + or [hl] + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + jr c, .okay_2_dmg + call BGEffect_FillLYOverridesBackup + ret + +.okay_2_dmg + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.two_dmg ; c8dc9 (32:4dc9) + call BattleBGEffects_ResetVideoHRAM + ld a, %11100100 + ld [rBGP], a + call EndBattleBGEffect + ret + +.cgb + push de + ld de, .Jumptable_CGB + call BatttleBGEffects_GetNamedJumptablePointer + pop de + jp hl + +.Jumptable_CGB: ; c8ddd (32:4ddd) + dw .zero_cgb + dw .one_cgb + dw .two_cgb + dw .three_cgb + dw .four_cgb + + +.zero_cgb ; c8de7 (32:4de7) + call BGEffect_CheckBattleTurn + jr nz, .player_turn_cgb + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_IncrementJumptable +.player_turn_cgb + call BattleBGEffects_IncrementJumptable + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld [hl], $0 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], a + ret + +.one_cgb ; c8e02 (32:4e02) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f + jr z, .okay_1_cgb + dec [hl] + ret + +.okay_1_cgb + ld a, [hl] + swap a + or [hl] + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + jr c, .okay_2_cgb + call BGEffects_LoadBGPal0_OBPal1 + ret + +.okay_2_cgb + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.two_cgb ; c8e21 (32:4e21) + ld a, $e4 + call BGEffects_LoadBGPal0_OBPal1 + call EndBattleBGEffect + ret + +.three_cgb ; c8e2a (32:4e2a) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f + jr z, .okay_3_cgb + dec [hl] + ret + +.okay_3_cgb + ld a, [hl] + swap a + or [hl] + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + jr c, .okay_4_cgb + call BGEffects_LoadBGPal1_OBPal0 + ret + +.okay_4_cgb + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.four_cgb ; c8e49 (32:4e49) + ld a, $e4 + call BGEffects_LoadBGPal1_OBPal0 + call EndBattleBGEffect + ret + +BGEffects_LoadBGPal0_OBPal1: ; c8e52 (32:4e52) + ld h, a + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld a, h + push bc + push af + ld hl, BGPals + ld de, UnknBGPals + ld b, a + ld c, $1 + call CopyPals + ld hl, OBPals + 8 + ld de, UnknOBPals + 8 + pop af + ld b, a + ld c, $1 + call CopyPals + pop bc + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret + +BGEffects_LoadBGPal1_OBPal0: ; c8e7f (32:4e7f) + ld h, a + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld a, h + push bc + push af + ld hl, BGPals + 8 + ld de, UnknBGPals + 8 + ld b, a + ld c, $1 + call CopyPals + ld hl, OBPals ; OBPals + ld de, UnknOBPals ; wd040 + pop af + ld b, a + ld c, $1 + call CopyPals + pop bc + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret + +BattleBGEffect_GetFirstDMGPal: ; c8eac (32:4eac) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] +BattleBGEffect_GetNextDMGPal: ; c8eb2 (32:4eb2) + ld l, a + ld h, $0 + add hl, de + ld a, [hl] + cp -1 + jr z, .quit + cp -2 + jr nz, .repeat + ld a, [de] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 +.repeat + and a + ret + +.quit + scf + ret + +BattleBGEffects_ClearLYOverrides: ; c8eca (32:4eca) + xor a +BattleBGEffects_SetLYOverrides: ; c8ecb (32:4ecb) + ld hl, LYOverrides ; wListPointer + ld e, $99 +.loop1 + ld [hli], a + dec e + jr nz, .loop1 + ld hl, LYOverridesBackup + ld e, $91 +.loop2 + ld [hli], a + dec e + jr nz, .loop2 + ret + +BattleBGEffect_SetLCDStatCustoms1: ; c8ede (32:4ede) + ld [hLCDCPointer], a + call BGEffect_CheckBattleTurn + jr nz, .player_turn + lb de, $00, $36 + jr .okay + +.player_turn + lb de, $2f, $5e +.okay + ld a, d + ld [hLYOverrideStart], a + ld a, e + ld [hLYOverrideEnd], a + ret + +BattleBGEffect_SetLCDStatCustoms2: ; c8ef4 (32:4ef4) + ld [hLCDCPointer], a + call BGEffect_CheckBattleTurn + jr nz, .player_turn + lb de, $00, $36 + jr .okay + +.player_turn + lb de, $2d, $5e +.okay + ld a, d + ld [hLYOverrideStart], a + ld a, e + ld [hLYOverrideEnd], a + ret + +BattleAnim_ResetLCDStatCustom: ; c8f0a (32:4f0a) + xor a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a + call BattleBGEffects_ClearLYOverrides + xor a + ld [hLCDCPointer], a + call EndBattleBGEffect + ret + +BattleBGEffects_ResetVideoHRAM: ; c8f19 (32:4f19) + xor a + ld [hLCDCPointer], a + ld a, %11100100 + ld [rBGP], a + ld [wBGP], a + ld [wOBP1], a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a + call BattleBGEffects_ClearLYOverrides + ret + +Functionc8f2e: ; c8f2e (32:4f2e) + push bc + xor a + ld [wBattleAnimTemp0], a + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + ld a, $80 + ld [wBattleAnimTemp3], a + ld bc, LYOverridesBackup +.loop + ld a, [hLYOverrideStart] + cp c + jr nc, .next + ld a, [hLYOverrideEnd] + cp c + jr c, .next + ld a, [wBattleAnimTemp2] + ld d, a + ld a, [wBattleAnimTemp0] + call BattleBGEffects_Sine + ld [bc], a +.next + inc bc + ld a, [wBattleAnimTemp1] + ld hl, wBattleAnimTemp0 + add [hl] + ld [hl], a + ld hl, wBattleAnimTemp3 + dec [hl] + jr nz, .loop + pop bc + ret + +InitSurfWaves: ; c8f69 (32:4f69) + push bc + xor a + ld [wBattleAnimTemp0], a + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + ld a, $40 + ld [wBattleAnimTemp3], a + ld bc, wSurfWaveBGEffect +.loop + ld a, [wBattleAnimTemp2] + ld d, a + ld a, [wBattleAnimTemp0] + call BattleBGEffects_Sine + ld [bc], a + inc bc + ld a, [wBattleAnimTemp1] + ld hl, wBattleAnimTemp0 + add [hl] + ld [hl], a + ld hl, wBattleAnimTemp3 + dec [hl] + jr nz, .loop + pop bc + ret + +Functionc8f9a: ; c8f9a (32:4f9a) + push bc + ld [wBattleAnimTemp3], a + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call .GetLYOverrideBackupAddrOffset + ld hl, LYOverridesBackup + add hl, de + ld c, l + ld b, h +.loop + ld a, [wBattleAnimTemp3] + and a + jr z, .done + dec a + ld [wBattleAnimTemp3], a + push af + ld a, [wBattleAnimTemp2] + ld d, a + ld a, [wBattleAnimTemp1] + push hl + call BattleBGEffects_Sine + ld e, a + pop hl + ld a, [hLYOverrideEnd] + cp c + jr c, .skip1 + ld a, e + ld [bc], a + inc bc +.skip1 + ld a, [hLYOverrideStart] + cp l + jr nc, .skip2 + ld [hl], e + dec hl +.skip2 + ld a, [wBattleAnimTemp1] + add $4 + ld [wBattleAnimTemp1], a + pop af + jr .loop + +.done + pop bc + and a + ret + +.GetLYOverrideBackupAddrOffset: + ld a, [hLYOverrideStart] + ld e, a + ld a, [wBattleAnimTemp0] + add e + ld e, a + ld d, $0 + ret + +BattleBGEffect_WavyScreenFX: ; c8fef (32:4fef) + push bc + ld a, [hLYOverrideStart] + ld l, a + inc a + ld e, a + ld h, HIGH(LYOverridesBackup) + ld d, h + ld a, [hLYOverrideEnd] + sub l + and a + jr z, .done + ld c, a + ld a, [hl] + push af +.loop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + pop af + ld [hl], a +.done + pop bc + ret + +BGEffect_FillLYOverridesBackup: ; c900b (32:500b) + push af + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + ld d, a + pop af +.loop + ld [hli], a + dec d + jr nz, .loop + ret + +BGEffect_DisplaceLYOverridesBackup: ; c901b (32:501b) + ; e = a; d = [hLYOverrideEnd] - [hLYOverrideStart] - a + push af + ld e, a + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + sub e + ld d, a + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideStart] + ld l, a + ld a, $90 +.loop + ld [hli], a + dec e + jr nz, .loop + pop af + xor $ff +.loop2 + ld [hli], a + dec d + jr nz, .loop2 + ret + +BGEffect_CheckBattleTurn: ; c9038 (32:5038) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hBattleTurn] + and $1 + xor [hl] + ret + +BGEffect_CheckFlyDigStatus: ; c9042 (32:5042) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hBattleTurn] + and $1 + xor [hl] + jr nz, .player + ld a, [EnemySubStatus3] ; EnemySubStatus3 + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +.player + ld a, [PlayerSubStatus3] ; PlayerSubStatus3 + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +BattleBGEffects_CheckSGB: ; c9059 (32:5059) + ld a, [hSGB] + and a + ret + +BattleBGEffects_Sine: ; c905d (32:505d) + ld e, a + callfar BattleAnim_Sine_e + ld a, e + ret + +BattleBGEffects_Cosine: ; c9066 (32:5066) + ld e, a + callfar BattleAnim_Cosine_e + ld a, e + ret + +; c906f (32:506f) diff --git a/engine/battle_anims/engine.asm b/engine/battle_anims/engine.asm new file mode 100755 index 000000000..55adeae8c --- /dev/null +++ b/engine/battle_anims/engine.asm @@ -0,0 +1,314 @@ +QueueBattleAnimation: ; cc9a1 (33:49a1) + ld hl, ActiveAnimObjects + ld e, 10 +.loop + ld a, [hl] + and a + jr z, .done + ld bc, BATTLEANIMSTRUCT_LENGTH + add hl, bc + dec e + jr nz, .loop + scf + ret + +.done + ld c, l + ld b, h + ld hl, wNumActiveBattleAnims + inc [hl] + call InitBattleAnimation + ret + +DeinitBattleAnimation: ; cc9bd + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld [hl], $0 + ret + +; cc9c4 + +InitBattleAnimation: ; cc9c4 (33:49c4) + ld a, [wBattleAnimTemp0] + ld e, a + ld d, 0 + ld hl, BattleAnimObjects +rept 6 + add hl, de +endr + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld a, [wNumActiveBattleAnims] + ld [hli], a ; Index + ld a, [de] + inc de + ld [hli], a ; 01 + ld a, [de] + inc de + ld [hli], a ; 02 + ld a, [de] + inc de + ld [hli], a ; Frameset ID + ld a, [de] + inc de + ld [hli], a ; Function + ld a, [de] + inc de + ld [hli], a ; 05 + ld a, [de] + call GetBattleAnimTileOffset + ld [hli], a ; Tile ID + ld a, [wBattleAnimTemp1] + ld [hli], a ; X Coord + ld a, [wBattleAnimTemp2] + ld [hli], a ; Y Coord + xor a + ld [hli], a ; X Offset + ld [hli], a ; Y Offset + ld a, [wBattleAnimTemp3] + ld [hli], a ; 0b + xor a + ld [hli], a ; 0c + dec a + ld [hli], a ; 0d + xor a + ld [hli], a ; 0e + ld [hli], a ; 0f + ld [hl], a ; 10 + ret + +BattleAnimOAMUpdate: ; cca09 + call InitBattleAnimBuffer + call GetBattleAnimFrame + cp -3 + jp z, .done + cp -4 + jp z, .delete + push af + ld hl, wBattleAnimTempOAMFlags + ld a, [wBattleAnimTempAddSubFlags] + xor [hl] + and $e0 + ld [hl], a + pop af + push bc + call GetBattleAnimOAMPointer + ld a, [wBattleAnimTempTileID] + add [hl] + ld [wBattleAnimTempTileID], a + inc hl + ld a, [hli] + ld c, a + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wBattleAnimOAMPointerLo] + ld e, a + ld d, HIGH(Sprites) +.loop + ld a, [wBattleAnimTempYCoord] + ld b, a + ld a, [wBattleAnimTempYOffset] + add b + ld b, a + push hl + ld a, [hl] + ld hl, wBattleAnimTempOAMFlags + bit 6, [hl] + jr z, .no_yflip + add $8 + xor $ff + inc a + +.no_yflip + pop hl + add b + ld [de], a + inc hl + inc de + ld a, [wBattleAnimTempXCoord] + ld b, a + ld a, [wBattleAnimTempXOffset] + add b + ld b, a + push hl + ld a, [hl] + ld hl, wBattleAnimTempOAMFlags + bit 5, [hl] + jr z, .no_xflip + add $8 + xor $ff + inc a + +.no_xflip + pop hl + add b + ld [de], a + inc hl + inc de + ld a, [wBattleAnimTempTileID] + add $31 + add [hl] + ld [de], a + inc hl + inc de + ld a, [wBattleAnimTempOAMFlags] + ld b, a + ld a, [hl] + xor b + and $e0 + ld b, a + ld a, [hl] + and $10 + or b + ld b, a + ld a, [wBattleAnimTempPalette] + and $f + or b + ld [de], a + inc hl + inc de + ld a, e + ld [wBattleAnimOAMPointerLo], a + cp $a0 + jr nc, .exit_set_carry + dec c + jr nz, .loop + pop bc + jr .done + +.delete + call DeinitBattleAnimation + +.done + and a + ret + +.exit_set_carry + pop bc + scf + ret + +; ccaaa + +InitBattleAnimBuffer: ; ccaaa + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + ld a, [hl] + and %10000000 + ld [wBattleAnimTempOAMFlags], a + xor a + ld [wBattleAnimTempAddSubFlags], a + ld hl, BATTLEANIMSTRUCT_PALETTE + add hl, bc + ld a, [hl] + ld [wBattleAnimTempPalette], a + ld hl, BATTLEANIMSTRUCT_02 + add hl, bc + ld a, [hl] + ld [wBattleAnimTempField02], a + ld hl, BATTLEANIMSTRUCT_TILEID + add hl, bc + ld a, [hli] + ld [wBattleAnimTempTileID], a + ld a, [hli] + ld [wBattleAnimTempXCoord], a + ld a, [hli] + ld [wBattleAnimTempYCoord], a + ld a, [hli] + ld [wBattleAnimTempXOffset], a + ld a, [hli] + ld [wBattleAnimTempYOffset], a + ld a, [hBattleTurn] + and a + ret z + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + ld a, [hl] + ld [wBattleAnimTempOAMFlags], a + bit 0, [hl] + ret z + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hli] + ld d, a + ld a, (-10 * 8) + 4 + sub d + ld [wBattleAnimTempXCoord], a + ld a, [hli] + ld d, a + ld a, [wBattleAnimTempField02] + cp $ff + jr nz, .check_kinesis_softboiled_milkdrink + ld a, 5 * 8 + add d + jr .done + +.check_kinesis_softboiled_milkdrink + sub d + push af + ld a, [FXAnimID + 1] + or a + jr nz, .no_sub + ld a, [FXAnimID] + cp KINESIS + jr z, .kinesis + cp SOFTBOILED + jr z, .softboiled + cp MILK_DRINK + jr nz, .no_sub +.kinesis +.softboiled +.milk_drink + pop af + sub 1 * 8 + jr .done + +.no_sub + pop af +.done + ld [wBattleAnimTempYCoord], a + ld a, [hli] + xor $ff + inc a + ld [wBattleAnimTempXOffset], a + ret + +; ccb31 + +GetBattleAnimTileOffset: ; ccb31 (33:4b31) + push hl + push bc + ld hl, wBattleAnimTileDict + ld b, a + ld c, 10 / 2 +.loop + ld a, [hli] + cp b + jr z, .load + inc hl + dec c + jr nz, .loop + xor a + jr .done + +.load + ld a, [hl] +.done + pop bc + pop hl + ret + +_ExecuteBGEffects: ; ccb48 + callfar ExecuteBGEffects + ret + +; ccb4f + +_QueueBGEffect: ; ccb4f (33:4b4f) + callfar QueueBGEffect + ret + +; ccb56 (33:4b56) diff --git a/engine/battle_anims/functions.asm b/engine/battle_anims/functions.asm new file mode 100755 index 000000000..ea9fb70b3 --- /dev/null +++ b/engine/battle_anims/functions.asm @@ -0,0 +1,4157 @@ +DoBattleAnimFrame: ; ccfbe + ld hl, BATTLEANIMSTRUCT_FUNCTION + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, .Jumptable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; ccfce + +.Jumptable: +; entries correspond to BATTLEANIMFUNC_* constants + dw BattleAnimFunction_Null ; 00 + dw BattleAnimFunction_01 ; 01 + dw BattleAnimFunction_02 ; 02 + dw BattleAnimFunction_03 ; 03 + dw BattleAnimFunction_04 ; 04 + dw BattleAnimFunction_ThrowFromPlayerToEnemy ; 05 + dw BattleAnimFunction_ThrowFromPlayerToEnemyAndDisappear ; 06 + dw BattleAnimFunction_07 ; 07 + dw BattleAnimFunction_08 ; 08 + dw BattleAnimFunction_09 ; 09 + dw BattleAnimFunction_0A ; 0a + dw BattleAnimFunction_RazorLeaf ; 0b + dw BattleAnimFunction_0C ; 0c + dw BattleAnimFunction_0D ; 0d + dw BattleAnimFunction_0E ; 0e + dw BattleAnimFunction_0F ; 0f + dw BattleAnimFunction_10 ; 10 + dw BattleAnimFunction_11 ; 11 + dw BattleAnimFunction_PokeBall ; 12 + dw BattleAnimFunction_PokeBallBlocked ; 13 + dw BattleAnimFunction_14 ; 14 + dw BattleAnimFunction_15 ; 15 + dw BattleAnimFunction_16 ; 16 + dw BattleAnimFunction_17 ; 17 + dw BattleAnimFunction_18 ; 18 + dw BattleAnimFunction_19 ; 19 + dw BattleAnimFunction_1A ; 1a + dw BattleAnimFunction_1B ; 1b + dw BattleAnimFunction_1C ; 1c + dw BattleAnimFunction_1D ; 1d + dw BattleAnimFunction_1E ; 1e + dw BattleAnimFunction_1F ; 1f + dw BattleAnimFunction_LeechSeed ; 20 + dw BattleAnimFunction_21 ; 21 + dw BattleAnimFunction_22 ; 22 + dw BattleAnimFunction_23 ; 23 + dw BattleAnimFunction_24 ; 24 + dw BattleAnimFunction_25 ; 25 + dw BattleAnimFunction_26 ; 26 + dw BattleAnimFunction_27 ; 27 + dw BattleAnimFunction_28 ; 28 + dw BattleAnimFunction_SpiralDescent ; 29 + dw BattleAnimFunction_PoisonGas ; 2a + dw BattleAnimFunction_Horn ; 2b + dw BattleAnimFunction_2C ; 2c + dw BattleAnimFunction_2D ; 2d + dw BattleAnimFunction_2E ; 2e + dw BattleAnimFunction_2F ; 2f + dw BattleAnimFunction_30 ; 30 + dw BattleAnimFunction_31 ; 31 + dw BattleAnimFunction_32 ; 32 + dw BattleAnimFunction_33 ; 33 + dw BattleAnimFunction_34 ; 34 + dw BattleAnimFunction_35 ; 35 + dw BattleAnimFunction_36 ; 36 + dw BattleAnimFunction_37 ; 37 + dw BattleAnimFunction_38 ; 38 + dw BattleAnimFunction_39 ; 39 + dw BattleAnimFunction_3A ; 3a + dw BattleAnimFunction_3B ; 3b + dw BattleAnimFunction_3C ; 3c + dw BattleAnimFunction_3D ; 3d + dw BattleAnimFunction_3E ; 3e + dw BattleAnimFunction_3F ; 3f + dw BattleAnimFunction_40 ; 40 + dw BattleAnimFunction_41 ; 41 + dw BattleAnimFunction_42 ; 42 + dw BattleAnimFunction_43 ; 43 + dw BattleAnimFunction_44 ; 44 + dw BattleAnimFunction_45 ; 45 + dw BattleAnimFunction_46 ; 46 + dw BattleAnimFunction_47 ; 47 + dw BattleAnimFunction_48 ; 48 + dw BattleAnimFunction_49 ; 49 + dw BattleAnimFunction_4A ; 4a + dw BattleAnimFunction_4B ; 4b + dw BattleAnimFunction_4C ; 4c + dw BattleAnimFunction_4D ; 4d + dw BattleAnimFunction_4E ; 4e + dw BattleAnimFunction_4F ; 4f + +BattleAnimFunction_Null: ; cd06e (33:506e) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.one + call DeinitBattleAnimation +.zero + ret + +BattleAnimFunction_ThrowFromPlayerToEnemyAndDisappear: ; cd079 (33:5079) + call BattleAnimFunction_ThrowFromPlayerToEnemy + ret c + call DeinitBattleAnimation + ret + +BattleAnimFunction_ThrowFromPlayerToEnemy: ; cd081 (33:5081) + ; If x coord at $88 or beyond, abort. + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + ret nc + ; Move right 2 pixels + add $2 + ld [hl], a + ; Move down 1 pixel + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ; Decrease ??? and hold onto its previous value (argument of the sine function) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + ; Get ???, which is the amplitude of the sine function + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + ; Store the result in the Y offset + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ; Carry flag denotes success + scf + ret + +BattleAnimFunction_04: ; cd0a6 (33:50a6) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr c, .asm_cd0b3 + call DeinitBattleAnimation + ret + +.asm_cd0b3 + add $2 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + inc [hl] + inc [hl] + ld d, $10 + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + sra a + sra a + sra a + sra a + ld [hl], a + ret + +BattleAnimFunction_03: ; cd0e3 (33:50e3) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + ld a, $0 + jr z, .asm_cd0f9 + ld a, $20 +.asm_cd0f9 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ret + +BattleAnimFunction_01: ; cd12a (33:512a) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.one + call DeinitBattleAnimation + ret + +.zero + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + ret nc + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +BattleAnimFunction_02: ; cd146 (33:5146) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr nc, .asm_cd158 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +.asm_cd158 + call DeinitBattleAnimation + ret + +BattleAnimFunction_PokeBall: ; cd15c (33:515c) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + dw .six + dw .seven + dw .eight + dw .nine + dw .ten + dw .eleven +.zero ; init + call GetBallAnimPal + call BattleAnim_IncAnonJumptableIndex + ret + +.one + call BattleAnimFunction_ThrowFromPlayerToEnemy + ret c + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + add [hl] + ld [hl], a + ld a, BATTLEANIMFRAMESET_0B + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +.three + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_09 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + inc hl + ld [hl], $10 +.four + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec a + ld [hl], a + and $1f + ret nz + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + sub $4 + ld [hl], a + ret nz + ld a, BATTLEANIMFRAMESET_0C + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +.six + ld a, BATTLEANIMFRAMESET_0D + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + dec [hl] +.two +.five +.nine + ret + +.seven + call GetBallAnimPal + ld a, BATTLEANIMFRAMESET_0A + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $20 +.eight +.ten + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec a + ld [hl], a + and $1f + jr z, .eleven + and $f + ret nz + call BattleAnim_IncAnonJumptableIndex + ret + +.eleven + call DeinitBattleAnimation + ret + +BattleAnimFunction_PokeBallBlocked: ; cd212 (33:5212) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two +.zero + call GetBallAnimPal + call BattleAnim_IncAnonJumptableIndex + ret + +.one + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $70 + jr nc, .next + call BattleAnimFunction_ThrowFromPlayerToEnemy + ret + +.next + call BattleAnim_IncAnonJumptableIndex +.two + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $80 + jr nc, .done + add $4 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] + dec [hl] + ret + +.done + call DeinitBattleAnimation + ret + +GetBallAnimPal: ; cd249 (33:5249) + ld hl, BallColors + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + ld a, [CurItem] ; CurItem + ld e, a + pop af + ld [rSVBK], a +.IsInArray: + ld a, [hli] + cp -1 + jr z, .load + cp e + jr z, .load + inc hl + jr .IsInArray + +.load + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_PALETTE + add hl, bc + ld [hl], a + ret +; cd26c (33:526c) + +INCLUDE "data/battle_anims/ball_colors.asm" + +BattleAnimFunction_10: ; cd284 (33:5284) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four +.zero + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + swap a + and $f + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +.one + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + ret nc + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +.two + call DeinitBattleAnimation + ret + +.three + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_0F + call ReinitBattleAnimFrameset +.four + ret + +BattleAnimFunction_07: ; cd2be (33:52be) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $30 + inc hl + ld [hl], $48 +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $20 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + sub [hl] + jr z, .done + jr c, .done + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ret + +.done + call DeinitBattleAnimation + ret + +BattleAnimFunction_08: ; cd306 (33:5306) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three +.zero + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $80 + jr nc, .next + call .SetCoords + ret + +.next + call BattleAnim_IncAnonJumptableIndex +.one + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 +.two + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $40 + jr nc, .loop_back + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + call BattleAnim_Cosine + sub $18 + sra a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + ld [hl], a + ret + +.loop_back + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + jr z, .finish + sub $10 + ld d, a + ld a, [hl] + and $f + or d + ld [hl], a + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + dec [hl] + ret + +.finish + call BattleAnim_IncAnonJumptableIndex +.three + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $b0 + jr c, .retain + call DeinitBattleAnimation + ret + +.retain + call .SetCoords + ret + +.SetCoords: + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld e, a + srl e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc +.loop + dec [hl] + dec e + jr nz, .loop + ret + +BattleAnimFunction_09: ; cd3ae (33:53ae) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .done_one + dec [hl] + ret + +.done_one + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + swap a + and $f + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ret + +.two + call DeinitBattleAnimation + ret + +BattleAnimFunction_0A: ; cd3f2 (33:53f2) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + dw .six + dw .seven + dw .eight + dw .nine +.zero + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + cp $7 + jr z, .seven + ld a, BATTLEANIMFRAMESET_11 + call ReinitBattleAnimFrameset + ret + +.seven + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr nc, .set_up_eight + add $2 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +.set_up_eight + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_10 + call ReinitBattleAnimFrameset +.eight + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ret + +.nine + call DeinitBattleAnimation + ret + +.one + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + dec [hl] + ret + +.four + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + inc [hl] +.two + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + dec [hl] + ret + +.five + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + inc [hl] +.three + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + inc [hl] +.six + ret + +BattleAnimFunction_RazorLeaf: ; cd478 (33:5478) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + dw .six + dw .seven + dw .eight +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $40 +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $30 + jr nc, .sine_cosine + call BattleAnim_IncAnonJumptableIndex + xor a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hli], a + ld [hl], a + ld a, BATTLEANIMFRAMESET_17 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 6, [hl] + ret z + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], $5 + ret + +.sine_cosine + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3f + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + call Functioncd557 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +.two + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $20 + jr nz, .sine_cosine_2 + call DeinitBattleAnimation + ret + +.sine_cosine_2 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 6, [hl] + jr nz, .decrease + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + jr .finish + +.decrease + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + dec [hl] +.finish + ld de, $80 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +.three + ld a, BATTLEANIMFRAMESET_16 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + res 5, [hl] +.four +.five +.six +.seven + call BattleAnim_IncAnonJumptableIndex + ret + +.eight + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $c0 + ret nc + ld a, $8 + call Functionce70a + ret + +Functioncd557: ; cd557 (33:5557) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + bit 7, a + jr nz, .negative + cp $20 + jr nc, .plus_256 + cp $18 + jr nc, .plus_384 + ld de, $200 + ret + +.plus_384 + ld de, $180 + ret + +.plus_256 + ld de, $100 + ret + +.negative + and $3f + cp $20 + jr nc, .minus_256 + cp $18 + jr nc, .minus_384 + ld de, -$200 + ret + +.minus_384 + ld de, -$180 + ret + +.minus_256 + ld de, -$100 + ret + +BattleAnimFunction_4E: ; cd58a (33:558a) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.zero + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $40 + rlca + rlca + add $19 + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], a + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $40 +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $30 + jr nc, .sine_cosine + call DeinitBattleAnimation + ret + +.sine_cosine + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3f + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + call Functioncd557 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +BattleAnimFunction_0C: ; cd5e9 (33:55e9) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $c +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .next + dec [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +.next + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + ld a, BATTLEANIMFRAMESET_22 + call ReinitBattleAnimFrameset +.two + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $98 + jr nc, .okay + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld h, [hl] + ld l, a + ld de, $60 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d +.okay + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $20 + ret c + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + ld e, a + ld d, $ff + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ret + +BattleAnimFunction_0D: ; cd66a (33:566a) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four +.zero + call BattleAnim_IncAnonJumptableIndex + ld a, rSCY - $ff00 + ld [hLCDCPointer], a + ld a, $58 + ld [hLYOverrideStart], a + ld a, $5e + ld [hLYOverrideEnd], a + ret + +.one + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp e + jr nc, .asm_cd69b + call BattleAnim_IncAnonJumptableIndex + xor a + ld [hLYOverrideStart], a + ret + +.asm_cd69b + dec a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + add [hl] + sub $10 + ret c + ld [hLYOverrideStart], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + inc a + and $7 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + inc [hl] +.two + ret + +.three + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $70 + jr c, asm_cd6da + xor a + ld [hLCDCPointer], a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a +.four + call DeinitBattleAnimation + ret + +asm_cd6da: ; cd6da (33:56da) + inc a + inc a + ld [hl], a + sub $10 + ret c + ld [hLYOverrideStart], a + ret + +BattleAnimFunction_0E: ; cd6e3 (33:56e3) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd6ea + dw Functioncd6f7 +Functioncd6ea: ; cd6ea (33:56ea) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, BATTLEANIMFRAMESET_24 + add [hl] ; offset + call ReinitBattleAnimFrameset +Functioncd6f7: ; cd6f7 (33:56f7) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $b8 + jr c, .asm_cd704 + call DeinitBattleAnimation + ret + +.asm_cd704 + ld a, $2 + call Functionce70a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_0F: ; cd71a (33:571a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd725 + dw Functioncd728 + dw Functioncd763 + dw Functioncd776 +Functioncd725: ; cd725 (33:5725) + call BattleAnim_IncAnonJumptableIndex +Functioncd728: ; cd728 (33:5728) + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_cd747 + ld a, $2 + call Functionce70a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +.asm_cd747 + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_28 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], $30 + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + ld a, [hl] + and $1 + ld [hl], a +Functioncd763: ; cd763 (33:5763) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $18 + jr nc, .asm_cd76e + inc [hl] + ret + +.asm_cd76e + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_29 + call ReinitBattleAnimFrameset +Functioncd776: ; cd776 (33:5776) + ret + +BattleAnimFunction_11: ; cd777 (33:5777) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $38 + jr c, .asm_cd784 + call DeinitBattleAnimation + ret + +.asm_cd784 + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld l, [hl] + ld h, a + ld de, $80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + xor $10 + ld [hl], a + ret + +BattleAnimFunction_14: ; cd7a4 (33:57a4) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd7ab + dw Functioncd7d2 +Functioncd7ab: ; cd7ab (33:57ab) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + sla a + sla a + sla a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld [hl], $1 +Functioncd7d2: ; cd7d2 (33:57d2) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr nz, .asm_cd7de + call DeinitBattleAnimation + ret + +.asm_cd7de + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + xor $1 + ld [hl], a + ret z + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + dec [hl] + ret + +BattleAnimFunction_15: ; cd80c (33:580c) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd81f + dw Functioncd817 + dw Functioncd81f + dw Functioncd820 +Functioncd817: ; cd817 (33:5817) + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_35 + call ReinitBattleAnimFrameset +Functioncd81f: ; cd81f (33:581f) + ret + +Functioncd820: ; cd820 (33:5820) + call DeinitBattleAnimation + ret + +BattleAnimFunction_16: ; cd824 (33:5824) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd835 + dw Functioncd860 + dw Functioncd88f + dw Functioncd88f + dw Functioncd88f + dw Functioncd88f + dw Functioncd893 +Functioncd835: ; cd835 (33:5835) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + jr nz, .asm_cd852 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $10 + jr .asm_cd858 + +.asm_cd852 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $30 +.asm_cd858 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +Functioncd860: ; cd860 (33:5860) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + bit 7, a + jr nz, .load_no_inc + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc a + jr .reinit + +.load_no_inc + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] +.reinit + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $1f + ret nz +Functioncd88f: ; cd88f (33:588f) + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncd893: ; cd893 (33:5893) + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], $1 + ret + +BattleAnimFunction_17: ; cd89a (33:589a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd8ab + dw Functioncd8cc + dw Functioncd8f5 + dw Functioncd8f5 + dw Functioncd8f5 + dw Functioncd8f5 + dw Functioncd8f9 +Functioncd8ab: ; cd8ab (33:58ab) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + jr nz, .asm_cd8be + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $10 + jr .asm_cd8c4 + +.asm_cd8be + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $30 +.asm_cd8c4 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +Functioncd8cc: ; cd8cc (33:58cc) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + bit 7, a + jr nz, .asm_cd8e6 + ld a, $3d + jr .asm_cd8e8 + +.asm_cd8e6 + ld a, $3c +.asm_cd8e8 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + inc [hl] + ld a, [hl] + and $1f + ret nz +Functioncd8f5: ; cd8f5 (33:58f5) + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncd8f9: ; cd8f9 (33:58f9) + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], $1 + ret + +BattleAnimFunction_18: ; cd900 (33:5900) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd907 + dw Functioncd913 +Functioncd907: ; cd907 (33:5907) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + inc hl + ld [hl], $0 +Functioncd913: ; cd913 (33:5913) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_cd950 + ld d, a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld e, [hl] + ld hl, hPushOAM ; $ff80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], d + ret + +.asm_cd950 + call DeinitBattleAnimation + ret + +BattleAnimFunction_19: ; cd954 (33:5954) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd961 + dw Functioncd96a + dw Functioncd96e + dw Functioncd96a + dw Functioncd97b +Functioncd961: ; cd961 (33:5961) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld [hl], $0 +Functioncd96a: ; cd96a (33:596a) + call Functioncd99a + ret + +Functioncd96e: ; cd96e (33:596e) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr c, asm_cd988 + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncd97b: ; cd97b (33:597b) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $b8 + jr c, asm_cd988 + call DeinitBattleAnimation + ret + +asm_cd988: ; cd988 (33:5988) + call Functioncd99a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +Functioncd99a: ; cd99a (33:599a) + call Functioncd9f4 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + sub $8 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr z, .asm_cd9d7 + cp $c2 + jr c, .asm_cd9e2 +.asm_cd9d7 + dec a + ld [hl], a + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + inc [hl] + ret + +.asm_cd9e2 + xor a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hli], a + ld [hl], a + ret + +Functioncd9f4: ; cd9f4 (33:59f4) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, Unknown_cda01 + add hl, de + ld d, [hl] + ret + +; cda01 (33:5a01) +Unknown_cda01: ; cda01 + db 8, 6, 5, 4, 5, 6, 8, 12, 16 +; cda0a +BattleAnimFunction_1C: ; cda0a (33:5a0a) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $30 + jr nc, .asm_cda17 + call DeinitBattleAnimation + ret + +.asm_cda17 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld e, a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + sub e + ld [hl], a + srl e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc +.asm_cda2c + inc [hl] + dec e + jr nz, .asm_cda2c + ret + +BattleAnimFunction_1F: ; cda31 (33:5a31) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncda4c + dw Functioncda3a + dw Functioncda4c +Functioncda3a: ; cda3a (33:5a3a) + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + inc a + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $8 +Functioncda4c: ; cda4c (33:5a4c) + ret + +BattleAnimFunction_LeechSeed: ; cda4d (33:5a4d) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three +.zero: ; cda58 (33:5a58) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $40 + ret + +.one: ; cda62 (33:5a62) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $20 + jr c, .sprout + call Functioncda8d + ret + +.sprout + ld [hl], $40 + ld a, BATTLEANIMFRAMESET_57 + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +.two: ; cda7a (33:5a7a) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr z, .flutter + dec [hl] + ret + +.flutter + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_58 + call ReinitBattleAnimFrameset +.three: ; cda8c (33:5a8c) + ret + +Functioncda8d: ; cda8d (33:5a8d) + dec [hl] + ld d, $20 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_02 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld h, [hl] + ld a, h + and $f + swap a + ld l, a + ld a, h + and $f0 + swap a + ld h, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +BattleAnimFunction_3F: ; cdad6 (33:5ad6) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdadf + dw Functioncdae9 + dw Functioncdaf9 +Functioncdadf: ; cdadf (33:5adf) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $40 + ret + +Functioncdae9: ; cdae9 (33:5ae9) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $20 + jr c, .asm_cdaf6 + call Functioncda8d + ret + +.asm_cdaf6 + call BattleAnim_IncAnonJumptableIndex +Functioncdaf9: ; cdaf9 (33:5af9) + ret + +BattleAnimFunction_1A: ; cdafa (33:5afa) + call BattleAnimFunction_03 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + add $f + ld [hl], a + ret + +BattleAnimFunction_1B: ; cdb06 (33:5b06) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdb13 + dw Functioncdb14 + dw Functioncdb28 + dw Functioncdb50 + dw Functioncdb65 +Functioncdb13: ; cdb13 (33:5b13) + ret + +Functioncdb14: ; cdb14 (33:5b14) + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_cdb24 + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], $0 + ret + +.asm_cdb24 + add $4 + ld [hl], a + ret + +Functioncdb28: ; cdb28 (33:5b28) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $98 + ret nc + inc [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + set 0, [hl] + ld hl, BATTLEANIMSTRUCT_02 + add hl, bc + ld [hl], $90 + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], $2 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +Functioncdb50: ; cdb50 (33:5b50) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $2c + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], $80 +Functioncdb65: ; cdb65 (33:5b65) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $98 + ret nc + inc [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_1D: ; cdb80 (33:5b80) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdb9f + dw Functioncdbb3 + dw Functioncdbcf + dw Functioncdbeb + dw Functioncdc74 + dw Functioncdc1a + dw Functioncdbc1 + dw Functioncdc1e + dw Functioncdc27 + dw Functioncdc39 + dw Functioncdc74 + dw Functioncdc48 + dw Functioncdc57 + dw Functioncdc74 +Functioncdb9f: ; cdb9f (33:5b9f) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + inc hl + ld [hl], $10 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +Functioncdbb3: ; cdbb3 (33:5bb3) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $40 + jr nc, .asm_cdbbd + inc [hl] +.asm_cdbbd + call Functioncdc75 + ret + +Functioncdbc1: ; cdbc1 (33:5bc1) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $4b + jr nc, .asm_cdbcb + inc [hl] +.asm_cdbcb + call Functioncdc75 + ret + +Functioncdbcf: ; cdbcf (33:5bcf) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr nc, .asm_cdbe6 + and $f + jr nz, asm_cdbfa + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $10 + call BattleAnim_IncAnonJumptableIndex + ret + +.asm_cdbe6 + call BattleAnim_IncAnonJumptableIndex + inc [hl] + ret + +Functioncdbeb: ; cdbeb (33:5beb) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdbf5 + dec [hl] + ret + +.asm_cdbf5 + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + dec [hl] +asm_cdbfa: ; cdbfa (33:5bfa) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, hPushOAM ; $ff80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ret + +Functioncdc1a: ; cdc1a (33:5c1a) + call DeinitBattleAnimation + ret + +Functioncdc1e: ; cdc1e (33:5c1e) + ld a, BATTLEANIMFRAMESET_4E + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncdc27: ; cdc27 (33:5c27) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + ld d, $2 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +Functioncdc39: ; cdc39 (33:5c39) + ld a, BATTLEANIMFRAMESET_50 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $4 + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncdc48: ; cdc48 (33:5c48) + ld a, BATTLEANIMFRAMESET_4F + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $40 + ret + +Functioncdc57: ; cdc57 (33:5c57) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $20 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_cdc71 + dec [hl] + ret + +.asm_cdc71 + call BattleAnim_IncAnonJumptableIndex +Functioncdc74: ; cdc74 (33:5c74) + ret + +Functioncdc75: ; cdc75 (33:5c75) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $20 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + sub $8 + ld [hl], a + ret nz + xor a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hli], a + ld [hl], a + call BattleAnim_IncAnonJumptableIndex + ret + +BattleAnimFunction_1E: ; cdca6 (33:5ca6) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdcb6 + cp $d8 + jr nc, .asm_cdcb6 + call DeinitBattleAnimation + ret + +.asm_cdcb6 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + sub d + ld [hl], a + ret + +BattleAnimFunction_21: ; cdcc3 (33:5cc3) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdcca + dw Functioncdced +Functioncdcca: ; cdcca (33:5cca) + ld a, [hBattleTurn] + and a + jr z, .asm_cdcd9 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + xor $ff + add $3 + ld [hl], a +.asm_cdcd9 + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $8 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, BATTLEANIMFRAMESET_59 + add [hl] + call ReinitBattleAnimFrameset + ret + +Functioncdced: ; cdced (33:5ced) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdcfa + dec [hl] + call Functioncdcfe + ret + +.asm_cdcfa + call DeinitBattleAnimation + ret + +Functioncdcfe: ; cdcfe (33:5cfe) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + ld d, $10 + call BattleAnim_Sine + ld d, a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdd20 + dec a + ret z + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ret + +.asm_cdd20 + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, d + xor $ff + inc a + ld [hl], a + ret + +BattleAnimFunction_22: ; cdd2a (33:5d2a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdd31 + dw Functioncdd4f +Functioncdd31: ; cdd31 (33:5d31) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3f + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $80 + rlca + ld [hl], a + add BATTLEANIMFRAMESET_5D + call ReinitBattleAnimFrameset + ret + +Functioncdd4f: ; cdd4f (33:5d4f) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + swap a + ld d, a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $80 + ret nc + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and $3 + jr nz, .asm_cdd87 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] +.asm_cdd87 + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ret + +BattleAnimFunction_23: ; cdd90 (33:5d90) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdd97 + dw Functioncddbc +Functioncdd97: ; cdd97 (33:5d97) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $80 + rlca + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +Functioncddbc: ; cddbc (33:5dbc) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $10 + push af + push de + call BattleAnim_Sine + sra a + sra a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + and $3f + jr z, .asm_cddf0 + and $1f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc a + jr .asm_cddf5 + +.asm_cddf0 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] +.asm_cddf5 + call ReinitBattleAnimFrameset + ret + +BattleAnimFunction_24: ; cddf9 (33:5df9) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncde02 + dw Functioncde20 + dw Functioncde21 +Functioncde02: ; cde02 (33:5e02) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + add BATTLEANIMFRAMESET_63 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, Unknown_cde25 + add hl, de + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a +Functioncde20: ; cde20 (33:5e20) + ret + +Functioncde21: ; cde21 (33:5e21) + call DeinitBattleAnimation + ret + +; cde25 (33:5e25) +Unknown_cde25: ; cde25 + db $ec, $f8, $00 +; cde28 +BattleAnimFunction_25: ; cde28 (33:5e28) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + ld d, $4 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld e, [hl] + ld hl, $ffa0 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +BattleAnimFunction_26: ; cde54 (33:5e54) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + dec [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ret + +BattleAnimFunction_27: ; cde6b (33:5e6b) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncde72 + dw Functioncde88 +Functioncde72: ; cde72 (33:5e72) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr nz, .asm_cde83 + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + set 6, [hl] +.asm_cde83 + add BATTLEANIMFRAMESET_6A + call ReinitBattleAnimFrameset +Functioncde88: ; cde88 (33:5e88) + ret + +BattleAnimFunction_28: ; cde89 (33:5e89) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncde90 + dw Functioncdebf +Functioncde90: ; cde90 (33:5e90) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld a, e + and $70 + swap a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, e + and $80 + jr nz, .asm_cdeb2 + ld a, e + and $f + ld [hl], a + ret + +.asm_cdeb2 + ld a, e + and $f + xor $ff + inc a + ld [hl], a + ld a, BATTLEANIMFRAMESET_6E + call ReinitBattleAnimFrameset + ret + +Functioncdebf: ; cdebf (33:5ebf) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdec9 + dec [hl] + ret + +.asm_cdec9 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ret + +BattleAnimFunction_SpiralDescent: ; cdedd (33:5edd) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $28 + jr nc, .delete + inc [hl] + ret + +.delete + call DeinitBattleAnimation + ret + +BattleAnimFunction_2D: ; cdf1b (33:5f1b) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $28 + jr nc, .asm_cdf55 + inc [hl] + ret + +.asm_cdf55 + call DeinitBattleAnimation + ret + +BattleAnimFunction_PoisonGas: ; cdf59 (33:5f59) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdf60 + dw BattleAnimFunction_SpiralDescent +Functioncdf60: ; cdf60 (33:5f60) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr nc, .next + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld d, $18 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +.next + call BattleAnim_IncAnonJumptableIndex + ret + +BattleAnimFunction_34: ; cdf8c (33:5f8c) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + inc [hl] + ld a, [hl] + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $e8 + jr z, .asm_cdfc7 + dec [hl] + ret + +.asm_cdfc7 + call DeinitBattleAnimation + ret + +BattleAnimFunction_3C: ; cdfcb (33:5fcb) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + inc [hl] + ld a, [hl] + and $3 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $d0 + jr z, .asm_ce007 + dec [hl] + dec [hl] + ret + +.asm_ce007 + call DeinitBattleAnimation + ret + +BattleAnimFunction_35: ; ce00b (33:600b) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce014 + dw Functionce023 + dw Functionce05f +Functionce014: ; ce014 (33:6014) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $34 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $10 +Functionce023: ; ce023 (33:6023) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $6c + jr c, .asm_ce02d + ret + +.asm_ce02d + ld a, $2 + call Functionce70a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld d, [hl] + call BattleAnim_Sine + bit 7, a + jr nz, .asm_ce046 + xor $ff + inc a +.asm_ce046 + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + sub $4 + ld [hl], a + and $1f + cp $20 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + srl [hl] + ret + +Functionce05f: ; ce05f (33:605f) + call DeinitBattleAnimation + ret + +BattleAnimFunction_Horn: ; ce063 (33:6063) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw Functionce09e +.zero: ; ce06e (33:606e) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ret + +.one: ; ce083 (33:6083) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $58 + ret nc + ld a, $2 + call Functionce70a + ret + +.two: ; ce091 (33:6091) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $20 + jr c, Functionce09e + call DeinitBattleAnimation + ret + +Functionce09e: ; ce09e (33:609e) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + sra a + xor $ff + inc a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + add $8 + ld [hl], a + ret + +BattleAnimFunction_2C: ; ce0c5 (33:60c5) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce0ce + dw Functionce0f8 + dw Functionce0dd +Functionce0ce: ; ce0ce (33:60ce) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + swap a + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +Functionce0dd: ; ce0dd (33:60dd) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + bit 7, a + jr z, .asm_ce0f0 + ld [hl], a +.asm_ce0f0 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + sub $4 + ld [hl], a +Functionce0f8: ; ce0f8 (33:60f8) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr c, .asm_ce105 + call DeinitBattleAnimation + ret + +.asm_ce105 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +BattleAnimFunction_2E: ; ce10e (33:610e) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce115 + dw Functionce12a +Functionce115: ; ce115 (33:6115) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + sub $28 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a +Functionce12a: ; ce12a (33:612a) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + and [hl] + jr nz, .asm_ce149 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] +.asm_ce149 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $20 + inc hl + srl [hl] + ret + +BattleAnimFunction_2F: ; ce15c (33:615c) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + ld a, [hl] + and $1 + jr nz, .asm_ce189 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] +.asm_ce189 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3 + jr nz, .asm_ce197 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + inc [hl] +.asm_ce197 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + cp $5a + jr nc, .asm_ce1aa + ld a, [hl] + and a + jr z, .asm_ce1ac + dec [hl] + ret + +.asm_ce1aa + inc [hl] + ret + +.asm_ce1ac + call DeinitBattleAnimation + ret + +BattleAnimFunction_42: ; ce1b0 (33:61b0) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + cp $40 + jr nc, .asm_ce1df + inc [hl] + ret + +.asm_ce1df + ld a, [hl] + dec [hl] + and a + ret nz + call DeinitBattleAnimation + ret + +BattleAnimFunction_30: ; ce1e7 (33:61e7) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce1ee + dw Functionce1fb +Functionce1ee: ; ce1ee (33:61ee) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a +Functionce1fb: ; ce1fb (33:61fb) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $30 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + add $8 + ld d, $30 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + ret + +BattleAnimFunction_31: ; ce226 (33:6226) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce22d + dw Functionce254 +Functionce22d: ; ce22d (33:622d) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $f +Functionce254: ; ce254 (33:6254) + ret + +BattleAnimFunction_32: ; ce255 (33:6255) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce260 + dw Functionce274 + dw Functionce278 + dw Functionce289 +Functionce260: ; ce260 (33:6260) + call BattleAnim_IncAnonJumptableIndex + ld a, [hBattleTurn] + and a + jr nz, .asm_ce26c + ld a, $f0 + jr .asm_ce26e + +.asm_ce26c + ld a, $cc +.asm_ce26e + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ret + +Functionce274: ; ce274 (33:6274) + call Functionce29f + ret + +Functionce278: ; ce278 (33:6278) + call Functionce29f + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + ret nc + ld a, $4 + call Functionce70a + ret + +Functionce289: ; ce289 (33:6289) + call Functionce29f + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $d0 + jr nc, .asm_ce29b + ld a, $4 + call Functionce70a + ret + +.asm_ce29b + call DeinitBattleAnimation + ret + +Functionce29f: ; ce29f (33:629f) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and $7 + inc [hl] + srl a + ld e, a + ld d, $0 + ld a, [hSGB] + and a + jr nz, .asm_ce2b6 + ld hl, Unknown_ce2c4 + jr .asm_ce2b9 + +.asm_ce2b6 + ld hl, Unknown_ce2c8 +.asm_ce2b9 + add hl, de + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + and [hl] + ld [wOBP0], a + ret + +; ce2c4 (33:62c4) +Unknown_ce2c4: ; ce2c4 + db $ff, $aa, $55, $aa +Unknown_ce2c8: ; ce2c8 + db $ff, $ff, $00, $00 +; ce2cc +BattleAnimFunction_33: ; ce2cc (33:62cc) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + ld d, $18 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + dec [hl] + dec [hl] + ret + +BattleAnimFunction_36: ; ce2fd (33:62fd) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce306 + dw Functionce330 + dw Functionce34c +Functionce306: ; ce306 (33:6306) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $e0 + jr nz, .asm_ce319 + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $2 + ret + +.asm_ce319 + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, hPushOAM ; $ff80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ret + +Functionce330: ; ce330 (33:6330) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr z, .asm_ce33a + dec [hl] + ret + +.asm_ce33a + ld [hl], $4 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + add [hl] + ld [hl], a + ret + +Functionce34c: ; ce34c (33:634c) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr nc, .asm_ce35b + ld a, $4 + call Functionce70a + ret + +.asm_ce35b + call DeinitBattleAnimation + ret + +BattleAnimFunction_37: ; ce35f (33:635f) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce366 + dw Functionce375 +Functionce366: ; ce366 (33:6366) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + add BATTLEANIMFRAMESET_81 + call ReinitBattleAnimFrameset +Functionce375: ; ce375 (33:6375) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + jr nz, .asm_ce383 + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + inc [hl] + ret + +.asm_ce383 + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + dec [hl] + ret + +BattleAnimFunction_38: ; ce389 (33:6389) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce392 + dw Functionce39c + dw Functionce3ae +Functionce392: ; ce392 (33:6392) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $c + ret + +Functionce39c: ; ce39c (33:639c) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_ce3a6 + dec [hl] + ret + +.asm_ce3a6 + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_20 + call ReinitBattleAnimFrameset +Functionce3ae: ; ce3ae (33:63ae) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + dec [hl] + ret + +BattleAnimFunction_39: ; ce3b4 (33:63b4) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + push af + ld d, $2 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop af + ld d, $8 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_3A: ; ce3d2 (33:63d2) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $20 + jr c, .asm_ce3df + call DeinitBattleAnimation + ret + +.asm_ce3df + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $8 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + inc [hl] + ret + +BattleAnimFunction_3B: ; ce3ff (33:63ff) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce406 + dw Functionce412 +Functionce406: ; ce406 (33:6406) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + ld [hl], a + ret + +Functionce412: ; ce412 (33:6412) + call DeinitBattleAnimation + ret + +BattleAnimFunction_3D: ; ce416 (33:6416) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + sra a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + ret + +BattleAnimFunction_3E: ; ce43a (33:643a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce443 + dw Functionce465 + dw Functionce490 +Functionce443: ; ce443 (33:6443) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + add [hl] + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + or $8 + ld [hl], a +Functionce465: ; ce465 (33:6465) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_ce48b + dec [hl] + add $8 + ld d, a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.asm_ce48b + ld [hl], $10 + call BattleAnim_IncAnonJumptableIndex +Functionce490: ; ce490 (33:6490) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + and a + ret nz + call DeinitBattleAnimation + ret + +BattleAnimFunction_40: ; ce49c (33:649c) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce4a3 + dw Functionce4b0 +Functionce4a3: ; ce4a3 (33:64a3) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, BATTLEANIMFRAMESET_24 + add [hl] + call ReinitBattleAnimFrameset +Functionce4b0: ; ce4b0 (33:64b0) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $38 + jr nc, .asm_ce4d8 + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld d, $18 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] + ret + +.asm_ce4d8 + call DeinitBattleAnimation + ret + +BattleAnimFunction_41: ; ce4dc (33:64dc) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + ret z + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + call BattleAnim_Sine + bit 7, a + jr nz, .asm_ce4f4 + xor $ff + inc a +.asm_ce4f4 + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and $1f + ret nz + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + srl [hl] + ret + +BattleAnimFunction_43: ; ce508 (33:6508) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $10 + jr nc, .asm_ce52e + inc [hl] + inc [hl] + ld d, a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.asm_ce52e + call DeinitBattleAnimation + ret + +BattleAnimFunction_44: ; ce532 (33:6532) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + ld a, e + and $c0 + rlca + rlca + add [hl] + ld [hl], a + ld a, e + and $3f + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_45: ; ce55b (33:655b) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce564 + dw Functionce56e + dw Functionce577 +Functionce564: ; ce564 (33:6564) + ld d, $18 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + jr asm_ce58f + +Functionce56e: ; ce56e (33:656e) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $18 +Functionce577: ; ce577 (33:6577) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $80 + jr nc, .asm_ce58b + ld d, a + add $8 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + jr asm_ce58f + +.asm_ce58b + call DeinitBattleAnimation + ret + +asm_ce58f: ; ce58f (33:658f) + call Functionce6f1 + ret + +BattleAnimFunction_46: ; ce593 (33:6593) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce5b3 + dw Functionce59a +Functionce59a: ; ce59a (33:659a) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_ce5b0 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] + dec [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + inc [hl] + inc [hl] + ret + +.asm_ce5b0 + call DeinitBattleAnimation +Functionce5b3: ; ce5b3 (33:65b3) + ret + +BattleAnimFunction_47: ; ce5b4 (33:65b4) + ld d, $50 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + push af + push de + call BattleAnim_Sine + sra a + sra a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_48: ; ce5dc (33:65dc) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $d0 + jr z, .disappear + dec [hl] + dec [hl] + dec [hl] + dec [hl] + ret + +.disappear + call DeinitBattleAnimation + ret + +BattleAnimFunction_49: ; ce5ee (33:65ee) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce5f9 + dw Functionce60a + dw Functionce622 + dw Functionce618 +Functionce5f9: ; ce5f9 (33:65f9) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr nz, asm_ce61c + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $ec +Functionce60a: ; ce60a (33:660a) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $4 + jr z, Functionce618 + inc [hl] + inc [hl] + inc [hl] + inc [hl] + ret + +Functionce618: ; ce618 (33:6618) + call DeinitBattleAnimation + ret + +asm_ce61c: ; ce61c (33:661c) + call BattleAnim_IncAnonJumptableIndex + call BattleAnim_IncAnonJumptableIndex +Functionce622: ; ce622 (33:6622) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $d8 + ret z + dec [hl] + dec [hl] + dec [hl] + dec [hl] + ret + +BattleAnimFunction_4A: ; ce62f (33:662f) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce63a + dw Functionce648 + dw Functionce65c + dw Functionce672 +Functionce63a: ; ce63a (33:663a) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + call BattleAnim_IncAnonJumptableIndex + ret + +Functionce648: ; ce648 (33:6648) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + add $4 + cp $70 + jr c, .asm_ce654 + xor a +.asm_ce654 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + inc [hl] + inc [hl] + ret + +Functionce65c: ; ce65c (33:665c) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + add $4 + cp $70 + jr c, .asm_ce668 + xor a +.asm_ce668 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + add $8 + ld [hl], a + ret + +Functionce672: ; ce672 (33:6672) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + add $4 + cp $70 + jr c, .asm_ce67e + xor a +.asm_ce67e + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + add $4 + ld [hl], a + ret + +BattleAnimFunction_4B: ; ce688 (33:6688) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld l, a + and $f0 + ld h, a + swap a + or h + ld h, a + ld a, l + and $f + swap a + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ret + +BattleAnimFunction_4C: ; ce6b3 (33:66b3) + ld d, $18 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + call Functionce6f1 + ret + +BattleAnimFunction_4F: ; ce6bf (33:66bf) + ld d, $18 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + srl a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + add [hl] + call Functionce6f1 + ret + +BattleAnimFunction_4D: ; ce6d2 (33:66d2) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $20 + jr nc, .asm_ce6ed + inc [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + xor $ff + inc a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +.asm_ce6ed + call DeinitBattleAnimation + ret + +Functionce6f1: ; ce6f1 (33:66f1) + push af + push de + call BattleAnim_Sine + sra a + sra a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +Functionce70a: ; ce70a (33:670a) + and $f + ld e, a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + ld [hl], a + srl e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc +.asm_ce719 + dec [hl] + dec e + jr nz, .asm_ce719 + ret + +BattleAnim_AnonJumptable: ; ce71e (33:671e) + pop de + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld l, [hl] + ld h, $0 + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +BattleAnim_IncAnonJumptableIndex: ; ce72c (33:672c) + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleAnim_Cosine: ; ce732 (33:6732) + add $10 +BattleAnim_Sine: ; ce734 (33:6734) +; a = d sin a + and $3f + cp $20 + jr nc, .negative + call .ApplySineWave + ld a, h + ret + +.negative + and $1f + call .ApplySineWave + ld a, h + xor $ff + inc a + ret + +.ApplySineWave: + ld e, a + ld a, d + ld d, 0 + ld hl, BattleAnimSineWave + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld hl, $0 +.multiply + srl a + jr nc, .even + add hl, de +.even + sla e + rl d + and a + jr nz, .multiply + ret + +BattleAnim_Sine_e: ; ce765 (33:6765) + ld a, e + call BattleAnim_Sine + ld e, a + ret + +BattleAnim_Cosine_e: ; ce76b (33:676b) + ld a, e + call BattleAnim_Cosine + ld e, a + ret + +; ce771 (33:6771) +BattleAnim_AbsSinePrecise: ; ce771 + ld a, e + call BattleAnim_Sine + ld e, l + ld d, h + ret + +; ce778 +BattleAnim_AbsCosinePrecise: ; ce778 + ld a, e + call BattleAnim_Cosine + ld e, l + ld d, h + ret + +; ce77f +BattleAnimSineWave: ; ce77f + sine_wave $100 +; ce7bf diff --git a/engine/routines/getpokeballwobble.asm b/engine/battle_anims/getpokeballwobble.asm index 7fb4d3e38..7fb4d3e38 100755 --- a/engine/routines/getpokeballwobble.asm +++ b/engine/battle_anims/getpokeballwobble.asm diff --git a/engine/battle_anims/helpers.asm b/engine/battle_anims/helpers.asm new file mode 100755 index 000000000..0a00b65a4 --- /dev/null +++ b/engine/battle_anims/helpers.asm @@ -0,0 +1,130 @@ +ReinitBattleAnimFrameset: ; ce7bf (33:67bf) + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], 0 + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], -1 + ret + +GetBattleAnimFrame: ; ce7d1 +.loop + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld a, [hl] + and a + jr z, .next_frame + dec [hl] + call .GetPointer + ld a, [hli] + push af + jr .okay + +.next_frame + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + inc [hl] + call .GetPointer + ld a, [hli] + cp dorestart_command + jr z, .restart + cp endanim_command + jr z, .repeat_last + + push af + ld a, [hl] + push hl + and $3f + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], a + pop hl +.okay + ld a, [hl] + and $c0 + srl a + ld [wBattleAnimTempAddSubFlags], a + pop af + ret + +.repeat_last + xor a + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + dec [hl] + dec [hl] + jr .loop + +.restart + xor a + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], a + dec a + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], a + jr .loop + +; ce823 + +.GetPointer: ; ce823 + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, BattleAnimFrameData + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld l, [hl] + ld h, $0 + add hl, hl + add hl, de + ret + +; ce83c + +GetBattleAnimOAMPointer: ; ce83c + ld l, a + ld h, 0 + ld de, BattleAnimOAMData + add hl, hl + add hl, hl + add hl, de + ret + +; ce846 + +LoadBattleAnimObj: ; ce846 (33:6846) + push hl + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, AnimObjGFX + add hl, de + ld c, [hl] + inc hl + ld b, [hl] + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + pop de + push bc + call DecompressRequest2bpp + pop bc + ret + +; ce85e (33:685e) diff --git a/engine/color.asm b/engine/color.asm index 23f953ebe..3eafbad70 100644 --- a/engine/color.asm +++ b/engine/color.asm @@ -1008,8 +1008,8 @@ PushSGBBorder: ret SGB_ClearVRAM: - ld hl, VTiles0 - ld bc, VRAM_End - VTiles0 + ld hl, VRAM_Begin + ld bc, VRAM_End - VRAM_Begin xor a call ByteFill ret @@ -1218,8 +1218,9 @@ INCLUDE "data/palettes/hp_bar.pal" ExpBarPalette: INCLUDE "data/palettes/exp_bar.pal" -INCLUDE "gfx/pics/palette_pointers.asm" -INCLUDE "gfx/trainer_palettes.asm" +INCLUDE "data/pokemon/palettes.asm" + +INCLUDE "data/trainers/palettes.asm" LoadMapPals: farcall LoadSpecialMapPalette diff --git a/engine/credits.asm b/engine/credits.asm index 70729ed3b..12199f904 100644 --- a/engine/credits.asm +++ b/engine/credits.asm @@ -612,6 +612,13 @@ Credits_TheEnd: ; 109c11 (42:5c11) ; 109c24 (42:5c24) -INCLUDE "gfx/credits.asm" +CreditsBorderGFX: INCBIN "gfx/credits/border.2bpp" + +CreditsMonsGFX: +CreditsPichuGFX: INCBIN "gfx/credits/pichu.2bpp" +CreditsSmoochumGFX: INCBIN "gfx/credits/smoochum.2bpp" +CreditsDittoGFX: INCBIN "gfx/credits/ditto.2bpp" +CreditsIgglybuffGFX: INCBIN "gfx/credits/igglybuff.2bpp" + INCLUDE "data/credits_script.asm" INCLUDE "data/credits_strings.asm" diff --git a/engine/decorations.asm b/engine/decorations.asm index 1e9effe97..c1b703fb6 100755 --- a/engine/decorations.asm +++ b/engine/decorations.asm @@ -541,36 +541,9 @@ GetDecorationSprite: ; 26a44 ret ; 26a4f -INCLUDE "data/decoration_attributes.asm" +INCLUDE "data/decorations/attributes.asm" -DecorationNames: ; 26b8d - db "CANCEL@" - db "PUT IT AWAY@" - db "MAGNAPLANT@" - db "TROPICPLANT@" - db "JUMBOPLANT@" - db "TOWN MAP@" - db "NES@" - db "SUPER NES@" - db "NINTENDO 64@" - db "VIRTUAL BOY@" - db "GOLD TROPHY@" - db "SILVER TROPHY@" - db "SURF PIKACHU DOLL@" - db " BED@" - db " CARPET@" - db " POSTER@" - db " DOLL@" - db "BIG @" - db "FEATHERY@" - db "PIKACHU@" - db "PINK@" - db "POLKADOT@" - db "RED@" - db "BLUE@" - db "YELLOW@" - db "GREEN@" -; 26c72 +INCLUDE "data/decorations/names.asm" GetDecoName: ; 26c72 ld a, [hli] @@ -1084,60 +1057,7 @@ SetAllDecorationFlags: ; 26f19 ret ; 26f2b -DecorationIDs: ; 26f2b - db DECO_FEATHERY_BED ; 2 - db DECO_PINK_BED ; 3 - db DECO_POLKADOT_BED ; 4 - db DECO_PIKACHU_BED ; 5 - - db DECO_RED_CARPET ; 7 - db DECO_BLUE_CARPET ; 8 - db DECO_YELLOW_CARPET ; 9 - db DECO_GREEN_CARPET ; a - - db DECO_MAGNAPLANT ; c - db DECO_TROPICPLANT ; d - db DECO_JUMBOPLANT ; e - - db DECO_TOWN_MAP ; 10 - db DECO_PIKACHU_POSTER ; 11 - db DECO_CLEFAIRY_POSTER ; 12 - db DECO_JIGGLYPUFF_POSTER ; 13 - - db DECO_FAMICOM ; 15 - db DECO_SNES ; 16 - db DECO_N64 ; 17 - db DECO_VIRTUAL_BOY ; 18 - - db DECO_PIKACHU_DOLL ; 1e - db DECO_SURF_PIKACHU_DOLL ; 1f - db DECO_CLEFAIRY_DOLL ; 20 - db DECO_JIGGLYPUFF_DOLL ; 21 - db DECO_BULBASAUR_DOLL ; 22 - db DECO_CHARMANDER_DOLL ; 23 - db DECO_SQUIRTLE_DOLL ; 24 - db DECO_POLIWAG_DOLL ; 25 - db DECO_DIGLETT_DOLL ; 26 - db DECO_STARMIE_DOLL ; 27 - db DECO_MAGIKARP_DOLL ; 28 - db DECO_ODDISH_DOLL ; 29 - db DECO_GENGAR_DOLL ; 2a - db DECO_SHELLDER_DOLL ; 2b - db DECO_GRIMER_DOLL ; 2c - db DECO_VOLTORB_DOLL ; 2d - db DECO_WEEDLE_DOLL ; 2e - db DECO_UNOWN_DOLL ; 2f - db DECO_GEODUDE_DOLL ; 30 - db DECO_MACHOP_DOLL ; 31 - db DECO_TENTACOOL_DOLL ; 32 - db DECO_BIG_SNORLAX_DOLL ; 1a - db DECO_BIG_ONIX_DOLL ; 1b - db DECO_BIG_LAPRAS_DOLL ; 1c -Trophys: - db DECO_GOLD_TROPHY_DOLL ; 33 - db DECO_SILVER_TROPHY_DOLL ; 34 - db -1 -; 26f59 +INCLUDE "data/decorations/decorations.asm" DescribeDecoration:: ; 26f59 ld a, b diff --git a/engine/events/basement_key.asm b/engine/events/basement_key.asm new file mode 100755 index 000000000..b15288d09 --- /dev/null +++ b/engine/events/basement_key.asm @@ -0,0 +1,34 @@ +_BasementKey: ; 507b4 +; Are we even in the right map to use this? + ld a, [MapGroup] + cp GROUP_GOLDENROD_UNDERGROUND + jr nz, .nope + + ld a, [MapNumber] + cp MAP_GOLDENROD_UNDERGROUND + jr nz, .nope +; Are we on the tile in front of the door? + call GetFacingTileCoord + ld a, d + cp 22 + jr nz, .nope + ld a, e + cp 10 + jr nz, .nope +; Let's use the Basement Key + ld hl, .BasementKeyScript + call QueueScript + ld a, TRUE + ld [wItemEffectSucceeded], a + ret + +.nope + ld a, FALSE + ld [wItemEffectSucceeded], a + ret +; 507e1 + +.BasementKeyScript: ; 0x507e1 + closetext + farjump BasementDoorScript +; 0x507e6 diff --git a/engine/battle_tower.asm b/engine/events/battle_tower.asm index b880a099b..b880a099b 100644 --- a/engine/battle_tower.asm +++ b/engine/events/battle_tower.asm diff --git a/engine/events/battle_tower_rules.asm b/engine/events/battle_tower_rules.asm new file mode 100644 index 000000000..de6022145 --- /dev/null +++ b/engine/events/battle_tower_rules.asm @@ -0,0 +1,342 @@ +CheckForMobileBattleRules: ; 8b1e1 + ld de, .PointerTables + call BattleTower_ExecuteJumptable + ret z + call BattleTower_PleaseReturnWhenReady + scf + ret +; 8b1ed + +.PointerTables: ; 8b1ed + db 2 + dw .Functions + dw .TextPointers + +.Functions: ; 8b1f2 + dw BattleTower_CheckPartyLengthIs3 + dw BattleTower_CheckPartyHasThreeMonsThatAreNotEggs +; 8b1f6 + +.TextPointers: ; 8b1f6 + dw .ExcuseMeText + dw JumpText_NeedAtLeastThreeMon + dw JumpText_EggDoesNotQualify +; 8b1fc + +.ExcuseMeText: ; 0x8b1fc + ; Excuse me! + text_jump UnknownText_0x1c5937 + db "@" +; 0x8b201 + +CheckForBattleTowerRules: ; 8b201 + ld hl, StringBuffer2 + ld [hl], "3" + inc hl + ld [hl], "@" + ld de, .PointerTables + call BattleTower_ExecuteJumptable + ret z + call BattleTower_PleaseReturnWhenReady + scf + ret +; 8b215 + +.PointerTables: ; 8b215 + db 4 + dw .Functions + dw .TextPointers + +.Functions: ; 8b21a + dw Function_PartyCountEq3 + dw Function_PartySpeciesAreUnique + dw Function_PartyItemsAreUnique + dw Function_HasPartyAnEgg +; 8b222 + +.TextPointers: ; 8b222 + dw JumpText_ExcuseMeYoureNotReady + dw JumpText_OnlyThreePkmnMayBeEntered + dw JumpText_ThePkmnMustAllBeDifferentKinds + dw JumpText_ThePkmnMustNotHoldTheSameItems + dw JumpText_YouCantTakeAnEgg +; 8b22c + +JumpText_ExcuseMeYoureNotReady: ; 0x8b22c + ; Excuse me. You're not ready. + text_jump Text_ExcuseMeYoureNotReady + db "@" +; 0x8b231 + +BattleTower_PleaseReturnWhenReady: ; 8b231 + ld hl, .PleaseReturnWhenReady + call PrintText + ret +; 8b238 + +.PleaseReturnWhenReady: ; 0x8b238 + ; Please return when you're ready. + text_jump UnknownText_0x1c5962 + db "@" +; 0x8b23d + +JumpText_NeedAtLeastThreeMon: ; 0x8b23d + ; You need at least three #MON. + text_jump UnknownText_0x1c5983 + db "@" +; 0x8b242 + +JumpText_EggDoesNotQualify: ; 0x8b242 + ; Sorry, an EGG doesn't qualify. + text_jump UnknownText_0x1c59a3 + db "@" +; 0x8b247 + +JumpText_OnlyThreePkmnMayBeEntered: ; 0x8b247 + ; Only three #MON may be entered. + text_jump Text_OnlyThreePkmnMayBeEntered + db "@" +; 0x8b24c + +JumpText_ThePkmnMustAllBeDifferentKinds: ; 0x8b24c + ; The @ #MON must all be different kinds. + text_jump Text_ThePkmnMustAllBeDifferentKinds + db "@" +; 0x8b251 + +JumpText_ThePkmnMustNotHoldTheSameItems: ; 0x8b251 + ; The @ #MON must not hold the same items. + text_jump Text_ThePkmnMustNotHoldTheSameItems + db "@" +; 0x8b256 + +JumpText_YouCantTakeAnEgg: ; 0x8b256 + ; You can't take an EGG! + text_jump Text_YouCantTakeAnEgg + db "@" +; 0x8b25b + +BattleTower_ExecuteJumptable: ; 8b25b + ld bc, 0 +.loop + call .DoJumptableFunction + call c, .PrintFailureText + call .Next_CheckReachedEnd + jr nz, .loop + ld a, b + and a + ret +; 8b26c + +.DoJumptableFunction: ; 8b26c + push de + push bc + call .GetFunctionPointer + ld a, c + rst JumpTable + pop bc + pop de + ret +; 8b276 + +.Next_CheckReachedEnd: ; 8b276 + inc c + ld a, [de] + cp c + ret +; 8b27a + +.GetFunctionPointer: ; 8b27a + inc de + ld a, [de] + ld l, a + inc de + ld a, [de] + ld h, a + ret +; 8b281 + +.GetTextPointers: ; 8b281 + inc de + inc de + inc de + ld a, [de] + ld l, a + inc de + ld a, [de] + ld h, a + ret +; 8b28a + +.LoadTextPointer: ; 8b28a + ld a, [hli] + ld h, [hl] + ld l, a + ret +; 8b28e + +.PrintFailureText: ; 8b28e + push de + push bc + ld a, b + and a + call z, .PrintFirstText + pop bc + call .PrintNthText + ld b, $1 + pop de + ret +; 8b29d + +.PrintFirstText: ; 8b29d + push de + call .GetTextPointers + call .LoadTextPointer + call PrintText + pop de + ret +; 8b2a9 + +.PrintNthText: ; 8b2a9 + push bc + call .GetTextPointers + inc hl + inc hl + ld b, $0 + add hl, bc + add hl, bc + call .LoadTextPointer + call PrintText + pop bc + ret +; 8b2bb + +BattleTower_CheckPartyLengthIs3: ; 8b2bb + ld a, [PartyCount] + cp 3 + ret +; 8b2c1 + +BattleTower_CheckPartyHasThreeMonsThatAreNotEggs: ; 8b2c1 + ld hl, PartyCount + ld a, [hli] + ld b, $0 + ld c, a +.loop + ld a, [hli] + cp EGG + jr z, .egg + inc b + +.egg + dec c + jr nz, .loop + ld a, [PartyCount] + cp b + ret z + ld a, b + cp 3 + ret +; 8b2da + +Function_PartyCountEq3: ; 8b2da + ld a, [PartyCount] + cp 3 + ret z + scf + ret +; 8b2e2 + +Function_PartySpeciesAreUnique: ; 8b2e2 + ld hl, PartyMon1Species + call VerifyUniqueness + ret +; 8b2e9 + +VerifyUniqueness: ; 8b2e9 + ld de, PartyCount + ld a, [de] + inc de + dec a + jr z, .done + ld b, a +.loop + push hl + push de + ld c, b + call .isegg + jr z, .next + ld a, [hl] + and a + jr z, .next +.loop2 + call .nextmon + call .isegg + jr z, .next2 + cp [hl] + jr z, .gotcha + +.next2 + dec c + jr nz, .loop2 + +.next + pop de + pop hl + call .nextmon + dec b + jr nz, .loop + +.done + and a + ret + +.gotcha + pop de + pop hl + scf + ret +; 8b31a + +.nextmon ; 8b31a + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + inc de + pop bc + ret +; 8b322 + +.isegg ; 8b322 + push bc + ld b, a + ld a, [de] + cp EGG + ld a, b + pop bc + ret +; 8b32a + +Function_PartyItemsAreUnique: ; 8b32a + ld hl, PartyMon1Item + call VerifyUniqueness + ret +; 8b331 + +Function_HasPartyAnEgg: ; 8b331 + ld hl, PartyCount + ld a, [hli] + ld c, a +.loop + ld a, [hli] + cp EGG + jr z, .found + dec c + jr nz, .loop + and a + ret + +.found + scf + ret +; 8b342 diff --git a/engine/events/buena.asm b/engine/events/buena.asm new file mode 100644 index 000000000..1227593eb --- /dev/null +++ b/engine/events/buena.asm @@ -0,0 +1,336 @@ +SpecialBuenasPassword: ; 8af6b + xor a + ld [wWhichIndexSet], a + ld hl, .MenuDataHeader + call CopyMenuDataHeader + ld a, [wBuenasPassword] + ld c, a + farcall GetBuenasPassword + ld a, [wMenuBorderLeftCoord] + add c + add $2 + ld [wMenuBorderRightCoord], a + call PushWindow + call DoNthMenu ; menu + farcall Buena_ExitMenu + ld b, $0 + ld a, [MenuSelection] + ld c, a + ld a, [wBuenasPassword] + and $3 + cp c + jr nz, .wrong + ld b, $1 + +.wrong + ld a, b + ld [ScriptVar], a + ret +; 8afa9 + +.MenuDataHeader: ; 0x8afa9 + db $40 ; flags + db 00, 00 ; start coords + db 07, 10 ; end coords + dw .MenuData2 + db 1 ; default option +; 0x8afb1 + + db 0 + +.MenuData2: ; 0x8afb2 + db $81 ; flags + db 0 ; items + dw .PasswordIndices + dw .PlacePasswordChoices +; 0x8afb4 + +.PasswordIndices: ; 8afb8 + db 3 + db 0, 1, 2 + db -1 + +.PlacePasswordChoices: ; 8afbd + push de + ld a, [wBuenasPassword] + and $f0 + ld c, a + ld a, [MenuSelection] + add c + ld c, a + farcall GetBuenasPassword + pop hl + call PlaceString + ret +; 8afd4 + +SpecialBuenaPrize: ; 8afd4 + xor a + ld [wMenuScrollPosition], a + ld a, $1 + ld [MenuSelection], a + call Buena_PlacePrizeMenuBox + call Buena_DisplayBlueCardBalance + ld hl, .Text_AskWhichPrize + call PrintText + jr .okay + +.loop + ld hl, .Text_AskWhichPrize + call BuenaPrintText + +.okay + call DelayFrame + call UpdateSprites + call PrintBlueCardBalance + call Buena_PrizeMenu + jr z, .done + ld [MenuSelectionQuantity], a + call Buena_getprize + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, .Text_IsThatRight + call BuenaPrintText + call YesNoBox + jr c, .loop + + ld a, [MenuSelectionQuantity] + call Buena_getprize + inc hl + ld a, [hld] + ld c, a + ld a, [wBlueCardBalance] + cp c + jr c, .InsufficientBalance + + ld a, [hli] + push hl + ld [CurItem], a + ld a, $1 + ld [wItemQuantityChangeBuffer], a + ld hl, NumItems + call ReceiveItem + pop hl + jr nc, .BagFull + ld a, [hl] + ld c, a + ld a, [wBlueCardBalance] + sub c + ld [wBlueCardBalance], a + call PrintBlueCardBalance + jr .Purchase + +.InsufficientBalance: + ld hl, .Text_NotEnoughPoints + jr .print + +.BagFull: + ld hl, .Text_NoRoom + jr .print + +.Purchase: + ld de, SFX_TRANSACTION + call PlaySFX + ld hl, .Text_HereYouGo + +.print + call BuenaPrintText + jr .loop + +.done + call CloseWindow + call CloseWindow + ld hl, .Text_PleaseComeBackAgain + call PrintText + call JoyWaitAorB + call PlayClickSFX + ret +; 8b072 + +.Text_AskWhichPrize: ; 0x8b072 + ; Which prize would you like? + text_jump UnknownText_0x1c589f + db "@" +; 0x8b077 + +.Text_IsThatRight: ; 0x8b077 + ; ? Is that right? + text_jump UnknownText_0x1c58bc + db "@" +; 0x8b07c + +.Text_HereYouGo: ; Here you go! + text_jump UnknownText_0x1c58d1 + db "@" +; 0x8b081 + +.Text_NotEnoughPoints: ; 0x8b081 + ; You don't have enough points. + text_jump UnknownText_0x1c58e0 + db "@" +; 0x8b086 + +.Text_NoRoom: ; 0x8b086 + ; You have no room for it. + text_jump UnknownText_0x1c58ff + db "@" +; 0x8b08b + +.Text_PleaseComeBackAgain: ; 0x8b08b + ; Oh. Please come back again! + text_jump UnknownText_0x1c591a + db "@" +; 0x8b090 + +Buena_DisplayBlueCardBalance: ; 8b090 + ld hl, BlueCardBalanceMenuDataHeader + call LoadMenuDataHeader + ret +; 8b097 + +PrintBlueCardBalance: ; 8b097 + ld de, wBlueCardBalance + call .DrawBox + ret +; 8b09e + +.DrawBox: ; 8b09e + push de + xor a + ld [hBGMapMode], a + ld hl, BlueCardBalanceMenuDataHeader + call CopyMenuDataHeader + call MenuBox + call UpdateSprites + call MenuBoxCoord2Tile + ld bc, SCREEN_WIDTH + 1 + add hl, bc + ld de, .Points_string + call PlaceString + ld h, b + ld l, c + inc hl + ld a, " " + ld [hli], a + ld [hld], a + pop de + lb bc, 1, 2 + call PrintNum + ret +; 8b0ca + +.Points_string: + db "Points@" +; 8b0d1 + +BlueCardBalanceMenuDataHeader: ; 0x8b0d1 + db $40 ; flags + db 11, 00 ; start coords + db 13, 11 ; end coords +; 8b0d6 + +Buena_PlacePrizeMenuBox: ; 8b0d6 + ld hl, .menudataheader + call LoadMenuDataHeader + ret +; 8b0dd + +.menudataheader ; 0x8b0dd + db $40 ; flags + db 00, 00 ; start coords + db 11, 17 ; end coords +; 8b0e2 + +Buena_PrizeMenu: ; 8b0e2 + ld hl, .MenuDataHeader + call CopyMenuDataHeader + ld a, [MenuSelection] + ld [wMenuCursorBuffer], a + xor a + ld [wWhichIndexSet], a + ld [hBGMapMode], a + call InitScrollingMenu + call UpdateSprites + call ScrollingMenu + ld a, [MenuSelection] + ld c, a + ld a, [wMenuCursorY] + ld [MenuSelection], a + ld a, [wMenuJoypad] + cp $2 + jr z, .cancel + ld a, c + and a + ret nz + +.cancel + xor a + ret +; 8b113 + +.MenuDataHeader: ; 0x8b113 + db $40 ; flags + db 01, 01 ; start coords + db 09, 16 ; end coords + dw .MenuData2 + db 1 ; default option +; 0x8b11b + + db 0 + +.MenuData2: ; 0x8b11c + db $10 ; flags + db 4, 13 ; rows, columns + db 1 ; spacing + dba .indices + dba .prizeitem + dba .prizepoints +; 8b129 + +NUM_BUENA_PRIZES EQU 9 ; ((BuenaPrizeItemsEnd - BuenaPrizeItems) / 2) + +.indices ; 8b129 + db NUM_BUENA_PRIZES +x = 1 +rept NUM_BUENA_PRIZES + db x +x = x + 1 +endr + db -1 +; 8b134 + +.prizeitem ; 8b134 + ld a, [MenuSelection] + call Buena_getprize + ld a, [hl] + push de + ld [wNamedObjectIndexBuffer], a + call GetItemName + pop hl + call PlaceString + ret +; 8b147 + +.prizepoints ; 8b147 + ld a, [MenuSelection] + call Buena_getprize + inc hl + ld a, [hl] + ld c, "0" + add c + ld [de], a + ret +; 8b154 + +Buena_getprize: ; 8b154 + dec a + ld hl, BuenaPrizeItems + ld b, 0 + ld c, a + add hl, bc + add hl, bc + ret +; 8b15e + +INCLUDE "data/items/buena_prizes.asm" diff --git a/engine/events/buena_menu.asm b/engine/events/buena_menu.asm new file mode 100644 index 000000000..b453da783 --- /dev/null +++ b/engine/events/buena_menu.asm @@ -0,0 +1,58 @@ +AskRememberPassword: ; 4ae12 + call .DoMenu + ld a, $0 + jr c, .okay + ld a, $1 + +.okay + ld [ScriptVar], a + ret + +.DoMenu: ; 4ae1f + lb bc, 14, 7 + push bc + ld hl, YesNoMenuDataHeader + call CopyMenuDataHeader + pop bc + ld a, b + ld [wMenuBorderLeftCoord], a + add $5 + ld [wMenuBorderRightCoord], a + ld a, c + ld [wMenuBorderTopCoord], a + add $4 + ld [wMenuBorderBottomCoord], a + call PushWindow + call VerticalMenu + push af + ld c, 15 + call DelayFrames + call Buena_ExitMenu + pop af + jr c, .refused + ld a, [wMenuCursorY] + cp $2 + jr z, .refused + and a + ret + +.refused + ld a, $2 + ld [wMenuCursorY], a + scf + ret + +Buena_ExitMenu: ; 4ae5e + ld a, [hOAMUpdate] + push af + call ExitMenu + call UpdateSprites + xor a + ld [hOAMUpdate], a + call DelayFrame + ld a, $1 + ld [hOAMUpdate], a + call ApplyTilemap + pop af + ld [hOAMUpdate], a + ret diff --git a/engine/events/bug_contest/caught_mon.asm b/engine/events/bug_contest/caught_mon.asm new file mode 100644 index 000000000..5d423f466 --- /dev/null +++ b/engine/events/bug_contest/caught_mon.asm @@ -0,0 +1,38 @@ +BugContest_SetCaughtContestMon: ; e6ce + ld a, [wContestMon] + and a + jr z, .firstcatch + ld [wd265], a + farcall DisplayAlreadyCaughtText + farcall DisplayCaughtContestMonStats + lb bc, 14, 7 + call PlaceYesNoBox + ret c + +.firstcatch + call .generatestats + ld a, [TempEnemyMonSpecies] + ld [wd265], a + call GetPokemonName + ld hl, .caughttext + call PrintText + ret + +.generatestats ; e6fd + ld a, [TempEnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + xor a + ld bc, PARTYMON_STRUCT_LENGTH + ld hl, wContestMon + call ByteFill + xor a + ld [MonType], a + ld hl, wContestMon + jp GeneratePartyMonStats + +.caughttext ; 0xe71d + ; Caught @ ! + text_jump UnknownText_0x1c10c0 + db "@" diff --git a/engine/events/bug_contest/contest.asm b/engine/events/bug_contest/contest.asm new file mode 100644 index 000000000..ba561abf2 --- /dev/null +++ b/engine/events/bug_contest/contest.asm @@ -0,0 +1,43 @@ +Special_GiveParkBalls: ; 135db + xor a + ld [wContestMon], a + ld a, 20 + ld [wParkBallsRemaining], a + farcall StartBugContestTimer + ret + +BugCatchingContestBattleScript:: ; 0x135eb + writecode VAR_BATTLETYPE, BATTLETYPE_CONTEST + randomwildmon + startbattle + reloadmapafterbattle + copybytetovar wParkBallsRemaining + iffalse BugCatchingContestOutOfBallsScript + end + +BugCatchingContestOverScript:: ; 0x135f8 + playsound SFX_ELEVATOR_END + opentext + writetext BugCatchingContestText_BeeepTimesUp + waitbutton + jump BugCatchingContestReturnToGateScript + +BugCatchingContestOutOfBallsScript: ; 0x13603 + playsound SFX_ELEVATOR_END + opentext + writetext BugCatchingContestText_ContestIsOver + waitbutton + +BugCatchingContestReturnToGateScript: ; 0x1360b + closetext + jumpstd bugcontestresultswarp + +BugCatchingContestText_BeeepTimesUp: ; 0x1360f + ; ANNOUNCER: BEEEP! Time's up! + text_jump UnknownText_0x1bd2ca + db "@" + +BugCatchingContestText_ContestIsOver: ; 0x13614 + ; ANNOUNCER: The Contest is over! + text_jump UnknownText_0x1bd2e7 + db "@" diff --git a/engine/events/bug_contest/contest_2.asm b/engine/events/bug_contest/contest_2.asm new file mode 100755 index 000000000..493c69d0c --- /dev/null +++ b/engine/events/bug_contest/contest_2.asm @@ -0,0 +1,133 @@ +Special_SelectRandomBugContestContestants: ; 139a8 +; Select five random people to participate in the current contest. + +; First we have to make sure that any old data is cleared away. + ld c, 10 ; Number of people to choose from. + ld hl, BugCatchingContestantEventFlagTable +.loop1 + push bc + push hl + ld e, [hl] + inc hl + ld d, [hl] + ld b, RESET_FLAG + call EventFlagAction + pop hl + inc hl + inc hl + pop bc + dec c + jr nz, .loop1 + +; Now that that's out of the way, we can get on to the good stuff. + ld c, 5 +.loop2 + push bc +.next +; Choose a flag at uniform random to be set. + call Random + cp 250 + jr nc, .next + ld c, 25 + call SimpleDivide + ld e, b + ld d, 0 + ld hl, BugCatchingContestantEventFlagTable + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + push de +; If we've already set it, it doesn't count. + ld b, CHECK_FLAG + call EventFlagAction + pop de + ld a, c + and a + jr nz, .next +; Set the flag. This will cause that sprite to not be visible in the contest. + ld b, SET_FLAG + call EventFlagAction + pop bc +; Check if we're done. If so, return. Otherwise, choose the next victim. + dec c + jr nz, .loop2 + ret +; 139ed + +Special_CheckBugContestContestantFlag: ; 139ed +; Checks the flag of the Bug Catching Contestant whose index is loaded in a. + +; Bug: If a >= 10 when this is called, it will read beyond the table. + + ld hl, BugCatchingContestantEventFlagTable + ld e, a + ld d, 0 + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld b, CHECK_FLAG + call EventFlagAction + ret +; 139fe + +BugCatchingContestantEventFlagTable: ; 139fe + dw EVENT_BUG_CATCHING_CONTESTANT_1A + dw EVENT_BUG_CATCHING_CONTESTANT_2A + dw EVENT_BUG_CATCHING_CONTESTANT_3A + dw EVENT_BUG_CATCHING_CONTESTANT_4A + dw EVENT_BUG_CATCHING_CONTESTANT_5A + dw EVENT_BUG_CATCHING_CONTESTANT_6A + dw EVENT_BUG_CATCHING_CONTESTANT_7A + dw EVENT_BUG_CATCHING_CONTESTANT_8A + dw EVENT_BUG_CATCHING_CONTESTANT_9A + dw EVENT_BUG_CATCHING_CONTESTANT_10A +; 13a12 + +ContestDropOffMons: ; 13a12 + ld hl, PartyMon1HP + ld a, [hli] + or [hl] + jr z, .fainted +; Mask the rest of your party by setting the count to 1... + ld hl, PartyCount + ld a, 1 + ld [hli], a + inc hl +; ... backing up the second mon index somewhere... + ld a, [hl] + ld [wBugContestSecondPartySpecies], a +; ... and replacing it with the terminator byte + ld [hl], $ff + xor a + ld [ScriptVar], a + ret + +.fainted + ld a, $1 + ld [ScriptVar], a + ret +; 13a31 + +ContestReturnMons: ; 13a31 +; Restore the species of the second mon. + ld hl, PartySpecies + 1 + ld a, [wBugContestSecondPartySpecies] + ld [hl], a +; Restore the party count, which must be recomputed. + ld b, $1 +.loop + ld a, [hli] + cp -1 + jr z, .done + inc b + jr .loop + +.done + ld a, b + ld [PartyCount], a + ret +; 13a47 diff --git a/engine/events/bug_contest/display_stats.asm b/engine/events/bug_contest/display_stats.asm new file mode 100644 index 000000000..d6ad3997e --- /dev/null +++ b/engine/events/bug_contest/display_stats.asm @@ -0,0 +1,107 @@ +DisplayCaughtContestMonStats: ; cc000 + call ClearBGPalettes + call ClearTileMap + call ClearSprites + call LoadFontsBattleExtra + + ld hl, Options + ld a, [hl] + push af + set 4, [hl] + + hlcoord 0, 0 + ld b, 4 + ld c, 13 + call TextBox + + hlcoord 0, 6 + ld b, 4 + ld c, 13 + call TextBox + + hlcoord 2, 0 + ld de, .Stock + call PlaceString + + hlcoord 2, 6 + ld de, .This + call PlaceString + + hlcoord 5, 4 + ld de, .Health + call PlaceString + + hlcoord 5, 10 + ld de, .Health + call PlaceString + + ld a, [wContestMon] + ld [wd265], a + call GetPokemonName + ld de, StringBuffer1 + hlcoord 1, 2 + call PlaceString + + ld h, b + ld l, c + ld a, [wContestMonLevel] + ld [TempMonLevel], a + call PrintLevel + + ld de, EnemyMonNick + hlcoord 1, 8 + call PlaceString + + ld h, b + ld l, c + ld a, [EnemyMonLevel] + ld [TempMonLevel], a + call PrintLevel + + hlcoord 11, 4 + ld de, wContestMonMaxHP + lb bc, 2, 3 + call PrintNum + + hlcoord 11, 10 + ld de, EnemyMonMaxHP + call PrintNum + + ld hl, SwitchMonText + call PrintText + + pop af + ld [Options], a + + call WaitBGMap + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + ret + +.Health: + db "HEALTH@" +.Stock: + db " STOCK ", $4a, " @" +.This: + db " THIS ", $4a, " @" + +SwitchMonText: ; cc0c2 + ; Switch #MON? + text_jump UnknownText_0x1c10cf + db "@" + +DisplayAlreadyCaughtText: ; cc0c7 + call GetPokemonName + ld hl, .AlreadyCaughtText + jp PrintText + +.AlreadyCaughtText: ; 0xcc0d0 + ; You already caught a @ . + text_jump UnknownText_0x1c10dd + db "@" + +Predef2F: +Predef38: +Predef39: ; cc0d5 + ret diff --git a/engine/events/bug_contest/judging.asm b/engine/events/bug_contest/judging.asm new file mode 100755 index 000000000..901ae88fa --- /dev/null +++ b/engine/events/bug_contest/judging.asm @@ -0,0 +1,395 @@ +_BugContestJudging: ; 1369d + call ContestScore + farcall TrainerRankings_BugContestScore + call BugContest_JudgeContestants + ld a, [wBugContestThirdPlaceWinnerID] + call LoadContestantName + ld a, [wBugContestThirdPlaceMon] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BugContest_ThirdPlaceText + call PrintText + ld a, [wBugContestSecondPlaceWinnerID] + call LoadContestantName + ld a, [wBugContestSecondPlaceMon] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BugContest_SecondPlaceText + call PrintText + ld a, [wBugContestFirstPlaceWinnerID] + call LoadContestantName + ld a, [wBugContestFirstPlaceMon] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BugContest_FirstPlaceText + call PrintText + jp BugContest_GetPlayersResult +; 136eb + +BugContest_FirstPlaceText: ; 0x136eb + text_jump ContestJudging_FirstPlaceText + start_asm + ld de, SFX_1ST_PLACE + call PlaySFX + call WaitSFX + ld hl, BugContest_FirstPlaceScoreText + ret +; 136fd + +BugContest_FirstPlaceScoreText: ; 0x136fd + ; The winning score was @ points! + text_jump ContestJudging_FirstPlaceScoreText + db "@" +; 0x13702 + +BugContest_SecondPlaceText: ; 0x13702 + ; Placing second was @ , who caught a @ !@ @ + text_jump ContestJudging_SecondPlaceText + start_asm + ld de, SFX_2ND_PLACE + call PlaySFX + call WaitSFX + ld hl, BugContest_SecondPlaceScoreText + ret +; 13714 + +BugContest_SecondPlaceScoreText: ; 0x13714 + ; The score was @ points! + text_jump ContestJudging_SecondPlaceScoreText + db "@" +; 0x13719 + +BugContest_ThirdPlaceText: ; 0x13719 + ; Placing third was @ , who caught a @ !@ @ + text_jump ContestJudging_ThirdPlaceText + start_asm + ld de, SFX_3RD_PLACE + call PlaySFX + call WaitSFX + ld hl, BugContest_ThirdPlaceScoreText + ret +; 1372b + +BugContest_ThirdPlaceScoreText: ; 0x1372b + ; The score was @ points! + text_jump ContestJudging_ThirdPlaceScoreText + db "@" +; 0x13730 + +LoadContestantName: ; 13730 + +; If a = 0, get your name. + dec a + jr z, .player +; Find the pointer for the trainer class of the Bug Catching Contestant whose ID is in a. + ld c, a + ld b, 0 + ld hl, BugContestantPointers + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a +; Copy the Trainer Class to c. + ld a, [hli] + ld c, a +; Save hl and bc for later. + push hl + push bc +; Get the Trainer Class name and copy it into wBugContestWinnerName. + callfar GetTrainerClassName + ld hl, StringBuffer1 + ld de, wBugContestWinnerName + ld bc, TRAINER_CLASS_NAME_LENGTH + call CopyBytes + ld hl, wBugContestWinnerName +; Delete the trailing terminator and replace it with a space. +.next + ld a, [hli] + cp "@" + jr nz, .next + dec hl + ld [hl], " " + inc hl + ld d, h + ld e, l +; Restore the Trainer Class ID and Trainer ID pointer. Save de for later. + pop bc + pop hl + push de +; Get the name of the trainer with class c and ID b. + ld a, [hl] + ld b, a + callfar GetTrainerName +; Append the name to wBugContestWinnerName. + ld hl, StringBuffer1 + pop de + ld bc, NAME_LENGTH - 1 + jp CopyBytes + +.player + ld hl, PlayerName + ld de, wBugContestWinnerName + ld bc, NAME_LENGTH + jp CopyBytes +; 13783 + + +INCLUDE "data/bug_contest_winners.asm" +; 13807 + + +BugContest_GetPlayersResult: ; 13807 + ld hl, wBugContestThirdPlaceWinnerID + ld de, -4 + ld b, 3 +.loop + ld a, [hl] + cp 1 ; Player + jr z, .done + add hl, de + dec b + jr nz, .loop + +.done + ret +; 13819 + +BugContest_JudgeContestants: ; 13819 + call ClearContestResults + call ComputeAIContestantScores + ld hl, wBugContestTempWinnerID + ld a, 1 ; Player + ld [hli], a + ld a, [wContestMon] + ld [hli], a + ld a, [hProduct] + ld [hli], a + ld a, [hProduct + 1] + ld [hl], a + call DetermineContestWinners + ret +; 13833 + +ClearContestResults: ; 13833 + ld hl, wBugContestResults + ld b, wBugContestWinnersEnd - wBugContestResults + xor a +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 1383e + +DetermineContestWinners: ; 1383e + ld de, wBugContestTempScore + ld hl, wBugContestFirstPlaceScore + ld c, 2 + call StringCmp + jr c, .not_first_place + ld hl, wBugContestSecondPlaceWinnerID + ld de, wBugContestThirdPlaceWinnerID + ld bc, 4 + call CopyBytes + ld hl, wBugContestFirstPlaceWinnerID + ld de, wBugContestSecondPlaceWinnerID + ld bc, 4 + call CopyBytes + ld hl, wBugContestFirstPlaceWinnerID + call CopyTempContestant + jr .done + +.not_first_place + ld de, wBugContestTempScore + ld hl, wBugContestSecondPlaceScore + ld c, 2 + call StringCmp + jr c, .not_second_place + ld hl, wBugContestSecondPlaceWinnerID + ld de, wBugContestThirdPlaceWinnerID + ld bc, 4 + call CopyBytes + ld hl, wBugContestSecondPlaceWinnerID + call CopyTempContestant + jr .done + +.not_second_place + ld de, wBugContestTempScore + ld hl, wBugContestThirdPlaceScore + ld c, 2 + call StringCmp + jr c, .done + ld hl, wBugContestThirdPlaceWinnerID + call CopyTempContestant + +.done + ret +; 138a0 + +CopyTempContestant: ; 138a0 +; Could've just called CopyBytes. + ld de, wBugContestTempWinnerID +rept 3 + ld a, [de] + inc de + ld [hli], a +endr + ld a, [de] + inc de + ld [hl], a + ret +; 138b0 + +ComputeAIContestantScores: ; 138b0 + ld e, 0 +.loop + push de + call Special_CheckBugContestContestantFlag + pop de + jr nz, .done + ld a, e + inc a + inc a + ld [wBugContestTempWinnerID], a + dec a + ld c, a + ld b, 0 + ld hl, BugContestantPointers + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + inc hl +.loop2 + call Random + and 3 + cp 3 + jr z, .loop2 + ld c, a + ld b, 0 + add hl, bc + add hl, bc + add hl, bc + ld a, [hli] + ld [wBugContestTempMon], a + ld a, [hli] + ld h, [hl] + ld l, a + call Random + and 7 + ld c, a + ld b, 0 + add hl, bc + ld a, h + ld [wBugContestTempScore], a + ld a, l + ld [wBugContestTempScore + 1], a + push de + call DetermineContestWinners + pop de + +.done + inc e + ld a, e + cp 10 + jr nz, .loop + ret +; 13900 + +ContestScore: ; 13900 +; Determine the player's score in the Bug Catching Contest. + + xor a + ld [hProduct], a + ld [hMultiplicand], a + + ld a, [wContestMonSpecies] ; Species + and a + jr z, .done + + ; Tally the following: + + ; Max HP * 4 + ld a, [wContestMonMaxHP + 1] + call .AddContestStat + ld a, [wContestMonMaxHP + 1] + call .AddContestStat + ld a, [wContestMonMaxHP + 1] + call .AddContestStat + ld a, [wContestMonMaxHP + 1] + call .AddContestStat + + ; Stats + ld a, [wContestMonAttack + 1] + call .AddContestStat + ld a, [wContestMonDefense + 1] + call .AddContestStat + ld a, [wContestMonSpeed + 1] + call .AddContestStat + ld a, [wContestMonSpclAtk + 1] + call .AddContestStat + ld a, [wContestMonSpclDef + 1] + call .AddContestStat + + ; DVs + ld a, [wContestMonDVs + 0] + ld b, a + and 2 + add a + add a + ld c, a + + swap b + ld a, b + and 2 + add a + add c + ld d, a + + ld a, [wContestMonDVs + 1] + ld b, a + and 2 + ld c, a + + swap b + ld a, b + and 2 + srl a + add c + add c + add d + add d + + call .AddContestStat + + ; Remaining HP / 8 + ld a, [wContestMonHP + 1] + srl a + srl a + srl a + call .AddContestStat + + ; Whether it's holding an item + ld a, [wContestMonItem] + and a + jr z, .done + + ld a, 1 + call .AddContestStat + +.done + ret +; 1397f + +.AddContestStat: ; 1397f + ld hl, hMultiplicand + add [hl] + ld [hl], a + ret nc + dec hl + inc [hl] + ret +; 13988 diff --git a/engine/events/card_key.asm b/engine/events/card_key.asm new file mode 100755 index 000000000..dc4c73ad2 --- /dev/null +++ b/engine/events/card_key.asm @@ -0,0 +1,39 @@ +_CardKey: ; 50779 +; Are we even in the right map to use this? + ld a, [MapGroup] + cp GROUP_RADIO_TOWER_3F + jr nz, .nope + + ld a, [MapNumber] + cp MAP_RADIO_TOWER_3F + jr nz, .nope +; Are we facing the slot? + ld a, [PlayerDirection] + and %1100 + cp OW_UP + jr nz, .nope + + call GetFacingTileCoord + ld a, d + cp 18 + jr nz, .nope + ld a, e + cp 6 + jr nz, .nope +; Let's use the Card Key. + ld hl, .CardKeyScript + call QueueScript + ld a, TRUE + ld [wItemEffectSucceeded], a + ret + +.nope + ld a, FALSE + ld [wItemEffectSucceeded], a + ret +; 507af + +.CardKeyScript: ; 0x507af + closetext + farjump MapRadioTower3FSignpost2Script +; 0x507b4 diff --git a/engine/events/catch_tutorial.asm b/engine/events/catch_tutorial.asm new file mode 100644 index 000000000..b9352ccd6 --- /dev/null +++ b/engine/events/catch_tutorial.asm @@ -0,0 +1,81 @@ +CatchTutorial:: ; 4e554 + ld a, [BattleType] + dec a + ld c, a + ld hl, .dw + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.dw ; 4e564 (13:6564) + dw .DudeTutorial + dw .DudeTutorial + dw .DudeTutorial + +.DudeTutorial: ; 4e56a (13:656a) +; Back up your name to your Mom's name. + ld hl, PlayerName + ld de, MomsName + ld bc, NAME_LENGTH + call CopyBytes +; Copy Dude's name to your name + ld hl, .Dude + ld de, PlayerName + ld bc, NAME_LENGTH + call CopyBytes + + call .LoadDudeData + + xor a + ld [hJoyDown], a + ld [hJoyPressed], a + ld a, [Options] + push af + and $f8 + add $3 + ld [Options], a + ld hl, .AutoInput + ld a, BANK(.AutoInput) + call StartAutoInput + callfar StartBattle + call StopAutoInput + pop af + + ld [Options], a + ld hl, MomsName + ld de, PlayerName + ld bc, NAME_LENGTH + call CopyBytes + ret + +.LoadDudeData: ; 4e5b7 (13:65b7) + ld hl, wDudeNumItems + ld [hl], 1 + inc hl + ld [hl], POTION + inc hl + ld [hl], 1 + inc hl + ld [hl], -1 + ld hl, wDudeNumKeyItems + ld [hl], 0 + inc hl + ld [hl], -1 + ld hl, wDudeNumBalls + ld a, 1 + ld [hli], a + ld a, POKE_BALL ; 5 + ld [hli], a + ld [hli], a + ld [hl], -1 + ret + +.Dude: ; 4e5da + db "DUDE@" + +.AutoInput: ; 4e5df + db NO_INPUT, $ff ; end diff --git a/engine/events/catch_tutorial_input.asm b/engine/events/catch_tutorial_input.asm new file mode 100644 index 000000000..9d2a03db2 --- /dev/null +++ b/engine/events/catch_tutorial_input.asm @@ -0,0 +1,43 @@ +_DudeAutoInput_A:: ; 1de28a + ld hl, DudeAutoInput_A + jr _DudeAutoInput + +_DudeAutoInput_RightA: ; 1de28f + ld hl, DudeAutoInput_RightA + jr _DudeAutoInput + +_DudeAutoInput_DownA: ; 1de294 + ld hl, DudeAutoInput_DownA + jr _DudeAutoInput + +_DudeAutoInput: ; 1de299 + ld a, BANK(DudeAutoInputs) + call StartAutoInput + ret + +DudeAutoInputs: + +DudeAutoInput_A: ; 1de29f + db NO_INPUT, $50 + db A_BUTTON, $00 + db NO_INPUT, $ff ; end + +DudeAutoInput_RightA: ; 1de2a5 + db NO_INPUT, $08 + db D_RIGHT, $00 + db NO_INPUT, $08 + db A_BUTTON, $00 + db NO_INPUT, $ff ; end + +DudeAutoInput_DownA: ; 1de2af + db NO_INPUT, $fe + db NO_INPUT, $fe + db NO_INPUT, $fe + db NO_INPUT, $fe + db D_DOWN, $00 + db NO_INPUT, $fe + db NO_INPUT, $fe + db NO_INPUT, $fe + db NO_INPUT, $fe + db A_BUTTON, $00 + db NO_INPUT, $ff ; end diff --git a/engine/events/celebi.asm b/engine/events/celebi.asm new file mode 100755 index 000000000..b7bf95145 --- /dev/null +++ b/engine/events/celebi.asm @@ -0,0 +1,380 @@ +Special_CelebiShrineEvent: ; 4989a + call DelayFrame + ld a, [VramState] + push af + xor a + ld [VramState], a + call LoadCelebiGFX + depixel 0, 10, 7, 0 + ld a, SPRITE_ANIM_INDEX_CELEBI + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $84 + ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID + add hl, bc + ld [hl], SPRITE_ANIM_SEQ_CELEBI + ld hl, SPRITEANIMSTRUCT_0F + add hl, bc + ld a, $80 + ld [hl], a + ld a, 160 ; frame count + ld [wcf64], a + ld d, $0 +.loop + ld a, [wJumptableIndex] + bit 7, a + jr nz, .done + push bc + call GetCelebiSpriteTile + inc d + push de + ld a, $90 + ld [wCurrSpriteOAMAddr], a + farcall DoNextFrameForAllSprites + call CelebiEvent_CountDown + ld c, 2 + call DelayFrames + pop de + pop bc + jr .loop + + +.done + pop af + ld [VramState], a + call .RefreshPlayerSprite_ClearAllOthers + call CelebiEvent_SetBattleType + ret + +; 498f9 + +.RefreshPlayerSprite_ClearAllOthers: ; 498f9 + ld hl, Sprites + 2 + xor a + ld c, $4 +.OAMloop: + ld [hli], a + inc hl + inc hl + inc hl + inc a + dec c + jr nz, .OAMloop + ld hl, Sprites + 4 * 4 + ld bc, 36 * 4 + xor a + call ByteFill + ret + +; 49912 + +LoadCelebiGFX: ; 49912 + farcall ClearSpriteAnims + ld de, SpecialCelebiLeafGFX + ld hl, VTiles1 + lb bc, BANK(SpecialCelebiLeafGFX), 4 + call Request2bpp + ld de, SpecialCelebiGFX + ld hl, VTiles0 tile $84 + lb bc, BANK(SpecialCelebiGFX), $10 + call Request2bpp + xor a + ld [wJumptableIndex], a + ret + +; 49935 + +CelebiEvent_CountDown: ; 49935 + ld hl, wcf64 + ld a, [hl] + and a + jr z, .done + dec [hl] + ret + + +.done + ld hl, wJumptableIndex + set 7, [hl] + ret + +; 49944 + +CelebiEvent_SpawnLeaf: ; 49944 +; unused + ld hl, wcf65 + ld a, [hl] + inc [hl] + and $7 + ret nz + ld a, [hl] + and $18 + sla a + add $40 + ld d, a + ld e, $0 + ld a, SPRITE_ANIM_INDEX_FLY_LEAF ; fly land + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $80 + ret + +; 49962 + +SpecialCelebiLeafGFX: ; 49962 +INCBIN "gfx/overworld/cut_grass.2bpp" + +SpecialCelebiGFX: ; 499a2 +INCBIN "gfx/overworld/celebi/1.2bpp" +INCBIN "gfx/overworld/celebi/2.2bpp" +INCBIN "gfx/overworld/celebi/3.2bpp" +INCBIN "gfx/overworld/celebi/4.2bpp" + + +UpdateCelebiPosition: ; 49aa2 (12:5aa2) + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + push af + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp 8 * 10 + 2 + jp nc, .FreezeCelebiPosition + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + inc [hl] + ld hl, SPRITEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, a + cp $3a + jr c, .skip + jr z, .skip + sub $3 + ld [hl], a +.skip + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + ld a, [hl] + inc [hl] + call CelebiEvent_Cosine + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld d, a + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + cp 8 * 11 + 4 + jr nc, .ShiftY + cp 8 * 8 + 4 + jr nc, .ReinitSpriteAnimFrame +.ShiftY: + pop af + push af + cp d + jr nc, .moving_left + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + cp 8 * 10 + jr c, .float_up + jr .float_down + +.moving_left + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + cp 8 * 10 + jr nc, .float_up +.float_down + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + sub $2 + ld [hl], a + jr .ReinitSpriteAnimFrame + +.float_up + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + add $1 + ld [hl], a +.ReinitSpriteAnimFrame: + pop af + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + cp 8 * 10 + jr c, .left + cp -(8 * 3 + 2) + jr nc, .left + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, SPRITE_ANIM_FRAMESET_CELEBI_RIGHT + call ReinitSpriteAnimFrame + jr .done + +.left + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, SPRITE_ANIM_FRAMESET_CELEBI_LEFT + call ReinitSpriteAnimFrame +.done + ret + + +.FreezeCelebiPosition: ; 49b30 (12:5b30) + pop af + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, SPRITE_ANIM_FRAMESET_CELEBI_LEFT + call ReinitSpriteAnimFrame + ret + + +CelebiEvent_Cosine: ; 49b3b (12:5b3b) + add $10 + and $3f + cp $20 + jr nc, .negative + call .SineFunction + ld a, h + ret + +.negative + and $1f + call .SineFunction + ld a, h + xor $ff + inc a + ret + + +.SineFunction: ; 49b52 (12:5b52) + ld e, a + ld a, d + ld d, $0 + ld hl, .sinewave + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld hl, 0 +.multiply + srl a + jr nc, .even + add hl, de +.even + sla e + rl d + and a + jr nz, .multiply + ret + +; 49b6e (12:5b6e) + +.sinewave ; 49b6e + sine_wave $100 +; 49bae + +GetCelebiSpriteTile: ; 49bae + push hl + push bc + push de + ld a, d + ld d, $3 + ld e, d + cp $0 + jr z, .Frame1 + cp d + jr z, .Frame2 + call .AddE + cp d + jr z, .Frame3 + call .AddE + cp d + jr z, .Frame4 + call .AddE + cp d + jr c, .done + jr .restart + + +.Frame1: + ld a, $84 + jr .load_tile + + +.Frame2: + ld a, $88 + jr .load_tile + + +.Frame3: + ld a, $8c + jr .load_tile + + +.Frame4: + ld a, $90 + +.load_tile + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], a + jr .done + + +.restart + pop de + ld d, $ff + push de + +.done + pop de + pop bc + pop hl + ret + +; 49bed + +.AddE: ; 49bed + push af + ld a, d + add e + ld d, a + pop af + ret + +; 49bf3 + +CelebiEvent_SetBattleType: ; 49bf3 + ld a, BATTLETYPE_CELEBI + ld [BattleType], a + ret + +; 49bf9 + +CheckCaughtCelebi: ; 49bf9 + ld a, [wBattleResult] + bit 6, a + jr z, .false + ld a, $1 + ld [ScriptVar], a + jr .done + + +.false + xor a + ld [ScriptVar], a + +.done + ret + +; 49c0c diff --git a/engine/events/crystal_unown.asm b/engine/events/crystal_unown.asm new file mode 100644 index 000000000..6c0e972f8 --- /dev/null +++ b/engine/events/crystal_unown.asm @@ -0,0 +1,327 @@ +SpecialHoOhChamber: ; 0x8addb + ld hl, PartySpecies + ld a, [hl] + cp HO_OH ; is Ho-oh the first Pokémon in the party? + jr nz, .done ; if not, we're done + call GetSecondaryMapHeaderPointer + ld de, EVENT_WALL_OPENED_IN_HO_OH_CHAMBER + ld b, SET_FLAG + call EventFlagAction +.done + ret +; 0x8adef + +SpecialOmanyteChamber: ; 8adef + call GetSecondaryMapHeaderPointer + ld de, EVENT_WALL_OPENED_IN_OMANYTE_CHAMBER + ld b, CHECK_FLAG + call EventFlagAction + ld a, c + and a + jr nz, .nope + + ld a, WATER_STONE + ld [CurItem], a + ld hl, NumItems + call CheckItem + jr c, .open + + ld a, [PartyCount] + ld b, a + inc b +.loop + dec b + jr z, .nope + ld a, b + dec a + ld [CurPartyMon], a + push bc + ld a, MON_ITEM + call GetPartyParamLocation + pop bc + ld a, [hl] + cp WATER_STONE + jr nz, .loop + +.open + call GetSecondaryMapHeaderPointer + ld de, EVENT_WALL_OPENED_IN_OMANYTE_CHAMBER + ld b, SET_FLAG + call EventFlagAction + +.nope + ret +; 8ae30 + +SpecialAerodactylChamber: ; 8ae30 + push de + push bc + + call GetSecondaryMapHeaderPointer + ld a, h + cp HIGH(RuinsOfAlphAerodactylChamber_SecondMapHeader) + jr nz, .nope + ld a, l + cp LOW(RuinsOfAlphAerodactylChamber_SecondMapHeader) + jr nz, .nope + + ld de, EVENT_WALL_OPENED_IN_AERODACTYL_CHAMBER + ld b, SET_FLAG + call EventFlagAction + + scf + jr .done + +.nope + and a + +.done + pop bc + pop de + ret +; 8ae4e + +SpecialKabutoChamber: ; 8ae4e + push hl + push de + + call GetSecondaryMapHeaderPointer + ld a, h + cp HIGH(RuinsOfAlphKabutoChamber_SecondMapHeader) + jr nz, .done + ld a, l + cp LOW(RuinsOfAlphKabutoChamber_SecondMapHeader) + jr nz, .done + + ld de, EVENT_WALL_OPENED_IN_KABUTO_CHAMBER + ld b, SET_FLAG + call EventFlagAction + +.done + pop de + pop hl + ret +; 8ae68 + +Special_DisplayUnownWords: ; 8ae68 + ld a, [ScriptVar] + ld hl, .MenuDataHeader_Escape + and a + jr z, .load + + ld d, $0 + ld e, $5 +.loop + add hl, de + dec a + jr nz, .loop + +.load + call LoadMenuDataHeader + xor a + ld [hBGMapMode], a + call MenuBox + call UpdateSprites + call ApplyTilemap + call MenuBoxCoord2Tile + inc hl + ld d, 0 + ld e, SCREEN_WIDTH + add hl, de + add hl, de + ld a, [ScriptVar] + ld c, a + ld de, .UnownText + and a + jr z, .copy +.loop2 + ld a, [de] + inc de + cp $ff + jr nz, .loop2 + dec c + jr nz, .loop2 +.copy + call .CopyWord + ld bc, AttrMap - TileMap + add hl, bc + call .FillAttr + call WaitBGMap2 + call JoyWaitAorB + call PlayClickSFX + call CloseWindow + ret +; 8aebc + +.UnownText: ; 8aebc + +unownwall: MACRO +rept _NARG +if \1 == "-" +x = $64 +else +if \1 >= "Y" +x = 2 * (\1 - "Y") + $60 +else +if \1 >= "Q" +x = 2 * (\1 - "Q") + $40 +else +if \1 >= "I" +x = 2 * (\1 - "I") + $20 +else +x = 2 * (\1 - "A") +endc +endc +endc +endc + db x +shift +endr + db $ff +endm + +.UnownText_Escape: + ; db $08, $44, $04, $00, $2e, $08, $ff + unownwall "E", "S", "C", "A", "P", "E" +.UnownText_Light: + ; db $26, $20, $0c, $0e, $46, $ff + unownwall "L", "I", "G", "H", "T" +.UnownText_Water: + ; db $4c, $00, $46, $08, $42, $ff + unownwall "W", "A", "T", "E", "R" +.UnownText_Ho_Oh: + ; db $0e, $2c, $64, $2c, $0e, $ff + unownwall "H", "O", "-", "O", "H" +; 8aed5 + +.MenuDataHeader_Escape: ; 0x8aed5 + db $40 ; flags + db 04, 03 ; start coords + db 09, 16 ; end coords + +.MenuDataHeader_Light: ; 0x8aeda + db $40 ; flags + db 04, 04 ; start coords + db 09, 15 ; end coords + +.MenuDataHeader_Water: ; 0x8aedf + db $40 ; flags + db 04, 04 ; start coords + db 09, 15 ; end coords + +.MenuDataHeader_Ho_Oh: ; 0x8aee4 + db $40 ; flags + db 04, 04 ; start coords + db 09, 15 ; end coords +; 8aee9 + +.FillAttr: ; 8aee9 + ld a, [de] + cp $ff + ret z + cp $60 + ld a, VRAM_BANK_1 | PAL_BG_BROWN + jr c, .got_pal + ld a, PAL_BG_BROWN + +.got_pal + call .PlaceSquare + inc hl + inc hl + inc de + jr .FillAttr +; 8aefd + +.PlaceSquare: ; 8aefd + push hl + ld [hli], a + ld [hld], a + ld b, 0 + ld c, SCREEN_WIDTH + add hl, bc + ld [hli], a + ld [hl], a + pop hl + ret +; 8af09 + +.CopyWord: ; 8af09 + push hl + push de +.word_loop + ld a, [de] + cp $ff + jr z, .word_done + ld c, a + call .ConvertChar + inc hl + inc hl + inc de + jr .word_loop + +.word_done + pop de + pop hl + ret +; 8af1c + +.ConvertChar: ; 8af1c + push hl + ld a, c + cp $60 + jr z, .Tile60 + cp $62 + jr z, .Tile62 + cp $64 + jr z, .Tile64 + ld [hli], a + inc a + ld [hld], a + dec a + ld b, 0 + ld c, SCREEN_WIDTH + add hl, bc + ld c, $10 + add c + ld [hli], a + inc a + ld [hl], a + pop hl + ret + +.Tile60: + ld [hl], $5b + inc hl + ld [hl], $5c + ld bc, SCREEN_WIDTH - 1 + add hl, bc + ld [hl], $4d + inc hl + ld [hl], $5d + pop hl + ret + +.Tile62: + ld [hl], $4e + inc hl + ld [hl], $4f + ld bc, SCREEN_WIDTH - 1 + add hl, bc + ld [hl], $5e + inc hl + ld [hl], $5f + pop hl + ret + +.Tile64: + ld [hl], $2 + inc hl + ld [hl], $3 + ld bc, SCREEN_WIDTH - 1 + add hl, bc + ld [hl], $3 + inc hl + ld [hl], $2 + pop hl + ret +; 8af6b diff --git a/engine/events/daycare.asm b/engine/events/daycare.asm new file mode 100755 index 000000000..6395a40fb --- /dev/null +++ b/engine/events/daycare.asm @@ -0,0 +1,792 @@ + const_def + const DAYCARETEXT_MAN_INTRO + const DAYCARETEXT_MAN_EGG + const DAYCARETEXT_LADY_INTRO + const DAYCARETEXT_LADY_EGG + const DAYCARETEXT_WHICH_ONE + const DAYCARETEXT_DEPOSIT + const DAYCARETEXT_CANT_BREED_EGG + const DAYCARETEXT_LAST_MON + const DAYCARETEXT_LAST_ALIVE_MON + const DAYCARETEXT_COME_BACK_LATER + const DAYCARETEXT_REMOVE_MAIL + const DAYCARETEXT_GENIUSES + const DAYCARETEXT_ASK_WITHDRAW + const DAYCARETEXT_WITHDRAW + const DAYCARETEXT_TOO_SOON + const DAYCARETEXT_PARTY_FULL + const DAYCARETEXT_NOT_ENOUGH_MONEY + const DAYCARETEXT_OH_FINE + const DAYCARETEXT_COME_AGAIN + const DAYCARETEXT_13 + +Special_DayCareMan: ; 166d6 + ld hl, wDayCareMan + bit 0, [hl] + jr nz, .AskWithdrawMon + ld hl, wDayCareMan + ld a, DAYCARETEXT_MAN_INTRO + call DayCareManIntroText + jr c, .cancel + call DayCareAskDepositPokemon + jr c, .print_text + farcall DepositMonWithDayCareMan + ld hl, wDayCareMan + set 0, [hl] + call DayCare_DepositPokemonText + call DayCare_InitBreeding + ret + +.AskWithdrawMon: + farcall GetBreedMon1LevelGrowth + ld hl, wBreedMon1Nick + call GetPriceToRetrieveBreedmon + call DayCare_AskWithdrawBreedMon + jr c, .print_text + farcall RetrievePokemonFromDayCareMan + call DayCare_TakeMoney_PlayCry + ld hl, wDayCareMan + res 0, [hl] + res 5, [hl] + jr .cancel + +.print_text + call PrintDayCareText + +.cancel + ld a, DAYCARETEXT_13 + call PrintDayCareText + ret +; 1672a + +Special_DayCareLady: ; 1672a + ld hl, wDayCareLady + bit 0, [hl] + jr nz, .AskWithdrawMon + ld hl, wDayCareLady + ld a, DAYCARETEXT_LADY_INTRO + call DayCareLadyIntroText + jr c, .cancel + call DayCareAskDepositPokemon + jr c, .print_text + farcall DepositMonWithDayCareLady + ld hl, wDayCareLady + set 0, [hl] + call DayCare_DepositPokemonText + call DayCare_InitBreeding + ret + +.AskWithdrawMon: + farcall GetBreedMon2LevelGrowth + ld hl, wBreedMon2Nick + call GetPriceToRetrieveBreedmon + call DayCare_AskWithdrawBreedMon + jr c, .print_text + farcall RetrievePokemonFromDayCareLady + call DayCare_TakeMoney_PlayCry + ld hl, wDayCareLady + res 0, [hl] + ld hl, wDayCareMan + res 5, [hl] + jr .cancel + +.print_text + call PrintDayCareText + +.cancel + ld a, DAYCARETEXT_13 + call PrintDayCareText + ret +; 16781 + +DayCareLadyIntroText: ; 16781 + bit 7, [hl] + jr nz, .okay + set 7, [hl] + inc a +.okay + call PrintDayCareText + call YesNoBox + ret +; 1678f + +DayCareManIntroText: ; 1678f + set 7, [hl] + call PrintDayCareText + call YesNoBox + ret +; 16798 + +DayCareAskDepositPokemon: ; 16798 + ld a, [PartyCount] + cp 2 + jr c, .OnlyOneMon + ld a, DAYCARETEXT_WHICH_ONE + call PrintDayCareText + ld b, PARTYMENUACTION_GIVE_MON + farcall SelectTradeOrDayCareMon + jr c, .Declined + ld a, [CurPartySpecies] + cp EGG + jr z, .Egg + farcall CheckCurPartyMonFainted + jr c, .OutOfUsableMons + ld hl, PartyMon1Item + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [CurPartyMon] + call AddNTimes + ld d, [hl] + farcall ItemIsMail + jr c, .HoldingMail + ld hl, PartyMonNicknames + ld a, [CurPartyMon] + call GetNick + and a + ret + +.Declined: + ld a, DAYCARETEXT_COME_AGAIN + scf + ret + +.Egg: + ld a, DAYCARETEXT_CANT_BREED_EGG + scf + ret + +.OnlyOneMon: + ld a, DAYCARETEXT_LAST_MON + scf + ret + +.OutOfUsableMons: + ld a, DAYCARETEXT_LAST_ALIVE_MON + scf + ret + +.HoldingMail: + ld a, DAYCARETEXT_REMOVE_MAIL + scf + ret +; 167f1 + +.DummyText: ; 0x167f1 + ; + text_jump UnknownText_0x1bdaa7 + db "@" +; 0x167f6 + +DayCare_DepositPokemonText: ; 167f6 + ld a, DAYCARETEXT_DEPOSIT + call PrintDayCareText + ld a, [CurPartySpecies] + call PlayCry + ld a, DAYCARETEXT_COME_BACK_LATER + call PrintDayCareText + ret +; 16807 + +DayCare_AskWithdrawBreedMon: ; 16807 + ld a, [StringBuffer2 + 1] + and a + jr nz, .grew_at_least_one_level + ld a, DAYCARETEXT_PARTY_FULL + call PrintDayCareText + call YesNoBox + jr c, .refused + jr .check_money + +.grew_at_least_one_level + ld a, DAYCARETEXT_GENIUSES + call PrintDayCareText + call YesNoBox + jr c, .refused + ld a, DAYCARETEXT_ASK_WITHDRAW + call PrintDayCareText + call YesNoBox + jr c, .refused + +.check_money + ld de, Money + ld bc, StringBuffer2 + 2 + farcall CompareMoney + jr c, .not_enough_money + ld a, [PartyCount] + cp PARTY_LENGTH + jr nc, .PartyFull + and a + ret + +.refused + ld a, DAYCARETEXT_COME_AGAIN + scf + ret + +.not_enough_money + ld a, DAYCARETEXT_OH_FINE + scf + ret + +.PartyFull: + ld a, DAYCARETEXT_NOT_ENOUGH_MONEY + scf + ret +; 16850 + +DayCare_TakeMoney_PlayCry: ; 16850 + ld bc, StringBuffer2 + 2 + ld de, Money + farcall TakeMoney + ld a, DAYCARETEXT_WITHDRAW + call PrintDayCareText + ld a, [CurPartySpecies] + call PlayCry + ld a, DAYCARETEXT_TOO_SOON + call PrintDayCareText + ret +; 1686d + +GetPriceToRetrieveBreedmon: ; 1686d + ld a, b + ld [StringBuffer2], a + ld a, d + ld [StringBuffer2 + 1], a + ld de, StringBuffer1 + ld bc, NAME_LENGTH + call CopyBytes + ld hl, 0 + ld bc, 100 + ld a, [StringBuffer2 + 1] + call AddNTimes + ld de, 100 + add hl, de + xor a + ld [StringBuffer2 + 2], a + ld a, h + ld [StringBuffer2 + 3], a + ld a, l + ld [StringBuffer2 + 4], a + ret +; 1689b + +PrintDayCareText: ; 1689b + ld e, a + ld d, 0 + ld hl, .TextTable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + ret +; 168aa + +.TextTable: ; 168aa + dw .DayCareManIntro ; 00 + dw .DayCareManOddEgg ; 01 + dw .DayCareLadyIntro ; 02 + dw .DayCareLadyOddEgg ; 03 + dw .WhichOne ; 04 + dw .OkayIllRaiseYourMon ; 05 + dw .CantAcceptEgg ; 06 + dw .JustOneMon ; 07 + dw .LastHealthyMon ; 08 + dw .ComeBackForItLater ; 09 + dw .RemoveMail ; 0a + dw .AreWeGeniusesOrWhat ; 0b + dw .AskRetrieveMon ; 0c + dw .PerfectHeresYourMon ; 0d + dw .GotBackMon ; 0e + dw .ImmediatelyWithdrawMon ; 0f + dw .PartyFull ; 10 + dw .NotEnoughMoney ; 11 + dw .OhFineThen ; 12 + dw .ComeAgain ; 13 +; 168d2 + +.DayCareManIntro: ; 0x168d2 + ; I'm the DAY-CARE MAN. Want me to raise a #MON? + text_jump UnknownText_0x1bdaa9 + db "@" +; 0x168d7 + +.DayCareManOddEgg: ; 0x168d7 + ; I'm the DAY-CARE MAN. Do you know about EGGS? I was raising #MON with my wife, you see. We were shocked to find an EGG! How incredible is that? So, want me to raise a #MON? + text_jump UnknownText_0x1bdad8 + db "@" +; 0x168dc + +.DayCareLadyIntro: ; 0x168dc + ; I'm the DAY-CARE LADY. Should I raise a #MON for you? + text_jump UnknownText_0x1bdb85 + db "@" +; 0x168e1 + +.DayCareLadyOddEgg: ; 0x168e1 + ; I'm the DAY-CARE LADY. Do you know about EGGS? My husband and I were raising some #MON, you see. We were shocked to find an EGG! How incredible could that be? Should I raise a #MON for you? + text_jump UnknownText_0x1bdbbb + db "@" +; 0x168e6 + +.WhichOne: ; 0x168e6 + ; What should I raise for you? + text_jump UnknownText_0x1bdc79 + db "@" +; 0x168eb + +.JustOneMon: ; 0x168eb + ; Oh? But you have just one #MON. + text_jump UnknownText_0x1bdc97 + db "@" +; 0x168f0 + +.CantAcceptEgg: ; 0x168f0 + ; Sorry, but I can't accept an EGG. + text_jump UnknownText_0x1bdcb8 + db "@" +; 0x168f5 + +.RemoveMail: ; 0x168f5 + ; Remove MAIL before you come see me. + text_jump UnknownText_0x1bdcda + db "@" +; 0x168fa + +.LastHealthyMon: ; 0x168fa + ; If you give me that, what will you battle with? + text_jump UnknownText_0x1bdcff + db "@" +; 0x168ff + +.OkayIllRaiseYourMon: ; 0x168ff + ; OK. I'll raise your @ . + text_jump UnknownText_0x1bdd30 + db "@" +; 0x16904 + +.ComeBackForItLater: ; 0x16904 + ; Come back for it later. + text_jump UnknownText_0x1bdd4b + db "@" +; 0x16909 + +.AreWeGeniusesOrWhat: ; 0x16909 + ; Are we geniuses or what? Want to see your @ ? + text_jump UnknownText_0x1bdd64 + db "@" +; 0x1690e + +.AskRetrieveMon: ; 0x1690e + ; Your @ has grown a lot. By level, it's grown by @ . If you want your #MON back, it will cost ¥@ . + text_jump UnknownText_0x1bdd96 + db "@" +; 0x16913 + +.PerfectHeresYourMon: ; 0x16913 + ; Perfect! Here's your #MON. + text_jump UnknownText_0x1bde04 + db "@" +; 0x16918 + +.GotBackMon: ; 0x16918 + ; got back @ . + text_jump UnknownText_0x1bde1f + db "@" +; 0x1691d + +.ImmediatelyWithdrawMon: ; 0x1691d + ; Huh? Back already? Your @ needs a little more time with us. If you want your #MON back, it will cost ¥100. + text_jump UnknownText_0x1bde32 + db "@" +; 0x16922 + +.PartyFull: ; 0x16922 + ; You have no room for it. + text_jump UnknownText_0x1bdea2 + db "@" +; 0x16927 + +.NotEnoughMoney: ; 0x16927 + ; You don't have enough money. + text_jump UnknownText_0x1bdebc + db "@" +; 0x1692c + +.OhFineThen: ; 0x1692c + ; Oh, fine then. + text_jump UnknownText_0x1bded9 + db "@" +; 0x16931 + +.ComeAgain: ; 0x16931 + ; Come again. + text_jump UnknownText_0x1bdee9 + db "@" +; 0x16936 + +Special_DayCareManOutside: ; 16936 + ld hl, wDayCareMan + bit 6, [hl] + jr nz, .AskGiveEgg + ld hl, .NotYet + call PrintText + ret + +.NotYet: ; 0x16944 + ; Not yet… + text_jump UnknownText_0x1bdef6 + db "@" +; 0x16949 + +.AskGiveEgg: ; 16949 + ld hl, .IntroText + call PrintText + call YesNoBox + jr c, .Declined + ld a, [PartyCount] + cp PARTY_LENGTH + jr nc, .PartyFull + call DayCare_GiveEgg + ld hl, wDayCareMan + res 6, [hl] + call DayCare_InitBreeding + ld hl, .GotEggText + call PrintText + ld de, SFX_GET_EGG_FROM_DAY_CARE_LADY + call PlaySFX + ld c, 120 + call DelayFrames + ld hl, .TakeGoodCareOfItText + jr .Load0 + +.Declined: + ld hl, .IllKeepItThanksText + +.Load0: + call PrintText + xor a + ld [ScriptVar], a + ret + +.PartyFull: + ld hl, .PartyFullText + call PrintText + ld a, $1 + ld [ScriptVar], a + ret +; 16993 + +.IntroText: ; 0x16993 + ; Ah, it's you! We were raising your #MON, and my goodness, were we surprised! Your #MON had an EGG! We don't know how it got there, but your #MON had it. You want it? + text_jump UnknownText_0x1bdf00 + db "@" +; 0x16998 + +.GotEggText: ; 0x16998 + ; received the EGG! + text_jump UnknownText_0x1bdfa5 + db "@" +; 0x1699d + +.TakeGoodCareOfItText: ; 0x1699d + ; Take good care of it. + text_jump UnknownText_0x1bdfba + db "@" +; 0x169a2 + +.IllKeepItThanksText: ; 0x169a2 + ; Well then, I'll keep it. Thanks! + text_jump UnknownText_0x1bdfd1 + db "@" +; 0x169a7 + +.PartyFullText: ; 0x169a7 + ; You have no room in your party. Come back later. + text_jump UnknownText_0x1bdff2 + db "@" +; 0x169ac + +DayCare_GiveEgg: ; 169ac + ld a, [wEggMonLevel] + ld [CurPartyLevel], a + ld hl, PartyCount + ld a, [hl] + cp PARTY_LENGTH + jr nc, .PartyFull + inc a + ld [hl], a + + ld c, a + ld b, 0 + add hl, bc + ld a, EGG + ld [hli], a + ld a, [wEggMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + ld a, -1 + ld [hl], a + + ld hl, PartyMonNicknames + ld bc, PKMN_NAME_LENGTH + call DayCare_GetCurrentPartyMember + ld hl, wEggNick + call CopyBytes + + ld hl, PartyMonOT + ld bc, NAME_LENGTH + call DayCare_GetCurrentPartyMember + ld hl, wEggOT + call CopyBytes + + ld hl, PartyMon1 + ld bc, PARTYMON_STRUCT_LENGTH + call DayCare_GetCurrentPartyMember + ld hl, wEggMon + ld bc, wEggMonEnd - wEggMon + call CopyBytes + + call GetBaseData + ld a, [PartyCount] + dec a + ld hl, PartyMon1 + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld b, h + ld c, l + ld hl, MON_ID + 1 + add hl, bc + push hl + ld hl, MON_MAXHP + add hl, bc + ld d, h + ld e, l + pop hl + push bc + ld b, $0 + predef CalcPkmnStats + pop bc + ld hl, MON_HP + add hl, bc + xor a + ld [hli], a + ld [hl], a + and a + ret + +.PartyFull: + scf + ret +; 16a31 + +DayCare_GetCurrentPartyMember: ; 16a31 + ld a, [PartyCount] + dec a + call AddNTimes + ld d, h + ld e, l + ret +; 16a3b + +DayCare_InitBreeding: ; 16a3b + ld a, [wDayCareLady] + bit 0, a + ret z + ld a, [wDayCareMan] + bit 0, a + ret z + callfar CheckBreedmonCompatibility + ld a, [wd265] + and a + ret z + inc a + ret z + ld hl, wDayCareMan + set 5, [hl] +.loop + call Random + cp 150 + jr c, .loop + ld [wStepsToEgg], a + jp .UselessJump +; 16a66 + +.UselessJump: ; 16a66 + xor a + ld hl, wEggMon + ld bc, wEggMonEnd - wEggMon + call ByteFill + ld hl, wEggNick + ld bc, PKMN_NAME_LENGTH + call ByteFill + ld hl, wEggOT + ld bc, NAME_LENGTH + call ByteFill + ld a, [wBreedMon1DVs] + ld [TempMonDVs], a + ld a, [wBreedMon1DVs + 1] + ld [TempMonDVs + 1], a + ld a, [wBreedMon1Species] + ld [CurPartySpecies], a + ld a, $3 + ld [MonType], a + ld a, [wBreedMon1Species] + cp DITTO + ld a, $1 + jr z, .LoadWhichBreedmonIsTheMother + ld a, [wBreedMon2Species] + cp DITTO + ld a, $0 + jr z, .LoadWhichBreedmonIsTheMother + farcall GetGender + ld a, $0 + jr z, .LoadWhichBreedmonIsTheMother + inc a + +.LoadWhichBreedmonIsTheMother: + ld [wBreedMotherOrNonDitto], a + and a + ld a, [wBreedMon1Species] + jr z, .GotMother + ld a, [wBreedMon2Species] + +.GotMother: + ld [CurPartySpecies], a + callfar GetPreEvolution + callfar GetPreEvolution + ld a, EGG_LEVEL + ld [CurPartyLevel], a + + ld a, [CurPartySpecies] + cp NIDORAN_F + jr nz, .GotEggSpecies + call Random + cp 1 + 50 percent + ld a, NIDORAN_F + jr c, .GotEggSpecies + ld a, NIDORAN_M +.GotEggSpecies: + ld [CurPartySpecies], a + ld [CurSpecies], a + ld [wEggMonSpecies], a + + call GetBaseData + ld hl, wEggNick + ld de, .String_EGG + call CopyName2 + ld hl, PlayerName + ld de, wEggOT + ld bc, NAME_LENGTH + call CopyBytes + xor a + ld [wEggMonItem], a + ld de, wEggMonMoves + xor a + ld [Buffer1], a + predef FillMoves + farcall InitEggMoves + ld hl, wEggMonID + ld a, [PlayerID] + ld [hli], a + ld a, [PlayerID + 1] + ld [hl], a + ld a, [CurPartyLevel] + ld d, a + callfar CalcExpAtLevel + ld hl, wEggMonExp + ld a, [hMultiplicand] + ld [hli], a + ld a, [hMultiplicand + 1] + ld [hli], a + ld a, [hMultiplicand + 2] + ld [hl], a + xor a + ld b, wEggMonDVs - wEggMonStatExp + ld hl, wEggMonStatExp +.loop2 + ld [hli], a + dec b + jr nz, .loop2 + ld hl, wEggMonDVs + call Random + ld [hli], a + ld [TempMonDVs], a + call Random + ld [hld], a + ld [TempMonDVs + 1], a + ld de, wBreedMon1DVs + ld a, [wBreedMon1Species] + cp DITTO + jr z, .GotDVs + ld de, wBreedMon2DVs + ld a, [wBreedMon2Species] + cp DITTO + jr z, .GotDVs + ld a, TEMPMON + ld [MonType], a + push hl + farcall GetGender + pop hl + ld de, wBreedMon1DVs + ld bc, wBreedMon2DVs + jr c, .SkipDVs + jr z, .ParentCheck2 + ld a, [wBreedMotherOrNonDitto] + and a + jr z, .GotDVs + ld d, b + ld e, c + jr .GotDVs + +.ParentCheck2: + ld a, [wBreedMotherOrNonDitto] + and a + jr nz, .GotDVs + ld d, b + ld e, c + +.GotDVs: + ld a, [de] + inc de + and $f + ld b, a + ld a, [hl] + and $f0 + add b + ld [hli], a + ld a, [de] + and $7 + ld b, a + ld a, [hl] + and $f8 + add b + ld [hl], a + +.SkipDVs: + ld hl, StringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, NAME_LENGTH + call CopyBytes + ld hl, wEggMonMoves + ld de, wEggMonPP + predef FillPP + ld hl, wMonOrItemNameBuffer + ld de, StringBuffer1 + ld bc, NAME_LENGTH + call CopyBytes + ld a, [BaseEggSteps] + ld hl, wEggMonHappiness + ld [hli], a + xor a + ld [hli], a + ld [hli], a + ld [hl], a + ld a, [CurPartyLevel] + ld [wEggMonLevel], a + ret +; 16be0 + +.String_EGG: ; 16be0 + db "EGG@" +; 16be4 diff --git a/engine/events/dratini.asm b/engine/events/dratini.asm new file mode 100644 index 000000000..f110b34ab --- /dev/null +++ b/engine/events/dratini.asm @@ -0,0 +1,112 @@ +SpecialDratini: ; 0x8b170 +; if ScriptVar is 0 or 1, change the moveset of the last Dratini in the party. +; 0: give it a special moveset with Extremespeed. +; 1: give it the normal moveset of a level 15 Dratini. + + ld a, [ScriptVar] + cp $2 + ret nc + ld bc, PartyCount + ld a, [bc] + ld hl, MON_SPECIES + call .GetNthPartyMon + ld a, [bc] + ld c, a + ld de, PARTYMON_STRUCT_LENGTH +.CheckForDratini: +; start at the end of the party and search backwards for a Dratini + ld a, [hl] + cp DRATINI + jr z, .GiveMoveset + ld a, l + sub e + ld l, a + ld a, h + sbc d + ld h, a + dec c + jr nz, .CheckForDratini + ret + +.GiveMoveset: + push hl + ld a, [ScriptVar] + ld hl, .Movesets + ld bc, .Moveset1 - .Moveset0 + call AddNTimes + + ; get address of mon's first move + pop de + inc de + inc de + +.GiveMoves: + ld a, [hl] + and a ; is the move 00? + ret z ; if so, we're done here + + push hl + push de + ld [de], a ; give the Pokémon the new move + + ; get the PP of the new move + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + + ; get the address of the move's PP and update the PP + ld hl, MON_PP - MON_MOVES + add hl, de + ld [hl], a + + pop de + pop hl + inc de + inc hl + jr .GiveMoves + +.Movesets: +.Moveset0: +; Dratini does not normally learn Extremespeed. This is a special gift. + db WRAP + db THUNDER_WAVE + db TWISTER + db EXTREMESPEED + db 0 +.Moveset1: +; This is the normal moveset of a level 15 Dratini + db WRAP + db LEER + db THUNDER_WAVE + db TWISTER + db 0 + +.GetNthPartyMon: ; 0x8b1ce +; inputs: +; hl must be set to 0 before calling this function. +; a must be set to the number of Pokémon in the party. + +; outputs: +; returns the address of the last Pokémon in the party in hl. +; sets carry if a is 0. + + ld de, PartyMon1 + add hl, de + and a + jr z, .EmptyParty + dec a + ret z + ld de, PARTYMON_STRUCT_LENGTH +.loop + add hl, de + dec a + jr nz, .loop + ret + +.EmptyParty: + scf + ret +; 8b1e1 diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm new file mode 100755 index 000000000..9170b642d --- /dev/null +++ b/engine/events/elevator.asm @@ -0,0 +1,283 @@ +Elevator:: ; 1342d + call .LoadPointer + call .FindCurrentFloor + jr c, .quit + ld [wElevatorOriginFloor], a + call Elevator_AskWhichFloor + jr c, .quit + ld hl, wElevatorOriginFloor + cp [hl] + jr z, .quit + call Elevator_GoToFloor + and a + ret + +.quit + scf + ret +; 1344a + +.LoadPointer: ; 1344a + ld a, b + ld [wElevatorPointerBank], a + ld a, e + ld [wElevatorPointer], a + ld a, d + ld [wElevatorPointer + 1], a + call .LoadFloors + ret +; 1345a + +.LoadFloors: ; 1345a + ld de, CurElevator + ld bc, 4 + ld hl, wElevatorPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wElevatorPointerBank] + call GetFarByte + inc hl + ld [de], a + inc de +.loop + ld a, [wElevatorPointerBank] + call GetFarByte + ld [de], a + inc de + add hl, bc + cp -1 + jr nz, .loop + ret +; 1347d + +.FindCurrentFloor: ; 1347d + ld hl, wElevatorPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wElevatorPointerBank] + call GetFarByte + ld c, a + inc hl + ld a, [BackupMapGroup] + ld d, a + ld a, [BackupMapNumber] + ld e, a + ld b, 0 +.loop2 + ld a, [wElevatorPointerBank] + call GetFarByte + cp -1 + jr z, .fail + inc hl + inc hl + ld a, [wElevatorPointerBank] + call GetFarByte + inc hl + cp d + jr nz, .next1 + ld a, [wElevatorPointerBank] + call GetFarByte + inc hl + cp e + jr nz, .next2 + jr .done + +.next1 + inc hl +.next2 + inc b + jr .loop2 + +.done + xor a + ld a, b + ret + +.fail + scf + ret +; 134c0 + +Elevator_GoToFloor: ; 134c0 + push af + ld hl, wElevatorPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + pop af + ld bc, 4 + call AddNTimes + inc hl + ld de, BackupWarpNumber + ld a, [wElevatorPointerBank] + ld bc, 3 + call FarCopyBytes + ret +; 134dd + +Elevator_AskWhichFloor: ; 134dd + call LoadStandardMenuDataHeader + ld hl, Elevator_WhichFloorText + call PrintText + call Elevator_GetCurrentFloorText + ld hl, Elevator_MenuDataHeader + call CopyMenuDataHeader + call InitScrollingMenu + call UpdateSprites + xor a + ld [wMenuScrollPosition], a + call ScrollingMenu + call CloseWindow + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .cancel + xor a + ld a, [wScrollingMenuCursorPosition] + ret + +.cancel + scf + ret +; 1350d + +Elevator_WhichFloorText: ; 0x1350d + ; Which floor? + text_jump UnknownText_0x1bd2bc + db "@" +; 0x13512 + + +Elevator_GetCurrentFloorText: ; 13512 + ld hl, Options + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + hlcoord 0, 0 + ld b, 4 + ld c, 8 + call TextBox + hlcoord 1, 2 + ld de, Elevator_CurrentFloorText + call PlaceString + hlcoord 4, 4 + call Elevator_GetCurrentFloorString + pop af + ld [Options], a + ret +; 13537 + +Elevator_CurrentFloorText: ; 13537 + db "Now on:@" +; 1353f + + +Elevator_GetCurrentFloorString: ; 1353f + push hl + ld a, [wElevatorOriginFloor] + ld e, a + ld d, 0 + ld hl, CurElevatorFloors + add hl, de + ld a, [hl] + pop de + call GetFloorString + ret +; 13550 + +Elevator_MenuDataHeader: ; 0x13550 + db $40 ; flags + db 01, 12 ; start coords + db 09, 18 ; end coords + dw Elevator_MenuData2 + db 1 ; default option +; 0x13558 + +Elevator_MenuData2: ; 0x13558 + db $10 ; flags + db 4, 0 ; rows, columns + db 1 ; horizontal spacing + dbw 0, CurElevator + dba GetElevatorFlorStrings + dba NULL + dba NULL +; 13568 + +GetElevatorFlorStrings: ; 13568 + ld a, [MenuSelection] +GetFloorString: ; 1356b + push de + call FloorToString + ld d, h + ld e, l + pop hl + jp PlaceString +; 13575 + +FloorToString: ; 13575 + push de + ld e, a + ld d, 0 + ld hl, .floors + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + pop de + ret +; 13583 + +.floors + dw .b4f + dw .b3f + dw .b2f + dw .b1f + dw ._1f + dw ._2f + dw ._3f + dw ._4f + dw ._5f + dw ._6f + dw ._7f + dw ._8f + dw ._9f + dw ._10f + dw ._11f + dw .roof + +.b4f + db "B4F@" +.b3f + db "B3F@" +.b2f + db "B2F@" +.b1f + db "B1F@" +._1f + db "1F@" +._2f + db "2F@" +._3f + db "3F@" +._4f + db "4F@" +._5f + db "5F@" +._6f + db "6F@" +._7f + db "7F@" +._8f + db "8F@" +._9f + db "9F@" +._10f + db "10F@" +._11f + db "11F@" +.roof + db "ROOF@" +; 135db diff --git a/engine/events/field_moves.asm b/engine/events/field_moves.asm new file mode 100755 index 000000000..1c21f4995 --- /dev/null +++ b/engine/events/field_moves.asm @@ -0,0 +1,469 @@ +PlayWhirlpoolSound: ; 8c7d4 + call WaitSFX + ld de, SFX_SURF + call PlaySFX + call WaitSFX + ret +; 8c7e1 + +BlindingFlash: ; 8c7e1 + farcall FadeOutPalettes + ld hl, StatusFlags + set 2, [hl] ; Flash + farcall ReplaceTimeOfDayPals + farcall UpdateTimeOfDayPal + ld b, SCGB_MAPPALS + call GetSGBLayout + farcall LoadOW_BGPal7 + farcall FadeInPalettes + ret +; 8c80a + +ShakeHeadbuttTree: ; 8c80a + farcall ClearSpriteAnims + ld de, CutGrassGFX + ld hl, VTiles1 + lb bc, BANK(CutGrassGFX), 4 + call Request2bpp + ld de, HeadbuttTreeGFX + ld hl, VTiles1 tile $04 + lb bc, BANK(HeadbuttTreeGFX), 8 + call Request2bpp + call Cut_Headbutt_GetPixelFacing + ld a, SPRITE_ANIM_INDEX_HEADBUTT + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $84 + ld a, 36 * 4 + ld [wCurrSpriteOAMAddr], a + farcall DoNextFrameForAllSprites + call HideHeadbuttTree + ld a, $20 + ld [wcf64], a + call WaitSFX + ld de, SFX_SANDSTORM + call PlaySFX +.loop + ld hl, wcf64 + ld a, [hl] + and a + jr z, .done + dec [hl] + ld a, 36 * 4 + ld [wCurrSpriteOAMAddr], a + farcall DoNextFrameForAllSprites + call DelayFrame + jr .loop + +.done + call OverworldTextModeSwitch + call WaitBGMap + xor a + ld [hBGMapMode], a + farcall ClearSpriteAnims + ld hl, Sprites + 36 * 4 + ld bc, SpritesEnd - (Sprites + 36 * 4) + xor a + call ByteFill + ld de, Font + ld hl, VTiles1 + lb bc, BANK(Font), 12 + call Get1bpp + call ReplaceKrisSprite + ret +; 8c893 + +HeadbuttTreeGFX: ; 8c893 +INCBIN "gfx/overworld/headbutt_tree.2bpp" +; 8c913 + +HideHeadbuttTree: ; 8c913 + xor a + ld [hBGMapMode], a + ld a, [PlayerDirection] + and %00001100 + srl a + ld e, a + ld d, 0 + ld hl, TreeRelativeLocationTable + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + ld a, $5 + ld [hli], a + ld [hld], a + ld bc, SCREEN_WIDTH + add hl, bc + ld [hli], a + ld [hld], a + call WaitBGMap + xor a + ld [hBGMapMode], a + ret +; 8c938 + +TreeRelativeLocationTable: ; 8c938 + dwcoord 8, 8 + 2 ; RIGHT + dwcoord 8, 8 - 2 ; LEFT + dwcoord 8 - 2, 8 ; DOWN + dwcoord 8 + 2, 8 ; UP +; 8c940 + +OWCutAnimation: ; 8c940 + ; Animation index in e + ; 0: Split tree in half + ; 1: Mow the lawn + ld a, e + and $1 + ld [wJumptableIndex], a + call .LoadCutGFX + call WaitSFX + ld de, SFX_PLACE_PUZZLE_PIECE_DOWN + call PlaySFX +.loop + ld a, [wJumptableIndex] + bit 7, a + jr nz, .finish + ld a, 36 * 4 + ld [wCurrSpriteOAMAddr], a + callfar DoNextFrameForAllSprites + call OWCutJumptable + call DelayFrame + jr .loop + +.finish + ret +; 8c96d + +.LoadCutGFX: ; 8c96d + callfar ClearSpriteAnims ; pointless to farcall + ld de, CutGrassGFX + ld hl, VTiles1 + lb bc, BANK(CutGrassGFX), 4 + call Request2bpp + ld de, CutTreeGFX + ld hl, VTiles1 tile $4 + lb bc, BANK(CutTreeGFX), 4 + call Request2bpp + ret +; 8c98c + +CutTreeGFX: ; c898c +INCBIN "gfx/overworld/cut_tree.2bpp" +; c89cc + +CutGrassGFX: ; 8c9cc +INCBIN "gfx/overworld/cut_grass.2bpp" +; 8ca0c + +OWCutJumptable: ; 8ca0c + ld a, [wJumptableIndex] + ld e, a + ld d, 0 + ld hl, .dw + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; 8ca1b + + +.dw ; 8ca1b (23:4a1b) + dw Cut_SpawnAnimateTree + dw Cut_SpawnAnimateLeaves + dw Cut_StartWaiting + dw Cut_WaitAnimSFX + + +Cut_SpawnAnimateTree: ; 8ca23 (23:4a23) + call Cut_Headbutt_GetPixelFacing + ld a, SPRITE_ANIM_INDEX_CUT_TREE ; cut tree + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $84 + ld a, 32 + ld [wcf64], a +; Cut_StartWaiting + ld hl, wJumptableIndex + inc [hl] + inc [hl] + ret + +Cut_SpawnAnimateLeaves: ; 8ca3c (23:4a3c) + call Cut_GetLeafSpawnCoords + xor a + call Cut_SpawnLeaf + ld a, $10 + call Cut_SpawnLeaf + ld a, $20 + call Cut_SpawnLeaf + ld a, $30 + call Cut_SpawnLeaf + ld a, 32 ; frames + ld [wcf64], a +; Cut_StartWaiting + ld hl, wJumptableIndex + inc [hl] + ret + +Cut_StartWaiting: ; 8ca5c (23:4a5c) + ld a, $1 + ld [hBGMapMode], a +; Cut_WaitAnimSFX + ld hl, wJumptableIndex + inc [hl] + +Cut_WaitAnimSFX: ; 8ca64 (23:4a64) + ld hl, wcf64 + ld a, [hl] + and a + jr z, .finished + dec [hl] + ret + +.finished + ld hl, wJumptableIndex + set 7, [hl] + ret + +Cut_SpawnLeaf: ; 8ca73 (23:4a73) + push de + push af + ld a, SPRITE_ANIM_INDEX_LEAF ; leaf + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $80 + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + ld [hl], $4 + pop af + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], a + pop de + ret + +Cut_GetLeafSpawnCoords: ; 8ca8e (23:4a8e) + ld de, 0 + ld a, [wMetatileStandingX] + bit 0, a + jr z, .left_side + set 0, e +.left_side + ld a, [wMetatileStandingY] + bit 0, a + jr z, .top_side + set 1, e +.top_side + ld a, [PlayerDirection] + and %00001100 + add e + ld e, a + ld hl, .Coords + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ret +; 8cab3 (23:4ab3) + +.Coords: ; 8cab3 + dbpixel 11, 12 ; facing down, top left + dbpixel 9, 12 ; facing down, top right + dbpixel 11, 14 ; facing down, bottom left + dbpixel 9, 14 ; facing down, bottom right + + dbpixel 11, 8 ; facing up, top left + dbpixel 9, 8 ; facing up, top right + dbpixel 11, 10 ; facing up, bottom left + dbpixel 9, 10 ; facing up, bottom right + + dbpixel 7, 12 ; facing left, top left + dbpixel 9, 12 ; facing left, top right + dbpixel 7, 10 ; facing left, bottom left + dbpixel 9, 10 ; facing left, bottom right + + dbpixel 11, 12 ; facing right, top left + dbpixel 13, 12 ; facing right, top right + dbpixel 11, 10 ; facing right, bottom left + dbpixel 13, 10 ; facing right, bottom right +; 8cad3 + +Cut_Headbutt_GetPixelFacing: ; 8cad3 (23:4ad3) + ld a, [PlayerDirection] + and %00001100 + srl a + ld e, a + ld d, 0 + ld hl, .Coords + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ret +; 8cae5 (23:4ae5) + +.Coords: ; 8cae5 + dbpixel 10, 13 + dbpixel 10, 9 + dbpixel 8, 11 + dbpixel 12, 11 +; 8caed + + +FlyFromAnim: ; 8caed + call DelayFrame + ld a, [VramState] + push af + xor a + ld [VramState], a + call FlyFunction_InitGFX + depixel 10, 10, 4, 0 + ld a, SPRITE_ANIM_INDEX_RED_WALK + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $84 + ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID + add hl, bc + ld [hl], SPRITE_ANIM_SEQ_FLY_FROM + ld a, 128 + ld [wcf64], a +.loop + ld a, [wJumptableIndex] + bit 7, a + jr nz, .exit + ld a, 0 * 4 + ld [wCurrSpriteOAMAddr], a + callfar DoNextFrameForAllSprites + call FlyFunction_FrameTimer + call DelayFrame + jr .loop + +.exit + pop af + ld [VramState], a + ret +; 8cb33 + +FlyToAnim: ; 8cb33 + call DelayFrame + ld a, [VramState] + push af + xor a + ld [VramState], a + call FlyFunction_InitGFX + depixel 31, 10, 4, 0 + ld a, SPRITE_ANIM_INDEX_RED_WALK + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $84 + ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID + add hl, bc + ld [hl], SPRITE_ANIM_SEQ_FLY_TO + ld hl, SPRITEANIMSTRUCT_0F + add hl, bc + ld [hl], 11 * 8 + ld a, 64 + ld [wcf64], a +.loop + ld a, [wJumptableIndex] + bit 7, a + jr nz, .exit + ld a, 0 * 4 + ld [wCurrSpriteOAMAddr], a + callfar DoNextFrameForAllSprites + call FlyFunction_FrameTimer + call DelayFrame + jr .loop + +.exit + pop af + ld [VramState], a + call .RestorePlayerSprite_DespawnLeaves + ret + +.RestorePlayerSprite_DespawnLeaves: ; 8cb82 (23:4b82) + ld hl, Sprites + 2 ; Tile ID + xor a + ld c, $4 +.loop2 + ld [hli], a + inc hl + inc hl + inc hl + inc a + dec c + jr nz, .loop2 + ld hl, Sprites + 4 * 4 + ld bc, SpritesEnd - (Sprites + 4 * 4) + xor a + call ByteFill + ret + +FlyFunction_InitGFX: ; 8cb9b (23:4b9b) + callfar ClearSpriteAnims + ld de, CutGrassGFX + ld hl, VTiles1 tile $00 + lb bc, BANK(CutGrassGFX), 4 + call Request2bpp + ld a, [CurPartyMon] + ld hl, PartySpecies + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + ld [wd265], a + ld e, $84 + farcall FlyFunction_GetMonIcon + xor a + ld [wJumptableIndex], a + ret + +FlyFunction_FrameTimer: ; 8cbc8 (23:4bc8) + call .SpawnLeaf + ld hl, wcf64 + ld a, [hl] + and a + jr z, .exit + dec [hl] + cp $40 + ret c + and $7 + ret nz + ld de, SFX_FLY + call PlaySFX + ret + +.exit + ld hl, wJumptableIndex + set 7, [hl] + ret + +.SpawnLeaf: ; 8cbe6 (23:4be6) + ld hl, wcf65 + ld a, [hl] + inc [hl] + and $7 + ret nz + ld a, [hl] + and (6 * 8) >> 1 + sla a + add 8 * 8 ; gives a number in [$40, $50, $60, $70] + ld d, a + ld e, $0 + ld a, SPRITE_ANIM_INDEX_FLY_LEAF ; fly land + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $80 + ret diff --git a/engine/fish.asm b/engine/events/fish.asm index c571bba56..c571bba56 100644 --- a/engine/fish.asm +++ b/engine/events/fish.asm diff --git a/engine/events/forced_movement.asm b/engine/events/forced_movement.asm new file mode 100755 index 000000000..136698501 --- /dev/null +++ b/engine/events/forced_movement.asm @@ -0,0 +1,60 @@ +Script_ForcedMovement:: ; 0x1253d + checkcode VAR_FACING + if_equal DOWN, .down + if_equal UP, .up + if_equal LEFT, .left + if_equal RIGHT, .right + end +; 0x12550 + +.up ; 0x12550 + applymovement PLAYER, .MovementData_up + end +; 0x12555 + +.down ; 0x12555 + applymovement PLAYER, .MovementData_down + end +; 0x1255a + +.right ; 0x1255a + applymovement PLAYER, .MovementData_right + end +; 0x1255f + +.left ; 0x1255f + applymovement PLAYER, .MovementData_left + end +; 0x12564 + +.MovementData_up: ; 0x12564 + step_dig 16 + turn_in DOWN + step_dig 16 + turn_head DOWN + step_end +; 0x1256b + +.MovementData_down: ; 0x1256b + step_dig 16 + turn_in UP + step_dig 16 + turn_head UP + step_end +; 0x12572 + +.MovementData_right: ; 0x12572 + step_dig 16 + turn_in LEFT + step_dig 16 + turn_head LEFT + step_end +; 0x12579 + +.MovementData_left: ; 0x12579 + step_dig 16 + turn_in RIGHT + step_dig 16 + turn_head RIGHT + step_end +; 0x12580 diff --git a/engine/fruit_trees.asm b/engine/events/fruit_trees.asm index 595e41824..595e41824 100644 --- a/engine/fruit_trees.asm +++ b/engine/events/fruit_trees.asm diff --git a/engine/events/halloffame.asm b/engine/events/halloffame.asm new file mode 100755 index 000000000..5fa1dc270 --- /dev/null +++ b/engine/events/halloffame.asm @@ -0,0 +1,622 @@ +HALLOFFAME_COLON EQU $63 + +HallOfFame:: ; 0x8640e + call HallOfFame_FadeOutMusic + ld a, [StatusFlags] + push af + ld a, 1 + ld [wGameLogicPaused], a + call DisableSpriteUpdates + ld a, SPAWN_LANCE + ld [wSpawnAfterChampion], a + + ; Enable the Pokégear map to cycle through all of Kanto + ld hl, StatusFlags + set 6, [hl] ; hall of fame + + farcall HallOfFame_InitSaveIfNeeded + + ld hl, wHallOfFameCount + ld a, [hl] + cp 200 + jr nc, .ok + inc [hl] +.ok + farcall SaveGameData + call GetHallOfFameParty + farcall AddHallOfFameEntry + + xor a + ld [wGameLogicPaused], a + call AnimateHallOfFame + pop af + ld b, a + farcall Credits + ret +; 0x86455 + +RedCredits:: ; 86455 + ld a, LOW(MUSIC_NONE) + ld [MusicFadeID], a + ld a, HIGH(MUSIC_NONE) + ld [MusicFadeID + 1], a + ld a, 10 + ld [MusicFade], a + farcall FadeOutPalettes + xor a + ld [VramState], a + ld [hMapAnims], a + farcall InitDisplayForRedCredits + ld c, 8 + call DelayFrames + call DisableSpriteUpdates + ld a, SPAWN_RED + ld [wSpawnAfterChampion], a + ld a, [StatusFlags] + ld b, a + farcall Credits + ret +; 8648e + +HallOfFame_FadeOutMusic: ; 8648e + ld a, LOW(MUSIC_NONE) + ld [MusicFadeID], a + ld a, HIGH(MUSIC_NONE) + ld [MusicFadeID + 1], a + ld a, 10 + ld [MusicFade], a + farcall FadeOutPalettes + xor a + ld [VramState], a + ld [hMapAnims], a + farcall InitDisplayForHallOfFame + ld c, 100 + jp DelayFrames +; 864b4 + +HallOfFame_PlayMusicDE: ; 864b4 + push de + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + pop de + call PlayMusic + ret +; 864c3 + +AnimateHallOfFame: ; 864c3 + xor a + ld [wJumptableIndex], a + call LoadHOFTeam + jr c, .done + ld de, MUSIC_HALL_OF_FAME + call HallOfFame_PlayMusicDE + xor a + ld [wcf64], a +.loop + ld a, [wcf64] + cp PARTY_LENGTH + jr nc, .done + ld hl, wHallOfFameTempMon1 + ld bc, wHallOfFameTempMon1End - wHallOfFameTempMon1 + call AddNTimes + ld a, [hl] + cp -1 + jr z, .done + push hl + call AnimateHOFMonEntrance + pop hl + call .DisplayNewHallOfFamer + jr c, .done + ld hl, wcf64 + inc [hl] + jr .loop + +.done + call HOF_AnimatePlayerPic + ld a, $4 + ld [MusicFade], a + call RotateThreePalettesRight + ld c, 8 + call DelayFrames + ret +; 8650c + +.DisplayNewHallOfFamer: ; 8650c + call DisplayHOFMon + ld de, .String_NewHallOfFamer + hlcoord 1, 2 + call PlaceString + call WaitBGMap + decoord 6, 5 + ld c, $6 + predef HOF_AnimateFrontpic + ld c, 60 + call DelayFrames + and a + ret +; 8652c + +.String_NewHallOfFamer: + db "New Hall of Famer!@" +; 8653f + + +GetHallOfFameParty: ; 8653f + ld hl, OverworldMap + ld bc, HOF_LENGTH + xor a + call ByteFill + ld a, [wHallOfFameCount] + ld de, OverworldMap + ld [de], a + inc de + ld hl, PartySpecies + ld c, 0 +.next + ld a, [hli] + cp -1 + jr z, .done + cp EGG + jr nz, .mon + inc c + jr .next + +.mon + push hl + push de + push bc + + ld a, c + ld hl, PartyMons + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld c, l + ld b, h + + ld hl, MON_SPECIES + add hl, bc + ld a, [hl] + ld [de], a + inc de + + ld hl, MON_ID + add hl, bc + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + + ld hl, MON_DVS + add hl, bc + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [de], a + inc de + + pop bc + push bc + ld a, c + ld hl, PartyMonNicknames + ld bc, PKMN_NAME_LENGTH + call AddNTimes + ld bc, PKMN_NAME_LENGTH - 1 + call CopyBytes + + pop bc + inc c + pop de + ld hl, HOF_MON_LENGTH + add hl, de + ld e, l + ld d, h + pop hl + jr .next + +.done + ld a, $ff + ld [de], a + ret +; 865b5 + +AnimateHOFMonEntrance: ; 865b5 + push hl + call ClearBGPalettes + farcall ResetDisplayBetweenHallOfFameMons + pop hl + ld a, [hli] + ld [TempMonSpecies], a + ld [CurPartySpecies], a + inc hl + inc hl + ld a, [hli] + ld [TempMonDVs], a + ld a, [hli] + ld [TempMonDVs + 1], a + ld hl, TempMonDVs + predef GetUnownLetter + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + ld de, VTiles2 tile $31 + predef GetMonBackpic + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 6, 6 + lb bc, 6, 6 + predef PlaceGraphic + ld a, $d0 + ld [hSCY], a + ld a, $90 + ld [hSCX], a + call WaitBGMap + xor a + ld [hBGMapMode], a + ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call SetPalettes + call HOF_SlideBackpic + xor a + ld [wBoxAlignment], a + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + hlcoord 6, 5 + call _PrepMonFrontpic + call WaitBGMap + xor a + ld [hBGMapMode], a + ld [hSCY], a + call HOF_SlideFrontpic + ret +; 86635 + +HOF_SlideBackpic: +.backpicloop + ld a, [hSCX] + cp $70 + ret z + add $4 + ld [hSCX], a + call DelayFrame + jr .backpicloop +; 86643 + +HOF_SlideFrontpic: +.frontpicloop + ld a, [hSCX] + and a + ret z + dec a + dec a + ld [hSCX], a + call DelayFrame + jr .frontpicloop +; 86650 + +_HallOfFamePC: ; 86650 + call LoadFontsBattleExtra + xor a + ld [wJumptableIndex], a +.MasterLoop: + call LoadHOFTeam + ret c + call .DisplayTeam + ret c + ld hl, wJumptableIndex + inc [hl] + jr .MasterLoop + +.DisplayTeam: + xor a + ld [wcf64], a +.next + call .DisplayMonAndStrings + jr c, .start_button +.loop + call JoyTextDelay + ld hl, hJoyLast + ld a, [hl] + and B_BUTTON + jr nz, .b_button + ld a, [hl] + and A_BUTTON + jr nz, .a_button + ld a, [hl] + and START + jr nz, .start_button + call DelayFrame + jr .loop + +.a_button + ld hl, wcf64 + inc [hl] + jr .next + +.b_button + scf + ret + +.start_button + and a + ret + +.DisplayMonAndStrings: +; Print the number of times the player has entered the Hall of Fame. +; If that number is above 200, print "HOF Master!" instead. + ld a, [wcf64] + cp PARTY_LENGTH + jr nc, .fail + ld hl, wHallOfFameTempMon1 + ld bc, wHallOfFameTempMon1End - wHallOfFameTempMon1 + call AddNTimes + ld a, [hl] + cp -1 + jr nz, .okay + +.fail + scf + ret + +.okay + push hl + call ClearBGPalettes + pop hl + call DisplayHOFMon + ld a, [wHallOfFameTempWinCount] + cp 200 + 1 + jr c, .print_num_hof + ld de, .HOFMaster + hlcoord 1, 2 + call PlaceString + hlcoord 13, 2 + jr .finish + +.print_num_hof + ld de, .TimeFamer + hlcoord 1, 2 + call PlaceString + hlcoord 2, 2 + ld de, wHallOfFameTempWinCount + lb bc, 1, 3 + call PrintNum + hlcoord 11, 2 + +.finish + ld de, .EmptyString + call PlaceString + call WaitBGMap + ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call SetPalettes + decoord 6, 5 + ld c, $6 + predef HOF_AnimateFrontpic + and a + ret + +.EmptyString: + db "@" + +.HOFMaster: + db " HOF Master!@" + +.TimeFamer: + db " -Time Famer@" +; 8671c + +LoadHOFTeam: ; 8671c + ld a, [wJumptableIndex] + cp NUM_HOF_TEAMS + jr nc, .invalid + ld hl, sHallOfFame + ld bc, HOF_LENGTH + call AddNTimes + ld a, BANK(sHallOfFame) + call GetSRAMBank + ld a, [hl] + and a + jr z, .absent + ld de, wHallOfFameTemp + ld bc, HOF_LENGTH + call CopyBytes + call CloseSRAM + and a + ret + +.absent + call CloseSRAM + +.invalid + scf + ret +; 86748 + +DisplayHOFMon: ; 86748 + xor a + ld [hBGMapMode], a + ld a, [hli] + ld [TempMonSpecies], a + ld a, [hli] + ld [TempMonID], a + ld a, [hli] + ld [TempMonID + 1], a + ld a, [hli] + ld [TempMonDVs], a + ld a, [hli] + ld [TempMonDVs + 1], a + ld a, [hli] + ld [TempMonLevel], a + ld de, StringBuffer2 + ld bc, PKMN_NAME_LENGTH - 1 + call CopyBytes + ld a, "@" + ld [StringBuffer2 + 10], a + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + hlcoord 0, 0 + lb bc, 3, SCREEN_WIDTH - 2 + call TextBox + hlcoord 0, 12 + lb bc, 4, SCREEN_WIDTH - 2 + call TextBox + ld a, [TempMonSpecies] + ld [CurPartySpecies], a + ld [wd265], a + ld hl, TempMonDVs + predef GetUnownLetter + xor a + ld [wBoxAlignment], a + hlcoord 6, 5 + call _PrepMonFrontpic + ld a, [CurPartySpecies] + cp EGG + jr z, .print_id_no + hlcoord 1, 13 + ld a, "№" + ld [hli], a + ld [hl], "<DOT>" + hlcoord 3, 13 + ld de, wd265 + lb bc, PRINTNUM_LEADINGZEROS | 1, 3 + call PrintNum + call GetBasePokemonName + hlcoord 7, 13 + call PlaceString + ld a, TEMPMON + ld [MonType], a + farcall GetGender + ld a, " " + jr c, .got_gender + ld a, "♂" + jr nz, .got_gender + ld a, "♀" + +.got_gender + hlcoord 18, 13 + ld [hli], a + hlcoord 8, 14 + ld a, "/" + ld [hli], a + ld de, StringBuffer2 + call PlaceString + hlcoord 1, 16 + call PrintLevel + +.print_id_no + hlcoord 7, 16 + ld a, "<ID>" + ld [hli], a + ld a, "№" + ld [hli], a + ld [hl], "/" + hlcoord 10, 16 + ld de, TempMonID + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + ret +; 86810 + +HOF_AnimatePlayerPic: ; 86810 + call ClearBGPalettes + ld hl, VTiles2 tile HALLOFFAME_COLON + ld de, FontExtra + 13 tiles ; "<COLON>" + lb bc, BANK(FontExtra), 1 + call Request2bpp + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + farcall GetPlayerBackpic + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 6, 6 + lb bc, 6, 6 + predef PlaceGraphic + ld a, $d0 + ld [hSCY], a + ld a, $90 + ld [hSCX], a + call WaitBGMap + xor a + ld [hBGMapMode], a + ld [CurPartySpecies], a + ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call SetPalettes + call HOF_SlideBackpic + xor a + ld [wBoxAlignment], a + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + farcall HOF_LoadTrainerFrontpic + xor a + ld [hGraphicStartTile], a + hlcoord 12, 5 + lb bc, 7, 7 + predef PlaceGraphic + ld a, $c0 + ld [hSCX], a + call WaitBGMap + xor a + ld [hBGMapMode], a + ld [hSCY], a + call HOF_SlideFrontpic + xor a + ld [hBGMapMode], a + hlcoord 0, 2 + lb bc, 8, 9 + call TextBox + hlcoord 0, 12 + lb bc, 4, 18 + call TextBox + hlcoord 2, 4 + ld de, PlayerName + call PlaceString + hlcoord 1, 6 + ld a, "<ID>" + ld [hli], a + ld a, "№" + ld [hli], a + ld [hl], "/" + hlcoord 4, 6 + ld de, PlayerID + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + hlcoord 1, 8 + ld de, .PlayTime + call PlaceString + hlcoord 3, 9 + ld de, GameTimeHours + lb bc, 2, 3 + call PrintNum + ld [hl], HALLOFFAME_COLON + inc hl + ld de, GameTimeMinutes + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + call WaitBGMap + farcall ProfOaksPCRating + ret +; 868ed + +.PlayTime: + db "PLAY TIME@" +; 868f7 + diff --git a/engine/events/happiness_egg.asm b/engine/events/happiness_egg.asm new file mode 100755 index 000000000..a4ae8b7e6 --- /dev/null +++ b/engine/events/happiness_egg.asm @@ -0,0 +1,223 @@ +GetFirstPokemonHappiness: ; 718d + ld hl, PartyMon1Happiness + ld bc, PARTYMON_STRUCT_LENGTH + ld de, PartySpecies +.loop + ld a, [de] + cp EGG + jr nz, .done + inc de + add hl, bc + jr .loop + +.done + ld [wd265], a + ld a, [hl] + ld [ScriptVar], a + call GetPokemonName + jp CopyPokemonName_Buffer1_Buffer3 + +CheckFirstMonIsEgg: ; 71ac + ld a, [PartySpecies] + ld [wd265], a + cp EGG + ld a, $1 + jr z, .egg + xor a + +.egg + ld [ScriptVar], a + call GetPokemonName + jp CopyPokemonName_Buffer1_Buffer3 + +ChangeHappiness: ; 71c2 +; Perform happiness action c on CurPartyMon + + ld a, [CurPartyMon] + inc a + ld e, a + ld d, 0 + ld hl, PartySpecies - 1 + add hl, de + ld a, [hl] + cp EGG + ret z + + push bc + ld hl, PartyMon1Happiness + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [CurPartyMon] + call AddNTimes + pop bc + + ld d, h + ld e, l + + push de + ld a, [de] + cp HAPPINESS_THRESHOLD_1 + ld e, 0 + jr c, .ok + inc e + cp HAPPINESS_THRESHOLD_2 + jr c, .ok + inc e + +.ok + dec c + ld b, 0 + ld hl, HappinessChanges + add hl, bc + add hl, bc + add hl, bc + ld d, 0 + add hl, de + ld a, [hl] + cp $64 ; why not $80? + pop de + + ld a, [de] + jr nc, .negative + add [hl] + jr nc, .done + ld a, -1 + jr .done + +.negative + add [hl] + jr c, .done + xor a + +.done + ld [de], a + ld a, [wBattleMode] + and a + ret z + ld a, [CurPartyMon] + ld b, a + ld a, [wPartyMenuCursor] + cp b + ret nz + ld a, [de] + ld [BattleMonHappiness], a + ret + + +INCLUDE "data/happiness_changes.asm" + + +StepHappiness:: ; 725a +; Raise the party's happiness by 1 point every other step cycle. + + ld hl, wHappinessStepCount + ld a, [hl] + inc a + and 1 + ld [hl], a + ret nz + + ld de, PartyCount + ld a, [de] + and a + ret z + + ld c, a + ld hl, PartyMon1Happiness +.loop + inc de + ld a, [de] + cp EGG + jr z, .next + inc [hl] + jr nz, .next + ld [hl], $ff + +.next + push de + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + pop de + dec c + jr nz, .loop + ret + + +DayCareStep:: ; 7282 +; Raise the experience of Day-Care Pokémon every step cycle. + + ld a, [wDayCareMan] + bit 0, a + jr z, .day_care_lady + + ld a, [wBreedMon1Level] ; level + cp MAX_LEVEL + jr nc, .day_care_lady + ld hl, wBreedMon1Exp + 2 ; exp + inc [hl] + jr nz, .day_care_lady + dec hl + inc [hl] + jr nz, .day_care_lady + dec hl + inc [hl] + ld a, [hl] + cp HIGH(MAX_DAY_CARE_EXP >> 8) + jr c, .day_care_lady + ld a, HIGH(MAX_DAY_CARE_EXP >> 8) + ld [hl], a + +.day_care_lady + ld a, [wDayCareLady] + bit 0, a + jr z, .check_egg + + ld a, [wBreedMon2Level] ; level + cp MAX_LEVEL + jr nc, .check_egg + ld hl, wBreedMon2Exp + 2 ; exp + inc [hl] + jr nz, .check_egg + dec hl + inc [hl] + jr nz, .check_egg + dec hl + inc [hl] + ld a, [hl] + cp HIGH(MAX_DAY_CARE_EXP >> 8) + jr c, .check_egg + ld a, HIGH(MAX_DAY_CARE_EXP >> 8) + ld [hl], a + +.check_egg + ld hl, wDayCareMan + bit 5, [hl] ; egg + ret z + ld hl, wStepsToEgg + dec [hl] + ret nz + + call Random + ld [hl], a + callfar CheckBreedmonCompatibility + ld a, [wd265] + cp 230 + ld b, 32 percent - 1 + jr nc, .okay + ld a, [wd265] + cp 170 + ld b, 16 percent + jr nc, .okay + ld a, [wd265] + cp 110 + ld b, 12 percent + jr nc, .okay + ld b, 4 percent + +.okay + call Random + cp b + ret nc + ld hl, wDayCareMan + res 5, [hl] + set 6, [hl] + ret diff --git a/engine/events/heal_machine_anim.asm b/engine/events/heal_machine_anim.asm new file mode 100755 index 000000000..c7789a28d --- /dev/null +++ b/engine/events/heal_machine_anim.asm @@ -0,0 +1,265 @@ +HealMachineAnim: ; 12324 + ; If you have no Pokemon, don't change the buffer. This can lead to some glitchy effects if you have no Pokemon. + ld a, [PartyCount] + and a + ret z + ; The location of the healing machine relative to the player is stored in ScriptVar. + ; 0: Up and left (Pokemon Center) + ; 1: Left (Elm's Lab) + ; 2: Up (Hall of Fame) + ld a, [ScriptVar] + ld [Buffer1], a + ld a, [rOBP1] + ld [Buffer2], a + call .DoJumptableFunctions + ld a, [Buffer2] + call DmgToCgbObjPal1 + ret +; 1233e + +.DoJumptableFunctions: ; 1233e + xor a + ld [Buffer3], a +.jumpable_loop + ld a, [Buffer1] + ld e, a + ld d, 0 + ld hl, .Pointers + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [Buffer3] + ld e, a + inc a + ld [Buffer3], a + add hl, de + ld a, [hl] + cp 5 + jr z, .finish + ld hl, .Jumptable + rst JumpTable + jr .jumpable_loop + +.finish + ret +; 12365 + +.Pointers: ; 12365 + dw .Pokecenter + dw .ElmLab + dw .HallOfFame +; 1236b + +.Pokecenter: ; 1236b + db 0, 1, 3, 5 +.ElmLab: ; 1236f + db 0, 1, 3, 5 +.HallOfFame: ; 12373 + db 0, 2, 4, 5 +; 12377 + +.Jumptable: ; 12377 + dw .LoadGFX + dw .PC_LoadBallsOntoMachine + dw .HOF_LoadBallsOntoMachine + dw .PlayHealMusic + dw .HOF_PlaySFX + dw .dummy_5 ; never encountered +; 12383 + +.LoadGFX: ; 12383 + call .LoadPalettes + ld de, .HealMachineGFX + ld hl, VTiles0 tile $7c + lb bc, BANK(.HealMachineGFX), $2 + call Request2bpp + ret +; 12393 + +.PC_LoadBallsOntoMachine: ; 12393 + ld hl, Sprites + $80 + ld de, .PC_ElmsLab_OAM + call .PlaceHealingMachineTile + call .PlaceHealingMachineTile + jr .LoadBallsOntoMachine + +.HOF_LoadBallsOntoMachine: ; 123a1 + ld hl, Sprites + $80 + ld de, .HOF_OAM + +.LoadBallsOntoMachine: ; 123a7 + ld a, [PartyCount] + ld b, a +.party_loop + call .PlaceHealingMachineTile + push de + ld de, SFX_SECOND_PART_OF_ITEMFINDER + call PlaySFX + pop de + ld c, 30 + call DelayFrames + dec b + jr nz, .party_loop + ret +; 123bf + +.PlayHealMusic: ; 123bf + ld de, MUSIC_HEAL + call PlayMusic + jp .FlashPalettes8Times +; 123c8 + +.HOF_PlaySFX: ; 123c8 + ld de, SFX_GAME_FREAK_LOGO_GS + call PlaySFX + call .FlashPalettes8Times + call WaitSFX + ld de, SFX_BOOT_PC + call PlaySFX + ret +; 123db + +.dummy_5 ; 123db + ret +; 123dc + +.PC_ElmsLab_OAM: ; 123dc + dsprite 4, 0, 4, 2, $7c, PAL_OW_TREE | OBP_NUM + dsprite 4, 0, 4, 6, $7c, PAL_OW_TREE | OBP_NUM + dsprite 4, 6, 4, 0, $7d, PAL_OW_TREE | OBP_NUM + dsprite 4, 6, 5, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP + dsprite 5, 3, 4, 0, $7d, PAL_OW_TREE | OBP_NUM + dsprite 5, 3, 5, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP + dsprite 6, 0, 4, 0, $7d, PAL_OW_TREE | OBP_NUM + dsprite 6, 0, 5, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP +; 123fc + +.HealMachineGFX: ; 123fc +INCBIN "gfx/overworld/heal_machine.2bpp" +; 1241c + +.HOF_OAM: ; 1241c + dsprite 7, 4, 10, 1, $7d, PAL_OW_TREE | OBP_NUM + dsprite 7, 4, 10, 6, $7d, PAL_OW_TREE | OBP_NUM + dsprite 7, 3, 9, 5, $7d, PAL_OW_TREE | OBP_NUM + dsprite 7, 3, 11, 2, $7d, PAL_OW_TREE | OBP_NUM + dsprite 7, 1, 9, 1, $7d, PAL_OW_TREE | OBP_NUM + dsprite 7, 1, 11, 5, $7d, PAL_OW_TREE | OBP_NUM +; 12434 + +.LoadPalettes: ; 12434 + call IsCGB + jr nz, .cgb + ld a, %11100000 + ld [rOBP1], a + ret + +.cgb + ld hl, .palettes + ld de, OBPals palette PAL_OW_TREE + ld bc, 1 palettes + ld a, $5 + call FarCopyWRAM + ld a, $1 + ld [hCGBPalUpdate], a + ret +; 12451 + +.palettes ; 12451 + RGB 31, 31, 31 + RGB 31, 19, 10 + RGB 31, 07, 01 + RGB 00, 00, 00 +; 12459 + +.FlashPalettes8Times: ; 12459 + ld c, $8 +.palette_loop + push bc + call .FlashPalettes + ld c, 10 + call DelayFrames + pop bc + dec c + jr nz, .palette_loop + ret +; 12469 + +.FlashPalettes: ; 12469 + call IsCGB + jr nz, .go + ld a, [rOBP1] + xor %00101000 + ld [rOBP1], a + ret + +.go + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + + ld hl, OBPals palette PAL_OW_TREE + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + push de + ld c, $3 +.palette_loop_2 + ld a, [hli] + ld e, a + ld a, [hld] + ld d, a + dec hl + ld a, d + ld [hld], a + ld a, e + ld [hli], a + inc hl + inc hl + inc hl + dec c + jr nz, .palette_loop_2 + pop de + dec hl + ld a, d + ld [hld], a + ld a, e + ld [hl], a + + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret +; 124a3 + +.PlaceHealingMachineTile: ; 124a3 + push bc + ld a, [Buffer1] + bcpixel 2, 4 + cp $1 ; ElmsLab + jr z, .okay + bcpixel 0, 0 + +.okay + ld a, [de] + add c + inc de + ld [hli], a + ld a, [de] + add b + inc de + ld [hli], a + ld a, [de] + inc de + ld [hli], a + ld a, [de] + inc de + ld [hli], a + pop bc + ret +; 124c1 diff --git a/engine/events/itemfinder.asm b/engine/events/itemfinder.asm new file mode 100755 index 000000000..71aaa5b69 --- /dev/null +++ b/engine/events/itemfinder.asm @@ -0,0 +1,58 @@ +ItemFinder: ; 12580 + farcall CheckForHiddenItems + jr c, .found_something + ld hl, .Script_FoundNothing + jr .resume + +.found_something + ld hl, .Script_FoundSomething + +.resume + call QueueScript + ld a, $1 + ld [wItemEffectSucceeded], a + ret +; 12599 + +.ItemfinderSound: ; 12599 + ld c, 4 +.sfx_loop + push bc + ld de, SFX_SECOND_PART_OF_ITEMFINDER + call WaitPlaySFX + ld de, SFX_TRANSACTION + call WaitPlaySFX + pop bc + dec c + jr nz, .sfx_loop + ret +; 125ad + +.Script_FoundSomething: ; 0x125ad + reloadmappart + special UpdateTimePals + callasm .ItemfinderSound + writetext .Text_FoundSomething + closetext + end +; 0x125ba + +.Script_FoundNothing: ; 0x125ba + reloadmappart + special UpdateTimePals + writetext .Text_FoundNothing + closetext + end +; 0x125c3 + +.Text_FoundSomething: ; 0x125c3 + ; Yes! ITEMFINDER indicates there's an item nearby. + text_jump UnknownText_0x1c0a77 + db "@" +; 0x125c8 + +.Text_FoundNothing: ; 0x125c8 + ; Nope! ITEMFINDER isn't responding. + text_jump UnknownText_0x1c0aa9 + db "@" +; 0x125cd diff --git a/engine/events/kurt.asm b/engine/events/kurt.asm new file mode 100644 index 000000000..9bc06a613 --- /dev/null +++ b/engine/events/kurt.asm @@ -0,0 +1,413 @@ +Kurt_PrintTextWhichApricorn: ; 88000 + ld hl, .Text + call PrintText + ret +; 88007 + +.Text: ; 0x88007 + ; Which APRICORN should I use? + text_jump UnknownText_0x1bc06b + db "@" +; 0x8800c + +Kurt_PrintTextHowMany: ; 8800c + ld hl, .Text + call PrintText + ret +; 88013 + +.Text: ; 0x88013 + ; How many should I make? + text_jump UnknownText_0x1bc089 + db "@" +; 0x88018 + +Special_SelectApricornForKurt: ; 88018 + call LoadStandardMenuDataHeader + ld c, $1 + xor a + ld [wMenuScrollPosition], a + ld [wKurtApricornQuantity], a +.loop + push bc + call Kurt_PrintTextWhichApricorn + pop bc + ld a, c + ld [MenuSelection], a + call Kurt_SelectApricorn + ld a, c + ld [ScriptVar], a + and a + jr z, .done + ld [CurItem], a + ld a, [wMenuCursorY] + ld c, a + push bc + call Kurt_PrintTextHowMany + call Kurt_SelectQuantity + pop bc + jr nc, .loop + ld a, [wItemQuantityChangeBuffer] + ld [wKurtApricornQuantity], a + call Kurt_GiveUpSelectedQuantityOfSelectedApricorn + +.done + call Call_ExitMenu + ret +; 88055 + +Kurt_SelectApricorn: ; 88055 + farcall FindApricornsInBag + jr c, .nope + ld hl, .MenuDataHeader + call CopyMenuDataHeader + ld a, [MenuSelection] + ld [wMenuCursorBuffer], a + xor a + ld [hBGMapMode], a + call InitScrollingMenu + call UpdateSprites + call ScrollingMenu + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .nope + ld a, [MenuSelection] + cp -1 + jr nz, .done + +.nope + xor a + +.done + ld c, a + ret +; 88086 + +.MenuDataHeader: ; 0x88086 + db $40 ; flags + db 01, 01 ; start coords + db 10, 13 ; end coords + dw .MenuData2 + db 1 ; default option +; 0x8808e + + db 0 + +.MenuData2: ; 0x8808f + db $10 ; flags + db 4, 7 + db 1 + dbw 0, Buffer1 + dba .Name + dba .Quantity + dba NULL + +.Name: ; 8809f + ld a, [MenuSelection] + and a + ret z + farcall PlaceMenuItemName + ret +; 880ab + +.Quantity: ; 880ab + ld a, [MenuSelection] + ld [CurItem], a + call Kurt_GetQuantityOfApricorn + ret z + ld a, [wItemQuantityChangeBuffer] + ld [MenuSelectionQuantity], a + farcall PlaceMenuItemQuantity + ret +; 880c2 + +Kurt_SelectQuantity: ; 880c2 + ld a, [CurItem] + ld [MenuSelection], a + call Kurt_GetQuantityOfApricorn + jr z, .done + ld a, [wItemQuantityChangeBuffer] + ld [wItemQuantityBuffer], a + ld a, $1 + ld [wItemQuantityChangeBuffer], a + ld hl, .MenuDataHeader + call LoadMenuDataHeader +.loop + xor a + ld [hBGMapMode], a + call MenuBox + call UpdateSprites + call .PlaceApricornName + call PlaceApricornQuantity + call ApplyTilemap + farcall Kurt_SelectQuantity_InterpretJoypad + jr nc, .loop + + push bc + call PlayClickSFX + pop bc + ld a, b + cp -1 + jr z, .done + ld a, [wItemQuantityChangeBuffer] + ld [wItemQuantityChangeBuffer], a ; What is the point of this operation? + scf + +.done + call CloseWindow + ret +; 8810d + +.MenuDataHeader: ; 0x8810d + db $40 ; flags + db 09, 06 ; start coords + db 12, 19 ; end coords + + db 0, 0, -1, 0 ; XXX + +.PlaceApricornName: ; 88116 + call MenuBoxCoord2Tile + ld de, SCREEN_WIDTH + 1 + add hl, de + ld d, h + ld e, l + farcall PlaceMenuItemName + ret +; 88126 + +PlaceApricornQuantity: ; 88126 + call MenuBoxCoord2Tile + ld de, 2 * SCREEN_WIDTH + 10 + add hl, de + ld [hl], "×" + inc hl + ld de, wItemQuantityChangeBuffer + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + jp PrintNum +; 88139 + +Kurt_GetQuantityOfApricorn: ; 88139 + push bc + ld hl, NumItems + ld a, [CurItem] + ld c, a + ld b, $0 +.loop + inc hl + ld a, [hli] + cp -1 + jr z, .done + cp c + jr nz, .loop + ld a, [hl] + add b + ld b, a + jr nc, .loop + ld b, -1 + +.done + ld a, b + sub 99 + jr c, .done2 + ld b, 99 + +.done2 + ld a, b + ld [wItemQuantityChangeBuffer], a + and a + pop bc + ret +; 88161 + +Kurt_GiveUpSelectedQuantityOfSelectedApricorn: ; 88161 +; Get the quantity of Apricorns of type [CurItem] +; in the bag. Compatible with multiple stacks. + +; Initialize the search. + push de + push bc + ld hl, NumItems + ld a, [CurItem] + ld c, a + ld e, $0 + xor a + ld [CurItemQuantity], a + ld a, -1 + ld [wApricorns], a + +; Search for [CurItem] in the bag. +.loop1 +; Increase the total count. + ld a, [CurItemQuantity] + inc a + ld [CurItemQuantity], a +; Get the index of the next item. + inc hl + ld a, [hli] +; If we've reached the end of the pocket, break. + cp -1 + jr z, .okay1 +; If we haven't found what we're looking for, continue. + cp c + jr nz, .loop1 +; Increment the result counter and store the bag index of the match. + ld d, $0 + push hl + ld hl, wApricorns + add hl, de + inc e + ld a, [CurItemQuantity] + dec a + ld [hli], a + ld a, -1 + ld [hl], a + pop hl + jr .loop1 + +.okay1 +; How many stacks have we found? + ld a, e + and a + jr z, .done + dec a + jr z, .OnlyOne + ld hl, wApricorns + +.loop2 + ld a, [hl] + ld c, a + push hl +.loop3 + inc hl + ld a, [hl] + cp -1 + jr z, .okay2 + ld b, a + ld a, c + call Kurt_GetAddressOfApricornQuantity + ld e, a + ld a, b + call Kurt_GetAddressOfApricornQuantity + sub e + jr z, .equal + jr c, .less + jr .loop3 + +.equal + ld a, c + sub b + jr nc, .loop3 + +.less + ld a, c + ld c, b + ld [hl], a + ld a, c + pop hl + ld [hl], a + push hl + jr .loop3 + +.okay2 + pop hl + inc hl + ld a, [hl] + cp -1 + jr nz, .loop2 + +.OnlyOne: + ld hl, wApricorns +.loop4 + ld a, [hl] + cp -1 + jr z, .done + push hl + ld [CurItemQuantity], a + call Kurt_GetRidOfItem + pop hl + ld a, [wItemQuantityChangeBuffer] + and a + jr z, .done + push hl + ld a, [hli] + ld c, a +.loop5 + ld a, [hli] + cp -1 + jr z, .okay3 + cp c + jr c, .loop5 + dec a + dec hl + ld [hli], a + jr .loop5 + +.okay3 + pop hl + inc hl + jr .loop4 + +.done + ld a, [wItemQuantityChangeBuffer] + and a + pop bc + pop de + ret +; 88201 + +Kurt_GetAddressOfApricornQuantity: ; 88201 + push hl + push bc + ld hl, NumItems + inc hl + ld c, a + ld b, $0 + add hl, bc + add hl, bc + inc hl + ld a, [hl] + pop bc + pop hl + ret +; 88211 + +Kurt_GetRidOfItem: ; 88211 + push bc + ld hl, NumItems + ld a, [CurItemQuantity] + ld c, a + ld b, $0 + inc hl + add hl, bc + add hl, bc + ld a, [CurItem] + ld c, a + ld a, [hli] + cp -1 + jr z, .done + cp c + jr nz, .done + ld a, [wItemQuantityChangeBuffer] + ld c, a + ld a, [hl] + sub c + ld b, c + jr nc, .okay + add c + ld b, a + +.okay + push bc + ld hl, NumItems + ld a, b + ld [wItemQuantityChangeBuffer], a + call TossItem + pop bc + ld a, c + sub b + +.done + ld [wItemQuantityChangeBuffer], a + pop bc + ret +; 88248 diff --git a/engine/routines/kurt_selectquantity_interpretjoypad.asm b/engine/events/kurt_selectquantity_interpretjoypad.asm index 12a43e325..12a43e325 100644 --- a/engine/routines/kurt_selectquantity_interpretjoypad.asm +++ b/engine/events/kurt_selectquantity_interpretjoypad.asm diff --git a/engine/events/lucky_number.asm b/engine/events/lucky_number.asm new file mode 100644 index 000000000..4488cfcc9 --- /dev/null +++ b/engine/events/lucky_number.asm @@ -0,0 +1,226 @@ +Special_CheckForLuckyNumberWinners: ; 4d87a + xor a + ld [ScriptVar], a + ld [wFoundMatchingIDInParty], a + ld a, [PartyCount] + and a + ret z + ld d, a + ld hl, PartyMon1ID + ld bc, PartySpecies +.PartyLoop: + ld a, [bc] + inc bc + cp EGG + call nz, .CompareLuckyNumberToMonID + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + dec d + jr nz, .PartyLoop + ld a, BANK(sBox) + call GetSRAMBank + ld a, [sBoxCount] + and a + jr z, .SkipOpenBox + ld d, a + ld hl, sBoxMon1ID + ld bc, sBoxSpecies +.OpenBoxLoop: + ld a, [bc] + inc bc + cp EGG + jr z, .SkipOpenBoxMon + call .CompareLuckyNumberToMonID + jr nc, .SkipOpenBoxMon + ld a, 1 + ld [wFoundMatchingIDInParty], a + +.SkipOpenBoxMon: + push bc + ld bc, BOXMON_STRUCT_LENGTH + add hl, bc + pop bc + dec d + jr nz, .OpenBoxLoop + +.SkipOpenBox: + call CloseSRAM + ld c, $0 +.BoxesLoop: + ld a, [wCurBox] + and $f + cp c + jr z, .SkipBox + ld hl, .BoxBankAddresses + ld b, 0 + add hl, bc + add hl, bc + add hl, bc + ld a, [hli] + call GetSRAMBank + ld a, [hli] + ld h, [hl] + ld l, a ; hl now contains the address of the loaded box in SRAM + ld a, [hl] + and a + jr z, .SkipBox ; no mons in this box + push bc + ld b, h + ld c, l + inc bc + ld de, sBoxMon1ID - sBox + add hl, de + ld d, a +.BoxNLoop: + ld a, [bc] + inc bc + cp EGG + jr z, .SkipBoxMon + + call .CompareLuckyNumberToMonID ; sets ScriptVar and CurPartySpecies appropriately + jr nc, .SkipBoxMon + ld a, 1 + ld [wFoundMatchingIDInParty], a + +.SkipBoxMon: + push bc + ld bc, BOXMON_STRUCT_LENGTH + add hl, bc + pop bc + dec d + jr nz, .BoxNLoop + pop bc + +.SkipBox: + inc c + ld a, c + cp NUM_BOXES + jr c, .BoxesLoop + + call CloseSRAM + ld a, [ScriptVar] + and a + ret z ; found nothing + farcall TrainerRankings_LuckyNumberShow + ld a, [wFoundMatchingIDInParty] + and a + push af + ld a, [CurPartySpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, .FoundPartymonText + pop af + jr z, .print + ld hl, .FoundBoxmonText + +.print + jp PrintText + +.CompareLuckyNumberToMonID: ; 4d939 + push bc + push de + push hl + ld d, h + ld e, l + ld hl, Buffer1 + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + ld hl, LuckyNumberDigit1Buffer + ld de, wLuckyIDNumber + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + ld b, 5 + ld c, 0 + ld hl, LuckyNumberDigit5Buffer + ld de, Buffer5 +.loop + ld a, [de] + cp [hl] + jr nz, .done + dec de + dec hl + inc c + dec b + jr nz, .loop + +.done + pop hl + push hl + ld de, -6 + add hl, de + ld a, [hl] + pop hl + pop de + push af + ld a, c + ld b, 1 + cp 5 + jr z, .okay + ld b, 2 + cp 3 + jr nc, .okay + ld b, 3 + cp 2 + jr nz, .nomatch + +.okay + inc b + ld a, [ScriptVar] + and a + jr z, .bettermatch + cp b + jr c, .nomatch + +.bettermatch + dec b + ld a, b + ld [ScriptVar], a + pop bc + ld a, b + ld [CurPartySpecies], a + pop bc + scf + ret + +.nomatch + pop bc + pop bc + and a + ret + +.BoxBankAddresses: ; 4d99f + dba sBox1 + dba sBox2 + dba sBox3 + dba sBox4 + dba sBox5 + dba sBox6 + dba sBox7 + dba sBox8 + dba sBox9 + dba sBox10 + dba sBox11 + dba sBox12 + dba sBox13 + dba sBox14 + +.FoundPartymonText: ; 0x4d9c9 + ; Congratulations! We have a match with the ID number of @ in your party. + text_jump UnknownText_0x1c1261 + db "@" + +.FoundBoxmonText: ; 0x4d9ce + ; Congratulations! We have a match with the ID number of @ in your PC BOX. + text_jump UnknownText_0x1c12ae + db "@" + +Special_PrintTodaysLuckyNumber: ; 4d9d3 + ld hl, StringBuffer3 + ld de, wLuckyIDNumber + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + ld a, "@" + ld [StringBuffer3 + 5], a + ret diff --git a/engine/events/magikarp.asm b/engine/events/magikarp.asm new file mode 100644 index 000000000..02c4b10cd --- /dev/null +++ b/engine/events/magikarp.asm @@ -0,0 +1,342 @@ +Special_CheckMagikarpLength: ; fbb32 + ; Returns 3 if you select a Magikarp that beats the previous record. + ; Returns 2 if you select a Magikarp, but the current record is longer. + ; Returns 1 if you press B in the Pokemon selection menu. + ; Returns 0 if the Pokemon you select is not a Magikarp. + + ; Let's start by selecting a Magikarp. + farcall SelectMonFromParty + jr c, .declined + ld a, [CurPartySpecies] + cp MAGIKARP + jr nz, .not_magikarp + + ; Now let's compute its length based on its DVs and ID. + ld a, [CurPartyMon] + ld hl, PartyMon1Species + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + push hl + ld bc, MON_DVS + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, MON_ID + add hl, bc + ld b, h + ld c, l + call CalcMagikarpLength + call PrintMagikarpLength + farcall TrainerRankings_MagikarpLength + ld hl, .MeasureItText + call PrintText + + ; Did we beat the record? + ld hl, wMagikarpLength + ld de, wBestMagikarpLengthFeet + ld c, 2 + call StringCmp + jr nc, .not_long_enough + + ; NEW RECORD!!! Let's save that. + ld hl, wMagikarpLength + ld de, wBestMagikarpLengthFeet + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + ld a, [CurPartyMon] + ld hl, PartyMonOT + call SkipNames + call CopyBytes + ld a, 3 + ld [ScriptVar], a + ret + +.not_long_enough + ld a, 2 + ld [ScriptVar], a + ret + +.declined + ld a, 1 + ld [ScriptVar], a + ret + +.not_magikarp + xor a + ld [ScriptVar], a + ret +; fbba9 + +.MeasureItText: ; 0xfbba9 + ; Let me measure that MAGIKARP. …Hm, it measures @ . + text_jump UnknownText_0x1c1203 + db "@" +; 0xfbbae + +Magikarp_LoadFeetInchesChars: ; fbbae + ld hl, VTiles2 tile "′" ; $6e + ld de, .feetinchchars + lb bc, BANK(.feetinchchars), 2 + call Request2bpp + ret +; fbbbb + +.feetinchchars ; fbbb +INCBIN "gfx/font/feet_inches.2bpp" +; fbbdb + +PrintMagikarpLength: ; fbbdb + call Magikarp_LoadFeetInchesChars + ld hl, StringBuffer1 + ld de, wMagikarpLength + lb bc, PRINTNUM_RIGHTALIGN | 1, 2 + call PrintNum + ld [hl], "′" + inc hl + ld de, wMagikarpLength + 1 + lb bc, PRINTNUM_RIGHTALIGN | 1, 2 + call PrintNum + ld [hl], "″" + inc hl + ld [hl], "@" + ret +; fbbfc + +CalcMagikarpLength: ; fbbfc +; Return Magikarp's length (in mm) at wMagikarpLength (big endian). +; +; input: +; de: EnemyMonDVs +; bc: PlayerID + +; This function is poorly commented. + +; In short, it generates a value between 190 and 1786 using +; a Magikarp's DVs and its trainer ID. This value is further +; filtered in LoadEnemyMon to make longer Magikarp even rarer. + +; The value is generated from a lookup table. +; The index is determined by the dv xored with the player's trainer id. + +; bc = rrc(dv[0]) ++ rrc(dv[1]) ^ rrc(id) + +; if bc < 10: [wMagikarpLength] = c + 190 +; if bc ≥ $ff00: [wMagikarpLength] = c + 1370 +; else: [wMagikarpLength] = z * 100 + (bc - x) / y + +; X, Y, and Z depend on the value of b as follows: + +; if b = 0: x = 310, y = 2, z = 3 +; if b = 1: x = 710, y = 4, z = 4 +; if b = 2-9: x = 2710, y = 20, z = 5 +; if b = 10-29: x = 7710, y = 50, z = 6 +; if b = 30-68: x = 17710, y = 100, z = 7 +; if b = 69-126: x = 32710, y = 150, z = 8 +; if b = 127-185: x = 47710, y = 150, z = 9 +; if b = 186-224: x = 57710, y = 100, z = 10 +; if b = 225-243: x = 62710, y = 50, z = 11 +; if b = 244-251: x = 64710, y = 20, z = 12 +; if b = 252-253: x = 65210, y = 5, z = 13 +; if b = 254: x = 65410, y = 2, z = 14 + + + ; bc = rrc(dv[0]) ++ rrc(dv[1]) ^ rrc(id) + + ; id + ld h, b + ld l, c + ld a, [hli] + ld b, a + ld c, [hl] + rrc b + rrc c + + ; dv + ld a, [de] + inc de + rrca + rrca + xor b + ld b, a + + ld a, [de] + rrca + rrca + xor c + ld c, a + + ; if bc < 10: + ; de = bc + 190 + ; break + + ld a, b + and a + jr nz, .no + ld a, c + cp 10 + jr nc, .no + + ld hl, 190 + add hl, bc + ld d, h + ld e, l + jr .done + +.no + + ld hl, .Lengths + ld a, 2 + ld [wd265], a + +.read + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + call .BCLessThanDE + jr nc, .next + + ; c = (bc - de) / [hl] + call .BCMinusDE + ld a, b + ld [hDividend + 0], a + ld a, c + ld [hDividend + 1], a + ld a, [hl] + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 2] + ld c, a + + ; de = c + 100 × (2 + i) + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, 100 + ld [hMultiplicand + 2], a + ld a, [wd265] + ld [hMultiplier], a + call Multiply + ld b, 0 + ld a, [hProduct + 3] + add c + ld e, a + ld a, [hProduct + 2] + adc b + ld d, a + jr .done + +.next + inc hl ; align to next triplet + ld a, [wd265] + inc a + ld [wd265], a + cp 16 + jr c, .read + + call .BCMinusDE + ld hl, 1600 + add hl, bc + ld d, h + ld e, l + +.done + ; hl = de × 10 + ld h, d + ld l, e + add hl, hl + add hl, hl + add hl, de + add hl, hl + + ; hl = hl / 254 + ld de, -254 + ld a, -1 +.div_254 + inc a + add hl, de + jr c, .div_254 + + ; d, e = hl / 12, hl % 12 + ld d, 0 +.mod_12 + cp 12 + jr c, .ok + sub 12 + inc d + jr .mod_12 +.ok + ld e, a + + ld hl, wMagikarpLength + ld [hl], d + inc hl + ld [hl], e + ret +; fbc9a + +.BCLessThanDE: ; fbc9a +; Intention: Return bc < de. +; Reality: Return b < d. + ld a, b + cp d + ret c + ret nc ; whoops + ld a, c + cp e + ret +; fbca1 + +.BCMinusDE: ; fbca1 +; bc -= de + ld a, c + sub e + ld c, a + ld a, b + sbc d + ld b, a + ret +; fbca8 + +.Lengths: ; fbca8 +; ????, divisor + dwb 110, 1 + dwb 310, 2 + dwb 710, 4 + dwb 2710, 20 + dwb 7710, 50 + dwb 17710, 100 + dwb 32710, 150 + dwb 47710, 150 + dwb 57710, 100 + dwb 62710, 50 + dwb 64710, 20 + dwb 65210, 5 + dwb 65410, 2 + dwb 65510, 1 ; not used +; fbcd2 + + + +Special_MagikarpHouseSign: ; fbcd2 + ld a, [wBestMagikarpLengthFeet] + ld [wMagikarpLength], a + ld a, [wBestMagikarpLengthInches] + ld [wMagikarpLength + 1], a + call PrintMagikarpLength + ld hl, .CurrentRecordtext + call PrintText + ret +; fbce8 + +.CurrentRecordtext: ; 0xfbce8 + ; "CURRENT RECORD" + text_jump UnknownText_0x1c123a + db "@" +; 0xfbced diff --git a/engine/events/magnet_train.asm b/engine/events/magnet_train.asm new file mode 100755 index 000000000..3a2f902c2 --- /dev/null +++ b/engine/events/magnet_train.asm @@ -0,0 +1,482 @@ +Special_MagnetTrain: ; 8cc04 + ld a, [ScriptVar] + and a + jr nz, .ToGoldenrod + ld a, 1 ; forwards + lb bc, $40, $60 + lb de, (11 * 8) - (11 * 8 + 4), -$60 + jr .continue + +.ToGoldenrod: + ld a, -1 ; backwards + lb bc, -$40, -$60 + lb de, (11 * 8) + (11 * 8 + 4), $60 + +.continue + ld h, a + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + + ld a, h + ld [wMagnetTrainDirection], a + ld a, c + ld [wMagnetTrainInitPosition], a + ld a, b + ld [wMagnetTrainHoldPosition], a + ld a, e + ld [wMagnetTrainFinalPosition], a + ld a, d + ld [wMagnetTrainPlayerSpriteInitX], a + + ld a, [hSCX] + push af + ld a, [hSCY] + push af + call MagntTrain_LoadGFX_PlayMusic + ld hl, hVBlank + ld a, [hl] + push af + ld [hl], $1 +.loop + ld a, [wJumptableIndex] + and a + jr z, .initialize + bit 7, a + jr nz, .done + callfar PlaySpriteAnimations + call MagnetTrain_Jumptable + call MagnetTrain_UpdateLYOverrides + call PushLYOverrides + call DelayFrame + jr .loop + +.initialize + call MagnetTrain_Jumptable_FirstRunThrough + jr .loop + +.done + pop af + ld [hVBlank], a + call ClearBGPalettes + xor a + ld [hLCDCPointer], a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a + ld [hSCX], a + ld [Requested2bppSource], a + ld [Requested2bppSource + 1], a + ld [Requested2bppDest], a + ld [Requested2bppDest + 1], a + ld [Requested2bpp], a + call ClearTileMap + + pop af + ld [hSCY], a + pop af + ld [hSCX], a + xor a + ld [hBGMapMode], a + pop af + ld [rSVBK], a + ret +; 8cc99 + +MagnetTrain_UpdateLYOverrides: ; 8cc99 + ld hl, LYOverridesBackup + ld c, $2f + ld a, [wcf64] + add a + ld [hSCX], a + call .loadloop + ld c, $30 + ld a, [wcf65] + call .loadloop + ld c, $31 + ld a, [wcf64] + add a + call .loadloop + ld a, [wMagnetTrainDirection] + ld d, a + ld hl, wcf64 + ld a, [hl] + add d + add d + ld [hl], a + ret + +.loadloop + ld [hli], a + dec c + jr nz, .loadloop + ret +; 8ccc9 + +MagntTrain_LoadGFX_PlayMusic: ; 8ccc9 + call ClearBGPalettes + call ClearSprites + call DisableLCD + callfar ClearSpriteAnims + call SetMagnetTrainPals + call DrawMagnetTrain + ld a, $90 + ld [hWY], a + call EnableLCD + xor a + ld [hBGMapMode], a + ld [hSCX], a + ld [hSCY], a + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + farcall GetPlayerIcon + pop af + ld [rSVBK], a + ld hl, VTiles0 + ld c, 4 + call Request2bpp + ld hl, 12 tiles + add hl, de + ld d, h + ld e, l + ld hl, VTiles0 tile $04 + ld c, 4 + call Request2bpp + call MagnetTrain_InitLYOverrides + ld hl, wJumptableIndex + xor a + ld [hli], a + ld a, [wMagnetTrainInitPosition] + ld [hli], a + ld [hli], a + ld [hli], a + ld de, MUSIC_MAGNET_TRAIN + call PlayMusic2 + ret +; 8cd27 + +DrawMagnetTrain: ; 8cd27 + hlbgcoord 0, 0 + xor a +.loop + call GetMagnetTrainBGTiles + ld b, 32 / 2 + call .FillAlt + inc a + cp $12 + jr c, .loop + hlbgcoord 0, 6 + ld de, MagnetTrainTilemap1 + ld c, 20 + call .FillLine + hlbgcoord 0, 7 + ld de, MagnetTrainTilemap2 + ld c, 20 + call .FillLine + hlbgcoord 0, 8 + ld de, MagnetTrainTilemap3 + ld c, 20 + call .FillLine + hlbgcoord 0, 9 + ld de, MagnetTrainTilemap4 + ld c, 20 + call .FillLine + ret +; 8cd65 + +.FillLine: ; 8cd65 + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .FillLine + ret +; 8cd6c + +.FillAlt: ; 8cd6c + ld [hl], e + inc hl + ld [hl], d + inc hl + dec b + jr nz, .FillAlt + ret +; 8cd74 + +GetMagnetTrainBGTiles: ; 8cd74 + push hl + ld e, a + ld d, 0 + ld hl, MagnetTrainBGTiles + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + pop hl + ret +; 8cd82 + +MagnetTrainBGTiles: ; 8cd82 +; Alternating tiles for each line +; of the Magnet Train tilemap. + db $4c, $4d ; bush + db $5c, $5d ; bush + db $4c, $4d ; bush + db $5c, $5d ; bush + db $08, $08 ; fence + db $18, $18 ; fence + db $1f, $1f ; track + db $31, $31 ; track + db $11, $11 ; track + db $11, $11 ; track + db $0d, $0d ; track + db $31, $31 ; track + db $04, $04 ; fence + db $18, $18 ; fence + db $4c, $4d ; bush + db $5c, $5d ; bush + db $4c, $4d ; bush + db $5c, $5d ; bush +; 8cda6 + +MagnetTrain_InitLYOverrides: ; 8cda6 + ld hl, LYOverrides + ld bc, LYOverridesEnd - LYOverrides + ld a, [wMagnetTrainInitPosition] + call ByteFill + ld hl, LYOverridesBackup + ld bc, LYOverridesBackupEnd - LYOverridesBackup + ld a, [wMagnetTrainInitPosition] + call ByteFill + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + ret +; 8cdc3 + +SetMagnetTrainPals: ; 8cdc3 + ld a, $1 + ld [rVBK], a + + ; bushes + hlbgcoord 0, 0 + ld bc, 4 bgrows + ld a, $2 + call ByteFill + + ; train + hlbgcoord 0, 4 + ld bc, 10 bgrows + xor a + call ByteFill + + ; more bushes + hlbgcoord 0, 14 + ld bc, 4 bgrows + ld a, $2 + call ByteFill + + ; train window + hlbgcoord 7, 8 + ld bc, 6 + ld a, $4 + call ByteFill + + ld a, $0 + ld [rVBK], a + ret +; 8cdf7 + +MagnetTrain_Jumptable: ; 8cdf7 + ld a, [wJumptableIndex] + ld e, a + ld d, 0 + ld hl, .Jumptable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; 8ce06 + +.Jumptable: ; 8ce06 + + dw .InitPlayerSpriteAnim + dw .WaitScene + dw .MoveTrain1 + dw .WaitScene + dw .MoveTrain2 + dw .WaitScene + dw .TrainArrived +; 8ce14 + +.Next: ; 8ce14 + ld hl, wJumptableIndex + inc [hl] + ret +; 8ce19 + +.InitPlayerSpriteAnim: ; 8ce19 + ld d, 10 * 8 + 5 + ld a, [wMagnetTrainPlayerSpriteInitX] + ld e, a + ld b, SPRITE_ANIM_INDEX_MAGNET_TRAIN_RED + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + ld a, [PlayerGender] + bit 0, a + jr z, .got_gender + ld b, SPRITE_ANIM_INDEX_MAGNET_TRAIN_BLUE + +.got_gender + pop af + ld [rSVBK], a + ld a, b + call _InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $0 + call .Next + ld a, $80 + ld [wcf66], a + ret +; 8ce47 + +.MoveTrain1: ; 8ce47 + ld hl, wMagnetTrainHoldPosition + ld a, [wcf65] + cp [hl] + jr z, .PrepareToHoldTrain + ld e, a + ld a, [wMagnetTrainDirection] + xor $ff + inc a + add e + ld [wcf65], a + ld hl, wGlobalAnimXOffset + ld a, [wMagnetTrainDirection] + add [hl] + ld [hl], a + ret + +.PrepareToHoldTrain: + call .Next + ld a, $80 + ld [wcf66], a + ret +; 8ce6d + +.WaitScene: ; 8ce6d + ld hl, wcf66 + ld a, [hl] + and a + jr z, .DoneWaiting + dec [hl] + ret + +.DoneWaiting: + call .Next + ret +; 8ce7a + +.MoveTrain2: ; 8ce7a + ld hl, wMagnetTrainFinalPosition + ld a, [wcf65] + cp [hl] + jr z, .PrepareToFinishAnim + ld e, a + ld a, [wMagnetTrainDirection] + xor $ff + inc a + ld d, a + ld a, e + add d + add d + ld [wcf65], a + ld hl, wGlobalAnimXOffset + ld a, [wMagnetTrainDirection] + ld d, a + ld a, [hl] + add d + add d + ld [hl], a + ret + + ret + +.PrepareToFinishAnim: + call .Next + ret +; 8cea2 + +.TrainArrived: ; 8cea2 + ld a, $80 + ld [wJumptableIndex], a + ld de, SFX_TRAIN_ARRIVED + call PlaySFX + ret +; 8ceae + +MagnetTrain_Jumptable_FirstRunThrough: ; 8ceae + farcall PlaySpriteAnimations + call MagnetTrain_Jumptable + call MagnetTrain_UpdateLYOverrides + call PushLYOverrides + call DelayFrame + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + ld a, [TimeOfDayPal] + push af + ld a, [wEnvironment] + push af + ld a, [TimeOfDay] + and $3 + ld [TimeOfDayPal], a + ld a, $1 + ld [wEnvironment], a + ld b, SCGB_MAPPALS + call GetSGBLayout + call UpdateTimePals + ld a, [rBGP] + ld [wBGP], a + ld a, [rOBP0] + ld [wOBP0], a + ld a, [rOBP1] + ld [wOBP1], a + pop af + ld [wEnvironment], a + pop af + ld [TimeOfDayPal], a + pop af + ld [rSVBK], a + ret +; 8ceff + +MagnetTrainTilemap1: + db $1f, $05, $06, $0a, $0a + db $0a, $09, $0a, $0a, $0a + db $0a, $0a, $0a, $09, $0a + db $0a, $0a, $0b, $0c, $1f +MagnetTrainTilemap2: + db $14, $15, $16, $1a, $1a + db $1a, $19, $1a, $1a, $1a + db $1a, $1a, $1a, $19, $1a + db $1a, $1a, $1b, $1c, $1d +MagnetTrainTilemap3: + db $24, $25, $26, $27, $07 + db $2f, $29, $28, $28, $28 + db $28, $28, $28, $29, $07 + db $2f, $2a, $2b, $2c, $2d +MagnetTrainTilemap4: + db $20, $1f, $2e, $1f, $17 + db $00, $2e, $1f, $1f, $1f + db $1f, $1f, $1f, $2e, $17 + db $00, $1f, $2e, $1f, $0f +; 8cf4f diff --git a/engine/events/misc_scripts.asm b/engine/events/misc_scripts.asm new file mode 100755 index 000000000..97372a57a --- /dev/null +++ b/engine/events/misc_scripts.asm @@ -0,0 +1,62 @@ +Script_AbortBugContest: ; 0x122c1 + checkflag ENGINE_BUG_CONTEST_TIMER + iffalse .finish + setflag ENGINE_DAILY_BUG_CONTEST + special ContestReturnMons +.finish + end + +FindItemInBallScript:: ; 0x122ce + callasm .TryReceiveItem + iffalse .no_room + disappear LAST_TALKED + opentext + writetext .text_found + playsound SFX_ITEM + pause 60 + itemnotify + closetext + end +; 0x122e3 + +.no_room ; 0x122e3 + opentext + writetext .text_found + waitbutton + writetext .text_bag_full + waitbutton + closetext + end +; 0x122ee + +.text_found ; 0x122ee + ; found @ ! + text_jump UnknownText_0x1c0a1c + db "@" +; 0x122f3 + +.text_bag_full ; 0x122f3 + ; But can't carry any more items. + text_jump UnknownText_0x1c0a2c + db "@" +; 0x122f8 + +.TryReceiveItem: ; 122f8 + xor a + ld [ScriptVar], a + ld a, [EngineBuffer1] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, StringBuffer3 + call CopyName2 + ld a, [EngineBuffer1] + ld [CurItem], a + ld a, [CurFruit] + ld [wItemQuantityChangeBuffer], a + ld hl, NumItems + call ReceiveItem + ret nc + ld a, $1 + ld [ScriptVar], a + ret +; 12324 diff --git a/engine/events/misc_scripts_2.asm b/engine/events/misc_scripts_2.asm new file mode 100644 index 000000000..c4c51d5e6 --- /dev/null +++ b/engine/events/misc_scripts_2.asm @@ -0,0 +1,51 @@ +RepelWoreOffScript:: ; 0x13619 + opentext + writetext .text + waitbutton + closetext + end + +.text ; 0x13620 + ; REPEL's effect wore off. + text_jump UnknownText_0x1bd308 + db "@" + +HiddenItemScript:: ; 0x13625 + opentext + copybytetovar EngineBuffer3 + itemtotext 0, 0 + writetext .found_text + giveitem ITEM_FROM_MEM + iffalse .bag_full + callasm SetMemEvent + specialsound + itemnotify + jump .finish + +.bag_full ; 0x1363e + buttonsound + writetext .no_room_text + waitbutton + +.finish ; 13643 + closetext + end + +.found_text ; 0x13645 + ; found @ ! + text_jump UnknownText_0x1bd321 + db "@" + +.no_room_text ; 0x1364a + ; But has no space left… + text_jump UnknownText_0x1bd331 + db "@" + +SetMemEvent: ; 1364f + ld hl, EngineBuffer1 + ld a, [hli] + ld d, [hl] + ld e, a + ld b, SET_FLAG + call EventFlagAction + ret diff --git a/engine/events/mom.asm b/engine/events/mom.asm new file mode 100644 index 000000000..6e3c7b320 --- /dev/null +++ b/engine/events/mom.asm @@ -0,0 +1,745 @@ +Special_BankOfMom: ; 16218 + ld a, [hInMenu] + push af + ld a, $1 + ld [hInMenu], a + xor a + ld [wJumptableIndex], a +.loop + ld a, [wJumptableIndex] + bit 7, a + jr nz, .done + call .RunJumptable + jr .loop + +.done + pop af + ld [hInMenu], a + ret +; 16233 + +.RunJumptable: ; 16233 + ld a, [wJumptableIndex] + ld e, a + ld d, 0 + ld hl, .dw + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; 16242 + +.dw ; 16242 + + dw .CheckIfBankInitialized + dw .InitializeBank + dw .IsThisAboutYourMoney + dw .AccessBankOfMom + dw .StoreMoney + dw .TakeMoney + dw .StopOrStartSavingMoney + dw .AskDST + dw .JustDoWhatYouCan +; 16254 + +.CheckIfBankInitialized: ; 16254 + ld a, [wMomSavingMoney] + bit 7, a + jr nz, .savingmoneyalready + set 7, a + ld [wMomSavingMoney], a + ld a, $1 + jr .done_0 + +.savingmoneyalready + ld a, $2 + +.done_0 + ld [wJumptableIndex], a + ret +; 1626a + +.InitializeBank: ; 1626a + ld hl, UnknownText_0x16649 + call PrintText + call YesNoBox + jr c, .DontSaveMoney + ld hl, UnknownText_0x1664e + call PrintText + ld a, %10000001 + jr .done_1 + +.DontSaveMoney: + ld a, %10000000 + +.done_1 + ld [wMomSavingMoney], a + ld hl, UnknownText_0x16653 + call PrintText + ld a, $8 + ld [wJumptableIndex], a + ret +; 16290 + +.IsThisAboutYourMoney: ; 16290 + ld hl, UnknownText_0x16658 + call PrintText + call YesNoBox + jr c, .nope + ld a, $3 + jr .done_2 + +.nope + call DSTChecks + ld a, $7 + +.done_2 + ld [wJumptableIndex], a + ret +; 162a8 + +.AccessBankOfMom: ; 162a8 + ld hl, UnknownText_0x1665d + call PrintText + call LoadStandardMenuDataHeader + ld hl, MenuDataHeader_0x166b5 + call CopyMenuDataHeader + call VerticalMenu + call CloseWindow + jr c, .cancel + ld a, [wMenuCursorY] + cp $1 + jr z, .withdraw + cp $2 + jr z, .deposit + cp $3 + jr z, .stopsaving + +.cancel + ld a, $7 + jr .done_3 + +.withdraw + ld a, $5 + jr .done_3 + +.deposit + ld a, $4 + jr .done_3 + +.stopsaving + ld a, $6 + +.done_3 + ld [wJumptableIndex], a + ret +; 162e0 + +.StoreMoney: ; 162e0 + ld hl, UnknownText_0x16662 + call PrintText + xor a + ld hl, StringBuffer2 + ld [hli], a + ld [hli], a + ld [hl], a + ld a, $5 + ld [wcf64], a + call LoadStandardMenuDataHeader + call Mom_SetUpDepositMenu + call Mom_Wait10Frames + call Mom_WithdrawDepositMenuJoypad + call CloseWindow + jr c, .CancelDeposit + ld hl, StringBuffer2 + ld a, [hli] + or [hl] + inc hl + or [hl] + jr z, .CancelDeposit + ld de, Money + ld bc, StringBuffer2 + farcall CompareMoney + jr c, .DontHaveThatMuchToDeposit + ld hl, StringBuffer2 + ld de, StringBuffer2 + 3 + ld bc, 3 + call CopyBytes + ld bc, wMomsMoney + ld de, StringBuffer2 + farcall GiveMoney + jr c, .CantDepositThatMuch + ld bc, StringBuffer2 + 3 + ld de, Money + farcall TakeMoney + ld hl, StringBuffer2 + ld de, wMomsMoney + ld bc, 3 + call CopyBytes + ld de, SFX_TRANSACTION + call PlaySFX + call WaitSFX + ld hl, UnknownText_0x1668a + call PrintText + ld a, $8 + jr .done_4 + +.DontHaveThatMuchToDeposit: + ld hl, UnknownText_0x1667b + call PrintText + ret + +.CantDepositThatMuch: + ld hl, UnknownText_0x16680 + call PrintText + ret + +.CancelDeposit: + ld a, $7 + +.done_4 + ld [wJumptableIndex], a + ret +; 16373 + +.TakeMoney: ; 16373 + ld hl, UnknownText_0x16667 + call PrintText + xor a + ld hl, StringBuffer2 + ld [hli], a + ld [hli], a + ld [hl], a + ld a, $5 + ld [wcf64], a + call LoadStandardMenuDataHeader + call Mom_SetUpWithdrawMenu + call Mom_Wait10Frames + call Mom_WithdrawDepositMenuJoypad + call CloseWindow + jr c, .CancelWithdraw + ld hl, StringBuffer2 + ld a, [hli] + or [hl] + inc hl + or [hl] + jr z, .CancelWithdraw + ld hl, StringBuffer2 + ld de, StringBuffer2 + 3 + ld bc, 3 + call CopyBytes + ld de, wMomsMoney + ld bc, StringBuffer2 + farcall CompareMoney + jr c, .InsufficientFundsInBank + ld bc, Money + ld de, StringBuffer2 + farcall GiveMoney + jr c, .NotEnoughRoomInWallet + ld bc, StringBuffer2 + 3 + ld de, wMomsMoney + farcall TakeMoney + ld hl, StringBuffer2 + ld de, Money + ld bc, 3 + call CopyBytes + ld de, SFX_TRANSACTION + call PlaySFX + call WaitSFX + ld hl, UnknownText_0x1668f + call PrintText + ld a, $8 + jr .done_5 + +.InsufficientFundsInBank: + ld hl, UnknownText_0x16671 + call PrintText + ret + +.NotEnoughRoomInWallet: + ld hl, UnknownText_0x16676 + call PrintText + ret + +.CancelWithdraw: + ld a, $7 + +.done_5 + ld [wJumptableIndex], a + ret +; 16406 + +.StopOrStartSavingMoney: ; 16406 + ld hl, UnknownText_0x1666c + call PrintText + call YesNoBox + jr c, .StopSavingMoney + ld a, $81 + ld [wMomSavingMoney], a + ld hl, UnknownText_0x16685 + call PrintText + ld a, $8 + ld [wJumptableIndex], a + ret + +.StopSavingMoney: + ld a, $80 + ld [wMomSavingMoney], a + ld a, $7 + ld [wJumptableIndex], a + ret +; 1642d + +.AskDST: ; 1642d + ld hl, UnknownText_0x16694 + call PrintText + +.JustDoWhatYouCan: ; 16433 + ld hl, wJumptableIndex + set 7, [hl] + ret +; 16439 + +DSTChecks: ; 16439 +; check the time; avoid changing DST if doing so would change the current day + ld a, [wDST] + bit 7, a + ld a, [hHours] + jr z, .NotDST + and a ; within one hour of 00:00? + jr z, .LostBooklet + jr .loop + +.NotDST: + cp 23 ; within one hour of 23:00? + jr nz, .loop + ; fallthrough + +.LostBooklet: + call .ClearBox + bccoord 1, 14 + ld hl, .Text_AdjustClock + call PlaceHLTextAtBC + call YesNoBox + ret c + call .ClearBox + bccoord 1, 14 + ld hl, .Text_LostInstructionBooklet + call PlaceHLTextAtBC + ret + +.loop + call .ClearBox + bccoord 1, 14 + ld a, [wDST] + bit 7, a + jr z, .SetDST + ld hl, .Text_IsDSTOver + call PlaceHLTextAtBC + call YesNoBox + ret c + ld a, [wDST] + res 7, a + ld [wDST], a + call .SetClockBack + call .ClearBox + bccoord 1, 14 + ld hl, .Text_SetClockBack + call PlaceHLTextAtBC + ret + +.SetDST: + ld hl, .Text_SwitchToDST + call PlaceHLTextAtBC + call YesNoBox + ret c + ld a, [wDST] + set 7, a + ld [wDST], a + call .SetClockForward + call .ClearBox + bccoord 1, 14 + ld hl, .Text_SetClockForward + call PlaceHLTextAtBC + ret +; 164b9 + +.SetClockForward: ; 164b9 + ld a, [StartHour] + add 1 + sub 24 + jr nc, .DontLoopHourForward + add 24 +.DontLoopHourForward: + ld [StartHour], a + ccf + ld a, [StartDay] + adc 0 + ld [StartDay], a + ret +; 164d1 + +.SetClockBack: ; 164d1 + ld a, [StartHour] + sub 1 + jr nc, .DontLoopHourBack + add 24 +.DontLoopHourBack: + ld [StartHour], a + ld a, [StartDay] + sbc 0 + jr nc, .DontLoopDayBack + add 7 +.DontLoopDayBack: + ld [StartDay], a + ret +; 164ea + +.ClearBox: ; 164ea + hlcoord 1, 14 + lb bc, 3, 18 + call ClearBox + ret +; 164f4 + +.Text_AdjustClock: ; 0x164f4 + ; Do you want to adjust your clock for Daylight Saving Time? + text_jump UnknownText_0x1c6095 + db "@" +; 0x164f9 + +.Text_LostInstructionBooklet: ; 0x164f9 + ; I lost the instruction booklet for the POKéGEAR. + ; Come back again in a while. + text_jump UnknownText_0x1c60d1 + db "@" +; 0x164fe + +.Text_SwitchToDST: ; 0x164fe + ; Do you want to switch to Daylight Saving Time? + text_jump UnknownText_0x1c6000 + db "@" +; 0x16503 + +.Text_SetClockForward: ; 0x16503 + ; I set the clock forward by one hour. + text_jump UnknownText_0x1c6030 + db "@" +; 0x16508 + +.Text_IsDSTOver: ; 0x16508 + ; Is Daylight Saving Time over? + text_jump UnknownText_0x1c6056 + db "@" +; 0x1650d + +.Text_SetClockBack: ; 0x1650d + ; I put the clock back one hour. + text_jump UnknownText_0x1c6075 + db "@" +; 0x16512 + +Mom_SetUpWithdrawMenu: ; 16512 + ld de, Mon_WithdrawString + jr Mom_ContinueMenuSetup + +Mom_SetUpDepositMenu: ; 16517 + ld de, Mom_DepositString +Mom_ContinueMenuSetup: ; 1651a + push de + xor a + ld [hBGMapMode], a + hlcoord 0, 0 + lb bc, 6, 18 + call TextBox + hlcoord 1, 2 + ld de, Mom_SavedString + call PlaceString + hlcoord 12, 2 + ld de, wMomsMoney + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + hlcoord 1, 4 + ld de, Mom_HeldString + call PlaceString + hlcoord 12, 4 + ld de, Money + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + hlcoord 1, 6 + pop de + call PlaceString + hlcoord 12, 6 + ld de, StringBuffer2 + lb bc, PRINTNUM_MONEY | PRINTNUM_LEADINGZEROS | 3, 6 + call PrintNum + call UpdateSprites + call CGBOnly_CopyTilemapAtOnce + ret +; 1656b + +Mom_Wait10Frames: ; 1656b + ld c, 10 + call DelayFrames + ret +; 16571 + +Mom_WithdrawDepositMenuJoypad: ; 16571 +.loop + call JoyTextDelay + ld hl, hJoyPressed + ld a, [hl] + and B_BUTTON + jr nz, .pressedB + ld a, [hl] + and A_BUTTON + jr nz, .pressedA + call .dpadaction + xor a + ld [hBGMapMode], a + hlcoord 12, 6 + ld bc, 7 + ld a, " " + call ByteFill + hlcoord 12, 6 + ld de, StringBuffer2 + lb bc, PRINTNUM_MONEY | PRINTNUM_LEADINGZEROS | 3, 6 + call PrintNum + ld a, [hVBlankCounter] + and $10 + jr nz, .skip + hlcoord 13, 6 + ld a, [wMomBankDigitCursorPosition] + ld c, a + ld b, 0 + add hl, bc + ld [hl], " " + +.skip + call WaitBGMap + jr .loop + +.pressedB + scf + ret + +.pressedA + and a + ret + +.dpadaction + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .incrementdigit + ld a, [hl] + and D_DOWN + jr nz, .decrementdigit + ld a, [hl] + and D_LEFT + jr nz, .movecursorleft + ld a, [hl] + and D_RIGHT + jr nz, .movecursorright + and a + ret + +.movecursorleft + ld hl, wMomBankDigitCursorPosition + ld a, [hl] + and a + ret z + dec [hl] + ret + +.movecursorright + ld hl, wMomBankDigitCursorPosition + ld a, [hl] + cp 5 + ret nc + inc [hl] + ret + +.incrementdigit + ld hl, .DigitQuantities + call .getdigitquantity + ld c, l + ld b, h + ld de, StringBuffer2 + farcall GiveMoney + ret + +.decrementdigit + ld hl, .DigitQuantities + call .getdigitquantity + ld c, l + ld b, h + ld de, StringBuffer2 + farcall TakeMoney + ret + +.getdigitquantity + ld a, [wMomBankDigitCursorPosition] + push de + ld e, a + ld d, 0 + add hl, de + add hl, de + add hl, de + pop de + ret +; 16613 + +.DigitQuantities: ; 16613 + dt 100000 + dt 10000 + dt 1000 + dt 100 + dt 10 + dt 1 + + dt 100000 + dt 10000 + dt 1000 + dt 100 + dt 10 + dt 1 + + dt 900000 + dt 90000 + dt 9000 + dt 900 + dt 90 + dt 9 +; 16649 + +UnknownText_0x16649: ; 0x16649 + ; Wow, that's a cute #MON. Where did you get it? … So, you're leaving on an adventure… OK! I'll help too. But what can I do for you? I know! I'll save money for you. On a long journey, money's important. Do you want me to save your money? + text_jump UnknownText_0x1bd77f + db "@" +; 0x1664e + +UnknownText_0x1664e: ; 0x1664e + ; OK, I'll take care of your money. + text_jump UnknownText_0x1bd868 + db "@" +; 0x16653 + +UnknownText_0x16653: ; 0x16653 + ; Be careful. #MON are your friends. You need to work as a team. Now, go on! + text_jump UnknownText_0x1bd88e + db "@" +; 0x16658 + +UnknownText_0x16658: ; 0x16658 + ; Hi! Welcome home! You're trying very hard, I see. I've kept your room tidy. Or is this about your money? + text_jump UnknownText_0x1bd8da + db "@" +; 0x1665d + +UnknownText_0x1665d: ; 0x1665d + ; What do you want to do? + text_jump UnknownText_0x1bd942 + db "@" +; 0x16662 + +UnknownText_0x16662: ; 0x16662 + ; How much do you want to save? + text_jump UnknownText_0x1bd95b + db "@" +; 0x16667 + +UnknownText_0x16667: ; 0x16667 + ; How much do you want to take? + text_jump UnknownText_0x1bd97a + db "@" +; 0x1666c + +UnknownText_0x1666c: ; 0x1666c + ; Do you want to save some money? + text_jump UnknownText_0x1bd999 + db "@" +; 0x16671 + +UnknownText_0x16671: ; 0x16671 + ; You haven't saved that much. + text_jump UnknownText_0x1bd9ba + db "@" +; 0x16676 + +UnknownText_0x16676: ; 0x16676 + ; You can't take that much. + text_jump UnknownText_0x1bd9d7 + db "@" +; 0x1667b + +UnknownText_0x1667b: ; 0x1667b + ; You don't have that much. + text_jump UnknownText_0x1bd9f1 + db "@" +; 0x16680 + +UnknownText_0x16680: ; 0x16680 + ; You can't save that much. + text_jump UnknownText_0x1bda0b + db "@" +; 0x16685 + +UnknownText_0x16685: ; 0x16685 + ; OK, I'll save your money. Trust me! , stick with it! + text_jump UnknownText_0x1bda25 + db "@" +; 0x1668a + +UnknownText_0x1668a: ; 0x1668a + ; Your money's safe here! Get going! + text_jump UnknownText_0x1bda5b + db "@" +; 0x1668f + +UnknownText_0x1668f: ; 0x1668f + ; , don't give up! + text_jump UnknownText_0x1bda7e + db "@" +; 0x16694 + +UnknownText_0x16694: ; 0x16694 + ; Just do what you can. + text_jump UnknownText_0x1bda90 + db "@" +; 0x16699 + +Mom_SavedString: ; 16699 + db "SAVED@" +; 1669f + +Mon_WithdrawString: ; 1669f + db "WITHDRAW@" +; 166a8 + +Mom_DepositString: ; 166a8 + db "DEPOSIT@" +; 166b0 + +Mom_HeldString: ; 166b0 + db "HELD@" +; 166b5 + +MenuDataHeader_0x166b5: ; 0x166b5 + db $40 ; flags + db 00, 00 ; start coords + db 10, 10 ; end coords + dw MenuData2_0x166bd + db 1 ; default option +; 0x166bd + +MenuData2_0x166bd: ; 0x166bd + db $80 ; flags + db 4 ; items + db "GET@" + db "SAVE@" + db "CHANGE@" + db "CANCEL@" +; 0x166d6 diff --git a/engine/events/mom_phone.asm b/engine/events/mom_phone.asm new file mode 100755 index 000000000..bef7d5688 --- /dev/null +++ b/engine/events/mom_phone.asm @@ -0,0 +1,264 @@ +NUM_MOM_ITEMS_1 EQUS "((MomItems_1End - MomItems_1) / 8)" +NUM_MOM_ITEMS_2 EQUS "((MomItems_2End - MomItems_2) / 8)" + +const_value = 1 + const MOM_ITEM + const MOM_DOLL + +MomTriesToBuySomething:: ; fcfec + ld a, [wMapReentryScriptQueueFlag] + and a + ret nz + call GetMapHeaderPhoneServiceNybble + and a + ret nz + xor a + ld [wWhichMomItemSet], a + call CheckBalance_MomItem2 + ret nc + call Mom_GiveItemOrDoll + ret nc + ld b, BANK(.Script) + ld de, .Script + farcall LoadScriptBDE + scf + ret +; fd00f + +.Script: ; 0xfd00f + callasm .ASMFunction + farjump Script_ReceivePhoneCall +; 0xfd017 + +.ASMFunction: ; fd017 + call MomBuysItem_DeductFunds + call Mom_GetScriptPointer + ld a, [wWhichMomItemSet] + and a + jr nz, .ok + ld hl, wWhichMomItem + inc [hl] +.ok + ld a, PHONE_MOM + ld [wCurrentCaller], a + ld bc, EngineBuffer2 + ld hl, 0 + add hl, bc + ld [hl], 0 + inc hl + ld [hl], 1 + ld hl, wPhoneScriptPointer - EngineBuffer2 + add hl, bc + ld a, BANK(Mom_GetScriptPointer) + ld [hli], a + ld a, e + ld [hli], a + ld a, d + ld [hl], a + ret +; fd044 + +CheckBalance_MomItem2: ; fd044 + ld a, [wWhichMomItem] + cp NUM_MOM_ITEMS_2 + jr nc, .nope + call GetItemFromMom + ld a, [hli] + ld [hMoneyTemp], a + ld a, [hli] + ld [hMoneyTemp + 1], a + ld a, [hli] + ld [hMoneyTemp + 2], a + ld de, wMomsMoney + ld bc, hMoneyTemp + farcall CompareMoney + jr nc, .have_enough_money + +.nope + jr .check_have_2300 + +.have_enough_money + scf + ret + +.check_have_2300 + ld hl, hMoneyTemp + ld [hl], HIGH(MOM_MONEY >> 8) + inc hl + ld [hl], HIGH(MOM_MONEY) ; mid + inc hl + ld [hl], LOW(MOM_MONEY) +.loop + ld de, MomItemTriggerBalance + ld bc, wMomsMoney + farcall CompareMoney + jr z, .exact + jr nc, .less_than + call .AddMoney + jr .loop + +.less_than + xor a + ret + +.exact + call .AddMoney + ld a, NUM_MOM_ITEMS_1 + call RandomRange + inc a + ld [wWhichMomItemSet], a + scf + ret + +.AddMoney: + ld de, MomItemTriggerBalance + ld bc, hMoneyTemp + farcall AddMoney + ret +; fd0a6 + + +MomBuysItem_DeductFunds: ; fd0a6 (3f:50a6) + call GetItemFromMom + ld de, 3 ; cost + add hl, de + ld a, [hli] + ld [hMoneyTemp], a + ld a, [hli] + ld [hMoneyTemp + 1], a + ld a, [hli] + ld [hMoneyTemp + 2], a + ld de, wMomsMoney + ld bc, hMoneyTemp + farcall TakeMoney + ret + + +Mom_GiveItemOrDoll: ; fd0c3 + call GetItemFromMom + ld de, 6 ; item type + add hl, de + ld a, [hli] + cp MOM_ITEM + jr z, .not_doll + ld a, [hl] + ld c, a + ld b, 1 + farcall DecorationFlagAction_c + scf + ret + +.not_doll + ld a, [hl] + ld [CurItem], a + ld a, 1 + ld [wItemQuantityChangeBuffer], a + ld hl, PCItems + call ReceiveItem + ret +; fd0eb + + +Mom_GetScriptPointer: ; fd0eb (3f:50eb) + call GetItemFromMom + ld de, 6 ; item type + add hl, de + ld a, [hli] + ld de, .ItemScript + cp MOM_ITEM + ret z + ld de, .DollScript + ret +; fd0fd (3f:50fd) + +.ItemScript: ; 0xfd0fd + writetext _MomText_HiHowAreYou + writetext _MomText_FoundAnItem + writetext _MomText_BoughtWithYourMoney + writetext _MomText_ItsInPC + end +; 0xfd10a + +.DollScript: ; 0xfd10a + writetext _MomText_HiHowAreYou + writetext _MomText_FoundADoll + writetext _MomText_BoughtWithYourMoney + writetext _MomText_ItsInRoom + end +; 0xfd117 + + +GetItemFromMom: ; fd117 + ld a, [wWhichMomItemSet] + and a + jr z, .zero + dec a + ld de, MomItems_1 + jr .GetFromList1 + +.zero + ld a, [wWhichMomItem] + cp NUM_MOM_ITEMS_2 + jr c, .ok + xor a + +.ok + ld de, MomItems_2 + +.GetFromList1: + ld l, a + ld h, 0 +rept 3 ; multiply hl by 8 + add hl, hl +endr + add hl, de + ret +; fd136 + +INCLUDE "data/items/mom_phone.asm" + + db 0, 0, 0 ; XXX + +_MomText_HiHowAreYou: ; 0xfd1b1 + ; Hi, ! How are you? + text_jump UnknownText_0x1bc615 + db "@" +; 0xfd1b6 + +_MomText_FoundAnItem: ; 0xfd1b6 + ; I found a useful item shopping, so + text_jump UnknownText_0x1bc62a + db "@" +; 0xfd1bb + +_MomText_BoughtWithYourMoney: ; 0xfd1bb + ; I bought it with your money. Sorry! + text_jump UnknownText_0x1bc64e + db "@" +; 0xfd1c0 + +_MomText_ItsInPC: ; 0xfd1c0 + ; It's in your PC. You'll like it! + text_jump UnknownText_0x1bc673 + db "@" +; 0xfd1c5 + +_MomText_FoundADoll: ; 0xfd1c5 + ; While shopping today, I saw this adorable doll, so + text_jump UnknownText_0x1bc693 + db "@" +; 0xfd1ca + +_MomText_ItsInRoom: ; 0xfd1ca + ; It's in your room. You'll love it! + text_jump UnknownText_0x1bc6c7 + db "@" +; 0xfd1cf + + db 0 ; XXX + +Predef3A: ; fd1d0 + ret +; fd1d1 + + ret ; XXX diff --git a/engine/events/move_deleter.asm b/engine/events/move_deleter.asm new file mode 100644 index 000000000..95fc0f1d8 --- /dev/null +++ b/engine/events/move_deleter.asm @@ -0,0 +1,166 @@ +MoveDeletion: + ld hl, .IntroText + call PrintText + call YesNoBox + jr c, .declined + ld hl, .AskWhichMonText + call PrintText + farcall SelectMonFromParty + jr c, .declined + ld a, [CurPartySpecies] + cp EGG + jr z, .egg + ld a, [CurPartyMon] + ld hl, PartyMon1Moves + 1 + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld a, [hl] + and a + jr z, .onlyonemove + ld hl, .AskWhichMoveText + call PrintText + call LoadStandardMenuDataHeader + farcall ChooseMoveToDelete + push af + call ReturnToMapWithSpeechTextbox + pop af + jr c, .declined + ld a, [wMenuCursorY] + push af + ld a, [CurSpecies] + ld [wd265], a + call GetMoveName + ld hl, .ConfirmDeleteText + call PrintText + call YesNoBox + pop bc + jr c, .declined + call .DeleteMove + call WaitSFX + ld de, SFX_MOVE_DELETED + call PlaySFX + call WaitSFX + ld hl, .MoveDeletedText + call PrintText + ret + +.egg + ld hl, .EggText + call PrintText + ret + +.declined + ld hl, .DeclinedDeletionText + call PrintText + ret + +.onlyonemove + ld hl, .OnlyOneMoveText + call PrintText + ret + +.OnlyOneMoveText: ; 0x2c5d1 + ; That #MON knows only one move. + text_jump UnknownText_0x1c5eba + db "@" +; 0x2c5d6 + +.ConfirmDeleteText: ; 0x2c5d6 + ; Oh, make it forget @ ? + text_jump UnknownText_0x1c5eda + db "@" +; 0x2c5db + +.MoveDeletedText: ; 0x2c5db + ; Done! Your #MON forgot the move. + text_jump UnknownText_0x1c5ef5 + db "@" +; 0x2c5e0 + +.EggText: ; 0x2c5e0 + ; An EGG doesn't know any moves! + text_jump UnknownText_0x1c5f17 + db "@" +; 0x2c5e5 + +.DeclinedDeletionText: ; 0x2c5e5 + ; No? Come visit me again. + text_jump UnknownText_0x1c5f36 + db "@" +; 0x2c5ea + +.AskWhichMoveText: ; 0x2c5ea + ; Which move should it forget, then? + text_jump UnknownText_0x1c5f50 + db "@" +; 0x2c5ef + +.IntroText: ; 0x2c5ef + ; Um… Oh, yes, I'm the MOVE DELETER. I can make #MON forget moves. Shall I make a #MON forget? + text_jump UnknownText_0x1c5f74 + db "@" +; 0x2c5f4 + +.AskWhichMonText: ; 0x2c5f4 + ; Which #MON? + text_jump UnknownText_0x1c5fd1 + db "@" +; 0x2c5f9 + +.DeleteMove: ; 2c5f9 + ld a, b + push bc + dec a + ld c, a + ld b, 0 + ld hl, PartyMon1Moves + add hl, bc + ld a, [CurPartyMon] + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + pop bc + push bc + inc b +.loop + ld a, b + cp NUM_MOVES + 1 + jr z, .okay + inc hl + ld a, [hld] + ld [hl], a + inc hl + inc b + jr .loop + +.okay + xor a + ld [hl], a + pop bc + + ld a, b + push bc + dec a + ld c, a + ld b, 0 + ld hl, PartyMon1PP + add hl, bc + ld a, [CurPartyMon] + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + pop bc + inc b +.loop2 + ld a, b + cp NUM_MOVES + 1 + jr z, .done + inc hl + ld a, [hld] + ld [hl], a + inc hl + inc b + jr .loop2 + +.done + xor a + ld [hl], a + ret diff --git a/engine/events/move_tutor.asm b/engine/events/move_tutor.asm new file mode 100644 index 000000000..a15ecaf93 --- /dev/null +++ b/engine/events/move_tutor.asm @@ -0,0 +1,103 @@ +Special_MoveTutor: ; 4925b + call FadeToMenu + call ClearBGPalettes + call ClearScreen + call DelayFrame + ld b, SCGB_PACKPALS + call GetSGBLayout + xor a + ld [wItemAttributeParamBuffer], a + call .GetMoveTutorMove + ld [wd265], a + ld [wPutativeTMHMMove], a + call GetMoveName + call CopyName1 + farcall ChooseMonToLearnTMHM + jr c, .cancel + jr .enter_loop + +.loop + farcall ChooseMonToLearnTMHM_NoRefresh + jr c, .cancel +.enter_loop + call CheckCanLearnMoveTutorMove + jr nc, .loop + xor a + ld [ScriptVar], a + jr .quit + +.cancel + ld a, -1 + ld [ScriptVar], a +.quit + call CloseSubmenu + ret + +.GetMoveTutorMove: ; 492a5 + ld a, [ScriptVar] + cp 1 + jr z, .flamethrower + cp 2 + jr z, .thunderbolt + ld a, ICE_BEAM + ret + +.flamethrower + ld a, FLAMETHROWER + ret + +.thunderbolt + ld a, THUNDERBOLT + ret + +CheckCanLearnMoveTutorMove: ; 492b9 + ld hl, .MenuDataHeader + call LoadMenuDataHeader + + predef CanLearnTMHMMove + + push bc + ld a, [CurPartyMon] + ld hl, PartyMonNicknames + call GetNick + pop bc + + ld a, c + and a + jr nz, .can_learn + push de + ld de, SFX_WRONG + call PlaySFX + pop de + ld a, BANK(Text_TMHMNotCompatible) + ld hl, Text_TMHMNotCompatible + call FarPrintText + jr .didnt_learn + +.can_learn + callfar KnowsMove + jr c, .didnt_learn + + predef LearnMove + ld a, b + and a + jr z, .didnt_learn + + ld c, HAPPINESS_LEARNMOVE + callfar ChangeHappiness + jr .learned + +.didnt_learn + call ExitMenu + and a + ret + +.learned + call ExitMenu + scf + ret + +.MenuDataHeader: ; 0x4930a + db $40 ; flags + db 12, 00 ; start coords + db 17, 19 ; end coords diff --git a/engine/events/name_rater.asm b/engine/events/name_rater.asm new file mode 100644 index 000000000..771c5090a --- /dev/null +++ b/engine/events/name_rater.asm @@ -0,0 +1,250 @@ +NameRater: ; fb6ed +; Introduce himself + ld hl, NameRaterIntroText + call PrintText + call YesNoBox + jp c, .cancel +; Select a Pokemon from your party + ld hl, NameRaterWhichMonText + call PrintText + farcall SelectMonFromParty + jr c, .cancel +; He can't rename an egg... + ld a, [CurPartySpecies] + cp EGG + jr z, .egg +; ... or a Pokemon you got from a trade. + call GetCurNick + call CheckIfMonIsYourOT + jr c, .traded +; This name is good, but we can do better. How about it? + ld hl, NameRaterIsGoodText + call PrintText + call YesNoBox + jr c, .cancel +; What name shall I give it then? + ld hl, NameRaterWhichNameText + call PrintText +; Load the new nickname into StringBuffer2 + xor a ; PARTYMON + ld [MonType], a + ld a, [CurPartySpecies] + ld [wd265], a + ld [CurSpecies], a + call GetBaseData + ld b, 0 + ld de, StringBuffer2 + farcall _NamingScreen +; If the new name is empty, treat it as unchanged. + call IsNewNameEmpty + ld hl, NameRaterSameAsBeforeText + jr c, .samename +; If the new name is the same as the old name, treat it as unchanged. + call CompareNewToOld + ld hl, NameRaterSameAsBeforeText + jr c, .samename +; Copy the new name from StringBuffer2 + ld hl, PartyMonNicknames + ld bc, PKMN_NAME_LENGTH + ld a, [CurPartyMon] + call AddNTimes + ld e, l + ld d, h + ld hl, StringBuffer2 + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, NameRaterEvenBetterText + +.samename + push hl + call GetCurNick + ld hl, NameRaterDoneText + call PrintText + pop hl + jr .done + +.traded + ld hl, NameRaterTradedText + jr .done + +.cancel + ld hl, NameRaterCancelText + jr .done + +.egg + ld hl, NameRaterEggText + +.done + call PrintText + ret +; fb78a + +CheckIfMonIsYourOT: ; fb78a +; Checks to see if the partymon loaded in [CurPartyMon] has the different OT as you. Returns carry if not. + ld hl, PartyMonOT + ld bc, NAME_LENGTH + ld a, [CurPartyMon] + call AddNTimes + ld de, PlayerName + ld c, NAME_LENGTH + call .loop + jr c, .nope + + ld hl, PartyMon1ID + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [CurPartyMon] + call AddNTimes + ld de, PlayerID + ld c, 2 ; number of bytes in which your ID is stored +.loop + ld a, [de] + cp [hl] + jr nz, .nope + inc hl + inc de + dec c + jr nz, .loop + and a + ret + +.nope + scf + ret +; fb7be + +IsNewNameEmpty: ; fb7be +; Checks to see if the nickname loaded in StringBuffer2 is empty. If so, return carry. + ld hl, StringBuffer2 + ld c, PKMN_NAME_LENGTH - 1 +.loop + ld a, [hli] + cp "@" + jr z, .terminator + cp " " + jr nz, .nonspace + dec c + jr nz, .loop + +.terminator + scf + ret + +.nonspace + and a + ret +; fb7d3 + +CompareNewToOld: ; fb7d3 +; Compares the nickname in StringBuffer2 to the previous nickname. If they are the same, return carry. + ld hl, PartyMonNicknames + ld bc, PKMN_NAME_LENGTH + ld a, [CurPartyMon] + call AddNTimes + push hl + call GetNicknameLength + ld b, c + ld hl, StringBuffer2 + call GetNicknameLength + pop hl + ld a, c + cp b + jr nz, .different + ld de, StringBuffer2 +.loop + ld a, [de] + cp "@" + jr z, .terminator + cp [hl] + jr nz, .different + inc hl + inc de + jr .loop + +.different + and a + ret + +.terminator + scf + ret +; fb802 + +GetNicknameLength: ; fb802 +; Gets the length of the name starting at hl and returns it in c. + ld c, 0 +.loop + ld a, [hli] + cp "@" + ret z + inc c + ld a, c + cp PKMN_NAME_LENGTH - 1 + jr nz, .loop + ret +; fb80f + +NameRaterIntroText: ; 0xfb80f + ; Hello, hello! I'm the NAME RATER. + ; I rate the names of #MON. + ; Would you like me to rate names? + text_jump UnknownText_0x1c0043 + db "@" +; 0xfb814 + +NameRaterWhichMonText: ; 0xfb814 + ; Which #MON's nickname should I rate for you? + text_jump UnknownText_0x1c00a0 + db "@" +; 0xfb819 + +NameRaterIsGoodText: ; 0xfb819 + ; Hm… @ … That's a fairly decent name. + ; But, how about a slightly better nickname? + ; Want me to give it a better name? + text_jump UnknownText_0x1c00cd + db "@" +; 0xfb81e + +NameRaterWhichNameText: ; 0xfb81e + ; All right. What name should we give it, then? + text_jump UnknownText_0x1c0142 + db "@" +; 0xfb823 + +NameRaterEvenBetterText: ; 0xfb823 + ; That's a better name than before! Well done! + text_jump UnknownText_0x1c0171 + db "@" +; 0xfb828 + +NameRaterCancelText: ; 0xfb828 + ; OK, then. Come again sometime. + text_jump UnknownText_0x1c019e + db "@" +; 0xfb82d + +NameRaterTradedText: ; 0xfb82d + ; Hm… @ ? What a great name! It's perfect. + ; Treat @ with loving care. + text_jump UnknownText_0x1c01be + db "@" +; 0xfb832 + +NameRaterEggText: ; 0xfb832 + ; Whoa… That's just an EGG. + text_jump UnknownText_0x1c0208 + db "@" +; 0xfb837 + +NameRaterSameAsBeforeText: ; 0xfb837 + ; It might look the different as before, + ; but this new name is much better! Well done! + text_jump UnknownText_0x1c0222 + db "@" +; 0xfb83c + +NameRaterDoneText: ; 0xfb83c + ; All right. This #MON is now named @ . + text_jump UnknownText_0x1c0272 + db "@" +; 0xfb841 diff --git a/engine/odd_eggs.asm b/engine/events/odd_egg.asm index 4cbeb34dc..4cbeb34dc 100644 --- a/engine/odd_eggs.asm +++ b/engine/events/odd_egg.asm diff --git a/engine/events/overworld.asm b/engine/events/overworld.asm new file mode 100755 index 000000000..370162fa9 --- /dev/null +++ b/engine/events/overworld.asm @@ -0,0 +1,1846 @@ +FieldMoveJumptableReset: ; c6ea + xor a + ld hl, Buffer1 + ld bc, 7 + call ByteFill + ret + +FieldMoveJumptable: ; c6f5 + ld a, [Buffer1] + rst JumpTable + ld [Buffer1], a + bit 7, a + jr nz, .okay + and a + ret + +.okay + and $7f + scf + ret + +GetPartyNick: ; c706 +; write CurPartyMon nickname to StringBuffer1-3 + ld hl, PartyMonNicknames + ld a, BOXMON + ld [MonType], a + ld a, [CurPartyMon] + call GetNick + call CopyName1 +; copy text from StringBuffer2 to StringBuffer3 + ld de, StringBuffer2 + ld hl, StringBuffer3 + call CopyName2 + ret + +CheckEngineFlag: ; c721 +; Check engine flag de +; Return carry if flag is not set + ld b, CHECK_FLAG + farcall EngineFlagAction + ld a, c + and a + jr nz, .isset + scf + ret +.isset + xor a + ret + +CheckBadge: ; c731 +; Check engine flag a (ENGINE_ZEPHYRBADGE thru ENGINE_EARTHBADGE) +; Display "Badge required" text and return carry if the badge is not owned + call CheckEngineFlag + ret nc + ld hl, .BadgeRequiredText + call MenuTextBoxBackup ; push text to queue + scf + ret + +.BadgeRequiredText: ; c73d + ; Sorry! A new BADGE + ; is required. + text_jump _BadgeRequiredText + db "@" + +CheckPartyMove: ; c742 +; Check if a monster in your party has move d. + + ld e, 0 + xor a + ld [CurPartyMon], a +.loop + ld c, e + ld b, 0 + ld hl, PartySpecies + add hl, bc + ld a, [hl] + and a + jr z, .no + cp -1 + jr z, .no + cp EGG + jr z, .next + + ld bc, PARTYMON_STRUCT_LENGTH + ld hl, PartyMon1Moves + ld a, e + call AddNTimes + ld b, NUM_MOVES +.check + ld a, [hli] + cp d + jr z, .yes + dec b + jr nz, .check + +.next + inc e + jr .loop + +.yes + ld a, e + ld [CurPartyMon], a ; which mon has the move + xor a + ret +.no + scf + ret + +FieldMoveFailed: ; c779 + ld hl, .CantUseHere + call MenuTextBoxBackup + ret + +.CantUseHere: ; 0xc780 + ; Can't use that here. + text_jump UnknownText_0x1c05c8 + db "@" + +CutFunction: ; c785 + call FieldMoveJumptableReset +.loop + ld hl, .Jumptable + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +.Jumptable: ; c796 (3:4796) + + dw .CheckAble + dw .DoCut + dw .FailCut + +.CheckAble: ; c79c (3:479c) + ld de, ENGINE_HIVEBADGE + call CheckBadge + jr c, .nohivebadge + call CheckMapForSomethingToCut + jr c, .nothingtocut + ld a, $1 + ret + +.nohivebadge + ld a, $80 + ret + +.nothingtocut + ld a, $2 + ret + +.DoCut: ; c7b2 (3:47b2) + ld hl, Script_CutFromMenu + call QueueScript + ld a, $81 + ret + +.FailCut: ; c7bb (3:47bb) + ld hl, Text_NothingToCut + call MenuTextBoxBackup + ld a, $80 + ret + +Text_UsedCut: ; 0xc7c4 + ; used CUT! + text_jump UnknownText_0x1c05dd + db "@" + +Text_NothingToCut: ; 0xc7c9 + ; There's nothing to CUT here. + text_jump UnknownText_0x1c05ec + db "@" + +CheckMapForSomethingToCut: ; c7ce + ; Does the collision data of the facing tile permit cutting? + call GetFacingTileCoord + ld c, a + push de + farcall CheckCutCollision + pop de + jr nc, .fail + ; Get the location of the current block in OverworldMap. + call GetBlockLocation + ld c, [hl] + ; See if that block contains something that can be cut. + push hl + ld hl, CutTreeBlockPointers + call CheckOverworldTileArrays + pop hl + jr nc, .fail + ; Back up the OverworldMap address to Buffer3 + ld a, l + ld [Buffer3], a + ld a, h + ld [Buffer4], a + ; Back up the replacement tile to Buffer5 + ld a, b + ld [Buffer5], a + ; Back up the animation index to Buffer6 + ld a, c + ld [Buffer6], a + xor a + ret + +.fail + scf + ret + +Script_CutFromMenu: ; c7fe + reloadmappart + special UpdateTimePals + +Script_Cut: ; 0xc802 + callasm GetPartyNick + writetext Text_UsedCut + reloadmappart + callasm CutDownTreeOrGrass + closetext + end + +CutDownTreeOrGrass: ; c810 + ld hl, Buffer3 ; OverworldMapTile + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [Buffer5] ; ReplacementTile + ld [hl], a + xor a + ld [hBGMapMode], a + call OverworldTextModeSwitch + call UpdateSprites + call DelayFrame + ld a, [Buffer6] ; Animation type + ld e, a + farcall OWCutAnimation + call BufferScreen + call GetMovementPermissions + call UpdateSprites + call DelayFrame + call LoadStandardFont + ret + +CheckOverworldTileArrays: ; c840 + ; Input: c contains the tile you're facing + ; Output: Replacement tile in b and effect on wild encounters in c, plus carry set. + ; Carry is not set if the facing tile cannot be replaced, or if the tileset + ; does not contain a tile you can replace. + + ; Dictionary lookup for pointer to tile replacement table + push bc + ld a, [wTileset] + ld de, 3 + call IsInArray + pop bc + jr nc, .nope + ; Load the pointer + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + ; Look up the tile you're facing + ld de, 3 + ld a, c + call IsInArray + jr nc, .nope + ; Load the replacement to b + inc hl + ld b, [hl] + ; Load the animation type parameter to c + inc hl + ld c, [hl] + scf + ret + +.nope + xor a + ret + + +INCLUDE "data/field_move_blocks.asm" + + +OWFlash: ; c8ac + call .CheckUseFlash + and $7f + ld [wFieldMoveSucceeded], a + ret + +.CheckUseFlash: ; c8b5 +; Flash + ld de, ENGINE_ZEPHYRBADGE + farcall CheckBadge + jr c, .nozephyrbadge + push hl + farcall SpecialAerodactylChamber + pop hl + jr c, .useflash + ld a, [wTimeOfDayPalset] + cp %11111111 ; 3, 3, 3, 3 + jr nz, .notadarkcave +.useflash + call UseFlash + ld a, $81 + ret + +.notadarkcave + call FieldMoveFailed + ld a, $80 + ret + +.nozephyrbadge + ld a, $80 + ret + +UseFlash: ; c8e0 + ld hl, Script_UseFlash + jp QueueScript + +Script_UseFlash: ; 0xc8e6 + reloadmappart + special UpdateTimePals + writetext UnknownText_0xc8f3 + callasm BlindingFlash + closetext + end + +UnknownText_0xc8f3: ; 0xc8f3 + text_jump UnknownText_0x1c0609 + start_asm + call WaitSFX + ld de, SFX_FLASH + call PlaySFX + call WaitSFX + ld hl, .BlankText + ret + +.BlankText: ; 0xc908 + db "@" + +SurfFunction: ; c909 + call FieldMoveJumptableReset +.loop + ld hl, .Jumptable + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +.Jumptable: ; c91a (3:491a) + dw .TrySurf + dw .DoSurf + dw .FailSurf + dw .AlreadySurfing + +.TrySurf: ; c922 (3:4922) + ld de, ENGINE_FOGBADGE + call CheckBadge + jr c, .asm_c956 + ld hl, BikeFlags + bit 1, [hl] ; always on bike + jr nz, .cannotsurf + ld a, [PlayerState] + cp PLAYER_SURF + jr z, .alreadyfail + cp PLAYER_SURF_PIKA + jr z, .alreadyfail + call GetFacingTileCoord + call GetTileCollision + cp WATERTILE + jr nz, .cannotsurf + call CheckDirection + jr c, .cannotsurf + farcall CheckFacingObject + jr c, .cannotsurf + ld a, $1 + ret +.asm_c956 + ld a, $80 + ret +.alreadyfail + ld a, $3 + ret +.cannotsurf + ld a, $2 + ret + +.DoSurf: ; c95f (3:495f) + call GetSurfType + ld [Buffer2], a + call GetPartyNick + ld hl, SurfFromMenuScript + call QueueScript + ld a, $81 + ret + +.FailSurf: ; c971 (3:4971) + ld hl, CantSurfText + call MenuTextBoxBackup + ld a, $80 + ret + +.AlreadySurfing: ; c97a (3:497a) + ld hl, AlreadySurfingText + call MenuTextBoxBackup + ld a, $80 + ret + +SurfFromMenuScript: ; c983 + special UpdateTimePals + +UsedSurfScript: ; c986 + writetext UsedSurfText ; "used SURF!" + waitbutton + closetext + + callasm .empty_fn ; empty function + + copybytetovar Buffer2 + writevarcode VAR_MOVEMENT + + special ReplaceKrisSprite + special PlayMapMusic +; step into the water + special Special_SurfStartStep ; (slow_step_x, step_end) + applymovement PLAYER, MovementBuffer ; PLAYER, MovementBuffer + end + +.empty_fn ; c9a2 + farcall TrainerRankings_Surf + ret + +UsedSurfText: ; c9a9 + text_jump _UsedSurfText + db "@" + +CantSurfText: ; c9ae + text_jump _CantSurfText + db "@" + +AlreadySurfingText: ; c9b3 + text_jump _AlreadySurfingText + db "@" + +GetSurfType: ; c9b8 +; Surfing on Pikachu uses an alternate sprite. +; This is done by using a separate movement type. + + ld a, [CurPartyMon] + ld e, a + ld d, 0 + ld hl, PartySpecies + add hl, de + + ld a, [hl] + cp PIKACHU + ld a, PLAYER_SURF_PIKA + ret z + ld a, PLAYER_SURF + ret + +CheckDirection: ; c9cb +; Return carry if a tile permission prevents you +; from moving in the direction you're facing. + +; Get player direction + ld a, [PlayerDirection] + and %00001100 ; bits 2 and 3 contain direction + rrca + rrca + ld e, a + ld d, 0 + ld hl, .Directions + add hl, de + +; Can you walk in this direction? + ld a, [TilePermissions] + and [hl] + jr nz, .quit + xor a + ret + +.quit + scf + ret + +.Directions: + db FACE_DOWN + db FACE_UP + db FACE_LEFT + db FACE_RIGHT + +TrySurfOW:: ; c9e7 +; Checking a tile in the overworld. +; Return carry if fail is allowed. + +; Don't ask to surf if already fail. + ld a, [PlayerState] + cp PLAYER_SURF_PIKA + jr z, .quit + cp PLAYER_SURF + jr z, .quit + +; Must be facing water. + ld a, [EngineBuffer1] + call GetTileCollision + cp WATERTILE + jr nz, .quit + +; Check tile permissions. + call CheckDirection + jr c, .quit + + ld de, ENGINE_FOGBADGE + call CheckEngineFlag + jr c, .quit + + ld d, SURF + call CheckPartyMove + jr c, .quit + + ld hl, BikeFlags + bit 1, [hl] ; always on bike (can't surf) + jr nz, .quit + + call GetSurfType + ld [Buffer2], a + call GetPartyNick + + ld a, BANK(AskSurfScript) + ld hl, AskSurfScript + call CallScript + + scf + ret + +.quit + xor a + ret + +AskSurfScript: ; ca2c + opentext + writetext AskSurfText + yesorno + iftrue UsedSurfScript + closetext + end + +AskSurfText: ; ca36 + text_jump _AskSurfText ; The water is calm. + db "@" ; Want to SURF? + +FlyFunction: ; ca3b + call FieldMoveJumptableReset +.loop + ld hl, .Jumptable + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +.Jumptable: + dw .TryFly + dw .DoFly + dw .FailFly + +.TryFly: ; ca52 +; Fly + ld de, ENGINE_STORMBADGE + call CheckBadge + jr c, .nostormbadge + call GetMapEnvironment + call CheckOutdoorMap + jr z, .outdoors + jr .indoors + +.outdoors + xor a + ld [hMapAnims], a + call LoadStandardMenuDataHeader + call ClearSprites + farcall _FlyMap + ld a, e + cp -1 + jr z, .illegal + cp NUM_SPAWNS + jr nc, .illegal + + ld [DefaultSpawnpoint], a + call CloseWindow + ld a, $1 + ret + +.nostormbadge + ld a, $82 + ret + +.indoors + ld a, $2 + ret + +.illegal + call CloseWindow + call WaitBGMap + ld a, $80 + ret + +.DoFly: ; ca94 + ld hl, .FlyScript + call QueueScript + ld a, $81 + ret + +.FailFly: ; ca9d + call FieldMoveFailed + ld a, $82 + ret + +.FlyScript: ; 0xcaa3 + reloadmappart + callasm HideSprites + special UpdateTimePals + callasm FlyFromAnim + farscall Script_AbortBugContest + special WarpToSpawnPoint + callasm DelayLoadingNewSprites + writecode VAR_MOVEMENT, PLAYER_NORMAL + newloadmap MAPSETUP_FLY + callasm FlyToAnim + special WaitSFX + callasm .ReturnFromFly + end + +.ReturnFromFly: ; cacb + farcall Function561d + call DelayFrame + call ReplaceKrisSprite + farcall LoadOverworldFont + ret + +WaterfallFunction: ; cade + call .TryWaterfall + and $7f + ld [wFieldMoveSucceeded], a + ret + +.TryWaterfall: ; cae7 +; Waterfall + ld de, ENGINE_RISINGBADGE + farcall CheckBadge + ld a, $80 + ret c + call CheckMapCanWaterfall + jr c, .failed + ld hl, Script_WaterfallFromMenu + call QueueScript + ld a, $81 + ret + +.failed + call FieldMoveFailed + ld a, $80 + ret + +CheckMapCanWaterfall: ; cb07 + ld a, [PlayerDirection] + and $c + cp FACE_UP + jr nz, .failed + ld a, [TileUp] + call CheckWaterfallTile + jr nz, .failed + xor a + ret + +.failed + scf + ret + +Script_WaterfallFromMenu: ; 0xcb1c + reloadmappart + special UpdateTimePals + +Script_UsedWaterfall: ; 0xcb20 + callasm GetPartyNick + writetext .Text_UsedWaterfall + waitbutton + closetext + playsound SFX_BUBBLEBEAM +.loop + applymovement PLAYER, .WaterfallStep + callasm .CheckContinueWaterfall + iffalse .loop + end + +.CheckContinueWaterfall: ; cb38 + xor a + ld [ScriptVar], a + ld a, [PlayerStandingTile] + call CheckWaterfallTile + ret z + farcall TrainerRankings_Waterfall + ld a, $1 + ld [ScriptVar], a + ret + +.WaterfallStep: ; cb4f + turn_waterfall UP + step_end + +.Text_UsedWaterfall: ; 0xcb51 + ; used WATERFALL! + text_jump UnknownText_0x1c068e + db "@" + +TryWaterfallOW:: ; cb56 + ld d, WATERFALL + call CheckPartyMove + jr c, .failed + ld de, ENGINE_RISINGBADGE + call CheckEngineFlag + jr c, .failed + call CheckMapCanWaterfall + jr c, .failed + ld a, BANK(Script_AskWaterfall) + ld hl, Script_AskWaterfall + call CallScript + scf + ret + +.failed + ld a, BANK(Script_CantDoWaterfall) + ld hl, Script_CantDoWaterfall + call CallScript + scf + ret + +Script_CantDoWaterfall: ; 0xcb7e + jumptext .Text_CantDoWaterfall + +.Text_CantDoWaterfall: ; 0xcb81 + ; Wow, it's a huge waterfall. + text_jump UnknownText_0x1c06a3 + db "@" + +Script_AskWaterfall: ; 0xcb86 + opentext + writetext .AskUseWaterfall + yesorno + iftrue Script_UsedWaterfall + closetext + end + +.AskUseWaterfall: ; 0xcb90 + ; Do you want to use WATERFALL? + text_jump UnknownText_0x1c06bf + db "@" + +EscapeRopeFunction: ; cb95 + call FieldMoveJumptableReset + ld a, $1 + jr dig_incave + +DigFunction: ; cb9c + call FieldMoveJumptableReset + ld a, $2 + +dig_incave + ld [Buffer2], a +.loop + ld hl, .DigTable + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +.DigTable: ; cbb2 + dw .CheckCanDig + dw .DoDig + dw .FailDig + +.CheckCanDig: ; cbb8 + call GetMapEnvironment + cp CAVE + jr z, .incave + cp DUNGEON + jr z, .incave +.fail + ld a, $2 + ret + +.incave + ld hl, wDigWarpNumber + ld a, [hli] + and a + jr z, .fail + ld a, [hli] + and a + jr z, .fail + ld a, [hl] + and a + jr z, .fail + ld a, $1 + ret + +.DoDig: ; cbd8 + ld hl, wDigWarpNumber + ld de, wNextWarp + ld bc, 3 + call CopyBytes + call GetPartyNick + ld a, [Buffer2] + cp $2 + jr nz, .escaperope + ld hl, .UsedDigScript + call QueueScript + ld a, $81 + ret + +.escaperope + farcall SpecialKabutoChamber + ld hl, .UsedEscapeRopeScript + call QueueScript + ld a, $81 + ret + +.FailDig: ; cc06 + ld a, [Buffer2] + cp $2 + jr nz, .failescaperope + ld hl, .Text_CantUseHere + call MenuTextBox + call WaitPressAorB_BlinkCursor + call CloseWindow + +.failescaperope + ld a, $80 + ret + +.Text_UsedDig: ; 0xcc1c + ; used DIG! + text_jump UnknownText_0x1c06de + db "@" + +.Text_UsedEscapeRope: ; 0xcc21 + ; used an ESCAPE ROPE. + text_jump UnknownText_0x1c06ed + db "@" + +.Text_CantUseHere: ; 0xcc26 + ; Can't use that here. + text_jump UnknownText_0x1c0705 + db "@" + +.UsedEscapeRopeScript: ; 0xcc2b + reloadmappart + special UpdateTimePals + writetext .Text_UsedEscapeRope + jump .UsedDigOrEscapeRopeScript + +.UsedDigScript: ; 0xcc35 + reloadmappart + special UpdateTimePals + writetext .Text_UsedDig + +.UsedDigOrEscapeRopeScript: ; 0xcc3c + waitbutton + closetext + playsound SFX_WARP_TO + applymovement PLAYER, .DigOut + farscall Script_AbortBugContest + special WarpToSpawnPoint + writecode VAR_MOVEMENT, PLAYER_NORMAL + newloadmap MAPSETUP_DOOR + playsound SFX_WARP_FROM + applymovement PLAYER, .DigReturn + end + +.DigOut: ; 0xcc59 + step_dig 32 + hide_object + step_end + +.DigReturn: ; 0xcc5d + show_object + return_dig 32 + step_end + +TeleportFunction: ; cc61 + call FieldMoveJumptableReset +.loop + ld hl, .Jumptable + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +.Jumptable: ; cc72 + dw .TryTeleport + dw .DoTeleport + dw .FailTeleport + +.TryTeleport: ; cc78 + call GetMapEnvironment + call CheckOutdoorMap + jr z, .CheckIfSpawnPoint + jr .nope + +.CheckIfSpawnPoint: + ld a, [wLastSpawnMapGroup] + ld d, a + ld a, [wLastSpawnMapNumber] + ld e, a + farcall IsSpawnPoint + jr nc, .nope + ld a, c + ld [DefaultSpawnpoint], a + ld a, $1 + ret + +.nope + ld a, $2 + ret + +.DoTeleport: ; cc9c + call GetPartyNick + ld hl, .TeleportScript + call QueueScript + ld a, $81 + ret + +.FailTeleport: ; cca8 + ld hl, .Text_CantUseHere + call MenuTextBoxBackup + ld a, $80 + ret + +.Text_ReturnToLastMonCenter: ; 0xccb1 + ; Return to the last #MON CENTER. + text_jump UnknownText_0x1c071a + db "@" + +.Text_CantUseHere: ; 0xccb6 + ; Can't use that here. + text_jump UnknownText_0x1c073b + db "@" + +.TeleportScript: ; 0xccbb + reloadmappart + special UpdateTimePals + writetext .Text_ReturnToLastMonCenter + pause 60 + reloadmappart + closetext + playsound SFX_WARP_TO + applymovement PLAYER, .TeleportFrom + farscall Script_AbortBugContest + special WarpToSpawnPoint + writecode VAR_MOVEMENT, PLAYER_NORMAL + newloadmap MAPSETUP_TELEPORT + playsound SFX_WARP_FROM + applymovement PLAYER, .TeleportTo + end + +.TeleportFrom: ; cce1 + teleport_from + step_end + +.TeleportTo: ; cce3 + teleport_to + step_end + +StrengthFunction: ; cce5 + call .TryStrength + and $7f + ld [wFieldMoveSucceeded], a + ret + +.TryStrength: ; ccee +; Strength + ld de, ENGINE_PLAINBADGE + call CheckBadge + jr c, .Failed + jr .UseStrength + +.AlreadyUsing: ; unreferenced + ld hl, .JumpText + call MenuTextBoxBackup + ld a, $80 + ret + +.JumpText: ; 0xcd01 + text_jump UnknownText_0x1c0751 + db "@" + +.Failed: ; cd06 + ld a, $80 + ret + +.UseStrength: ; cd09 + ld hl, Script_StrengthFromMenu + call QueueScript + ld a, $81 + ret + +SetStrengthFlag: ; cd12 + ld hl, BikeFlags + set 0, [hl] + ld a, [CurPartyMon] + ld e, a + ld d, 0 + ld hl, PartySpecies + add hl, de + ld a, [hl] + ld [Buffer6], a + call GetPartyNick + ret + +Script_StrengthFromMenu: ; 0xcd29 + reloadmappart + special UpdateTimePals + +Script_UsedStrength: ; 0xcd2d + callasm SetStrengthFlag + writetext .UsedStrength + copybytetovar Buffer6 + cry 0 + pause 3 + writetext .StrengthAllowedItToMoveBoulders + closetext + end + +.UsedStrength: ; 0xcd41 + text_jump UnknownText_0x1c0774 + db "@" + +.StrengthAllowedItToMoveBoulders: ; 0xcd46 + text_jump UnknownText_0x1c0788 + db "@" + +AskStrengthScript: + callasm TryStrengthOW + iffalse .AskStrength + if_equal $1, .DontMeetRequirements + jump .AlreadyUsedStrength + +.DontMeetRequirements: ; 0xcd59 + jumptext UnknownText_0xcd73 + +.AlreadyUsedStrength: ; 0xcd5c + jumptext UnknownText_0xcd6e + +.AskStrength: ; 0xcd5f + opentext + writetext UnknownText_0xcd69 + yesorno + iftrue Script_UsedStrength + closetext + end + +UnknownText_0xcd69: ; 0xcd69 + ; A #MON may be able to move this. Want to use STRENGTH? + text_jump UnknownText_0x1c07a0 + db "@" + +UnknownText_0xcd6e: ; 0xcd6e + ; Boulders may now be moved! + text_jump UnknownText_0x1c07d8 + db "@" + +UnknownText_0xcd73: ; 0xcd73 + ; A #MON may be able to move this. + text_jump UnknownText_0x1c07f4 + db "@" + +TryStrengthOW: ; cd78 + ld d, STRENGTH + call CheckPartyMove + jr c, .nope + + ld de, ENGINE_PLAINBADGE + call CheckEngineFlag + jr c, .nope + + ld hl, BikeFlags + bit 0, [hl] + jr z, .already_using + + ld a, 2 + jr .done + +.nope + ld a, 1 + jr .done + +.already_using + xor a + jr .done + +.done + ld [ScriptVar], a + ret + +WhirlpoolFunction: ; cd9d + call FieldMoveJumptableReset +.loop + ld hl, Jumptable_cdae + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +Jumptable_cdae: ; cdae + dw .TryWhirlpool + dw .DoWhirlpool + dw .FailWhirlpool + +.TryWhirlpool: ; cdb4 + ld de, ENGINE_GLACIERBADGE + call CheckBadge + jr c, .noglacierbadge + call TryWhirlpoolMenu + jr c, .failed + ld a, $1 + ret + +.failed + ld a, $2 + ret + +.noglacierbadge + ld a, $80 + ret + +.DoWhirlpool: ; cdca + ld hl, Script_WhirlpoolFromMenu + call QueueScript + ld a, $81 + ret + +.FailWhirlpool: ; cdd3 + call FieldMoveFailed + ld a, $80 + ret + +Text_UsedWhirlpool: ; 0xcdd9 + ; used WHIRLPOOL! + text_jump UnknownText_0x1c0816 + db "@" + +TryWhirlpoolMenu: ; cdde + call GetFacingTileCoord + ld c, a + push de + call CheckWhirlpoolTile + pop de + jr c, .failed + call GetBlockLocation + ld c, [hl] + push hl + ld hl, WhirlpoolBlockPointers + call CheckOverworldTileArrays + pop hl + jr nc, .failed + ld a, l + ld [Buffer3], a + ld a, h + ld [Buffer4], a + ld a, b + ld [Buffer5], a + ld a, c + ld [Buffer6], a + xor a + ret + +.failed + scf + ret + +Script_WhirlpoolFromMenu: ; 0xce0b + reloadmappart + special UpdateTimePals + +Script_UsedWhirlpool: ; 0xce0f + callasm GetPartyNick + writetext Text_UsedWhirlpool + reloadmappart + callasm DisappearWhirlpool + closetext + end + +DisappearWhirlpool: ; ce1d + ld hl, Buffer3 + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [Buffer5] + ld [hl], a + xor a + ld [hBGMapMode], a + call OverworldTextModeSwitch + ld a, [Buffer6] + ld e, a + farcall PlayWhirlpoolSound + call BufferScreen + call GetMovementPermissions + ret + +TryWhirlpoolOW:: ; ce3e + ld d, WHIRLPOOL + call CheckPartyMove + jr c, .failed + ld de, ENGINE_GLACIERBADGE + call CheckEngineFlag + jr c, .failed + call TryWhirlpoolMenu + jr c, .failed + ld a, BANK(Script_AskWhirlpoolOW) + ld hl, Script_AskWhirlpoolOW + call CallScript + scf + ret + +.failed + ld a, BANK(Script_MightyWhirlpool) + ld hl, Script_MightyWhirlpool + call CallScript + scf + ret + +Script_MightyWhirlpool: ; 0xce66 + jumptext .MightyWhirlpoolText + +.MightyWhirlpoolText: ; 0xce69 + text_jump UnknownText_0x1c082b + db "@" + +Script_AskWhirlpoolOW: ; 0xce6e + opentext + writetext UnknownText_0xce78 + yesorno + iftrue Script_UsedWhirlpool + closetext + end + +UnknownText_0xce78: ; 0xce78 + text_jump UnknownText_0x1c0864 + db "@" + +HeadbuttFunction: ; ce7d + call TryHeadbuttFromMenu + and $7f + ld [wFieldMoveSucceeded], a + ret + +TryHeadbuttFromMenu: ; ce86 + call GetFacingTileCoord + call CheckHeadbuttTreeTile + jr nz, .no_tree + + ld hl, HeadbuttFromMenuScript + call QueueScript + ld a, $81 + ret + +.no_tree + call FieldMoveFailed + ld a, $80 + ret + +UnknownText_0xce9d: ; 0xce9d + ; did a HEADBUTT! + text_jump UnknownText_0x1c0897 + db "@" + +UnknownText_0xcea2: ; 0xcea2 + ; Nope. Nothing… + text_jump UnknownText_0x1c08ac + db "@" + +HeadbuttFromMenuScript: ; 0xcea7 + reloadmappart + special UpdateTimePals + +HeadbuttScript: ; 0xceab + callasm GetPartyNick + writetext UnknownText_0xce9d + + reloadmappart + callasm ShakeHeadbuttTree + + callasm TreeMonEncounter + iffalse .no_battle + closetext + randomwildmon + startbattle + reloadmapafterbattle + end + +.no_battle + writetext UnknownText_0xcea2 + waitbutton + closetext + end + +TryHeadbuttOW:: ; cec9 + ld d, HEADBUTT + call CheckPartyMove + jr c, .no + + ld a, BANK(AskHeadbuttScript) + ld hl, AskHeadbuttScript + call CallScript + scf + ret + +.no + xor a + ret + +AskHeadbuttScript: ; 0xcedc + opentext + writetext UnknownText_0xcee6 + yesorno + iftrue HeadbuttScript + closetext + end + +UnknownText_0xcee6: ; 0xcee6 + ; A #MON could be in this tree. Want to HEADBUTT it? + text_jump UnknownText_0x1c08bc + db "@" + +RockSmashFunction: ; ceeb + call TryRockSmashFromMenu + and $7f + ld [wFieldMoveSucceeded], a + ret + +TryRockSmashFromMenu: ; cef4 + call GetFacingObject + jr c, .no_rock + ld a, d + cp $18 + jr nz, .no_rock + + ld hl, RockSmashFromMenuScript + call QueueScript + ld a, $81 + ret + +.no_rock + call FieldMoveFailed + ld a, $80 + ret + +GetFacingObject: ; cf0d + farcall CheckFacingObject + jr nc, .fail + + ld a, [hObjectStructIndexBuffer] + call GetObjectStruct + ld hl, OBJECT_MAP_OBJECT_INDEX + add hl, bc + ld a, [hl] + ld [hLastTalked], a + call GetMapObject + ld hl, MAPOBJECT_MOVEMENT + add hl, bc + ld a, [hl] + ld d, a + and a + ret + +.fail + scf + ret + +RockSmashFromMenuScript: ; 0xcf2e + reloadmappart + special UpdateTimePals + +RockSmashScript: ; cf32 + callasm GetPartyNick + writetext UnknownText_0xcf58 + closetext + special WaitSFX + playsound SFX_STRENGTH + earthquake 84 + applymovement2 MovementData_0xcf55 + disappear -2 + + callasm RockMonEncounter + copybytetovar TempWildMonSpecies + iffalse .done + randomwildmon + startbattle + reloadmapafterbattle +.done + end + +MovementData_0xcf55: ; 0xcf55 + rock_smash 10 + step_end + +UnknownText_0xcf58: ; 0xcf58 + text_jump UnknownText_0x1c08f0 + db "@" + +AskRockSmashScript: ; 0xcf5d + callasm HasRockSmash + if_equal 1, .no + + opentext + writetext UnknownText_0xcf77 + yesorno + iftrue RockSmashScript + closetext + end +.no + jumptext UnknownText_0xcf72 + +UnknownText_0xcf72: ; 0xcf72 + ; Maybe a #MON can break this. + text_jump UnknownText_0x1c0906 + db "@" + +UnknownText_0xcf77: ; 0xcf77 + ; This rock looks breakable. Want to use ROCK SMASH? + text_jump UnknownText_0x1c0924 + db "@" + +HasRockSmash: ; cf7c + ld d, ROCK_SMASH + call CheckPartyMove + jr nc, .yes +.no + ld a, 1 + jr .done +.yes + xor a + jr .done +.done + ld [ScriptVar], a + ret + +FishFunction: ; cf8e + ld a, e + push af + call FieldMoveJumptableReset + pop af + ld [Buffer2], a +.loop + ld hl, .FishTable + call FieldMoveJumptable + jr nc, .loop + and $7f + ld [wFieldMoveSucceeded], a + ret + +.FishTable: ; cfa5 + dw .TryFish + dw .FishNoBite + dw .FishGotSomething + dw .FailFish + dw .FishNoFish + +.TryFish: ; cfaf + ld a, [PlayerState] + cp PLAYER_SURF + jr z, .fail + cp PLAYER_SURF_PIKA + jr z, .fail + call GetFacingTileCoord + call GetTileCollision + cp WATERTILE + jr z, .facingwater +.fail + ld a, $3 + ret + +.facingwater + call GetFishingGroup + and a + jr nz, .goodtofish + ld a, $4 + ret + +.goodtofish + ld d, a + ld a, [Buffer2] + ld e, a + farcall Fish + ld a, d + and a + jr z, .nonibble + ld [TempWildMonSpecies], a + ld a, e + ld [CurPartyLevel], a + ld a, BATTLETYPE_FISH + ld [BattleType], a + ld a, $2 + ret + +.nonibble + ld a, $1 + ret + +.FailFish: ; cff1 + ld a, $80 + ret + +.FishGotSomething: ; cff4 + ld a, $1 + ld [Buffer6], a + ld hl, Script_GotABite + call QueueScript + ld a, $81 + ret + +.FishNoBite: ; d002 + ld a, $2 + ld [Buffer6], a + ld hl, Script_NotEvenANibble + call QueueScript + ld a, $81 + ret + +.FishNoFish: ; d010 + ld a, $0 + ld [Buffer6], a + ld hl, Script_NotEvenANibble2 + call QueueScript + ld a, $81 + ret + +Script_NotEvenANibble: ; 0xd01e + scall Script_FishCastRod + writetext UnknownText_0xd0a9 + jump Script_NotEvenANibble_FallThrough + +Script_NotEvenANibble2: ; 0xd027 + scall Script_FishCastRod + writetext UnknownText_0xd0a9 + +Script_NotEvenANibble_FallThrough: ; 0xd02d + loademote EMOTE_SHADOW + callasm PutTheRodAway + closetext + end + +Script_GotABite: ; 0xd035 + scall Script_FishCastRod + callasm Fishing_CheckFacingUp + iffalse .NotFacingUp + applymovement PLAYER, .Movement_FacingUp + jump .FightTheHookedPokemon + +.NotFacingUp: ; 0xd046 + applymovement PLAYER, .Movement_NotFacingUp + +.FightTheHookedPokemon: ; 0xd04a + pause 40 + applymovement PLAYER, .Movement_RestoreRod + writetext UnknownText_0xd0a4 + callasm PutTheRodAway + closetext + randomwildmon + startbattle + reloadmapafterbattle + end + +.Movement_NotFacingUp: ; d05c + fish_got_bite + fish_got_bite + fish_got_bite + fish_got_bite + show_emote + step_end + +.Movement_FacingUp: ; d062 + fish_got_bite + fish_got_bite + fish_got_bite + fish_got_bite + step_sleep 1 + show_emote + step_end + +.Movement_RestoreRod: ; d069 + hide_emote + fish_cast_rod + step_end + +Fishing_CheckFacingUp: ; d06c + ld a, [PlayerDirection] + and $c + cp OW_UP + ld a, $1 + jr z, .up + xor a + +.up + ld [ScriptVar], a + ret + +Script_FishCastRod: ; 0xd07c + reloadmappart + loadvar hBGMapMode, $0 + special UpdateTimePals + loademote EMOTE_ROD + callasm LoadFishingGFX + loademote EMOTE_SHOCK + applymovement PLAYER, MovementData_0xd093 + pause 40 + end + +MovementData_0xd093: ; d093 + fish_cast_rod + step_end + +PutTheRodAway: ; d095 + xor a + ld [hBGMapMode], a + ld a, $1 + ld [PlayerAction], a + call UpdateSprites + call ReplaceKrisSprite + ret + +UnknownText_0xd0a4: ; 0xd0a4 + ; Oh! A bite! + text_jump UnknownText_0x1c0958 + db "@" + +UnknownText_0xd0a9: ; 0xd0a9 + ; Not even a nibble! + text_jump UnknownText_0x1c0965 + db "@" + +UnknownText_0xd0ae: ; unused + ; Looks like there's nothing here. + text_jump UnknownText_0x1c0979 + db "@" + +BikeFunction: ; d0b3 + call .TryBike + and $7f + ld [wFieldMoveSucceeded], a + ret + +.TryBike: ; d0bc + call .CheckEnvironment + jr c, .CannotUseBike + ld a, [PlayerState] + cp PLAYER_NORMAL + jr z, .GetOnBike + cp PLAYER_BIKE + jr z, .GetOffBike + jr .CannotUseBike + +.GetOnBike: + ld hl, Script_GetOnBike + ld de, Script_GetOnBike_Register + call .CheckIfRegistered + call QueueScript + xor a + ld [MusicFade], a + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + call MaxVolume + ld de, MUSIC_BICYCLE + ld a, e + ld [wMapMusic], a + call PlayMusic + ld a, $1 + ret + +.GetOffBike: + ld hl, BikeFlags + bit 1, [hl] + jr nz, .CantGetOffBike + ld hl, Script_GetOffBike + ld de, Script_GetOffBike_Register + call .CheckIfRegistered + ld a, BANK(Script_GetOffBike) + jr .done + +.CantGetOffBike: + ld hl, Script_CantGetOffBike + jr .done + +.CannotUseBike: + ld a, $0 + ret + +.done + call QueueScript + ld a, $1 + ret + +.CheckIfRegistered: ; d119 + ld a, [wUsingItemWithSelect] + and a + ret z + ld h, d + ld l, e + ret + +.CheckEnvironment: ; d121 + call GetMapEnvironment + call CheckOutdoorMap + jr z, .ok + cp CAVE + jr z, .ok + cp GATE + jr z, .ok + jr .nope + +.ok + call GetPlayerStandingTile + and WALLTILE | WATERTILE ; can't use our bike in a wall or on water + jr nz, .nope + xor a + ret + +.nope + scf + ret + +Script_GetOnBike: ; 0xd13e + reloadmappart + special UpdateTimePals + writecode VAR_MOVEMENT, PLAYER_BIKE + writetext GotOnTheBikeText + waitbutton + closetext + special ReplaceKrisSprite + end + +Script_GetOnBike_Register: ; 0xd14e + writecode VAR_MOVEMENT, PLAYER_BIKE + closetext + special ReplaceKrisSprite + end + +; XXX + nop + ret + +Script_GetOffBike: ; 0xd158 + reloadmappart + special UpdateTimePals + writecode VAR_MOVEMENT, PLAYER_NORMAL + writetext GotOffTheBikeText + waitbutton + +FinishGettingOffBike: + closetext + special ReplaceKrisSprite + special PlayMapMusic + end + +Script_GetOffBike_Register: ; 0xd16b + writecode VAR_MOVEMENT, PLAYER_NORMAL + jump FinishGettingOffBike + +Script_CantGetOffBike: ; 0xd171 + writetext .CantGetOffBikeText + waitbutton + closetext + end + +.CantGetOffBikeText: ; 0xd177 + ; You can't get off here! + text_jump UnknownText_0x1c099a + db "@" + +GotOnTheBikeText: ; 0xd17c + ; got on the @ . + text_jump UnknownText_0x1c09b2 + db "@" + +GotOffTheBikeText: ; 0xd181 + ; got off the @ . + text_jump UnknownText_0x1c09c7 + db "@" + +TryCutOW:: ; d186 + ld d, CUT + call CheckPartyMove + jr c, .cant_cut + + ld de, ENGINE_HIVEBADGE + call CheckEngineFlag + jr c, .cant_cut + + ld a, BANK(AskCutScript) + ld hl, AskCutScript + call CallScript + scf + ret + +.cant_cut + ld a, BANK(CantCutScript) + ld hl, CantCutScript + call CallScript + scf + ret + +AskCutScript: ; 0xd1a9 + opentext + writetext UnknownText_0xd1c8 + yesorno + iffalse .script_d1b8 + callasm .CheckMap + iftrue Script_Cut +.script_d1b8 + closetext + end + +.CheckMap: ; d1ba + xor a + ld [ScriptVar], a + call CheckMapForSomethingToCut + ret c + ld a, TRUE + ld [ScriptVar], a + ret + +UnknownText_0xd1c8: ; 0xd1c8 + text_jump UnknownText_0x1c09dd + db "@" + +CantCutScript: ; 0xd1cd + jumptext UnknownText_0xd1d0 + +UnknownText_0xd1d0: ; 0xd1d0 + text_jump UnknownText_0x1c0a05 + db "@" diff --git a/engine/events/poisonstep.asm b/engine/events/poisonstep.asm new file mode 100755 index 000000000..00c7477bc --- /dev/null +++ b/engine/events/poisonstep.asm @@ -0,0 +1,162 @@ +DoPoisonStep:: ; 505da + ld a, [PartyCount] + and a + jr z, .no_faint + + xor a + ld c, 7 + ld hl, EngineBuffer1 +.loop_clearEngineBuffer1 + ld [hli], a + dec c + jr nz, .loop_clearEngineBuffer1 + + xor a + ld [CurPartyMon], a +.loop_check_poison + call .DamageMonIfPoisoned + jr nc, .not_poisoned +; the output flag is stored in c, copy it to the ([CurPartyMon] + 2)nd EngineBuffer +; and set the corresponding flag in EngineBuffer1 + ld a, [CurPartyMon] + ld e, a + ld d, 0 + ld hl, EngineBuffer2 + add hl, de + ld [hl], c + ld a, [EngineBuffer1] + or c + ld [EngineBuffer1], a + +.not_poisoned + ld a, [PartyCount] + ld hl, CurPartyMon + inc [hl] + cp [hl] + jr nz, .loop_check_poison + + ld a, [EngineBuffer1] + and %10 + jr nz, .someone_has_fainted + ld a, [EngineBuffer1] + and %01 + jr z, .no_faint + call .PlayPoisonSFX + xor a + ret + +.someone_has_fainted + ld a, BANK(.Script_MonFaintedToPoison) + ld hl, .Script_MonFaintedToPoison + call CallScript + scf + ret + +.no_faint + xor a + ret +; 5062e + +.DamageMonIfPoisoned: ; 5062e +; check if mon is poisoned, return if not + ld a, MON_STATUS + call GetPartyParamLocation + ld a, [hl] + and 1 << PSN + ret z + +; check if mon is already fainted, return if so + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + ld b, a + ld c, [hl] + or c + ret z + +; do 1 HP damage + dec bc + ld [hl], c + dec hl + ld [hl], b + +; check if mon has fainted as a result of poison damage + ld a, b + or c + jr nz, .not_fainted + +; the mon has fainted, reset its status, set carry, and return %10 + ld a, MON_STATUS + call GetPartyParamLocation + ld [hl], 0 + ld c, %10 + scf + ret + +.not_fainted +; set carry and return %01 + ld c, %01 + scf + ret +; 50658 + +.PlayPoisonSFX: ; 50658 + ld de, SFX_POISON + call PlaySFX + ld b, $2 + predef LoadPoisonBGPals + call DelayFrame + ret +; 50669 + +.Script_MonFaintedToPoison: ; 50669 + callasm .PlayPoisonSFX + opentext + callasm .CheckWhitedOut + iffalse .whiteout + closetext + end +; 50677 + +.whiteout ; 50677 + farjump Script_OverworldWhiteout +; 5067b + +.CheckWhitedOut: ; 5067b + xor a + ld [CurPartyMon], a + ld de, EngineBuffer2 +.party_loop + push de + ld a, [de] + and %10 + jr z, .mon_not_fainted + ld c, HAPPINESS_POISONFAINT + farcall ChangeHappiness + farcall GetPartyNick + ld hl, .PoisonFaintText + call PrintText + +.mon_not_fainted + pop de + inc de + ld hl, CurPartyMon + inc [hl] + ld a, [PartyCount] + cp [hl] + jr nz, .party_loop + predef CheckPlayerPartyForFitPkmn + ld a, d + ld [ScriptVar], a + ret +; 506b2 + +.PoisonFaintText: ; 506b2 + text_jump UnknownText_0x1c0acc + db "@" +; 506b7 + +.PoisonWhiteOutText: ; 506b7 + text_jump UnknownText_0x1c0ada + db "@" +; 506bc diff --git a/engine/events/poisonstep_pals.asm b/engine/events/poisonstep_pals.asm new file mode 100644 index 000000000..088be8848 --- /dev/null +++ b/engine/events/poisonstep_pals.asm @@ -0,0 +1,48 @@ +LoadPoisonBGPals: ; cbcdd + call .LoadPals + ld a, [hCGB] + and a + ret nz + ret ; ???? + +.LoadPals: ; cbce5 + ld a, [hCGB] + and a + jr nz, .cgb + ld a, [TimeOfDayPal] + and $3 + cp $3 + ld a, %00000000 + jr z, .convert_pals + ld a, %10101010 + +.convert_pals + call DmgToCgbBGPals + ld c, 4 + call DelayFrames + farcall _UpdateTimePals + ret + +.cgb + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld hl, BGPals + ld c, $20 +.loop +; RGB 28, 21, 31 + ld a, LOW(palred 28 + palgreen 21 + palblue 31) + ld [hli], a + ld a, HIGH(palred 28 + palgreen 21 + palblue 31) + ld [hli], a + dec c + jr nz, .loop + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ld c, 4 + call DelayFrames + farcall _UpdateTimePals + ret diff --git a/engine/events/poke_seer.asm b/engine/events/poke_seer.asm new file mode 100644 index 000000000..d6e335298 --- /dev/null +++ b/engine/events/poke_seer.asm @@ -0,0 +1,461 @@ + const_def + const SEER_INTRO + const SEER_CANT_TELL + const SEER_MET_AT + const SEER_TIME_LEVEL + const SEER_TRADED + const SEER_CANCEL + const SEER_EGG + const SEER_LEVEL_ONLY + + const_def + const SEERACTION_MET + const SEERACTION_TRADED + const SEERACTION_CANT_TELL_1 + const SEERACTION_CANT_TELL_2 + const SEERACTION_LEVEL_ONLY + +SpecialPokeSeer: ; 4f0bc + ld a, SEER_INTRO + call PrintSeerText + call JoyWaitAorB + + ld b, $6 + farcall SelectMonFromParty + jr c, .cancel + + ld a, [CurPartySpecies] + cp EGG + jr z, .egg + + call IsAPokemon + jr c, .no_mon + + call ReadCaughtData + call SeerAction + ret + +.cancel + ld a, SEER_CANCEL + call PrintSeerText + ret + +.no_mon + ret + +.egg + ld a, SEER_EGG + call PrintSeerText + ret +; 4f0ee + + +SeerAction: ; 4f0ee + ld a, [wSeerAction] + ld hl, SeerActions + rst JumpTable + ret +; 4f0f6 + +SeerActions: ; 4f0f6 + dw SeerAction0 + dw SeerAction1 + dw SeerAction2 + dw SeerAction3 + dw SeerAction4 +; 4f100 + +SeerAction0: ; 4f100 + ld a, SEER_MET_AT + call PrintSeerText + ld a, SEER_TIME_LEVEL + call PrintSeerText + call SeerAdvice + ret +; 4f10e + +SeerAction1: ; 4f10e + call GetCaughtOT + ld a, SEER_TRADED + call PrintSeerText + ld a, SEER_TIME_LEVEL + call PrintSeerText + call SeerAdvice + ret +; 4f11f + +SeerAction2: ; 4f11f + ld a, SEER_CANT_TELL + call PrintSeerText + ret +; 4f125 + +SeerAction3: ; 4f125 + ld a, SEER_CANT_TELL + call PrintSeerText + ret +; 4f12b + +SeerAction4: ; 4f12b + ld a, SEER_LEVEL_ONLY + call PrintSeerText + call SeerAdvice + ret +; 4f134 + +ReadCaughtData: ; 4f134 + ld a, MON_CAUGHTDATA + call GetPartyParamLocation + ld a, [hli] + ld [wSeerCaughtData], a + ld a, [hld] + ld [wSeerCaughtGender], a + or [hl] + jr z, .error + + ld a, SEERACTION_TRADED + ld [wSeerAction], a + + ld a, MON_ID + call GetPartyParamLocation + ld a, [PlayerID] + cp [hl] + jr nz, .traded + + inc hl + ld a, [PlayerID + 1] + ; cp [hl] + jr nz, .traded + + ld a, SEERACTION_MET + ld [wSeerAction], a + +.traded + call GetCaughtLevel + call GetCaughtOT + call GetCaughtName + call GetCaughtTime + call GetCaughtLocation + and a + ret + +.error + ld a, SEERACTION_CANT_TELL_1 + ld [wSeerAction], a + ret +; 4f176 + +GetCaughtName: ; 4f176 + ld a, [CurPartyMon] + ld hl, PartyMonNicknames + ld bc, PKMN_NAME_LENGTH + call AddNTimes + ld de, wSeerNickname + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ret +; 4f18c + +GetCaughtLevel: ; 4f18c + ld a, "@" + ld hl, wSeerCaughtLevelString + ld bc, 4 + call ByteFill + + ; caught level + ; Limited to between 1 and 63 for some reason. + ld a, [wSeerCaughtData] + and $3f + jr z, .unknown + cp 1 ; hatched from an egg + jr nz, .print + ld a, EGG_LEVEL ; egg hatch level + +.print + ld [wSeerCaughtLevel], a + ld hl, wSeerCaughtLevelString + ld de, wSeerCaughtLevel + lb bc, PRINTNUM_RIGHTALIGN | 1, 3 + call PrintNum + ret + +.unknown + ld de, wSeerCaughtLevelString + ld hl, .unknown_level + ld bc, 4 + call CopyBytes + ret +; 4f1c1 + +.unknown_level ; 4f1c1 + db "???@" +; 4f1c5 + +GetCaughtTime: ; 4f1c5 + ld a, [wSeerCaughtData] + and $c0 + jr z, .none + + rlca + rlca + dec a + ld hl, .times + call GetNthString + ld d, h + ld e, l + ld hl, wSeerTimeOfDay + call CopyName2 + and a + ret + +.none + ld de, wSeerTimeOfDay + call UnknownCaughtData + ret +; 4f1e6 + +.times ; 4f1e6 + db "Morning@" + db "Day@" + db "Night@" +; 4f1f8 + +UnknownCaughtData: ; 4f1f8 + ld hl, .unknown + ld bc, NAME_LENGTH + call CopyBytes + ret +; 4f202 + +.unknown ; 4f202 + db "Unknown@" +; 4f20a + +GetCaughtLocation: ; 4f20a + ld a, [wSeerCaughtGender] + and $7f + jr z, .Unknown + cp $7f + jr z, .event + cp $7e + jr z, .fail + ld e, a + farcall GetLandmarkName + ld hl, StringBuffer1 + ld de, wSeerCaughtLocation + ld bc, 17 + call CopyBytes + and a + ret + +.Unknown: + ld de, wSeerCaughtLocation + jp UnknownCaughtData + +.event + ld a, SEERACTION_LEVEL_ONLY + ld [wSeerAction], a + scf + ret + +.fail + ld a, SEERACTION_CANT_TELL_2 + ld [wSeerAction], a + scf + ret +; 4f242 + +GetCaughtOT: ; 4f242 + ld a, [CurPartyMon] + ld hl, PartyMonOT + ld bc, NAME_LENGTH + call AddNTimes + ld de, wSeerOTName + ld bc, NAME_LENGTH + call CopyBytes + +; this routine is useless in Western localizations + ld hl, .male + ld a, [wSeerCaughtGender] + bit 7, a + jr z, .got_grammar + ld hl, .female + +.got_grammar + ld de, wSeerOTNameGrammar + ld a, "@" + ld [de], a + ret +; 4f26b + +.male ; 4f26b + db "@" +.female ; 4f26c + db "@" +; 4f26d + +PrintSeerText: ; 4f26d + ld e, a + ld d, 0 + ld hl, SeerTexts + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + ret +; 4f27c + +SeerTexts: ; 4f27c + dw SeerIntroText + dw SeerCantTellText + dw SeerMetAtText + dw SeerTimeLevelText + dw SeerTradedText + dw SeerCancelText + dw SeerEggText + dw SeerLevelOnlyText +; 4f28c + +SeerIntroText: ; 0x4f28c + ; I see all. I know all… Certainly, I know of your #MON! + text_jump UnknownText_0x1c475f + db "@" +; 0x4f291 + +SeerCantTellText: ; 0x4f291 + ; Whaaaat? I can't tell a thing! How could I not know of this? + text_jump UnknownText_0x1c4797 + db "@" +; 0x4f296 + +SeerMetAtText: ; 0x4f296 + ; Hm… I see you met @ here: @ ! + text_jump UnknownText_0x1c47d4 + db "@" +; 0x4f29b + +SeerTimeLevelText: ; 0x4f29b + ; The time was @ ! Its level was @ ! Am I good or what? + text_jump UnknownText_0x1c47fa + db "@" +; 0x4f2a0 + +SeerTradedText: ; 0x4f2a0 + ; Hm… @ came from @ in a trade? @ was where @ met @ ! + text_jump UnknownText_0x1c4837 + db "@" +; 0x4f2a5 + +SeerLevelOnlyText: ; 0x4f2a5 + ; What!? Incredible! I don't understand how, but it is incredible! You are special. I can't tell where you met it, but it was at level @ . Am I good or what? + text_jump UnknownText_0x1c487f + db "@" +; 0x4f2aa + +SeerEggText: ; 0x4f2aa + ; Hey! That's an EGG! You can't say that you've met it yet… + text_jump UnknownText_0x1c491d + db "@" +; 0x4f2af + +SeerCancelText: ; 0x4f2af + ; Fufufu! I saw that you'd do nothing! + text_jump UnknownText_0x1c4955 + db "@" +; 0x4f2b4 + + +SeerAdvice: ; 4f2b4 + ld a, MON_LEVEL + call GetPartyParamLocation + ld a, [wSeerCaughtLevel] + ld c, a + ld a, [hl] + sub c + ld c, a + + ld hl, SeerAdviceTexts + ld de, 3 +.next + cp [hl] + jr c, .print + jr z, .print + add hl, de + jr .next + +.print + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + ret +; 4f2d6 + +SeerAdviceTexts: ; 4f2d6 +; level, text + dbw 9, SeerAdvice1 + dbw 29, SeerAdvice2 + dbw 59, SeerAdvice3 + dbw 89, SeerAdvice4 + dbw 100, SeerAdvice5 + dbw 255, SeerAdvice1 +; 4f2e8 + +SeerAdvice1: ; 0x4f2e8 + ; Incidentally… It would be wise to raise your #MON with a little more care. + text_jump UnknownText_0x1c497a + db "@" +; 0x4f2ed + +SeerAdvice2: ; 0x4f2ed + ; Incidentally… It seems to have grown a little. @ seems to be becoming more confident. + text_jump UnknownText_0x1c49c6 + db "@" +; 0x4f2f2 + +SeerAdvice3: ; 0x4f2f2 + ; Incidentally… @ has grown. It's gained much strength. + text_jump UnknownText_0x1c4a21 + db "@" +; 0x4f2f7 + +SeerAdvice4: ; 0x4f2f7 + ; Incidentally… It certainly has grown mighty! This @ must have come through numerous #MON battles. It looks brimming with confidence. + text_jump UnknownText_0x1c4a5b + db "@" +; 0x4f2fc + +SeerAdvice5: ; 0x4f2fc + ; Incidentally… I'm impressed by your dedication. It's been a long time since I've seen a #MON as mighty as this @ . I'm sure that seeing @ in battle would excite anyone. + text_jump UnknownText_0x1c4ae5 + db "@" +; 0x4f301 + + +GetCaughtGender: ; 4f301 + ld hl, MON_CAUGHTGENDER + add hl, bc + + ld a, [hl] + and $7f + jr z, .genderless + cp $7f + jr z, .genderless + + ld a, [hl] + and $80 + jr nz, .male + ld c, 1 + ret + +.male + ld c, 2 + ret + +.genderless + ld c, 0 + ret +; 4f31c diff --git a/engine/pokecenter_pc.asm b/engine/events/pokecenter_pc.asm index 7045dc1c8..7045dc1c8 100755 --- a/engine/pokecenter_pc.asm +++ b/engine/events/pokecenter_pc.asm diff --git a/engine/pokepic.asm b/engine/events/pokepic.asm index ea5b3c300..ea5b3c300 100755 --- a/engine/pokepic.asm +++ b/engine/events/pokepic.asm diff --git a/engine/pokerus/apply_pokerus_tick.asm b/engine/events/pokerus/apply_pokerus_tick.asm index 3c97fdc5e..3c97fdc5e 100644 --- a/engine/pokerus/apply_pokerus_tick.asm +++ b/engine/events/pokerus/apply_pokerus_tick.asm diff --git a/engine/pokerus/check_pokerus.asm b/engine/events/pokerus/check_pokerus.asm index 285024754..285024754 100644 --- a/engine/pokerus/check_pokerus.asm +++ b/engine/events/pokerus/check_pokerus.asm diff --git a/engine/pokerus/pokerus.asm b/engine/events/pokerus/pokerus.asm index 3e5e094e4..3e5e094e4 100644 --- a/engine/pokerus/pokerus.asm +++ b/engine/events/pokerus/pokerus.asm diff --git a/engine/events/print_photo.asm b/engine/events/print_photo.asm new file mode 100755 index 000000000..06b01bbcf --- /dev/null +++ b/engine/events/print_photo.asm @@ -0,0 +1,61 @@ +PhotoStudio: ; 16dc7 + ld hl, .Text_AskWhichMon + call PrintText + farcall SelectMonFromParty + jr c, .cancel + ld a, [CurPartySpecies] + cp EGG + jr z, .egg + + ld hl, .Text_HoldStill + call PrintText + call DisableSpriteUpdates + farcall PrintPartymon + call ReturnToMapWithSpeechTextbox + ld a, [hPrinter] + and a + jr nz, .cancel + ld hl, .Text_Presto + jr .print_text + +.cancel + ld hl, .Text_NoPicture + jr .print_text + +.egg + ld hl, .Text_Egg + +.print_text + call PrintText + ret +; 16e04 + +.Text_AskWhichMon: ; 0x16e04 + ; Which #MON should I photo- graph? + text_jump UnknownText_0x1be024 + db "@" +; 0x16e09 + +.Text_HoldStill: ; 0x16e09 + ; All righty. Hold still for a bit. + text_jump UnknownText_0x1be047 + db "@" +; 0x16e0e + +.Text_Presto: ; 0x16e0e + ; Presto! All done. Come again, OK? + text_jump UnknownText_0x1be06a + db "@" +; 0x16e13 + +.Text_NoPicture: ; 0x16e13 + ; Oh, no picture? Come again, OK? + text_jump UnknownText_0x1c0000 + db "@" +; 0x16e18 + +.Text_Egg: ; 0x16e18 + ; An EGG? My talent is worth more… + text_jump UnknownText_0x1c0021 + db "@" +; 0x16e1d diff --git a/engine/events/print_unown.asm b/engine/events/print_unown.asm new file mode 100644 index 000000000..7841a688b --- /dev/null +++ b/engine/events/print_unown.asm @@ -0,0 +1,233 @@ +UnownPrinter: ; 16be4 + ld a, [UnownDex] + and a + ret z + + ld a, [hInMenu] + push af + ld a, $1 + ld [hInMenu], a + ld a, [Options] + push af + set NO_TEXT_SCROLL, a + ld [Options], a + call ClearBGPalettes + call ClearTileMap + + ld de, UnownDexATile + ld hl, VTiles1 tile $6f + lb bc, BANK(UnownDexBTile), 1 + call Request1bpp + + ld de, UnownDexBTile + ld hl, VTiles1 tile $75 + lb bc, BANK(UnownDexBTile), 1 + call Request1bpp + + hlcoord 0, 0 + lb bc, 3, 18 + call TextBox + + hlcoord 0, 5 + lb bc, 7, 7 + call TextBox + + hlcoord 0, 14 + lb bc, 2, 18 + call TextBox + + hlcoord 1, 2 + ld de, AlphRuinsStampString + call PlaceString + + hlcoord 1, 16 + ld de, UnownDexDoWhatString + call PlaceString + + hlcoord 10, 6 + ld de, UnownDexMenuString + call PlaceString + + xor a + ld [wJumptableIndex], a + call .UpdateUnownFrontpic + call WaitBGMap + + ld a, UNOWN + ld [CurPartySpecies], a + xor a + ld [TempMonDVs], a + ld [TempMonDVs + 1], a + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call SetPalettes + +.joy_loop + call JoyTextDelay + + ld a, [hJoyPressed] + and B_BUTTON + jr nz, .pressed_b + + ld a, [hJoyPressed] + and A_BUTTON + jr nz, .pressed_a + + call .LeftRight + call DelayFrame + jr .joy_loop + +.pressed_a + ld a, [wJumptableIndex] + push af + farcall PrintUnownStamp + call RestartMapMusic + pop af + ld [wJumptableIndex], a + jr .joy_loop + +.pressed_b + pop af + ld [Options], a + pop af + ld [hInMenu], a + call ReturnToMapFromSubmenu + ret +; 16ca0 + +.LeftRight: ; 16ca0 + ld a, [hJoyLast] + and D_RIGHT + jr nz, .press_right + ld a, [hJoyLast] + and D_LEFT + jr nz, .press_left + ret + +.press_left + ld hl, wJumptableIndex + ld a, [hl] + and a + jr nz, .wrap_around_left + ld [hl], 26 + 1 +.wrap_around_left + dec [hl] + jr .return + +.press_right + ld hl, wJumptableIndex + ld a, [hl] + cp 26 + jr c, .wrap_around_right + ld [hl], -1 +.wrap_around_right + inc [hl] + +.return + call .UpdateUnownFrontpic + ret +; 16cc8 + +.UpdateUnownFrontpic: ; 16cc8 + ld a, [wJumptableIndex] + cp 26 + jr z, .vacant + inc a + ld [UnownLetter], a + ld a, UNOWN + ld [CurPartySpecies], a + xor a + ld [wBoxAlignment], a + ld de, VTiles2 + predef GetMonFrontpic + call .Load2bppToSRAM + hlcoord 1, 6 + xor a + ld [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + ld de, VTiles2 tile $31 + farcall RotateUnownFrontpic + ret + +.Load2bppToSRAM: ; 16cff + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + + ld a, BANK(sScratch) + call GetSRAMBank + ld de, wDecompressScratch + ld hl, sScratch + ld a, [hROMBank] + ld b, a + ld c, $31 + call Get2bpp + call CloseSRAM + + pop af + ld [rSVBK], a + ret + +.vacant + hlcoord 1, 6 + lb bc, 7, 7 + call ClearBox + hlcoord 1, 9 + ld de, UnownDexVacantString + call PlaceString + xor a + call GetSRAMBank + ld hl, sScratch + ld bc, $31 tiles + xor a + call ByteFill + ld hl, VTiles2 tile $31 + ld de, sScratch + ld c, $31 + ld a, [hROMBank] + ld b, a + call Get2bpp + call CloseSRAM + ld c, 20 + call DelayFrames + ret +; 16d57 + +AlphRuinsStampString: + db " ALPH RUINS STAMP@" + +UnownDexDoWhatString: + db "Do what?@" + +UnownDexMenuString: + db "♂ PRINT" + next "♀ CANCEL" + next "← PREVIOUS" + next "→ NEXT" + db "@" + +UnownDexVacantString: + db "VACANT@" +; 16d9c + +UnownDexATile: ; 16d9c +INCBIN "gfx/printer/bold_a.1bpp" +UnownDexBTile: ; 16da4 +INCBIN "gfx/printer/bold_b.1bpp" +; 16dac + +PlaceUnownPrinterFrontpic: ; 16dac + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + hlcoord 7, 11 + ld a, $31 + ld [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + ret +; 16dc7 diff --git a/engine/events/print_unown_2.asm b/engine/events/print_unown_2.asm new file mode 100644 index 000000000..057db5176 --- /dev/null +++ b/engine/events/print_unown_2.asm @@ -0,0 +1,111 @@ +RotateUnownFrontpic: ; e0000 +; something to do with Unown printer + push de + xor a + call GetSRAMBank + ld hl, sScratch + ld bc, 0 +.loop + push bc + push hl + push bc + ld de, wd002 + call .Copy + call .Rotate + ld hl, UnownPrinter_OverworldMapRectangle + pop bc + add hl, bc + add hl, bc + ld a, [hli] + ld e, a + ld d, [hl] + ld hl, wd012 + call .Copy + pop hl + ld bc, $10 + add hl, bc + pop bc + inc c + ld a, c + cp 7 * 7 + jr c, .loop + + ld hl, OverworldMap + ld de, sScratch + ld bc, 7 * 7 tiles + call CopyBytes + pop hl + ld de, sScratch + ld c, 7 * 7 + ld a, [hROMBank] + ld b, a + call Get2bpp + call CloseSRAM + ret + +.Copy: ; e004e + ld c, $10 +.loop_copy + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop_copy + ret + +.Rotate: ; e0057 + ld hl, wd012 + ld e, %10000000 + ld d, 8 +.loop_decompress + push hl + ld hl, wd002 + call .CountSetBit + pop hl + ld a, b + ld [hli], a + push hl + ld hl, wd003 + call .CountSetBit + pop hl + ld a, b + ld [hli], a + srl e + dec d + jr nz, .loop_decompress + ret + +.CountSetBit: ; e0078 + ld b, 0 + ld c, 8 +.loop_count + ld a, [hli] + and e + jr z, .clear + scf + jr .apply + +.clear + and a + +.apply + rr b + inc hl + dec c + jr nz, .loop_count + ret + +overworldmaprect: MACRO +y = 0 +rept \1 +x = \1 * (\2 +- 1) + y +rept \2 + dw OverworldMap tile x +x = x +- \2 +endr +y = y + 1 +endr +endm + +UnownPrinter_OverworldMapRectangle: ; e008b + overworldmaprect 7, 7 diff --git a/engine/prof_oaks_pc.asm b/engine/events/prof_oaks_pc.asm index 69949940b..69949940b 100755 --- a/engine/prof_oaks_pc.asm +++ b/engine/events/prof_oaks_pc.asm diff --git a/engine/events/sacred_ash.asm b/engine/events/sacred_ash.asm new file mode 100755 index 000000000..cc46eac9f --- /dev/null +++ b/engine/events/sacred_ash.asm @@ -0,0 +1,74 @@ + +_SacredAsh: ; 507e6 + ld a, $0 + ld [wItemEffectSucceeded], a + call CheckAnyFaintedMon + ret nc + + ld hl, SacredAshScript + call QueueScript + ld a, $1 + ld [wItemEffectSucceeded], a + ret +; 507fb + +CheckAnyFaintedMon: ; 507fb + ld de, PARTYMON_STRUCT_LENGTH + ld bc, PartySpecies + ld hl, PartyMon1HP + ld a, [PartyCount] + and a + ret z + +.loop + push af + push hl + ld a, [bc] + inc bc + cp EGG + jr z, .next + + ld a, [hli] + or [hl] + jr z, .done + +.next + pop hl + add hl, de + pop af + dec a + jr nz, .loop + xor a + ret + +.done + pop hl + pop af + scf + ret +; 50821 + +SacredAshScript: ; 0x50821 + special HealParty + reloadmappart + playsound SFX_WARP_TO + special FadeOutPalettes + special FadeInPalettes + special FadeOutPalettes + special FadeInPalettes + special FadeOutPalettes + special FadeInPalettes + waitsfx + writetext UnknownText_0x50845 + playsound SFX_CAUGHT_MON + waitsfx + waitbutton + closetext + end +; 0x50845 + +UnknownText_0x50845: ; 0x50845 + ; 's #MON were all healed! + text_jump UnknownText_0x1c0b65 + db "@" +; 0x5084a diff --git a/engine/events/special.asm b/engine/events/special.asm new file mode 100755 index 000000000..d28d0de64 --- /dev/null +++ b/engine/events/special.asm @@ -0,0 +1,235 @@ +SpecialGiveShuckle: ; 7305 + +; Adding to the party. + xor a + ld [MonType], a + +; Level 15 Shuckle. + ld a, SHUCKLE + ld [CurPartySpecies], a + ld a, 15 + ld [CurPartyLevel], a + + predef TryAddMonToParty + jr nc, .NotGiven + +; Caught data. + ld b, 0 + farcall SetGiftPartyMonCaughtData + +; Holding a Berry. + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [PartyCount] + dec a + push af + push bc + ld hl, PartyMon1Item + call AddNTimes + ld [hl], BERRY + pop bc + pop af + +; OT ID. + ld hl, PartyMon1ID + call AddNTimes + ld a, $2 + ld [hli], a + ld [hl], $6 + +; Nickname. + ld a, [PartyCount] + dec a + ld hl, PartyMonNicknames + call SkipNames + ld de, SpecialShuckleNick + call CopyName2 + +; OT. + ld a, [PartyCount] + dec a + ld hl, PartyMonOT + call SkipNames + ld de, SpecialShuckleOT + call CopyName2 + +; Engine flag for this event. + ld hl, DailyFlags + set 5, [hl] +; setflag ENGINE_SHUCKLE_GIVEN + ld a, 1 + ld [ScriptVar], a + ret + +.NotGiven: + xor a + ld [ScriptVar], a + ret + +SpecialShuckleOT: + db "MANIA@" +SpecialShuckleNick: + db "SHUCKIE@" + +SpecialReturnShuckle: ; 737e + farcall SelectMonFromParty + jr c, .refused + + ld a, [CurPartySpecies] + cp SHUCKLE + jr nz, .DontReturn + + ld a, [CurPartyMon] + ld hl, PartyMon1ID + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + +; OT ID + ld a, [hli] + cp HIGH(00518) + jr nz, .DontReturn + ld a, [hl] + cp LOW(00518) + jr nz, .DontReturn + +; OT + ld a, [CurPartyMon] + ld hl, PartyMonOT + call SkipNames + ld de, SpecialShuckleOT +.CheckOT: + ld a, [de] + cp [hl] + jr nz, .DontReturn + cp "@" + jr z, .done + inc de + inc hl + jr .CheckOT + +.done + farcall CheckCurPartyMonFainted + jr c, .fainted + ld a, [CurPartyMon] + ld hl, PartyMon1Happiness + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld a, [hl] + cp 150 + ld a, $3 + jr nc, .HappyToStayWithYou + xor a ; take from pc + ld [wPokemonWithdrawDepositParameter], a + callfar RemoveMonFromPartyOrBox + ld a, $2 +.HappyToStayWithYou: + ld [ScriptVar], a + ret + +.refused + ld a, $1 + ld [ScriptVar], a + ret + +.DontReturn: + xor a + ld [ScriptVar], a + ret + +.fainted + ld a, $4 + ld [ScriptVar], a + ret + +Special_BillsGrandfather: ; 73f7 + farcall SelectMonFromParty + jr c, .cancel + ld a, [CurPartySpecies] + ld [ScriptVar], a + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + jp CopyPokemonName_Buffer1_Buffer3 + +.cancel + xor a + ld [ScriptVar], a + ret + +Special_YoungerHaircutBrother: ; 7413 + ld hl, Data_YoungerHaircutBrother + jr MassageOrHaircut + +Special_OlderHaircutBrother: ; 7418 + ld hl, Data_OlderHaircutBrother + jr MassageOrHaircut + +Special_DaisyMassage: ; 741d + ld hl, Data_DaisyMassage + +MassageOrHaircut: ; 7420 + push hl + farcall SelectMonFromParty + pop hl + jr c, .nope + ld a, [CurPartySpecies] + cp EGG + jr z, .egg + push hl + call GetCurNick + call CopyPokemonName_Buffer1_Buffer3 + pop hl + call Random +; Bug: Subtracting $ff from $ff fails to set c. +; This can result in overflow into the next data array. +; In the case of getting a massage from Daisy, we bleed +; into CopyPokemonName_Buffer1_Buffer3, which passes +; $d0 to ChangeHappiness and returns $73 to the script. +; The end result is that there is a 0.4% chance your +; Pokemon's happiness will not change at all. +.loop + sub [hl] + jr c, .ok + inc hl + inc hl + inc hl + jr .loop + +.ok + inc hl + ld a, [hli] + ld [ScriptVar], a + ld c, [hl] + call ChangeHappiness + ret + +.nope + xor a + ld [ScriptVar], a + ret + +.egg + ld a, 1 + ld [ScriptVar], a + ret + +Data_YoungerHaircutBrother: ; 7459 + db $4c, 2, HAPPINESS_YOUNGCUT1 ; 30% chance + db $80, 3, HAPPINESS_YOUNGCUT2 ; 20% chance + db $ff, 4, HAPPINESS_YOUNGCUT3 ; 50% chance + +Data_OlderHaircutBrother: ; 7462 + db $9a, 2, HAPPINESS_OLDERCUT1 ; 60% chance + db $4c, 3, HAPPINESS_OLDERCUT2 ; 10% chance + db $ff, 4, HAPPINESS_OLDERCUT3 ; 30% chance + +Data_DaisyMassage: ; 746b + db $ff, 2, HAPPINESS_MASSAGE ; 99.6% chance + +CopyPokemonName_Buffer1_Buffer3: ; 746e + ld hl, StringBuffer1 + ld de, StringBuffer3 + ld bc, PKMN_NAME_LENGTH + jp CopyBytes + +Predef1: ; 747a +; not used + ret diff --git a/engine/events/squirtbottle.asm b/engine/events/squirtbottle.asm new file mode 100755 index 000000000..1134f1bb0 --- /dev/null +++ b/engine/events/squirtbottle.asm @@ -0,0 +1,47 @@ +_Squirtbottle: ; 50730 + ld hl, .SquirtbottleScript + call QueueScript + ld a, $1 + ld [wItemEffectSucceeded], a + ret + +.SquirtbottleScript: + reloadmappart + special UpdateTimePals + callasm .CheckCanUseSquirtbottle + iffalse .NothingHappenedScript + farjump WateredWeirdTreeScript + +.NothingHappenedScript: + jumptext .NothingHappenedText + +.NothingHappenedText: + ; sprinkled water. But nothing happened… + text_jump UnknownText_0x1c0b3b + db "@" + +.CheckCanUseSquirtbottle: + ld a, [MapGroup] + cp GROUP_ROUTE_36 + jr nz, .nope + + ld a, [MapNumber] + cp MAP_ROUTE_36 + jr nz, .nope + + farcall GetFacingObject + jr c, .nope + + ld a, d + cp SPRITEMOVEDATA_SUDOWOODO + jr nz, .nope + + ld a, 1 + ld [ScriptVar], a + ret + +.nope + xor a + ld [ScriptVar], a + ret +; 50779 diff --git a/engine/events/std_collision.asm b/engine/events/std_collision.asm new file mode 100644 index 000000000..79dbc71f1 --- /dev/null +++ b/engine/events/std_collision.asm @@ -0,0 +1,29 @@ +CheckFacingTileForStdScript:: ; 1365b +; Checks to see if the tile you're facing has a std script associated with it. If so, executes the script and returns carry. + ld a, c + ld de, 3 + ld hl, TileCollisionStdScripts + call IsInArray + jr nc, .notintable + + ld a, jumpstd_command + ld [wJumpStdScriptBuffer], a + inc hl + ld a, [hli] + ld [wJumpStdScriptBuffer + 1], a + ld a, [hli] + ld [wJumpStdScriptBuffer + 2], a + ld a, BANK(Script_JumpStdFromRAM) + ld hl, Script_JumpStdFromRAM + call CallScript + scf + ret + +.notintable + xor a + ret + +INCLUDE "data/collision_stdscripts.asm" + +Script_JumpStdFromRAM: ; 0x1369a + jump wJumpStdScriptBuffer diff --git a/engine/std_scripts.asm b/engine/events/std_scripts.asm index 297725c60..297725c60 100644 --- a/engine/std_scripts.asm +++ b/engine/events/std_scripts.asm diff --git a/engine/events/sweet_scent.asm b/engine/events/sweet_scent.asm new file mode 100755 index 000000000..77567488c --- /dev/null +++ b/engine/events/sweet_scent.asm @@ -0,0 +1,75 @@ +SweetScentFromMenu: ; 506bc + ld hl, .SweetScent + call QueueScript + ld a, $1 + ld [wFieldMoveSucceeded], a + ret +; 506c8 + +.SweetScent: ; 0x506c8 + reloadmappart + special UpdateTimePals + callasm GetPartyNick + writetext UnknownText_0x50726 + waitbutton + callasm SweetScentEncounter + iffalse SweetScentNothing + checkflag ENGINE_BUG_CONTEST_TIMER + iftrue .BugCatchingContest + randomwildmon + startbattle + reloadmapafterbattle + end +; 0x506e5 + +.BugCatchingContest: ; 0x506e5 + farjump BugCatchingContestBattleScript +; 0x506e9 + +SweetScentNothing: ; 0x506e9 + writetext UnknownText_0x5072b + waitbutton + closetext + end +; 0x506ef + +SweetScentEncounter: ; 506ef + farcall CanUseSweetScent + jr nc, .no_battle + ld hl, StatusFlags2 + bit 2, [hl] + jr nz, .not_in_bug_contest + farcall GetMapEncounterRate + ld a, b + and a + jr z, .no_battle + farcall ChooseWildEncounter + jr nz, .no_battle + jr .start_battle + +.not_in_bug_contest + farcall ChooseWildEncounter_BugContest + +.start_battle + ld a, $1 + ld [ScriptVar], a + ret + +.no_battle + xor a + ld [ScriptVar], a + ld [BattleType], a + ret +; 50726 + +UnknownText_0x50726: ; 0x50726 + ; used SWEET SCENT! + text_jump UnknownText_0x1c0b03 + db "@" +; 0x5072b + +UnknownText_0x5072b: ; 0x5072b + ; Looks like there's nothing here… + text_jump UnknownText_0x1c0b1a + db "@" +; 0x50730 diff --git a/engine/trainer_scripts.asm b/engine/events/trainer_scripts.asm index 212cd7f28..212cd7f28 100644 --- a/engine/trainer_scripts.asm +++ b/engine/events/trainer_scripts.asm diff --git a/engine/events/whiteout.asm b/engine/events/whiteout.asm new file mode 100755 index 000000000..a9d6f900e --- /dev/null +++ b/engine/events/whiteout.asm @@ -0,0 +1,82 @@ +Script_BattleWhiteout:: ; 0x124c1 + callasm BattleBGMap + jump Script_Whiteout +; 0x124c8 + +Script_OverworldWhiteout:: ; 0x124c8 + refreshscreen $0 + callasm OverworldBGMap + +Script_Whiteout: ; 0x124ce + writetext .WhitedOutText + waitbutton + special FadeOutPalettes + pause 40 + special HealParty + checkflag ENGINE_BUG_CONTEST_TIMER + iftrue .bug_contest + callasm HalveMoney + callasm GetWhiteoutSpawn + farscall Script_AbortBugContest + special WarpToSpawnPoint + newloadmap MAPSETUP_WARP + end_all + +.bug_contest + jumpstd bugcontestresultswarp +; 0x124f5 + +.WhitedOutText: ; 0x124f5 + ; is out of useable #MON! whited out! + text_jump UnknownText_0x1c0a4e + db "@" +; 0x124fa + +OverworldBGMap: ; 124fa + call ClearPalettes + call ClearScreen + call WaitBGMap2 + call HideSprites + call RotateThreePalettesLeft + ret +; 1250a + +BattleBGMap: ; 1250a + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + call SetPalettes + ret +; 12513 + +HalveMoney: ; 12513 + farcall TrainerRankings_WhiteOuts + +; Halve the player's money. + ld hl, Money + ld a, [hl] + srl a + ld [hli], a + ld a, [hl] + rra + ld [hli], a + ld a, [hl] + rra + ld [hl], a + ret +; 12527 + + +GetWhiteoutSpawn: ; 12527 + ld a, [wLastSpawnMapGroup] + ld d, a + ld a, [wLastSpawnMapNumber] + ld e, a + farcall IsSpawnPoint + ld a, c + jr c, .yes + xor a ; SPAWN_HOME + +.yes + ld [DefaultSpawnpoint], a + ret +; 1253d diff --git a/engine/intro_menu.asm b/engine/intro_menu.asm index ec53549f8..77d1af6f9 100755 --- a/engine/intro_menu.asm +++ b/engine/intro_menu.asm @@ -111,8 +111,8 @@ _ResetWRAM: ; 5bae xor a call ByteFill - ld hl, wRAM1Start - ld bc, wGameData - wRAM1Start + ld hl, WRAM1_Begin + ld bc, wGameData - WRAM1_Begin xor a call ByteFill diff --git a/engine/link.asm b/engine/link.asm index bb3e98b3e..5c45707d7 100755 --- a/engine/link.asm +++ b/engine/link.asm @@ -861,7 +861,7 @@ Link_PrepPartyData_Gen2: ; 28595 pop bc dec b jr nz, .loop2 -; Copy the mail metadata to wcabf +; Copy the mail data to wcabf ld hl, sPartyMail ld b, PARTY_LENGTH .loop3 diff --git a/engine/mail.asm b/engine/mail.asm index 392405b20..0335a6dfe 100755 --- a/engine/mail.asm +++ b/engine/mail.asm @@ -383,7 +383,7 @@ MailboxPC_PrintMailAuthor: ; 0x447fb MailboxPC: ; 0x44806 xor a - ld [OBPals + 8 * 6], a + ld [wCurMessageScrollPosition], a ld a, 1 ld [wCurMessageIndex], a .loop @@ -397,11 +397,11 @@ MailboxPC: ; 0x44806 ld a, [wCurMessageIndex] ld [wMenuCursorBuffer], a - ld a, [OBPals + 8 * 6] + ld a, [wCurMessageScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [OBPals + 8 * 6], a + ld [wCurMessageScrollPosition], a ld a, [wMenuCursorY] ld [wCurMessageIndex], a diff --git a/engine/mail_2.asm b/engine/mail_2.asm new file mode 100755 index 000000000..dfbeca485 --- /dev/null +++ b/engine/mail_2.asm @@ -0,0 +1,950 @@ +ReadPartyMonMail: ; b9229 + ld a, [CurPartyMon] + ld hl, sPartyMail + ld bc, MAIL_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l +ReadAnyMail: ; b9237 + push de + call ClearBGPalettes + call ClearSprites + call ClearTileMap + call DisableLCD + call LoadFontsExtra + pop de + push de + ld a, BANK(sPartyMail) + call GetSRAMBank + farcall IsMailEuropean + call CloseSRAM + ld a, c + ld de, StandardEnglishFont + or a + jr z, .got_font + ld de, FrenchGermanFont + sub $3 + jr c, .got_font + ld de, SpanishItalianFont + +.got_font + ld hl, VTiles1 + lb bc, BANK(StandardEnglishFont), $80 + call Get1bpp + pop de + call .LoadGFX + call EnableLCD + call WaitBGMap + ld a, [Buffer3] + ld e, a + farcall LoadMailPalettes + call SetPalettes + xor a + ld [hJoyPressed], a + call .loop + call ClearBGPalettes + call DisableLCD + call LoadStandardFont + jp EnableLCD + +.loop + call GetJoypad + ld a, [hJoyPressed] + and A_BUTTON | B_BUTTON | START + jr z, .loop + and START + jr nz, .pressed_start + ret + +.pressed_start + ld a, [wJumptableIndex] + push af + callfar PrintMail ; printer + pop af + ld [wJumptableIndex], a + jr .loop +; b92b8 + +.LoadGFX: ; b92b8 + ld h, d + ld l, e + push hl + ld a, $0 + call GetSRAMBank + ld de, sPartyMon1MailAuthorID - sPartyMon1Mail + add hl, de + ld a, [hli] + ld [Buffer1], a + ld a, [hli] + ld [Buffer2], a + ld a, [hli] + ld [CurPartySpecies], a + ld b, [hl] + call CloseSRAM + ld hl, MailGFXPointers + ld c, 0 +.loop2 + ld a, [hli] + cp b + jr z, .got_pointer + cp -1 + jr z, .invalid + inc c + inc hl + inc hl + jr .loop2 + +.invalid + ld hl, MailGFXPointers + inc hl + +.got_pointer + ld a, c + ld [Buffer3], a + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .done + pop bc + push de + jp hl +.done + ret +; b92f8 + +MailGFXPointers: ; b92f8 + dbw FLOWER_MAIL, LoadFlowerMailGFX + dbw SURF_MAIL, LoadSurfMailGFX + dbw LITEBLUEMAIL, LoadLiteBlueMailGFX + dbw PORTRAITMAIL, LoadPortraitMailGFX + dbw LOVELY_MAIL, LoadLovelyMailGFX + dbw EON_MAIL, LoadEonMailGFX + dbw MORPH_MAIL, LoadMorphMailGFX + dbw BLUESKY_MAIL, LoadBlueSkyMailGFX + dbw MUSIC_MAIL, LoadMusicMailGFX + dbw MIRAGE_MAIL, LoadMirageMailGFX + db -1 +; b9317 + +LoadSurfMailGFX: ; b9317 + push bc + ld hl, VTiles2 tile $31 + ld de, SurfMailBorderGFX + ld c, 8 * 8 + call LoadMailGFX_Color2 + ld de, MailLaprasGFX + ld c, 6 * 8 + call LoadMailGFX_Color3 + ld de, SurfMailWaveGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + jr FinishLoadingSurfLiteBlueMailGFX + +LoadLiteBlueMailGFX: ; b9335 + push bc + ld hl, VTiles2 tile $31 + ld de, LiteBlueMailBorderGFX + ld c, 8 * 8 + call LoadMailGFX_Color2 + ld de, MailDratiniGFX + ld c, 6 * 8 + call LoadMailGFX_Color3 + ld de, PortraitMailUnderlineGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + +FinishLoadingSurfLiteBlueMailGFX: ; b9351 + ld de, SurfLiteBlueMailSmallShapesGFX + ld c, 2 * 8 + call LoadMailGFX_Color2 + ld c, 2 * 8 + call LoadMailGFX_Color1 + ld de, SurfLiteBlueMailLargeShapesGFX + ld c, 8 * 8 + call LoadMailGFX_Color1 + ld c, 8 * 8 + call LoadMailGFX_Color2 + + call DrawMailBorder + hlcoord 2, 15 + ld a, $3f + call Mail_Draw16TileRow + ld a, $39 + hlcoord 15, 14 + call Mail_Draw3x2Graphic + ld a, $44 + hlcoord 2, 2 + call Mail_Draw2x2Graphic + hlcoord 15, 11 + call Mail_Draw2x2Graphic + ld a, $4c + hlcoord 3, 12 + call Mail_Draw2x2Graphic + hlcoord 15, 2 + call Mail_Draw2x2Graphic + ld a, $50 + hlcoord 6, 3 + call Mail_Draw2x2Graphic + ld a, $40 + hlcoord 13, 2 + ld [hli], a + hlcoord 6, 14 + ld [hl], a + ld a, $41 + hlcoord 4, 5 + ld [hli], a + hlcoord 17, 5 + ld [hli], a + hlcoord 13, 12 + ld [hl], a + ld a, $42 + hlcoord 9, 2 + ld [hli], a + hlcoord 14, 5 + ld [hli], a + hlcoord 3, 10 + ld [hl], a + ld a, $43 + hlcoord 6, 11 + ld [hli], a + pop hl + jp MailGFX_PlaceMessage +; b93d2 + +LoadEonMailGFX: ; b93d2 + push bc + ld hl, VTiles2 tile $31 + ld de, EonMailBorder1GFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, EonMailBorder2GFX + ld c, 1 * 8 + call LoadMailGFX_Color1 + ld de, EonMailBorder2GFX + ld c, 1 * 8 + call LoadMailGFX_Color1 + ld de, EonMailBorder1GFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, SurfMailBorderGFX + 6 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, MailEeveeGFX + ld c, 6 * 8 + call LoadMailGFX_Color3 + ld hl, VTiles2 tile $3d + ld de, MailLargeCircleGFX + ld c, 4 * 8 + call LoadMailGFX_Color1 + ld de, EonMailBorder2GFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + + ld a, $31 + hlcoord 0, 0 + call Mail_Place18TileAlternatingRow + hlcoord 1, 17 + call Mail_Place18TileAlternatingRow + ld a, $33 + hlcoord 0, 1 + call Mail_Place16TileAlternatingColumn + hlcoord 19, 0 + call Mail_Place16TileAlternatingColumn + hlcoord 2, 15 + ld a, $35 + call Mail_Draw16TileRow + inc a + hlcoord 15, 14 + call Mail_Draw3x2Graphic + call LovelyEonMail_PlaceIcons + pop hl + jp MailGFX_PlaceMessage +; b944b + +LoadLovelyMailGFX: ; b944b + push bc + ld hl, VTiles2 tile $31 + ld de, LovelyMailBorderGFX + ld c, 5 * 8 + call LoadMailGFX_Color2 + ld de, MailPoliwagGFX + ld c, 6 * 8 + call LoadMailGFX_Color3 + ld de, LovelyMailUnderlineGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, LovelyMailLargeHeartGFX + ld c, 4 * 8 + call LoadMailGFX_Color2 + ld de, LovelyMailSmallHeartGFX + ld c, 1 * 8 + call LoadMailGFX_Color1 + + call DrawMailBorder2 + hlcoord 2, 15 + ld a, $3c + call Mail_Draw16TileRow + ld a, $36 + hlcoord 15, 14 + call Mail_Draw3x2Graphic + call LovelyEonMail_PlaceIcons + pop hl + jp MailGFX_PlaceMessage +; b9491 + +LovelyEonMail_PlaceIcons: ; b9491 + ld a, $3d + hlcoord 2, 2 + call Mail_Draw2x2Graphic + hlcoord 16, 2 + call Mail_Draw2x2Graphic + hlcoord 9, 4 + call Mail_Draw2x2Graphic + hlcoord 2, 11 + call Mail_Draw2x2Graphic + hlcoord 6, 12 + call Mail_Draw2x2Graphic + hlcoord 12, 11 + call Mail_Draw2x2Graphic + ld a, $41 + hlcoord 5, 4 + ld [hl], a + hlcoord 6, 2 + ld [hl], a + hlcoord 12, 4 + ld [hl], a + hlcoord 14, 2 + ld [hl], a + hlcoord 3, 13 + ld [hl], a + hlcoord 9, 11 + ld [hl], a + hlcoord 16, 12 + ld [hl], a + ret +; b94d6 + +LoadMorphMailGFX: ; b94d6 + push bc + ld hl, VTiles2 tile $31 + ld bc, 5 * 8 + call MailGFX_GenerateMonochromeTilesColor2 + ld de, MorphMailBorderCornerGFX + 3 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, MorphMailBorderCornerGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, MorphMailBorderGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, EonMailBorder1GFX + ld c, 1 * 8 + call LoadMailGFX_Color1 + ld de, MorphMailDividerGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, MailDittoGFX + ld c, 6 * 8 + call LoadMailGFX_Color3 + call DrawMailBorder2 + ld a, $31 + hlcoord 1, 1 + call Mail_Draw2x2Graphic + hlcoord 17, 15 + call Mail_Draw2x2Graphic + hlcoord 1, 3 + ld [hl], a + hlcoord 3, 1 + ld [hl], a + hlcoord 16, 16 + ld [hl], a + hlcoord 18, 14 + ld [hl], a + ld a, $36 + hlcoord 1, 4 + ld [hl], a + hlcoord 2, 3 + ld [hl], a + hlcoord 3, 2 + ld [hl], a + hlcoord 4, 1 + ld [hl], a + inc a + hlcoord 15, 16 + ld [hl], a + hlcoord 16, 15 + ld [hl], a + hlcoord 17, 14 + ld [hl], a + hlcoord 18, 13 + ld [hl], a + inc a + hlcoord 2, 15 + ld b, $e + call Mail_DrawRowLoop + inc a + hlcoord 2, 11 + call Mail_Draw16TileRow + hlcoord 2, 5 + call Mail_Draw16TileRow + inc a + hlcoord 6, 1 + call Mail_Draw13TileRow + hlcoord 1, 16 + call Mail_Draw13TileRow + inc a + hlcoord 3, 13 + call Mail_Draw3x2Graphic + pop hl + jp MailGFX_PlaceMessage +; b9582 + +LoadBlueSkyMailGFX: ; b9582 + push bc + ld hl, VTiles2 tile $31 + ld de, EonMailBorder1GFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld a, $ff + ld bc, 1 tiles + call ByteFill + ld de, BlueSkyMailGrassGFX + ld c, 1 * 8 + call LoadMailGFX_Color3 + ld de, MailDragoniteGFX + ld c, 23 * 8 + call LoadMailGFX_Color3 + ld de, MailCloudGFX + ld c, 6 * 8 + call LoadMailGFX_Color1 + ld de, FlowerMailBorderGFX + 6 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color1 + ld de, MailCloudGFX + ld c, 1 * 8 + call LoadMailGFX_Color1 + ld de, MailCloudGFX + 2 * 8 + ld c, 2 * 8 + call LoadMailGFX_Color1 + ld de, MailCloudGFX + 5 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color1 + + ld a, $31 + hlcoord 0, 0 + call Mail_DrawFullWidthBorder + hlcoord 0, 1 + call Mail_DrawLeftRightBorder + hlcoord 19, 1 + call Mail_DrawLeftRightBorder + inc a + hlcoord 0, 17 + call Mail_DrawFullWidthBorder + inc a + hlcoord 0, 16 + call Mail_DrawFullWidthBorder + inc a + hlcoord 2, 2 + call Mail_Place6TileRow + hlcoord 3, 3 + call Mail_Place6TileRow + hlcoord 4, 4 + call Mail_Place6TileRow + dec hl + ld [hl], $7f + dec a + hlcoord 15, 14 + call Mail_Draw2x2Graphic + add $4 + hlcoord 15, 16 + ld [hli], a + inc a + ld [hl], a + inc a + push af + hlcoord 12, 1 + call Mail_Draw3x2Graphic + pop af + hlcoord 15, 4 + call Mail_Draw3x2Graphic + inc a + hlcoord 2, 11 + call Mail_Draw16TileRow + inc a + hlcoord 10, 3 + call Mail_Draw2x2Graphic + pop hl + jp MailGFX_PlaceMessage +; b9636 + +Mail_Place6TileRow: ; b9636 + ld b, $6 +.loop + ld [hli], a + inc a + dec b + jr nz, .loop + ret +; b963e + +LoadFlowerMailGFX: ; b963e + push bc + ld hl, VTiles2 tile $31 + ld de, FlowerMailBorderGFX + ld c, 8 * 8 + call LoadMailGFX_Color1 + ld de, MailOddishGFX + ld c, 4 * 8 + call LoadMailGFX_Color3 + ld de, FlowerMailBorderGFX + 6 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, FlowerMailFlowerGFX + ld c, 4 * 8 + call LoadMailGFX_Color1 + ld c, 4 * 8 + call LoadMailGFX_Color2 + + call DrawMailBorder + hlcoord 2, 15 + ld a, $3d ; underline + call Mail_Draw16TileRow + ld a, $39 ; oddish + hlcoord 16, 13 + call Mail_Draw2x2Graphic + hlcoord 2, 13 + call Mail_Draw2x2Graphic + ld a, $3e + hlcoord 2, 2 + call Mail_Draw2x2Graphic + hlcoord 5, 3 + call Mail_Draw2x2Graphic + hlcoord 10, 2 + call Mail_Draw2x2Graphic + hlcoord 16, 3 + call Mail_Draw2x2Graphic + hlcoord 5, 11 + call Mail_Draw2x2Graphic + hlcoord 16, 10 + call Mail_Draw2x2Graphic + ld a, $42 + hlcoord 3, 4 + call Mail_Draw2x2Graphic + hlcoord 12, 3 + call Mail_Draw2x2Graphic + hlcoord 14, 2 + call Mail_Draw2x2Graphic + hlcoord 2, 10 + call Mail_Draw2x2Graphic + hlcoord 14, 11 + call Mail_Draw2x2Graphic + pop hl + jp MailGFX_PlaceMessage +; b96ca + +LoadPortraitMailGFX: ; b96ca + push bc + ld hl, VTiles2 tile $31 + ld de, PortraitMailBorderGFX + ld c, 5 * 8 + call LoadMailGFX_Color2 + ld de, PortraitMailUnderlineGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld hl, VTiles2 tile $3d + ld de, PortraitMailLargePokeballGFX + ld c, 4 * 8 + call LoadMailGFX_Color1 + ld de, PortraitMailSmallPokeballGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + + call DrawMailBorder2 + hlcoord 8, 15 + ld a, $36 + ld b, $a + call Mail_DrawRowLoop + call LovelyEonMail_PlaceIcons + ld a, $1 + ld [UnownLetter], a + hlcoord 1, 10 + call PrepMonFrontpic + pop hl + jp MailGFX_PlaceMessage +; b9710 + +LoadMusicMailGFX: ; b9710 + push bc + ld hl, VTiles2 tile $31 + ld de, MusicMailBorderGFX + ld c, 4 * 8 + call LoadMailGFX_Color2 + ld de, MorphMailBorderGFX + ld c, 2 * 8 + call LoadMailGFX_Color2 + ld de, MailNatuGFX + ld c, 6 * 8 + call LoadMailGFX_Color3 + xor a + ld bc, 1 tiles + call ByteFill + ld de, MusicMailLargeNoteGFX + ld c, 3 * 8 + call LoadMailGFX_Color1 + ld de, MusicMailSmallNoteGFX + ld c, 1 * 8 + call LoadMailGFX_Color1 + + ld a, $31 + hlcoord 0, 0 + call Mail_Place18TileAlternatingRow + hlcoord 1, 17 + call Mail_Place18TileAlternatingRow + ld a, $33 + hlcoord 0, 1 + call Mail_Place16TileAlternatingColumn + hlcoord 19, 0 + call Mail_Place16TileAlternatingColumn + ld a, $35 + hlcoord 2, 15 + call Mail_Place14TileAlternatingRow + ld a, $37 + hlcoord 15, 14 + call Mail_Draw3x2Graphic + call LovelyEonMail_PlaceIcons + pop hl + jp MailGFX_PlaceMessage +; b9776 + +LoadMirageMailGFX: ; b9776 + push bc + ld hl, VTiles2 tile $31 + ld bc, 5 * 8 + call MailGFX_GenerateMonochromeTilesColor2 + ld de, BlueSkyMailGrassGFX + ld c, 1 * 8 + call LoadMailGFX_Color2 + ld de, MailMewGFX + ld c, 18 * 8 + call LoadMailGFX_Color2 + ld de, LiteBlueMailBorderGFX + 1 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color1 + ld de, LiteBlueMailBorderGFX + 6 * 8 + ld c, 1 * 8 + call LoadMailGFX_Color1 + + call DrawMailBorder2 + ld a, $36 + hlcoord 1, 16 + call Mail_DrawTopBottomBorder + inc a + hlcoord 15, 14 + call Mail_Draw3x2Graphic + inc a + hlcoord 15, 16 + ld [hli], a + inc a + ld [hl], a + ld a, $3f + hlcoord 1, 1 + call Mail_Place18TileAlternatingRow + ld a, $41 + hlcoord 0, 2 + call Mail_Place14TileAlternatingColumn + ld a, $43 + hlcoord 19, 2 + call Mail_Place14TileAlternatingColumn + ld a, $45 + hlcoord 0, 1 + ld [hl], a + inc a + hlcoord 19, 1 + ld [hl], a + inc a + hlcoord 0, 16 + ld [hl], a + inc a + hlcoord 19, 16 + ld [hl], a + inc a + hlcoord 2, 5 + call Mail_Draw16TileRow + inc a + hlcoord 2, 11 + call Mail_Draw16TileRow + pop hl + jp MailGFX_PlaceMessage +; b97f8 + +MailGFX_GenerateMonochromeTilesColor2: ; b97f8 +.loop + xor a + ld [hli], a + ld a, $ff + ld [hli], a + dec bc + ld a, b + or c + jr nz, .loop + ret +; b9803 + +MailGFX_PlaceMessage: ; b9803 + ld bc, MAIL_STRUCT_LENGTH + ld de, wTempMail + ld a, BANK(sPartyMail) + call GetSRAMBank + call CopyBytes + call CloseSRAM + ld hl, wTempMailAuthor + ld de, wMonOrItemNameBuffer + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld a, "@" + ld [wTempMailAuthor], a + ld [wMonOrItemNameBuffer + NAME_LENGTH - 1], a + ld de, wTempMailMessage + hlcoord 2, 7 + call PlaceString + ld de, wMonOrItemNameBuffer + ld a, [de] + and a + ret z + ld a, [Buffer3] + hlcoord 8, 14 + cp $3 ; PORTRAITMAIL + jr z, .place_author + hlcoord 6, 14 + cp $6 ; MORPH_MAIL + jr z, .place_author + hlcoord 5, 14 + +.place_author + jp PlaceString +; b984e + +Functionb984e: ; b984e +; XXX +.loop + ld a, [hl] + xor $ff + ld [hli], a + dec bc + ld a, b + or c + jr nz, .loop + ret +; b9858 + +DrawMailBorder: ; b9858 + hlcoord 0, 0 + ld a, $31 + ld [hli], a + inc a + call Mail_DrawTopBottomBorder + inc a + ld [hli], a + inc a + call Mail_DrawLeftRightBorder + ld a, $36 + ld [hli], a + inc a + call Mail_DrawTopBottomBorder + hlcoord 19, 1 + ld a, $35 + call Mail_DrawLeftRightBorder + ld a, $38 + ld [hl], a + ret +; b987b + +DrawMailBorder2: ; b987b + hlcoord 0, 0 + ld a, $31 + ld [hli], a + inc a + call Mail_DrawTopBottomBorder + ld [hl], $31 + inc hl + inc a + call Mail_DrawLeftRightBorder + ld [hl], $31 + inc hl + inc a + call Mail_DrawTopBottomBorder + hlcoord 19, 1 + ld a, $35 + call Mail_DrawLeftRightBorder + ld [hl], $31 + ret +; b989e + +Mail_Place14TileAlternatingRow: ; b989e + push af + ld b, 14 / 2 + jr Mail_PlaceAlternatingRow + +Mail_Place16TileAlternatingRow: ; b98a3 + push af + ld b, 16 / 2 + jr Mail_PlaceAlternatingRow + +Mail_Place18TileAlternatingRow: ; b98a8 + push af + ld b, 18 / 2 + +Mail_PlaceAlternatingRow: ; b98ab +.loop + ld [hli], a + inc a + ld [hli], a + dec a + dec b + jr nz, .loop + ld [hl], a + pop af + ret +; b98b5 + +Mail_Place14TileAlternatingColumn: ; b98b5 + push af + ld b, 14 / 2 + jr Mail_PlaceAlternatingColumn + +Mail_Place16TileAlternatingColumn: ; b98ba + push af + ld b, 16 / 2 + +Mail_PlaceAlternatingColumn: ; b98bd +.loop + ld [hl], a + ld de, SCREEN_WIDTH + add hl, de + inc a + ld [hl], a + add hl, de + dec a + dec b + jr nz, .loop + ld [hl], a + pop af + ret +; b98cc + +Mail_Draw7TileRow: ; b98cc + ld b, $7 + jr Mail_DrawRowLoop + +Mail_Draw13TileRow: ; b98d0 + ld b, $d + jr Mail_DrawRowLoop + +Mail_Draw16TileRow: ; b98d4 + ld b, $10 + jr Mail_DrawRowLoop + +Mail_DrawTopBottomBorder: ; b98d8 + ld b, SCREEN_WIDTH - 2 + jr Mail_DrawRowLoop + +Mail_DrawFullWidthBorder: ; b98dc + ld b, SCREEN_WIDTH + +Mail_DrawRowLoop: ; b98de +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; b98e3 + +Mail_DrawLeftRightBorder: ; b98e3 + ld b, SCREEN_HEIGHT - 2 + ld de, SCREEN_WIDTH +.loop + ld [hl], a + add hl, de + dec b + jr nz, .loop + ret +; b98ee + +Mail_Draw2x2Graphic: ; b98ee + push af + ld [hli], a + inc a + ld [hl], a + ld bc, SCREEN_WIDTH - 1 + add hl, bc + inc a + ld [hli], a + inc a + ld [hl], a + pop af + ret +; b98fc + +Mail_Draw3x2Graphic: ; b98fc + ld [hli], a + inc a + ld [hli], a + inc a + ld [hl], a + ld bc, SCREEN_WIDTH - 2 + add hl, bc + inc a + ld [hli], a + inc a + ld [hli], a + inc a + ld [hl], a + ret +; b990c + +LoadMailGFX_Color1: ; b990c +.loop + ld a, [de] + inc de + ld [hli], a + xor a + ld [hli], a + dec c + jr nz, .loop + ret +; b9915 + +LoadMailGFX_Color2: ; b9915 +.loop + xor a + ld [hli], a + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + ret +; b991e + +LoadMailGFX_Color3: ; b991e +.loop + ld a, [de] + inc de + ld [hli], a + ld [hli], a + dec c + jr nz, .loop + ret +; b9926 + +INCLUDE "gfx/mail.asm" + +ItemIsMail: ; b9e76 + ld a, d + ld hl, MailItems + ld de, 1 + jp IsInArray +; b9e80 + +INCLUDE "data/items/mail_items.asm" diff --git a/engine/map_setup.asm b/engine/map_setup.asm index 01f3d05d7..562916442 100644 --- a/engine/map_setup.asm +++ b/engine/map_setup.asm @@ -1,4 +1,3 @@ - RunMapSetupScript:: ; 15363 ld a, [hMapEntryMethod] and $f @@ -15,183 +14,7 @@ RunMapSetupScript:: ; 15363 ret ; 15377 -MapSetupScripts: ; 15377 - dw MapSetupScript_Warp - dw MapSetupScript_Continue - dw MapSetupScript_ReloadMap - dw MapSetupScript_Teleport - dw MapSetupScript_Door - dw MapSetupScript_Fall - dw MapSetupScript_Connection - dw MapSetupScript_LinkReturn - dw MapSetupScript_Train - dw MapSetupScript_Submenu - dw MapSetupScript_BadWarp - dw MapSetupScript_Fly -; 1538f - -MapSetupScript_Teleport: ; 1538f - db map_prolong_sprites -MapSetupScript_Fly: ; 15390 - db map_fade_out_palettes - db map_keep_roam -MapSetupScript_Warp: ; 15392 - db map_lcd_off - db map_sound_off - db map_load_spawn - db map_attributes - db map_change_callback - db map_spawn_coord - db map_player_coord - db map_anchor_screen - db map_load_blocks - db map_buffer_screen - db map_load_graphics - db map_time_of_day - db map_load_objects - db map_lcd_on - db map_palettes - db map_face_down - db map_sprites - db map_bike_music - db map_max_volume - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_BadWarp: ; 153a9 - db map_load_spawn - db map_attributes - db map_change_callback - db map_spawn_coord - db map_player_coord - db map_anchor_screen - db map_load_blocks - db map_buffer_screen - db map_lcd_off - db map_load_graphics - db map_time_of_day - db map_fade_out_music - db map_lcd_on - db map_load_objects - db map_palettes - db map_face_down - db map_sprites - db map_fade_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_Connection: ; 153bf - db map_animations_off - db map_load_connection - db map_attributes - db map_change_callback - db map_player_coord - db map_load_blocks - db map_load_tileset_header - db map_save_screen - db map_load_objects - db map_fade_music - db map_palettes - db map_stop_script - db map_keep_palettes - db map_wildmons - db map_update_roam - db map_animations_on - db map_end - -MapSetupScript_Fall: ; 153d0 - db map_prolong_sprites -MapSetupScript_Door: ; 153d1 - db map_fade_out_palettes -MapSetupScript_Train: ; 153d2 - db map_load_warp - db map_attributes - db map_warp_face - db map_change_callback - db map_player_coord - db map_load_blocks - db map_buffer_screen - db map_lcd_off - db map_load_graphics - db map_time_of_day - db map_fade_out_music - db map_lcd_on - db map_load_objects - db map_palettes - db map_sprites - db map_fade_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_update_roam - db map_end - -MapSetupScript_ReloadMap: ; 153e7 - db map_fade - db map_clear_bg_palettes - db map_lcd_off - db map_sound_off - db map_load_blocks - db map_connection_blocks - db map_load_graphics - db map_time_of_day - db map_lcd_on - db map_palettes - db map_sprites - db map_music_force - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_LinkReturn: ; 153f7 - db map_fade - db map_lcd_off - db map_sound_off - db map_change_callback - db map_load_blocks - db map_buffer_screen - db map_load_graphics - db map_time_of_day - db map_lcd_on - db map_palettes - db map_sprites - db map_bike_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_text_scroll_off - db map_end - -MapSetupScript_Continue: ; 15408 - db map_lcd_off - db map_sound_off - db map_attributes_2 - db map_anchor_screen - db map_start_callback - db map_load_blocks - db map_connection_blocks - db map_buffer_screen - db map_load_graphics - db map_time_of_day - db map_lcd_on - db map_palettes - db map_sprites - db map_bike_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_Submenu: ; 1541a - db map_load_blocks - db map_connection_blocks - db map_end - +INCLUDE "data/maps/setup_scripts.asm" ReadMapSetupScript: ; 1541d .loop @@ -238,6 +61,7 @@ ReadMapSetupScript: ; 1541d ; 15440 MapSetupCommands: ; 15440 +; entries correspond to command indexes in constants/map_setup_constants.asm dba EnableLCD ; 00 dba DisableLCD ; 01 dba MapSetup_Sound_Off ; 02 @@ -253,7 +77,7 @@ MapSetupCommands: ; 15440 dba SaveScreen ; 0c dba BufferScreen ; 0d dba LoadGraphics ; 0e - dba LoadTilesetHeader ; 0f + dba LoadTileset ; 0f dba LoadMapTimeOfDay ; 10 dba LoadMapPalettes ; 11 dba LoadWildMonData ; 12 diff --git a/engine/mon_icons.asm b/engine/mon_icons.asm index 965d9f0ef..2ebeb67fa 100755 --- a/engine/mon_icons.asm +++ b/engine/mon_icons.asm @@ -468,6 +468,6 @@ ReadMonMenuIcon: ; 8eab3 INCLUDE "data/pokemon/menu_icons.asm" -INCLUDE "gfx/icon_pointers.asm" +INCLUDE "data/icon_pointers.asm" INCLUDE "gfx/icons.asm" diff --git a/engine/movement.asm b/engine/movement.asm index 66c501909..bec089978 100644 --- a/engine/movement.asm +++ b/engine/movement.asm @@ -1,5 +1,5 @@ MovementPointers: ; 5075 -; entries correspond to macros/movement.asm enumeration +; entries correspond to macros/scripts/movement.asm enumeration dw Movement_turn_head_down ; 00 dw Movement_turn_head_up ; 01 dw Movement_turn_head_left ; 02 diff --git a/engine/mystery_gift.asm b/engine/mystery_gift.asm index 9e097e6d4..3c8f9d029 100755 --- a/engine/mystery_gift.asm +++ b/engine/mystery_gift.asm @@ -1153,7 +1153,7 @@ MysteryGift_CopyReceivedDecosToPC: ; 105091 (41:5091) .skip inc c ld a, c - cp Trophys - DecorationIDs + cp TrophyIDs - DecorationIDs jr c, .loop jp CloseSRAM diff --git a/engine/mystery_gift_2.asm b/engine/mystery_gift_2.asm index dc0baf39c..1d180f714 100755 --- a/engine/mystery_gift_2.asm +++ b/engine/mystery_gift_2.asm @@ -147,6 +147,6 @@ MysteryGiftFallbackItem: ; 2c722 (b:4722) ; 2c725 (b:4725) -INCLUDE "data/mystery_gift/items.asm" +INCLUDE "data/mystery_gift_items.asm" -INCLUDE "data/mystery_gift/decos.asm" +INCLUDE "data/mystery_gift_decos.asm" diff --git a/engine/overworld.asm b/engine/overworld.asm index a1b4545a9..7941b74d7 100755 --- a/engine/overworld.asm +++ b/engine/overworld.asm @@ -202,11 +202,11 @@ GetSprite: ; 1423c call GetMonSprite ret c - ld hl, SpriteHeaders ; address + ld hl, OverworldSprites + SPRITEDATA_ADDR dec a ld c, a ld b, 0 - ld a, 6 + ld a, NUM_SPRITEDATA_FIELDS call AddNTimes ; load the address into de ld a, [hli] @@ -299,11 +299,11 @@ _DoesSpriteHaveFacings:: ; 142a7 push hl push bc - ld hl, SpriteHeaders + SPRITEHEADER_TYPE ; type + ld hl, OverworldSprites + SPRITEDATA_TYPE dec a ld c, a ld b, 0 - ld a, NUM_SPRITEHEADER_FIELDS + ld a, NUM_SPRITEDATA_FIELDS call AddNTimes ld a, [hl] pop bc @@ -324,11 +324,11 @@ _GetSpritePalette:: ; 142c4 call GetMonSprite jr c, .is_pokemon - ld hl, SpriteHeaders + 5 ; palette + ld hl, OverworldSprites + SPRITEDATA_PALETTE dec a ld c, a ld b, 0 - ld a, 6 + ld a, NUM_SPRITEDATA_FIELDS call AddNTimes ld c, [hl] ret @@ -691,8 +691,8 @@ endr LoadEmote:: ; 1442f ; Get the address of the pointer to emote c. ld a, c - ld bc, 6 - ld hl, EmotesPointers + ld bc, 6 ; sizeof(emote) + ld hl, Emotes call AddNTimes ; Load the emote address into de ld e, [hl] @@ -719,10 +719,10 @@ LoadEmote:: ; 1442f ; 1444d -INCLUDE "data/emote_headers.asm" +INCLUDE "data/emotes.asm" INCLUDE "data/sprite_mons.asm" INCLUDE "data/maps/outdoor_sprites.asm" -INCLUDE "gfx/sprite_headers.asm" +INCLUDE "data/sprites.asm" diff --git a/engine/pic_animation.asm b/engine/pic_animation.asm new file mode 100644 index 000000000..2b93ef749 --- /dev/null +++ b/engine/pic_animation.asm @@ -0,0 +1,1140 @@ +; Pic animation arrangement. + +AnimateMon_Slow_Normal: ; d0000 + hlcoord 12, 0 + ld a, [wBattleMode] + cp WILD_BATTLE + jr z, .wild + ld e, ANIM_MON_SLOW + ld d, $0 + call AnimateFrontpic + ret + +.wild + ld e, ANIM_MON_NORMAL + ld d, $0 + call AnimateFrontpic + ret +; d001a + +AnimateMon_Menu: ; d001a + ld e, ANIM_MON_MENU + ld d, $0 + call AnimateFrontpic + ret +; d0022 + +AnimateMon_Trade: ; d0022 + ld e, ANIM_MON_TRADE + ld d, $0 + call AnimateFrontpic + ret +; d002a + +AnimateMon_Evolve: ; d002a + ld e, ANIM_MON_EVOLVE + ld d, $0 + call AnimateFrontpic + ret +; d0032 + +AnimateMon_Hatch: ; d0032 + ld e, ANIM_MON_HATCH + ld d, $0 + call AnimateFrontpic + ret +; d003a + +AnimateMon_Unused: ; d003a + ld e, ANIM_MON_UNUSED + ld d, $0 + call AnimateFrontpic + ret +; d0042 + +pokeanim: MACRO + rept _NARG +; Workaround for a bug where macro args can't come after the start of a symbol +if !def(\1_POKEANIM) +\1_POKEANIM equs "PokeAnim_\1_" +endc + db (\1_POKEANIM - PokeAnim_SetupCommands) / 2 + shift + endr + db (PokeAnim_Finish_ - PokeAnim_SetupCommands) / 2 +ENDM + +PokeAnims: ; d0042 + dw .Slow + dw .Normal + dw .Menu + dw .Trade + dw .Evolve + dw .Hatch + dw .Unused ; same as .Menu + dw .Egg1 + dw .Egg2 + +.Slow: pokeanim StereoCry, Setup2, Play +.Normal: pokeanim StereoCry, Setup, Play +.Menu: pokeanim CryNoWait, Setup, Play, SetWait, Wait, Extra, Play +.Trade: pokeanim Extra, Play2, Extra, Play, SetWait, Wait, Cry, Setup, Play +.Evolve: pokeanim Extra, Play, SetWait, Wait, CryNoWait, Setup, Play +.Hatch: pokeanim Extra, Play, CryNoWait, Setup, Play, SetWait, Wait, Extra, Play +.Unused: pokeanim CryNoWait, Setup, Play, SetWait, Wait, Extra, Play +.Egg1: pokeanim Setup, Play +.Egg2: pokeanim Extra, Play + + +AnimateFrontpic: ; d008e + call AnimateMon_CheckIfPokemon + ret c + call LoadMonAnimation +.loop + call SetUpPokeAnim + push af + farcall HDMATransferTileMapToWRAMBank3 + pop af + jr nc, .loop + ret +; d00a3 + +LoadMonAnimation: ; d00a3 + push hl + ld c, e + ld b, 0 + ld hl, PokeAnims + add hl, bc + add hl, bc + ld a, [hli] + ld b, [hl] + ld c, a + pop hl + call PokeAnim_InitPicAttributes + ret +; d00b4 + +SetUpPokeAnim: ; d00b4 + ld a, [rSVBK] + push af + ld a, BANK(wPokeAnimSceneIndex) + ld [rSVBK], a + ld a, [wPokeAnimSceneIndex] + ld c, a + ld b, 0 + ld hl, wPokeAnimPointer + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + ld a, [hl] + ld hl, PokeAnim_SetupCommands + rst JumpTable + ld a, [wPokeAnimSceneIndex] + ld c, a + pop af + ld [rSVBK], a + ld a, c + and $80 + ret z + scf + ret +; d00da + +PokeAnim_SetupCommands: ; d00da +setup_command: macro +\1_: dw \1 +endm + setup_command PokeAnim_Finish + setup_command PokeAnim_BasePic + setup_command PokeAnim_SetWait + setup_command PokeAnim_Wait + setup_command PokeAnim_Setup + setup_command PokeAnim_Setup2 + setup_command PokeAnim_Extra + setup_command PokeAnim_Play + setup_command PokeAnim_Play2 + setup_command PokeAnim_Cry + setup_command PokeAnim_CryNoWait + setup_command PokeAnim_StereoCry +; d00f2 + +PokeAnim_SetWait: ; d00f2 + ld a, 18 + ld [wPokeAnimWaitCounter], a + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + +PokeAnim_Wait: ; d00fe + ld hl, wPokeAnimWaitCounter + dec [hl] + ret nz + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d010b + +PokeAnim_Setup: ; d010b + ld c, FALSE + ld b, 0 + call PokeAnim_InitAnim + call PokeAnim_SetVBank1 + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d011d + +PokeAnim_Setup2: ; d011d + ld c, FALSE + ld b, 4 + call PokeAnim_InitAnim + call PokeAnim_SetVBank1 + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d012f + +PokeAnim_Extra: ; d012f + ld c, TRUE + ld b, 0 + call PokeAnim_InitAnim + call PokeAnim_SetVBank1 + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d0141 + +PokeAnim_Play: ; d0141 + call PokeAnim_DoAnimScript + ld a, [wPokeAnimJumptableIndex] + bit 7, a + ret z + call PokeAnim_PlaceGraphic + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d0155 + +PokeAnim_Play2: ; d0155 + call PokeAnim_DoAnimScript + ld a, [wPokeAnimJumptableIndex] + bit 7, a + ret z + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d0166 + +PokeAnim_BasePic: ; d0166 + call PokeAnim_DeinitFrames + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d0171 + +PokeAnim_Finish: ; d0171 + call PokeAnim_DeinitFrames + ld hl, wPokeAnimSceneIndex + set 7, [hl] + ret +; d017a + +PokeAnim_Cry: ; d017a + ld a, [wPokeAnimSpecies] + call _PlayCry + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d0188 + +PokeAnim_CryNoWait: ; d0188 + ld a, [wPokeAnimSpecies] + call PlayCry2 + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d0196 + +PokeAnim_StereoCry: ; d0196 + ld a, $f + ld [CryTracks], a + ld a, [wPokeAnimSpecies] + call PlayStereoCry2 + ld a, [wPokeAnimSceneIndex] + inc a + ld [wPokeAnimSceneIndex], a + ret +; d01a9 + +PokeAnim_DeinitFrames: ; d01a9 + ld a, [rSVBK] + push af + ld a, $2 + ld [rSVBK], a + call PokeAnim_PlaceGraphic + farcall HDMATransferTileMapToWRAMBank3 + call PokeAnim_SetVBank0 + farcall HDMATransferAttrMapToWRAMBank3 + pop af + ld [rSVBK], a + ret +; d01c6 + +AnimateMon_CheckIfPokemon: ; d01c6 + ld a, [CurPartySpecies] + cp EGG + jr z, .fail + call IsAPokemon + jr c, .fail + and a + ret + +.fail + scf + ret +; d01d6 + +PokeAnim_InitPicAttributes: ; d01d6 + ld a, [rSVBK] + push af + ld a, BANK(wPokeAnimSceneIndex) + ld [rSVBK], a + + push bc + push de + push hl + ld hl, wPokeAnimSceneIndex + ld bc, wPokeAnimStructEnd - wPokeAnimSceneIndex + xor a + call ByteFill + pop hl + pop de + pop bc + +; bc contains anim pointer + ld a, c + ld [wPokeAnimPointer], a + ld a, b + ld [wPokeAnimPointer + 1], a +; hl contains TileMap coords + ld a, l + ld [wPokeAnimCoord], a + ld a, h + ld [wPokeAnimCoord + 1], a +; d = start tile + ld a, d + ld [wPokeAnimGraphicStartTile], a + + ld a, $1 + ld hl, CurPartySpecies + call GetFarWRAMByte + ld [wPokeAnimSpecies], a + + ld a, $1 + ld hl, UnownLetter + call GetFarWRAMByte + ld [wPokeAnimUnownLetter], a + + call PokeAnim_GetSpeciesOrUnown + ld [wPokeAnimSpeciesOrUnown], a + + call PokeAnim_GetFrontpicDims + ld a, c + ld [wPokeAnimFrontpicHeight], a + + pop af + ld [rSVBK], a + ret +; d0228 + +PokeAnim_InitAnim: ; d0228 + ld a, [rSVBK] + push af + ld a, BANK(wPokeAnimExtraFlag) + ld [rSVBK], a + push bc + ld hl, wPokeAnimExtraFlag + ld bc, wPokeAnimStructEnd - wPokeAnimExtraFlag + xor a + call ByteFill + pop bc + ld a, b + ld [wPokeAnimSpeed], a + ld a, c + ld [wPokeAnimExtraFlag], a + call GetMonAnimPointer + call GetMonFramesPointer + call GetMonBitmaskPointer + pop af + ld [rSVBK], a + ret +; d0250 + +PokeAnim_DoAnimScript: ; d0250 + xor a + ld [hBGMapMode], a +.loop + ld a, [wPokeAnimJumptableIndex] + and $7f + ld hl, .Jumptable + rst JumpTable + ret +; d025d + +.Jumptable: ; d025d + dw .RunAnim + dw .WaitAnim +; d0261 + +.RunAnim: ; d0261 + call PokeAnim_GetPointer + ld a, [wPokeAnimCommand] + cp -1 + jr z, PokeAnim_End + cp -2 + jr z, .SetRepeat + cp -3 + jr z, .DoRepeat + call PokeAnim_GetFrame + ld a, [wPokeAnimParameter] + call PokeAnim_GetDuration + ld [wPokeAnimWaitCounter], a + call PokeAnim_StartWaitAnim +.WaitAnim: ; d0282 + ld a, [wPokeAnimWaitCounter] + dec a + ld [wPokeAnimWaitCounter], a + ret nz + call PokeAnim_StopWaitAnim + ret +; d028e + +.SetRepeat: ; d028e + ld a, [wPokeAnimParameter] + ld [wPokeAnimRepeatTimer], a + jr .loop +; d0296 + +.DoRepeat: ; d0296 + ld a, [wPokeAnimRepeatTimer] + and a + ret z + dec a + ld [wPokeAnimRepeatTimer], a + ret z + ld a, [wPokeAnimParameter] + ld [wPokeAnimFrame], a + jr .loop +; d02a8 + +PokeAnim_End: ; d02a8 + ld hl, wPokeAnimJumptableIndex + set 7, [hl] + ret +; d02ae + +PokeAnim_GetDuration: ; d02ae +; a * (1 + [wPokeAnimSpeed] / 16) + ld c, a + ld b, $0 + ld hl, 0 + ld a, [wPokeAnimSpeed] + call AddNTimes + ld a, h + swap a + and $f0 + ld h, a + ld a, l + swap a + and $f + or h + add c + ret +; d02c8 + +PokeAnim_GetFrame: ; d02c8 + call PokeAnim_PlaceGraphic + ld a, [wPokeAnimCommand] + and a + ret z + call PokeAnim_GetBitmaskIndex + push hl + call PokeAnim_CopyBitmaskToBuffer + pop hl + call PokeAnim_ConvertAndApplyBitmask + ret +; d02dc + +PokeAnim_StartWaitAnim: ; d02dc + ld a, [wPokeAnimJumptableIndex] + inc a + ld [wPokeAnimJumptableIndex], a + ret +; d02e4 + +PokeAnim_StopWaitAnim: ; d02e4 + ld a, [wPokeAnimJumptableIndex] + dec a + ld [wPokeAnimJumptableIndex], a + ret +; d02ec + +PokeAnim_IsUnown: ; d02ec + ld a, [wPokeAnimSpecies] + cp UNOWN + ret +; d02f2 + +PokeAnim_IsEgg: ; d02f2 + ld a, [wPokeAnimSpecies] + cp EGG + ret +; d02f8 + +PokeAnim_GetPointer: ; d02f8 + push hl + ld a, [wPokeAnimFrame] + ld e, a + ld d, $0 + ld hl, wPokeAnimPointerAddr + ld a, [hli] + ld h, [hl] + ld l, a + add hl, de + add hl, de + ld a, [wPokeAnimPointerBank] + call GetFarHalfword + ld a, l + ld [wPokeAnimCommand], a + ld a, h + ld [wPokeAnimParameter], a + ld hl, wPokeAnimFrame + inc [hl] + pop hl + ret +; d031b + +PokeAnim_GetBitmaskIndex: ; d031b + ld a, [wPokeAnimCommand] + dec a + ld c, a + ld b, $0 + ld hl, wPokeAnimFramesAddr + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + add hl, bc + ld a, [wPokeAnimFramesBank] + call GetFarHalfword + ld a, [wPokeAnimFramesBank] + call GetFarByte + ld [wPokeAnimCurBitmask], a + inc hl + ret +; d033b + +PokeAnim_CopyBitmaskToBuffer: ; d033b + call .GetSize + push bc + ld hl, wPokeAnimBitmaskAddr + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wPokeAnimCurBitmask] + call AddNTimes + pop bc + ld de, wPokeAnimBitmaskBuffer + ld a, [wPokeAnimBitmaskBank] + call FarCopyBytes + ret +; d0356 + +.GetSize: ; d0356 + push hl + ld a, [wPokeAnimFrontpicHeight] + sub 5 ; to get a number 0, 1, or 2 + ld c, a + ld b, 0 + ld hl, .Sizes + add hl, bc + ld c, [hl] + ld b, 0 + pop hl + ret +; d0368 + +.Sizes: db 4, 5, 7 + +poke_anim_box: MACRO +y = 7 +rept \1 +x = 7 +- \1 +rept \1 + db x + y +x = x + 1 +endr +y = y + 7 +endr +endm + +PokeAnim_ConvertAndApplyBitmask: ; d036b + xor a + ld [wPokeAnimBitmaskCurBit], a + ld [wPokeAnimBitmaskCurRow], a + ld [wPokeAnimBitmaskCurCol], a +.loop + push hl + call .IsCurBitSet + pop hl + ld a, b + and a + jr z, .next + + ld a, [wPokeAnimFramesBank] + call GetFarByte + inc hl + push hl + call .ApplyFrame + pop hl + +.next + push hl + call .NextBit + pop hl + jr nc, .loop + ret +; d0392 + +.IsCurBitSet: ; d0392 +; which byte + ld a, [wPokeAnimBitmaskCurBit] + and $f8 + rrca + rrca + rrca + ld e, a + ld d, 0 + ld hl, wPokeAnimBitmaskBuffer + add hl, de + ld b, [hl] +; which bit + ld a, [wPokeAnimBitmaskCurBit] + and $7 + jr z, .skip + + ld c, a + ld a, b +.loop2 + rrca + dec c + jr nz, .loop2 + ld b, a + +.skip + xor a + bit 0, b + jr z, .finish + ld a, 1 + +.finish + ld b, a + ld hl, wPokeAnimBitmaskCurBit + inc [hl] + ret +; d03bd + +.ApplyFrame: ; d03bd + push af + call .GetCoord + pop af + push hl + call .GetTilemap + ld hl, wPokeAnimGraphicStartTile + add [hl] + pop hl + ld [hl], a + ret +; d03cd + +.GetCoord: ; d03cd + call .GetStartCoord + ld a, [wPokeAnimBitmaskCurRow] + ld bc, SCREEN_WIDTH + call AddNTimes + ld a, [wBoxAlignment] + and a + jr nz, .go + ld a, [wPokeAnimBitmaskCurCol] + ld e, a + ld d, 0 + add hl, de + jr .skip2 + +.go + ld a, [wPokeAnimBitmaskCurCol] + ld e, a + ld a, l + sub e + ld l, a + ld a, h + sbc 0 + ld h, a + +.skip2 + ret +; d03f4 + +; XXX + db 6, 5, 4 + +.GetTilemap: ; d03f7 + push af + ld a, [wPokeAnimFrontpicHeight] + cp 5 + jr z, .check_add_24 + cp 6 + jr z, .check_add_13 + pop af + ret + +.check_add_24 + pop af + cp 5 * 5 + jr nc, .add_24 + push hl + push de + ld hl, ._5by5 + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + pop de + pop hl + ret + +.add_24 + add 24 + ret + +.check_add_13 + pop af + cp 6 * 6 + jr nc, .add_13 + push hl + push de + ld hl, ._6by6 + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + pop de + pop hl + ret + +.add_13 + add 13 + ret +; d042f + +._5by5: + poke_anim_box 5 + ; db 9, 10, 11, 12, 13 + ; db 16, 17, 18, 19, 20 + ; db 23, 24, 25, 26, 27 + ; db 30, 31, 32, 33, 34 + ; db 37, 38, 39, 40, 41 + +._6by6: + poke_anim_box 6 + ; db 8, 9, 10, 11, 12, 13 + ; db 15, 16, 17, 18, 19, 20 + ; db 22, 23, 24, 25, 26, 27 + ; db 29, 30, 31, 32, 33, 34 + ; db 36, 37, 38, 39, 40, 41 + ; db 43, 44, 45, 46, 47, 48 + + +.GetStartCoord: ; d046c + ld hl, wPokeAnimCoord + ld a, [hli] + ld h, [hl] + ld l, a + + ld a, [wPokeAnimFrontpicHeight] + ld de, 0 + ld bc, 6 + cp 7 + jr z, .okay + ld de, SCREEN_WIDTH + 1 + ld bc, SCREEN_WIDTH + 5 + cp 6 + jr z, .okay + ld de, 2 * SCREEN_WIDTH + 1 + ld bc, 2 * SCREEN_WIDTH + 5 +.okay + + ld a, [wBoxAlignment] + and a + jr nz, .add_bc + add hl, de + ret + +.add_bc + add hl, bc + ret +; d0499 + +.NextBit: ; d0499 + ld a, [wPokeAnimBitmaskCurRow] + inc a + ld [wPokeAnimBitmaskCurRow], a + ld c, a + ld a, [wPokeAnimFrontpicHeight] + cp c + jr nz, .no_carry + xor a + ld [wPokeAnimBitmaskCurRow], a + ld a, [wPokeAnimBitmaskCurCol] + inc a + ld [wPokeAnimBitmaskCurCol], a + ld c, a + ld a, [wPokeAnimFrontpicHeight] + cp c + jr nz, .no_carry + scf + ret + +.no_carry + xor a + ret +; d04bd + +PokeAnim_PlaceGraphic: ; d04bd + call .ClearBox + ld a, [wBoxAlignment] + and a + jr nz, .flipped + ld de, 1 + ld bc, 0 + jr .okay + +.flipped + ld de, -1 + ld bc, 6 + +.okay + ld hl, wPokeAnimCoord + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + ld c, 7 + ld b, 7 + ld a, [wPokeAnimGraphicStartTile] +.loop + push bc + push hl + push de + ld de, SCREEN_WIDTH +.loop2 + ld [hl], a + inc a + add hl, de + dec b + jr nz, .loop2 + pop de + pop hl + add hl, de + pop bc + dec c + jr nz, .loop + ret +; d04f6 + +.ClearBox: ; d04f6 + ld hl, wPokeAnimCoord + ld a, [hli] + ld h, [hl] + ld l, a + ld b, 7 + ld c, 7 + call ClearBox + ret +; d0504 + +PokeAnim_SetVBank1: ; d0504 + ld a, [rSVBK] + push af + ld a, $2 + ld [rSVBK], a + xor a + ld [hBGMapMode], a + call .SetFlag + farcall HDMATransferAttrMapToWRAMBank3 + pop af + ld [rSVBK], a + ret +; d051b + +.SetFlag: ; d051b + call PokeAnim_GetAttrMapCoord + ld b, 7 + ld c, 7 + ld de, SCREEN_WIDTH +.row + push bc + push hl +.col + ld a, [hl] + or 8 + ld [hl], a + add hl, de + dec c + jr nz, .col + pop hl + inc hl + pop bc + dec b + jr nz, .row + ret +; d0536 + +PokeAnim_SetVBank0: ; d0536 + call PokeAnim_GetAttrMapCoord + ld b, 7 + ld c, 7 + ld de, SCREEN_WIDTH +.row + push bc + push hl +.col + ld a, [hl] + and $f7 + ld [hl], a + add hl, de + dec c + jr nz, .col + pop hl + inc hl + pop bc + dec b + jr nz, .row + ret +; d0551 + +PokeAnim_GetAttrMapCoord: ; d0551 + ld hl, wPokeAnimCoord + ld a, [hli] + ld h, [hl] + ld l, a + ld de, AttrMap - TileMap + add hl, de + ret +; d055c + +GetMonAnimPointer: ; d055c + call PokeAnim_IsEgg + jr z, .egg + + ld c, BANK(UnownAnimations) + ld hl, UnownAnimationPointers + ld de, UnownAnimationExtraPointers + call PokeAnim_IsUnown + jr z, .unown + ld c, BANK(PicAnimations) + ld hl, AnimationPointers + ld de, AnimationExtraPointers +.unown + + ld a, [wPokeAnimExtraFlag] + and a + jr z, .extras + ld h, d + ld l, e +.extras + + ld a, [wPokeAnimSpeciesOrUnown] + dec a + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, c + ld [wPokeAnimPointerBank], a + call GetFarHalfword + ld a, l + ld [wPokeAnimPointerAddr], a + ld a, h + ld [wPokeAnimPointerAddr + 1], a + ret + +.egg + ld hl, EggAnimation + ld c, BANK(EggAnimation) + ld a, [wPokeAnimExtraFlag] + and a + jr z, .extras_egg + ld hl, EggAnimationExtra + ld c, BANK(EggAnimationExtra) +.extras_egg + + ld a, c + ld [wPokeAnimPointerBank], a + ld a, l + ld [wPokeAnimPointerAddr], a + ld a, h + ld [wPokeAnimPointerAddr + 1], a + ret +; d05b4 + +PokeAnim_GetFrontpicDims: ; d05b4 + ld a, [rSVBK] + push af + ld a, BANK(CurPartySpecies) + ld [rSVBK], a + ld a, [CurPartySpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BasePicSize] + and $f + ld c, a + pop af + ld [rSVBK], a + ret +; d05ce + +GetMonFramesPointer: ; d05ce + call PokeAnim_IsEgg + jr z, .egg + + call PokeAnim_IsUnown + ld b, BANK(UnownFramesPointers) + ld c, BANK(UnownsFrames) + ld hl, UnownFramesPointers + jr z, .got_frames + ld a, [wPokeAnimSpecies] + cp CHIKORITA + ld b, BANK(FramesPointers) + ld c, BANK(KantoFrames) + ld hl, FramesPointers + jr c, .got_frames + ld c, BANK(JohtoFrames) +.got_frames + ld a, c + ld [wPokeAnimFramesBank], a + + ld a, [wPokeAnimSpeciesOrUnown] + dec a + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, b + call GetFarHalfword + ld a, l + ld [wPokeAnimFramesAddr], a + ld a, h + ld [wPokeAnimFramesAddr + 1], a + ret + +.egg + ld hl, EggFrames + ld c, BANK(EggFrames) + ld a, c + ld [wPokeAnimFramesBank], a + ld a, l + ld [wPokeAnimFramesAddr], a + ld a, h + ld [wPokeAnimFramesAddr + 1], a + ret +; d061b + +GetMonBitmaskPointer: ; d061b + call PokeAnim_IsEgg + jr z, .egg + + call PokeAnim_IsUnown + ld a, BANK(UnownBitmasksPointers) + ld hl, UnownBitmasksPointers + jr z, .unown + ld a, BANK(BitmasksPointers) + ld hl, BitmasksPointers +.unown + ld [wPokeAnimBitmaskBank], a + + ld a, [wPokeAnimSpeciesOrUnown] + dec a + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [wPokeAnimBitmaskBank] + call GetFarHalfword + ld a, l + ld [wPokeAnimBitmaskAddr], a + ld a, h + ld [wPokeAnimBitmaskAddr + 1], a + ret + +.egg + ld c, BANK(EggBitmasks) + ld hl, EggBitmasks + ld a, c + ld [wPokeAnimBitmaskBank], a + ld a, l + ld [wPokeAnimBitmaskAddr], a + ld a, h + ld [wPokeAnimBitmaskAddr + 1], a + ret +; d065c + +PokeAnim_GetSpeciesOrUnown: ; d065c + call PokeAnim_IsUnown + jr z, .unown + ld a, [wPokeAnimSpecies] + ret + +.unown + ld a, [wPokeAnimUnownLetter] + ret +; d0669 + +Predef48: ; d0669 Predef 48 + ld a, $1 + ld [wBoxAlignment], a +HOF_AnimateFrontpic: ; d066e Predef 49 + call AnimateMon_CheckIfPokemon + jr c, .fail + ld h, d + ld l, e + push bc + push hl + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + pop hl + pop bc + ld d, 0 + ld e, c + call AnimateFrontpic + xor a + ld [wBoxAlignment], a + ret + +.fail + xor a + ld [wBoxAlignment], a + inc a + ld [CurPartySpecies], a + ret +; d0695 diff --git a/engine/player_gfx.asm b/engine/player_gfx.asm index 1af444d73..6ffaa77c8 100644 --- a/engine/player_gfx.asm +++ b/engine/player_gfx.asm @@ -71,45 +71,7 @@ ShowPlayerNamingChoices: ; 88297 call CloseWindow ret -ChrisNameMenuHeader: ; 882b5 - db $40 ; flags - db 00, 00 ; start coords - db 11, 10 ; end coords - dw .MaleNames - db 1 ; ???? - db 0 ; default option - -.MaleNames: ; 882be - db $91 ; flags - db 5 ; items - db "NEW NAME@" -MalePlayerNameArray: ; 882c9 - db "CHRIS@" - db "MAT@" - db "ALLAN@" - db "JON@" - db 2 ; displacement - db " NAME @" ; title - -KrisNameMenuHeader: ; 882e5 - db $40 ; flags - db 00, 00 ; start coords - db 11, 10 ; end coords - dw .FemaleNames - db 1 ; ???? - db 0 ; default option - -.FemaleNames: ; 882ee - db $91 ; flags - db 5 ; items - db "NEW NAME@" -FemalePlayerNameArray: ; 882f9 - db "KRIS@" - db "AMANDA@" - db "JUANA@" - db "JODI@" - db 2 ; displacement - db " NAME @" ; title +INCLUDE "data/default_names.asm" GetPlayerNameArray: ; 88318 This Function is never called ld hl, PlayerName diff --git a/engine/pokedex_3.asm b/engine/pokedex_3.asm index 3414252c1..6ec2ce9fd 100644 --- a/engine/pokedex_3.asm +++ b/engine/pokedex_3.asm @@ -21,7 +21,7 @@ LoadQuestionMarkPic: ; 1de0d7 ret .QuestionMarkLZ: ; 1de0e1 -INCBIN "gfx/pics/questionmark/front.2bpp.lz" +INCBIN "gfx/pokemon/questionmark/front.2bpp.lz" DrawPokedexListWindow: ; 1de171 (77:6171) ld a, $32 diff --git a/engine/pokegear.asm b/engine/pokegear.asm index 96959205b..a3e43cebf 100755 --- a/engine/pokegear.asm +++ b/engine/pokegear.asm @@ -2338,7 +2338,7 @@ HasVisitedSpawn: ; 91c50 ; 91c5e -INCLUDE "data/flypoints.asm" +INCLUDE "data/maps/flypoints.asm" ret_91c8f: ; 91c8f ret diff --git a/engine/scripting.asm b/engine/scripting.asm index 9818bbac3..826267f6b 100644 --- a/engine/scripting.asm +++ b/engine/scripting.asm @@ -64,7 +64,7 @@ RunScriptCommand: ScriptCommandTable: -; entries correspond to macros/event.asm enumeration +; entries correspond to macros/scripts/events.asm enumeration dw Script_scall ; 00 dw Script_farscall ; 01 dw Script_ptcall ; 02 diff --git a/engine/specials.asm b/engine/specials.asm index 82b42d8c1..cd2394b96 100644 --- a/engine/specials.asm +++ b/engine/specials.asm @@ -1,4 +1,3 @@ - Special:: ; c01b ; Run script special de. ld hl, SpecialsPointers diff --git a/engine/sprites.asm b/engine/sprites.asm index 755ee0835..4a33eb5cf 100755 --- a/engine/sprites.asm +++ b/engine/sprites.asm @@ -444,9 +444,9 @@ GetSpriteAnimFrame: ; 8d132 inc [hl] call .GetPointer ; load pointer from SpriteAnimFrameData ld a, [hli] - cp -2 + cp dorestart_command jr z, .restart - cp -1 + cp endanim_command jr z, .repeat_last push af @@ -551,13 +551,13 @@ BrokenGetStdGraphics: ; 8d1ac ; 8d1c4 -INCLUDE "data/sprite_anim_seqs.asm" +INCLUDE "data/sprite_anims/sequences.asm" INCLUDE "engine/sprite_anims.asm" -INCLUDE "data/sprite_anim_frames.asm" +INCLUDE "data/sprite_anims/framesets.asm" -INCLUDE "data/sprite_anim_oam.asm" +INCLUDE "data/sprite_anims/oam.asm" BrokenStdGFXPointers: ; Broken 2bpp pointers diff --git a/engine/timeofdaypals.asm b/engine/timeofdaypals.asm index a4a07bc4d..7fc364f70 100644 --- a/engine/timeofdaypals.asm +++ b/engine/timeofdaypals.asm @@ -41,19 +41,18 @@ _TimeOfDayPals:: ; 8c011 ; update palette id ld [TimeOfDayPal], a - -; save bg palette 8 - ld hl, UnknBGPals + 8 * 7 ; UnknBGPals + 7 pals +; save bg palette 7 + ld hl, UnknBGPals palette PAL_BG_TEXT ; save wram bank ld a, [rSVBK] ld b, a ; wram bank 5 - ld a, 5 + ld a, $5 ld [rSVBK], a ; push palette - ld c, 4 ; NUM_PAL_COLORS + ld c, NUM_PAL_COLORS .push ld d, [hl] inc hl @@ -73,7 +72,7 @@ _TimeOfDayPals:: ; 8c011 call GetSGBLayout -; restore bg palette 8 +; restore bg palette 7 ld hl, UnknOBPals - 1 ; last byte in UnknBGPals ; save wram bank @@ -84,7 +83,7 @@ _TimeOfDayPals:: ; 8c011 ld [rSVBK], a ; pop palette - ld e, 4 ; NUM_PAL_COLORS + ld e, NUM_PAL_COLORS .pop pop bc ld [hl], c diff --git a/engine/title.asm b/engine/title.asm index ba7f34764..84e7550fd 100644 --- a/engine/title.asm +++ b/engine/title.asm @@ -88,7 +88,7 @@ _TitleScreen: ; 10ed67 ; Suicune gfx hlbgcoord 0, 12 ld bc, 6 bgrows ; the rest of the screen - ld a, 8 + ld a, 0 | VRAM_BANK_1 call ByteFill diff --git a/engine/tmhm.asm b/engine/tmhm.asm index 78d3b1707..6a9c76f00 100755 --- a/engine/tmhm.asm +++ b/engine/tmhm.asm @@ -46,4 +46,4 @@ GetTMHMMove: ; 1166a ; 1167a -INCLUDE "data/tmhm_moves.asm" +INCLUDE "data/moves/tmhm_moves.asm" diff --git a/engine/trade_animation.asm b/engine/trade_animation.asm index fa631ae4e..1305fab5b 100755 --- a/engine/trade_animation.asm +++ b/engine/trade_animation.asm @@ -236,7 +236,7 @@ DoTradeAnimation: ; 29082 ; 290af .JumpTable: ; 290af -; entries correspond to macros/trade_anim.asm enumeration +; entries correspond to macros/scripts/trade_anims.asm enumeration dw TradeAnim_AdvanceScriptPointer ; 00 dw TradeAnim_ShowGivemonData ; 01 dw TradeAnim_ShowGetmonData ; 02 diff --git a/engine/types.asm b/engine/types.asm new file mode 100644 index 000000000..375bfe434 --- /dev/null +++ b/engine/types.asm @@ -0,0 +1,101 @@ +PrintMonTypes: ; 5090d +; Print one or both types of [CurSpecies] +; on the stats screen at hl. + + push hl + call GetBaseData + pop hl + + push hl + ld a, [BaseType1] + call .Print + + ; Single-typed monsters really + ; have two of the same type. + ld a, [BaseType1] + ld b, a + ld a, [BaseType2] + cp b + pop hl + jr z, .hide_type_2 + + ld bc, SCREEN_WIDTH + add hl, bc + +.Print: + ld b, a + jr PrintType + +.hide_type_2 + ; Erase any type name that was here before. + ; Seems to be pointless in localized versions. + ld a, " " + ld bc, SCREEN_WIDTH - 3 + add hl, bc + ld [hl], a + inc bc + add hl, bc + ld bc, 5 + jp ByteFill +; 5093a + + +PrintMoveType: ; 5093a +; Print the type of move b at hl. + + push hl + ld a, b + dec a + ld bc, MOVE_LENGTH + ld hl, Moves + call AddNTimes + ld de, StringBuffer1 + ld a, BANK(Moves) + call FarCopyBytes + ld a, [StringBuffer1 + MOVE_TYPE] + pop hl + + ld b, a + + +PrintType: ; 50953 +; Print type b at hl. + + ld a, b + + push hl + add a + ld hl, TypeNames + ld e, a + ld d, 0 + add hl, de + ld a, [hli] + ld e, a + ld d, [hl] + pop hl + + jp PlaceString +; 50964 + + +GetTypeName: ; 50964 +; Copy the name of type [wd265] to StringBuffer1. + + ld a, [wd265] + ld hl, TypeNames + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, StringBuffer1 + ld bc, 13 + jp CopyBytes +; 5097b + + +INCLUDE "data/type_names.asm" + +; 50a28 diff --git a/engine/warp_connection.asm b/engine/warp_connection.asm index 13a624d7f..ca0daae73 100755 --- a/engine/warp_connection.asm +++ b/engine/warp_connection.asm @@ -292,8 +292,8 @@ LoadMapTimeOfDay: ; 104750 ret LoadGraphics: ; 1047cf - call LoadTilesetHeader call LoadTileset + call LoadTilesetGFX xor a ld [hMapAnims], a xor a |