diff options
Diffstat (limited to 'engine')
207 files changed, 77791 insertions, 13792 deletions
diff --git a/engine/battle/ai/items.asm b/engine/battle/ai/items.asm new file mode 100644 index 00000000..0f30199e --- /dev/null +++ b/engine/battle/ai/items.asm @@ -0,0 +1,824 @@ +AI_SwitchOrTryItem: + and a + + ld a, [wBattleMode] + dec a + ret z + + ld a, [wLinkMode] + and a + ret nz + + farcall CheckEnemyLockedIn + ret nz + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, DontSwitch + + ld a, [wEnemyWrapCount] + and a + jr nz, DontSwitch + + ld a, [wTrainerClass] + dec a + ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH + 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: + call AI_TryItem + ret + +SwitchOften: + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp 50 percent + 1 + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp 79 percent - 1 + 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 mon to switch to + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch + +SwitchRarely: + 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 79 percent - 1 + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch + +SwitchSometimes: + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp 20 percent - 1 + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp 50 percent + 1 + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp 20 percent - 1 + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch + +CheckSubstatusCantRun: + ld a, [wEnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + ret + +AI_TryItem: + ld a, [wEnemyTrainerItem1] + ld b, a + ld a, [wEnemyTrainerItem2] + or b + ret z + + call .IsHighestLevel + ret nc + + ld a, [wTrainerClass] + 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, wEnemySubStatus3 + res SUBSTATUS_BIDE, [hl] + + xor a + ld [wEnemyFuryCutterCount], a + ld [wEnemyProtectCount], a + ld [wEnemyRageCounter], a + + ld hl, wEnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + + scf + ret + +.IsHighestLevel: + ld a, [wOTPartyCount] + ld d, a + ld e, 0 + ld hl, wOTPartyMon1Level + 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, [wCurOTMon] + ld hl, wOTPartyMon1Level + call AddNTimes + ld a, [hl] + cp e + jr nc, .yes + +.no + and a + ret + +.yes + scf + ret + +AI_Items: + 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 -1 ; end + +.FullHeal: + call .Status + jp c, .DontUse + call EnemyUsedFullHeal + jp .Use + +.Status: + ld a, [wEnemyMonStatus] + 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 20 percent - 1 + jp c, .Use + jp .DontUse + +.StatusCheckContext: + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr z, .FailToxicCheck + ld a, [wEnemyToxicCount] + cp 4 + jr c, .FailToxicCheck + call Random + cp 50 percent + 1 + jp c, .Use +.FailToxicCheck: + ld a, [wEnemyMonStatus] + and 1 << FRZ | SLP + jp z, .DontUse + jp .Use + +.FullRestore: + 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 + +.MaxPotion: + call .HealItem + jp c, .DontUse + call EnemyUsedMaxPotion + jp .Use + +.HealItem: + 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 50 percent + 1 + jp c, .UseHealItem + jp .DontUse + +.CheckQuarterHP: + callfar AICheckEnemyQuarterHP + jp c, .DontUse + call Random + cp 20 percent - 1 + jp c, .DontUse + jr .UseHealItem + +.CheckHalfOrQuarterHP: + callfar AICheckEnemyHalfHP + jp c, .DontUse + callfar AICheckEnemyQuarterHP + jp nc, .UseHealItem + call Random + cp 20 percent - 1 + jp nc, .DontUse + +.UseHealItem: + jp .Use + +.HyperPotion: + call .HealItem + jp c, .DontUse + ld b, 200 + call EnemyUsedHyperPotion + jp .Use + +.SuperPotion: + call .HealItem + jp c, .DontUse + ld b, 50 + call EnemyUsedSuperPotion + jp .Use + +.Potion: + call .HealItem + jp c, .DontUse + ld b, 20 + call EnemyUsedPotion + jp .Use + +.asm_3829f ; This appears to be unused + callfar AICheckEnemyMaxHP + jr c, .dont_use + push bc + ld de, wEnemyMonMaxHP + 1 + ld hl, wEnemyMonHP + 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 50 percent + 1 + 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 39 percent + 1 + jp c, .Use + jp .DontUse + +.XAccuracy: + call .XItem + jp c, .DontUse + call EnemyUsedXAccuracy + jp .Use + +.GuardSpec: + call .XItem + jp c, .DontUse + call EnemyUsedGuardSpec + jp .Use + +.DireHit: + call .XItem + jp c, .DontUse + call EnemyUsedDireHit + jp .Use + +.XAttack: + call .XItem + jp c, .DontUse + call EnemyUsedXAttack + jp .Use + +.XDefend: + call .XItem + jp c, .DontUse + call EnemyUsedXDefend + jp .Use + +.XSpeed: + call .XItem + jp c, .DontUse + call EnemyUsedXSpeed + jp .Use + +.XSpecial: + call .XItem + jp c, .DontUse + call EnemyUsedXSpecial + jp .Use + +.XItem: + ld a, [wEnemyTurnsTaken] + and a + jr nz, .notfirstturnout + ld a, [bc] + bit ALWAYS_USE_F, a + jp nz, .Use + call Random + cp 50 percent + 1 + jp c, .DontUse + ld a, [bc] + bit CONTEXT_USE_F, a + jp nz, .Use + call Random + cp 50 percent + 1 + jp c, .DontUse + jp .Use +.notfirstturnout + ld a, [bc] + bit ALWAYS_USE_F, a + jp z, .DontUse + call Random + cp 20 percent - 1 + jp nc, .DontUse + jp .Use + +.DontUse: + scf + ret + +.Use: + and a + ret + +AIUpdateHUD: + call UpdateEnemyMonInParty + farcall UpdateEnemyHUD + ld a, $1 + ldh [hBGMapMode], a + ld hl, wEnemyItemState + dec [hl] + scf + ret + +AIUsedItemSound: + push de + ld de, SFX_FULL_HEAL + call PlaySFX + pop de + ret + +EnemyUsedFullHeal: + call AIUsedItemSound + call AI_HealStatus + ld a, FULL_HEAL + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +EnemyUsedMaxPotion: + ld a, MAX_POTION + ld [wCurEnemyItem], a + jr FullRestoreContinue + +EnemyUsedFullRestore: + call AI_HealStatus + ld a, FULL_RESTORE + ld [wCurEnemyItem], a + ld hl, wEnemySubStatus3 + res SUBSTATUS_CONFUSED, [hl] + xor a + ld [wEnemyConfuseCount], a + +FullRestoreContinue: + ld de, wCurHPAnimOldHP + ld hl, wEnemyMonHP + 1 + ld a, [hld] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + ld hl, wEnemyMonMaxHP + 1 + ld a, [hld] + ld [de], a + inc de + ld [wCurHPAnimMaxHP], a + ld [wEnemyMonHP + 1], a + ld a, [hl] + ld [de], a + ld [wCurHPAnimMaxHP + 1], a + ld [wEnemyMonHP], a + jr EnemyPotionFinish + +EnemyUsedPotion: + ld a, POTION + ld b, 20 + jr EnemyPotionContinue + +EnemyUsedSuperPotion: + ld a, SUPER_POTION + ld b, 50 + jr EnemyPotionContinue + +EnemyUsedHyperPotion: + ld a, HYPER_POTION + ld b, 200 + +EnemyPotionContinue: + ld [wCurEnemyItem], a + ld hl, wEnemyMonHP + 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, wEnemyMonMaxHP + 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: + call PrintText_UsedItemOn + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + call AIUsedItemSound + predef AnimateHPBar + jp AIUpdateHUD + +AI_TrySwitch: +; Determine whether the AI can switch based on how many Pokemon are still alive. +; If it can switch, it will. + ld a, [wOTPartyCount] + ld c, a + ld hl, wOTPartyMon1HP + 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 + +AI_Switch: + ld a, $1 + ld [wEnemyIsSwitching], a + ld [wEnemyGoesFirst], a + ld hl, wEnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ldh [hBattleTurn], a + callfar PursuitSwitch + + push af + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, wEnemyMonStatus + ld bc, MON_MAXHP - MON_STATUS + call CopyBytes + pop af + + jr c, .skiptext + ld hl, EnemyWithdrewText + call PrintText + +.skiptext + ld a, 1 + ld [wBattleHasJustStarted], a + callfar NewEnemyMonStatus + callfar ResetEnemyStatLevels + ld hl, wPlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + farcall EnemySwitch + farcall ResetBattleParticipants + xor a + ld [wBattleHasJustStarted], a + ld a, [wLinkMode] + cp LINK_COLOSSEUM + ret z + scf + ret + +EnemyWithdrewText: + text_far _EnemyWithdrewText + text_end + +Function384c7: ; This appears to be unused + call AIUsedItemSound + call AI_HealStatus + ld a, FULL_HEAL_RED ; X_SPEED + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +AI_HealStatus: + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + xor a + ld [hl], a + ld [wEnemyMonStatus], a + ; Bug: this should reset SUBSTATUS_NIGHTMARE + ; Uncomment the 2 lines below to fix + ; ld hl, wEnemySubStatus1 + ; res SUBSTATUS_NIGHTMARE, [hl] + ; Bug: this should reset SUBSTATUS_CONFUSED + ; Uncomment the 2 lines below to fix + ; ld hl, wEnemySubStatus3 + ; res SUBSTATUS_CONFUSED, [hl] + ld hl, wEnemySubStatus5 + res SUBSTATUS_TOXIC, [hl] + ret + +EnemyUsedXAccuracy: + call AIUsedItemSound + ld hl, wEnemySubStatus4 + set SUBSTATUS_X_ACCURACY, [hl] + ld a, X_ACCURACY + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +EnemyUsedGuardSpec: + call AIUsedItemSound + ld hl, wEnemySubStatus4 + set SUBSTATUS_MIST, [hl] + ld a, GUARD_SPEC + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +EnemyUsedDireHit: + call AIUsedItemSound + ld hl, wEnemySubStatus4 + set SUBSTATUS_FOCUS_ENERGY, [hl] + ld a, DIRE_HIT + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +Function38510: ; This appears to be unused + ldh [hDivisor], a + ld hl, wEnemyMonMaxHP + ld a, [hli] + ldh [hDividend], a + ld a, [hl] + ldh [hDividend + 1], a + ld b, 2 + call Divide + ldh a, [hQuotient + 3] + ld c, a + ldh a, [hQuotient + 2] + ld b, a + ld hl, wEnemyMonHP + 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 + +EnemyUsedXAttack: + ld b, ATTACK + ld a, X_ATTACK + jr EnemyUsedXItem + +EnemyUsedXDefend: + ld b, DEFENSE + ld a, X_DEFEND + jr EnemyUsedXItem + +EnemyUsedXSpeed: + ld b, SPEED + ld a, X_SPEED + jr EnemyUsedXItem + +EnemyUsedXSpecial: + 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 [wCurEnemyItem], a + push bc + call PrintText_UsedItemOn + pop bc + farcall RaiseStat + jp AIUpdateHUD + +; Parameter +; a = ITEM_CONSTANT +PrintText_UsedItemOn_AND_AIUpdateHUD: + ld [wCurEnemyItem], a + call PrintText_UsedItemOn + jp AIUpdateHUD + +PrintText_UsedItemOn: + ld a, [wCurEnemyItem] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, wStringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, ITEM_NAME_LENGTH + call CopyBytes + ld hl, EnemyUsedOnText + jp PrintText + +EnemyUsedOnText: + text_far _EnemyUsedOnText + text_end diff --git a/engine/battle/ai/move.asm b/engine/battle/ai/move.asm new file mode 100644 index 00000000..060761a0 --- /dev/null +++ b/engine/battle/ai/move.asm @@ -0,0 +1,208 @@ +AIChooseMove: +; Score each move in wEnemyMonMoves starting from wBuffer1. 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, wBuffer1 + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + +; Don't pick disabled moves. + ld a, [wEnemyDisabledMove] + and a + jr z, .CheckPP + + ld hl, wEnemyMonMoves + ld c, 0 +.CheckDisabledMove: + cp [hl] + jr z, .ScoreDisabledMove + inc c + inc hl + jr .CheckDisabledMove +.ScoreDisabledMove: + ld hl, wBuffer1 + ld b, 0 + add hl, bc + ld [hl], 80 + +; Don't pick moves with 0 PP. +.CheckPP: + ld hl, wBuffer1 - 1 + ld de, wEnemyMonPP + ld b, 0 +.CheckMovePP: + inc b + ld a, b + cp wEnemyMonMovesEnd - wEnemyMonMoves + 1 + jr z, .ApplyLayers + inc hl + ld a, [de] + inc de + and PP_MASK + 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 + ld a, [wTrainerClass] + dec a + ld bc, 7 ; Trainer2AI - Trainer1AI + call AddNTimes + 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 SmallFarFlagAction + 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, wBuffer1 + ld de, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + +.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, wBuffer1 + ld de, wEnemyMonMoves + 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, wBuffer1 + call Random + maskbits NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and a + jr z, .ChooseMove + + ld [wCurEnemyMove], a + ld a, c + ld [wCurEnemyMoveNum], a + ret + +AIScoringPointers: +; entries correspond to AI_* constants + 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 diff --git a/engine/battle/ai/redundant.asm b/engine/battle/ai/redundant.asm new file mode 100644 index 00000000..d78fccb8 --- /dev/null +++ b/engine/battle/ai/redundant.asm @@ -0,0 +1,198 @@ +AI_Redundant: +; 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: + 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: + ld a, [wEnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + ret + +.Mist: + ld a, [wEnemySubStatus4] + bit SUBSTATUS_MIST, a + ret + +.FocusEnergy: + ld a, [wEnemySubStatus4] + bit SUBSTATUS_FOCUS_ENERGY, a + ret + +.Confuse: + ld a, [wPlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + ret nz + ld a, [wPlayerScreens] + bit SCREENS_SAFEGUARD, a + ret + +.Transform: + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret + +.Reflect: + ld a, [wEnemyScreens] + bit SCREENS_REFLECT, a + ret + +.Substitute: + ld a, [wEnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ret + +.LeechSeed: + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + ret + +.Disable: + ld a, [wPlayerDisableCount] + and a + ret + +.Encore: + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_ENCORED, a + ret + +.Snore: +.SleepTalk: + ld a, [wEnemyMonStatus] + and SLP + jr z, .Redundant + jr .NotRedundant + +.MeanLook: + ld a, [wEnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + ret + +.Nightmare: + ld a, [wBattleMonStatus] + and a + jr z, .Redundant + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_NIGHTMARE, a + ret + +.Spikes: + ld a, [wPlayerScreens] + bit SCREENS_SPIKES, a + ret + +.Foresight: + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_IDENTIFIED, a + ret + +.PerishSong: + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_PERISH, a + ret + +.Sandstorm: + ld a, [wBattleWeather] + cp WEATHER_SANDSTORM + jr z, .Redundant + jr .NotRedundant + +.Attract: + farcall CheckOppositeGender + jr c, .Redundant + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_IN_LOVE, a + ret + +.Safeguard: + ld a, [wEnemyScreens] + bit SCREENS_SAFEGUARD, a + ret + +.RainDance: + ld a, [wBattleWeather] + cp WEATHER_RAIN + jr z, .Redundant + jr .NotRedundant + +.SunnyDay: + ld a, [wBattleWeather] + cp WEATHER_SUN + jr z, .Redundant + jr .NotRedundant + +.DreamEater: + ld a, [wBattleMonStatus] + and SLP + jr z, .Redundant + jr .NotRedundant + +.Swagger: + ld a, [wPlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + ret + +.FutureSight: + ld a, [wEnemyScreens] + bit 5, a + ret + +.Heal: +.MorningSun: +.Synthesis: +.Moonlight: + farcall AICheckEnemyMaxHP + jr nc, .NotRedundant + +.Teleport: +.Redundant: + ld a, 1 + and a + ret + +.NotRedundant: + xor a + ret diff --git a/engine/battle/ai/scoring.asm b/engine/battle/ai/scoring.asm new file mode 100644 index 00000000..bfb9c282 --- /dev/null +++ b/engine/battle/ai/scoring.asm @@ -0,0 +1,3208 @@ +AIScoring: ; used only for BANK(AIScoring) + + +AI_Basic: +; 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, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 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, [wBattleMonStatus] + and a + jr nz, .discourage + +; Dismiss Safeguard if it's already active. + ld a, [wPlayerScreens] + bit SCREENS_SAFEGUARD, a + jr z, .checkmove + +.discourage + call AIDiscourageMove + jr .checkmove + +INCLUDE "data/battle/ai/status_only_effects.asm" + + +AI_Setup: +; 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, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 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, [wEnemyTurnsTaken] + and a + jr nz, .discourage + + jr .encourage + +.statdown + ld a, [wPlayerTurnsTaken] + 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 + + +AI_Types: +; 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, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 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 + ldh [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop de + pop bc + pop hl + + ld a, [wTypeMatchup] + and a + jr z, .immune + cp EFFECTIVE + 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, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 1 + ld c, 0 +.checkmove2 + dec b + jr z, .asm_38685 + + ld a, [hli] + and a + jr z, .asm_38685 + + call AIGetEnemyMove + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp d + jr z, .checkmove2 + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr nz, .asm_38684 + jr .checkmove2 + +.asm_38684 + ld c, a +.asm_38685 + ld a, c + pop bc + pop de + pop hl + and a + jr z, .checkmove + inc [hl] + jr .checkmove + +.immune + call AIDiscourageMove + jr .checkmove + + +AI_Offensive: +; Greatly discourage non-damaging moves. + + ld hl, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 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 + + +AI_Smart: +; Context-specific scoring. + + ld hl, wBuffer1 + ld de, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 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_386e4 + 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_386e4 + 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 -1 ; end + +AI_Smart_Sleep: +; 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_387e2 + + ld b, EFFECT_NIGHTMARE + call AIHasMoveEffect + ret nc + +.asm_387e2 + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret + +AI_Smart_LeechHit: + push hl + ld a, 1 + ldh [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop hl + +; 60% chance to discourage this move if not very effective. + ld a, [wTypeMatchup] + cp EFFECTIVE + jr c, .asm_38807 + +; 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_38807 + call Random + cp 39 percent + 1 + ret c + + inc [hl] + ret + +AI_Smart_LockOn: + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .asm_38874 + + push hl + call AICheckEnemyQuarterHP + jr nc, .asm_38869 + + call AICheckEnemyHalfHP + jr c, .asm_38826 + + call AICompareSpeed + jr nc, .asm_38869 + +.asm_38826 + ld a, [wPlayerEvaLevel] + cp BASE_STAT_LEVEL + 3 + jr nc, .asm_3886c + cp BASE_STAT_LEVEL + 1 + jr nc, .asm_38867 + + ld a, [wEnemyAccLevel] + cp BASE_STAT_LEVEL - 2 + jr c, .asm_3886c + cp BASE_STAT_LEVEL + jr c, .asm_38867 + + ld hl, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1 +.asm_38841 + dec c + jr z, .asm_38869 + + ld a, [hli] + and a + jr z, .asm_38869 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_ACC] + cp 180 + jr nc, .asm_38841 + + ld a, $1 + ldh [hBattleTurn], a + + push hl + push bc + farcall BattleCheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + pop bc + pop hl + jr c, .asm_38841 + +.asm_38867 + pop hl + ret + +.asm_38869 + pop hl + inc [hl] + ret + +.asm_3886c + pop hl + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +.asm_38874 + push hl + ld hl, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1 + +.asm_3887d + inc hl + dec c + jr z, .asm_38894 + + ld a, [de] + and a + jr z, .asm_38894 + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_ACC] + cp 180 + jr nc, .asm_3887d + + dec [hl] + dec [hl] + jr .asm_3887d + +.asm_38894 + pop hl + jp AIDiscourageMove + +AI_Smart_Selfdestruct: +; Selfdestruct, Explosion + +; Greatly discourage this move if enemy's HP is above 50%. + call AICheckEnemyHalfHP + jr c, .asm_388a7 + +; 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 8 percent + ret c + +.asm_388a7 + inc [hl] + inc [hl] + inc [hl] + ret + +AI_Smart_DreamEater: +; 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 + +AI_Smart_EvasionUp: +; Dismiss this move if enemy's evasion can't raise anymore. + ld a, [wEnemyEvaLevel] + cp MAX_STAT_LEVEL + jp nc, AIDiscourageMove + +; If enemy's HP is full... + call AICheckEnemyMaxHP + jr nc, .asm_388d3 + +; ...greatly encourage this move if player is badly poisoned. + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_388d0 + +; ...70% chance to greatly encourage this move if player is not badly poisoned. + call Random + cp 70 percent + jr nc, .asm_388f2 + +.asm_388d0 + dec [hl] + dec [hl] + ret + +.asm_388d3 + +; Greatly discourage this move if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + jr nc, .asm_388f0 + +; 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_388d0 + +; If enemy's HP is between 25% and 50%,... + call AICheckEnemyHalfHP + jr nc, .asm_388eb + +; If enemy's HP is above 50% but not full, 20% chance to greatly encourage this move. + call AI_80_20 + jr c, .asm_388d0 + jr .asm_388f2 + +.asm_388eb +; ...50% chance to greatly discourage this move. + call AI_50_50 + jr c, .asm_388f2 + +.asm_388f0 + 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_388f2 + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38919 + + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_38922 + +; Discourage this move if enemy's evasion level is higher than player's accuracy level. + ld a, [wEnemyEvaLevel] + ld b, a + ld a, [wPlayerAccLevel] + cp b + jr c, .asm_38917 + +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. + ld a, [wPlayerFuryCutterCount] + and a + jr nz, .asm_388d0 + + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_ROLLOUT, a + jr nz, .asm_388d0 + +.asm_38917 + inc [hl] + ret + +; Player is badly poisoned. +; 70% chance to greatly encourage this move. +; This would counter any previous discouragement. +.asm_38919 + 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_38922 + call AI_50_50 + ret c + + dec [hl] + ret + +AI_Smart_AlwaysHit: +; 80% chance to greatly encourage this move if either... + +; ...enemy's accuracy level has been lowered three or more stages + ld a, [wEnemyAccLevel] + cp BASE_STAT_LEVEL - 2 + jr c, .asm_38935 + +; ...or player's evasion level has been raised three or more stages. + ld a, [wPlayerEvaLevel] + cp BASE_STAT_LEVEL + 3 + ret c + +.asm_38935 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret + +AI_Smart_MirrorMove: +; If the player did not use any move last turn... + ld a, [wLastPlayerCounterMove] + and a + jr nz, .asm_38949 + +; ...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_38949 + 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 + +AI_Smart_AccuracyDown: +; If player's HP is full... + call AICheckPlayerMaxHP + jr nc, .asm_38981 + +; ...and enemy's HP is above 50%... + call AICheckEnemyHalfHP + jr nc, .asm_38981 + +; ...greatly encourage this move if player is badly poisoned. + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_3897e + +; ...70% chance to greatly encourage this move if player is not badly poisoned. + call Random + cp 70 percent + jr nc, .asm_389a0 + +.asm_3897e + dec [hl] + dec [hl] + ret + +.asm_38981 + +; Greatly discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP + jr nc, .asm_3899e + +; 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_3897e + +; If player's HP is between 25% and 50%,... + call AICheckPlayerHalfHP + jr nc, .asm_38999 + +; If player's HP is above 50% but not full, 20% chance to greatly encourage this move. + call AI_80_20 + jr c, .asm_3897e + jr .asm_389a0 + +; ...50% chance to greatly discourage this move. +.asm_38999 + call AI_50_50 + jr c, .asm_389a0 + +.asm_3899e + inc [hl] + inc [hl] + +; We only end up here if the move has not been already encouraged. +.asm_389a0 + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_389c7 + + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_389d0 + +; Discourage this move if enemy's evasion level is higher than player's accuracy level. + ld a, [wEnemyEvaLevel] + ld b, a + ld a, [wPlayerAccLevel] + cp b + jr c, .asm_389c5 + +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. + ld a, [wPlayerFuryCutterCount] + and a + jr nz, .asm_3897e + + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_ROLLOUT, a + jr nz, .asm_3897e + +.asm_389c5 + inc [hl] + ret + +; Player is badly poisoned. +; 70% chance to greatly encourage this move. +; This would counter any previous discouragement. +.asm_389c7 + 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_389d0 + call AI_50_50 + ret c + + dec [hl] + ret + +AI_Smart_ResetStats: +; 85% chance to encourage this move if any of enemy's stat levels is lower than -2. + push hl + ld hl, wEnemyAtkLevel + ld c, NUM_LEVEL_STATS +.asm_389dc + dec c + jr z, .asm_389e6 + ld a, [hli] + cp BASE_STAT_LEVEL - 2 + jr c, .asm_389f3 + jr .asm_389dc + +; 85% chance to encourage this move if any of player's stat levels is higher than +2. +.asm_389e6 + ld hl, wPlayerAtkLevel + ld c, $8 +.asm_389eb + dec c + jr z, .asm_389fc + ld a, [hli] + cp BASE_STAT_LEVEL + 3 + jr c, .asm_389eb + +.asm_389f3 + 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_389fc + pop hl + inc [hl] + ret + +AI_Smart_Bide: +; 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 + +AI_Smart_ForceSwitch: +; 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 + +AI_Smart_Heal: +AI_Smart_MorningSun: +AI_Smart_Synthesis: +AI_Smart_Moonlight: +; 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_38a26 + call AICheckEnemyHalfHP + ret nc + inc [hl] + ret + +.asm_38a26 + call Random + cp 10 percent + ret c + dec [hl] + dec [hl] + ret + +AI_Smart_Toxic: +AI_Smart_LeechSeed: +; Discourage this move if player's HP is below 50%. + + call AICheckPlayerHalfHP + ret c + inc [hl] + ret + +AI_Smart_LightScreen: +AI_Smart_Reflect: +; 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 + +AI_Smart_Ohko: +; 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, [wBattleMonLevel] + ld b, a + ld a, [wEnemyMonLevel] + cp b + jp c, AIDiscourageMove + call AICheckPlayerHalfHP + ret c + inc [hl] + ret + +AI_Smart_TrapTarget: +; 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_38a6c + +; 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, [wPlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38a72 + + ld a, [wPlayerSubStatus1] + and 1 << SUBSTATUS_IN_LOVE | 1 << SUBSTATUS_ROLLOUT | 1 << SUBSTATUS_IDENTIFIED | 1 << SUBSTATUS_NIGHTMARE + jr nz, .asm_38a72 + +; Else, 50% chance to greatly encourage this move if it's the player's Pokemon first turn. + ld a, [wPlayerTurnsTaken] + and a + jr z, .asm_38a72 + +; 50% chance to discourage this move otherwise. +.asm_38a6c + call AI_50_50 + ret c + inc [hl] + ret + +.asm_38a72 + call AICheckEnemyQuarterHP + ret nc + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret + +AI_Smart_RazorWind: +AI_Smart_Unused2B: + ld a, [wEnemySubStatus1] + bit SUBSTATUS_PERISH, a + jr z, .asm_38a8b + + ld a, [wEnemyPerishCount] + cp 3 + jr c, .asm_38ab4 + +.asm_38a8b + push hl + ld hl, wPlayerUsedMoves + ld c, NUM_MOVES + +.asm_38a91 + ld a, [hli] + and a + jr z, .asm_38aa2 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + jr z, .asm_38ab6 + dec c + jr nz, .asm_38a91 + +.asm_38aa2 + pop hl + ld a, [wEnemySubStatus3] + bit SUBSTATUS_CONFUSED, a + jr nz, .asm_38aae + + call AICheckEnemyHalfHP + ret c + +.asm_38aae + call Random + cp 79 percent - 1 + ret c + +.asm_38ab4 + inc [hl] + ret + +.asm_38ab6 + pop hl + ld a, [hl] + add 6 + ld [hl], a + ret + +AI_Smart_Confuse: +; 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_38ac8 + inc [hl] + +.asm_38ac8 +; Discourage again if player's HP is below 25%. + call AICheckPlayerQuarterHP + ret c + inc [hl] + ret + +AI_Smart_SpDefenseUp2: +; Discourage this move if enemy's HP is lower than 50%. + call AICheckEnemyHalfHP + jr nc, .asm_38af1 + +; Discourage this move if enemy's special defense level is higher than +3. + ld a, [wEnemySDefLevel] + cp BASE_STAT_LEVEL + 4 + jr nc, .asm_38af1 + +; 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 BASE_STAT_LEVEL + 2 + ret nc + + ld a, [wBattleMonType1] + cp SPECIAL + jr nc, .asm_38aea + ld a, [wBattleMonType2] + cp SPECIAL + ret c + +.asm_38aea + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38af1 + inc [hl] + ret + +AI_Smart_Fly: +; Fly, Dig + +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + + ld a, [wPlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + call AICompareSpeed + ret nc + + dec [hl] + dec [hl] + dec [hl] + ret + +AI_Smart_SuperFang: +; Discourage this move if player's HP is below 25%. + + call AICheckPlayerQuarterHP + ret c + inc [hl] + ret + +AI_Smart_Paralyze: +; 50% chance to discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP + jr nc, .asm_38b1b + +; 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_38b1b + call AI_50_50 + ret c + inc [hl] + ret + +AI_Smart_SpeedDownHit: +; 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, [wPlayerTurnsTaken] + and a + ret nz + call AICompareSpeed + ret c + call Random + cp 12 percent + ret c + dec [hl] + dec [hl] + ret + +AI_Smart_Substitute: +; Dismiss this move if enemy's HP is below 50%. + + call AICheckEnemyHalfHP + ret c + jp AIDiscourageMove + +AI_Smart_HyperBeam: + call AICheckEnemyHalfHP + jr c, .asm_38b53 + +; 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_38b53 +; If enemy's HP is above 50%, discourage this move at random + call Random + cp 35 percent + 1 + ret c + inc [hl] + call AI_50_50 + ret c + inc [hl] + ret + +AI_Smart_Rage: + ld a, [wEnemySubStatus4] + bit SUBSTATUS_RAGE, a + jr z, .asm_38b7c + +; If enemy's Rage is building, 50% chance to encourage this move. + call AI_50_50 + jr c, .asm_38b6d + + dec [hl] + +; Encourage this move based on Rage's counter. +.asm_38b6d + ld a, [wEnemyRageCounter] + cp 2 + ret c + dec [hl] + ld a, [wEnemyRageCounter] + cp 3 + ret c + dec [hl] + ret + +.asm_38b7c +; If enemy's Rage is not building, discourage this move if enemy's HP is below 50%. + call AICheckEnemyHalfHP + jr nc, .asm_38b87 + +; 50% chance to encourage this move otherwise. + call AI_80_20 + ret nc + dec [hl] + ret + +.asm_38b87 + inc [hl] + ret + +AI_Smart_Mimic: + ld a, [wLastPlayerCounterMove] + and a + jr z, .asm_38bca + + call AICheckEnemyHalfHP + jr nc, .asm_38bd0 + + push hl + ld a, [wLastPlayerCounterMove] + call AIGetEnemyMove + + ld a, $1 + ldh [hBattleTurn], a + callfar BattleCheckTypeMatchup + + ld a, [wTypeMatchup] + cp EFFECTIVE + pop hl + jr c, .asm_38bd0 + jr z, .asm_38bb5 + + call AI_50_50 + jr c, .asm_38bb5 + + dec [hl] + +.asm_38bb5 + ld a, [wLastPlayerCounterMove] + push hl + ld hl, UsefulMoves + ld de, 1 + call IsInArray + + pop hl + ret nc + call AI_50_50 + ret c + dec [hl] + ret + +.asm_38bca + call AICompareSpeed + jp c, AIDiscourageMove + +.asm_38bd0 + inc [hl] + ret + +AI_Smart_Counter: + push hl + ld hl, wPlayerUsedMoves + ld c, NUM_MOVES + ld b, 0 + +.asm_38bda + 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_38bda + + pop hl + ld a, b + and a + jr z, .asm_38c1a + + cp $3 + jr nc, .asm_38c11 + + ld a, [wLastPlayerCounterMove] + and a + jr z, .asm_38c19 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c19 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr nc, .asm_38c19 + +.asm_38c11 + call Random + cp 39 percent + 1 + jr c, .asm_38c19 + + dec [hl] + +.asm_38c19 + ret + +.asm_38c1a + inc [hl] + ret + +AI_Smart_Encore: + call AICompareSpeed + jr nc, .asm_38c62 + + ld a, [wLastPlayerMove] + and a + jp z, AIDiscourageMove + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c49 + + push hl + ld a, [wEnemyMoveStruct + MOVE_TYPE] + ld hl, wEnemyMonType1 + predef CheckTypeMatchup + + pop hl + ld a, [wTypeMatchup] + cp EFFECTIVE + jr nc, .asm_38c49 + + and a + ret nz + jr .asm_38c59 + +.asm_38c49 + push hl + ld a, [wLastPlayerCounterMove] + ld hl, EncoreMoves + ld de, 1 + call IsInArray + pop hl + jr nc, .asm_38c62 + +.asm_38c59 + call Random + cp 28 percent - 1 + ret c + dec [hl] + dec [hl] + ret + +.asm_38c62 + inc [hl] + inc [hl] + inc [hl] + ret + +INCLUDE "data/battle/ai/encore_moves.asm" + +AI_Smart_PainSplit: +; Discourage this move if [enemy's current HP * 2 > player's current HP]. + + push hl + ld hl, wEnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + ld hl, wBattleMonHP + 1 + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret nc + inc [hl] + ret + +AI_Smart_Snore: +AI_Smart_SleepTalk: +; Greatly encourage this move if enemy is fast asleep. +; Greatly discourage this move otherwise. + + ld a, [wEnemyMonStatus] + and SLP + cp 1 + jr z, .asm_38ca8 + + dec [hl] + dec [hl] + dec [hl] + ret + +.asm_38ca8 + inc [hl] + inc [hl] + inc [hl] + ret + +AI_Smart_DefrostOpponent: +; Greatly encourage this move if enemy is frozen. +; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused. + + ld a, [wEnemyMonStatus] + and 1 << FRZ + ret z + dec [hl] + dec [hl] + dec [hl] + ret + +AI_Smart_Spite: + ld a, [wLastPlayerCounterMove] + and a + jr nz, .asm_38cc8 + + call AICompareSpeed + jp c, AIDiscourageMove + + call AI_50_50 + ret c + inc [hl] + ret + +.asm_38cc8 + push hl + ld b, a + ld c, NUM_MOVES + ld hl, wBattleMonMoves + ld de, wBattleMonPP + +.asm_38cd2 + ld a, [hli] + cp b + jr z, .asm_38cdc + + inc de + dec c + jr nz, .asm_38cd2 + + pop hl + ret + +.asm_38cdc + pop hl + ld a, [de] + cp 6 + jr c, .asm_38cee + cp 15 + jr nc, .asm_38cec + + call Random + cp 39 percent + 1 + ret nc + +.asm_38cec + inc [hl] + ret + +.asm_38cee + call Random + cp 39 percent + 1 + ret c + dec [hl] + dec [hl] + ret + +Function_0x38cf7: + jp AIDiscourageMove + +AI_Smart_DestinyBond: +AI_Smart_Reversal: +AI_Smart_SkullBash: +; Discourage this move if enemy's HP is above 25%. + + call AICheckEnemyQuarterHP + ret nc + inc [hl] + ret + +AI_Smart_HealBell: +; 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, [wOTPartyCount] + ld b, a + ld c, 0 + ld hl, wOTPartyMon1HP + 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, [wEnemyMonStatus] + 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, [wEnemyMonStatus] + and a + ret nz + jp AIDiscourageMove + + +AI_Smart_PriorityHit: + call AICompareSpeed + ret c + +; Dismiss this move if the player is flying or underground. + ld a, [wPlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + jp nz, AIDiscourageMove + +; Greatly encourage this move if it will KO the player. + ld a, $1 + ldh [hBattleTurn], a + push hl + callfar EnemyAttackDamage + callfar BattleCommand_DamageCalc + callfar BattleCommand_Stab + pop hl + ld a, [wCurDamage + 1] + ld c, a + ld a, [wCurDamage] + ld b, a + ld a, [wBattleMonHP + 1] + cp c + ld a, [wBattleMonHP] + sbc b + ret nc + dec [hl] + dec [hl] + dec [hl] + ret + +AI_Smart_Thief: +; Don't use Thief unless it's the only move available. + + ld a, [hl] + add $1e + ld [hl], a + ret + +AI_Smart_Conversion2: + ld a, [wLastPlayerMove] + and a + jr nz, .asm_38daa + + 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 + ldh [hBattleTurn], a + + callfar BattleCheckTypeMatchup + + ld a, [wTypeMatchup] + cp EFFECTIVE + pop hl + jr c, .asm_38daa + ret z + + call AI_50_50 + ret c + + dec [hl] + ret + +.asm_38daa + call Random + cp 10 percent + ret c + inc [hl] + ret + +AI_Smart_Disable: + call AICompareSpeed + jr nc, .asm_38dd4 + + push hl + ld a, [wLastPlayerCounterMove] + ld hl, UsefulMoves + ld de, 1 + call IsInArray + + pop hl + jr nc, .asm_38dcf + + call Random + cp 39 percent + 1 + ret c + dec [hl] + ret + +.asm_38dcf + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + ret nz + +.asm_38dd4 + call Random + cp 8 percent + ret c + inc [hl] + ret + +AI_Smart_MeanLook: + call AICheckEnemyHalfHP + jr nc, .asm_38e05 + + 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 wPlayerSubStatus5 instead. + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38e07 + +; 80% chance to greatly encourage this move if the player is either +; in love, identified, stuck in Rollout, or has a Nightmare. + ld a, [wPlayerSubStatus1] + and 1 << SUBSTATUS_IN_LOVE | 1 << SUBSTATUS_ROLLOUT | 1 << SUBSTATUS_IDENTIFIED | 1 << SUBSTATUS_NIGHTMARE + jr nz, .asm_38e07 + +; 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_38e05 + inc [hl] + ret + +.asm_38e07 + call AI_80_20 + ret c + dec [hl] + dec [hl] + dec [hl] + ret + +AICheckLastPlayerMon: + ld a, [wPartyCount] + ld b, a + ld c, 0 + ld hl, wPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + ld a, [wCurBattleMon] + cp c + jr z, .asm_38e25 + + ld a, [hli] + or [hl] + ret nz + dec hl + +.asm_38e25 + add hl, de + inc c + dec b + jr nz, .loop + + ret + +AI_Smart_Nightmare: +; 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 + +AI_Smart_FlameWheel: +; Use this move if the enemy is frozen. + + ld a, [wEnemyMonStatus] + bit FRZ, a + ret z +rept 5 + dec [hl] +endr + ret + +AI_Smart_Curse: + ld a, [wEnemyMonType1] + cp GHOST + jr z, .ghostcurse + ld a, [wEnemyMonType2] + cp GHOST + jr z, .ghostcurse + + call AICheckEnemyHalfHP + jr nc, .asm_38e72 + + ld a, [wEnemyAtkLevel] + cp BASE_STAT_LEVEL + 4 + jr nc, .asm_38e72 + cp BASE_STAT_LEVEL + 2 + ret nc + + ld a, [wBattleMonType1] + cp GHOST + jr z, .asm_38e71 + cp SPECIAL + ret nc + ld a, [wBattleMonType2] + cp SPECIAL + ret nc + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38e71 + inc [hl] +.asm_38e72 + inc [hl] + ret + +.ghostcurse + call AICheckEnemyQuarterHP + jp nc, AIDiscourageMove + + call AICheckEnemyHalfHP + jr nc, .asm_38e72 + + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_CURSE, a + jp nz, AIDiscourageMove + + ld a, [wPlayerTurnsTaken] + and a + ret nz + + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +AI_Smart_Protect: + ld a, [wEnemyProtectCount] + and a + jr nz, .asm_38ed4 + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .asm_38ed5 + + ld a, [wPlayerFuryCutterCount] + cp 3 + jr nc, .asm_38ece + + ld a, [wPlayerSubStatus3] + bit SUBSTATUS_CHARGED, a + jr nz, .asm_38ece + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38ece + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_38ece + ld a, [wPlayerSubStatus1] + bit SUBSTATUS_CURSE, a + jr nz, .asm_38ece + + bit SUBSTATUS_ROLLOUT, a + jr z, .asm_38ed5 + + ld a, [wPlayerRolloutCount] + cp 3 + jr c, .asm_38ed5 + +.asm_38ece + call AI_80_20 + ret c + dec [hl] + ret + +.asm_38ed4 + inc [hl] + +.asm_38ed5 + call Random + cp 8 percent + ret c + inc [hl] + inc [hl] + ret + +AI_Smart_Foresight: + ld a, [wEnemyAccLevel] + cp BASE_STAT_LEVEL - 2 + jr c, .asm_38f02 + ld a, [wPlayerEvaLevel] + cp BASE_STAT_LEVEL + 3 + jr nc, .asm_38f02 + + ld a, [wBattleMonType1] + cp GHOST + jr z, .asm_38f02 + ld a, [wBattleMonType2] + cp GHOST + jr z, .asm_38f02 + + call Random + cp 8 percent + ret c + inc [hl] + ret + +.asm_38f02 + call Random + cp 39 percent + 1 + ret c + dec [hl] + dec [hl] + ret + +AI_Smart_PerishSong: + push hl + callfar FindAliveEnemyMons + pop hl + jr c, .no + + ld a, [wPlayerSubStatus5] + 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 + +AI_Smart_Sandstorm: +; Greatly discourage this move if the player is immune to Sandstorm damage. + ld a, [wBattleMonType1] + push hl + ld hl, .SandstormImmuneTypes + ld de, 1 + call IsInArray + pop hl + jr c, .asm_38f66 + + ld a, [wBattleMonType2] + push hl + ld hl, .SandstormImmuneTypes + ld de, 1 + call IsInArray + pop hl + jr c, .asm_38f66 + +; Discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP + jr nc, .asm_38f67 + +; 50% chance to encourage this move otherwise. + call AI_50_50 + ret c + + dec [hl] + ret + +.asm_38f66 + inc [hl] + +.asm_38f67 + inc [hl] + ret + +.SandstormImmuneTypes: + db ROCK + db GROUND + db STEEL + db -1 ; end + +AI_Smart_Endure: + ld a, [wEnemyProtectCount] + and a + jr nz, .asm_38f99 + + call AICheckEnemyMaxHP + jr c, .asm_38f99 + + call AICheckEnemyQuarterHP + jr c, .asm_38f9a + + ld b, EFFECT_REVERSAL + call AIHasMoveEffect + jr nc, .asm_38f8c + + call AI_80_20 + ret c + + dec [hl] + dec [hl] + dec [hl] + ret + +.asm_38f8c + ld a, [wEnemySubStatus5] + bit SUBSTATUS_LOCK_ON, a + ret z + + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +.asm_38f99 + inc [hl] + +.asm_38f9a + inc [hl] + ret + +AI_Smart_FuryCutter: +; Encourage this move based on Fury Cutter's count. + + ld a, [wEnemyFuryCutterCount] + 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 + +AI_Smart_Rollout: +; Rollout, Fury Cutter + +; 80% chance to discourage this move if the enemy is in love, confused, or paralyzed. + ld a, [wEnemySubStatus1] + bit SUBSTATUS_IN_LOVE, a + jr nz, .asm_38fe1 + + ld a, [wEnemySubStatus3] + bit SUBSTATUS_CONFUSED, a + jr nz, .asm_38fe1 + + ld a, [wEnemyMonStatus] + bit PAR, a + jr nz, .asm_38fe1 + +; 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_38fe1 + + ld a, [wEnemyAccLevel] + cp BASE_STAT_LEVEL + jr c, .asm_38fe1 + ld a, [wPlayerEvaLevel] + cp BASE_STAT_LEVEL + 1 + jr nc, .asm_38fe1 + +; Otherwise, 80% chance to greatly encourage this move. + call Random + cp 79 percent - 1 + ret nc + dec [hl] + dec [hl] + ret + +.asm_38fe1 + call AI_80_20 + ret c + inc [hl] + ret + +AI_Smart_Swagger: +AI_Smart_Attract: +; 80% chance to encourage this move during the first turn of player's Pokemon. +; 80% chance to discourage this move otherwise. + + ld a, [wPlayerTurnsTaken] + 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 + +AI_Smart_Safeguard: +; 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 + +AI_Smart_Magnitude: +AI_Smart_Earthquake: +; Greatly encourage this move if the player is underground and the enemy is faster. + ld a, [wLastPlayerCounterMove] + cp DIG + ret nz + + ld a, [wPlayerSubStatus3] + 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 + +AI_Smart_BatonPass: +; 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 + +AI_Smart_Pursuit: +; 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_3903e + call AI_80_20 + ret c + inc [hl] + ret + +.asm_3903e + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret + +AI_Smart_RapidSpin: +; 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_39058 + + ld a, [wEnemySubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_39058 + + ld a, [wEnemyScreens] + bit SCREENS_SPIKES, a + ret z + +.asm_39058 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret + +AI_Smart_HiddenPower: + push hl + ld a, 1 + ldh [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, [wTypeMatchup] + cp EFFECTIVE + 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, [wTypeMatchup] + cp EFFECTIVE + 1 + 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 + +AI_Smart_RainDance: +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Water-type. + ld a, [wBattleMonType1] + cp WATER + jr z, AIBadWeatherType + cp FIRE + jr z, AIGoodWeatherType + + ld a, [wBattleMonType2] + cp WATER + jr z, AIBadWeatherType + cp FIRE + jr z, AIGoodWeatherType + + push hl + ld hl, RainDanceMoves + jr AI_Smart_WeatherMove + +INCLUDE "data/battle/ai/rain_dance_moves.asm" + +AI_Smart_SunnyDay: +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Fire-type. + ld a, [wBattleMonType1] + cp FIRE + jr z, AIBadWeatherType + cp WATER + jr z, AIGoodWeatherType + + ld a, [wBattleMonType2] + cp FIRE + jr z, AIBadWeatherType + cp WATER + jr z, AIGoodWeatherType + + push hl + ld hl, SunnyDayMoves + + ; fallthrough + +AI_Smart_WeatherMove: +; 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 + +AIBadWeatherType: + inc [hl] + inc [hl] + inc [hl] + ret + +AIGoodWeatherType: +; 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, [wPlayerTurnsTaken] + and a + jr z, .good + +; Or it's the first turn of the enemy's Pokemon. + ld a, [wEnemyTurnsTaken] + and a + ret nz + +.good + dec [hl] + dec [hl] + ret + +INCLUDE "data/battle/ai/sunny_day_moves.asm" + +AI_Smart_BellyDrum: +; 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, [wEnemyAtkLevel] + cp BASE_STAT_LEVEL + 3 + jr nc, .asm_3910e + + call AICheckEnemyMaxHP + ret c + + inc [hl] + + call AICheckEnemyHalfHP + ret c + +.asm_3910e + ld a, [hl] + add $5 + ld [hl], a + ret + +AI_Smart_PsychUp: + push hl + ld hl, wEnemyAtkLevel + 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_3911b + ld a, [hli] + sub $7 + add c + ld c, a + dec b + jr nz, .asm_3911b + +; 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, wPlayerAtkLevel + ld b, $8 + ld d, 100 + +.asm_3912a + ld a, [hli] + sub $7 + add d + ld d, a + dec b + jr nz, .asm_3912a + +; 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_3914f + +; This block will always ret, since the comparisons to wPlayerEvaLevel capture every possible value + ld a, [wPlayerAccLevel] + cp BASE_STAT_LEVEL - 1 + ret c + + ld a, [wPlayerEvaLevel] + cp BASE_STAT_LEVEL + 2 + ret c + + ld a, [wPlayerEvaLevel] + cp BASE_STAT_LEVEL + 1 + ret nc + +; unused + call AI_80_20 + ret c + + dec [hl] + ret + +.asm_3914f + inc [hl] + ret + +AI_Smart_MirrorCoat: + push hl + ld hl, wPlayerUsedMoves + ld c, NUM_MOVES + ld b, 0 + +.asm_39159 + ld a, [hli] + and a + jr z, .asm_3916e + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_3916e + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr c, .asm_3916e + + inc b + +.asm_3916e + dec c + jr nz, .asm_39159 + + pop hl + ld a, b + and a + jr z, .asm_39199 + + cp $3 + jr nc, .asm_39190 + + ld a, [wLastPlayerCounterMove] + and a + jr z, .asm_39198 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_39198 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr c, .asm_39198 + +.asm_39190 + call Random + cp 100 + jr c, .asm_39198 + dec [hl] + +.asm_39198 + ret + +.asm_39199 + inc [hl] + ret + +AI_Smart_Twister: +AI_Smart_Gust: +; Greatly encourage this move if the player is flying and the enemy is faster. + ld a, [wLastPlayerCounterMove] + cp FLY + ret nz + + ld a, [wPlayerSubStatus3] + 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 + +AI_Smart_FutureSight: +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + + call AICompareSpeed + ret nc + + ld a, [wPlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + dec [hl] + dec [hl] + ret + +AI_Smart_Stomp: +; 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 + +AI_Smart_Solarbeam: +; 80% chance to encourage this move when it's sunny. +; 90% chance to discourage this move when it's raining. + + ld a, [wBattleWeather] + cp WEATHER_SUN + jr z, .asm_391e4 + + cp WEATHER_RAIN + ret nz + + call Random + cp 10 percent + ret c + + inc [hl] + inc [hl] + ret + +.asm_391e4 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret + +AI_Smart_Thunder: +; 90% chance to discourage this move when it's sunny. + + ld a, [wBattleWeather] + cp WEATHER_SUN + ret nz + + call Random + cp 10 percent + ret c + + inc [hl] + ret + +AICompareSpeed: +; Return carry if enemy is faster than player. + + push bc + ld a, [wEnemyMonSpeed + 1] + ld b, a + ld a, [wBattleMonSpeed + 1] + cp b + ld a, [wEnemyMonSpeed] + ld b, a + ld a, [wBattleMonSpeed] + sbc b + pop bc + ret + +AICheckPlayerMaxHP: + push hl + push de + push bc + ld de, wBattleMonHP + ld hl, wBattleMonMaxHP + jr AICheckMaxHP + +AICheckEnemyMaxHP: + push hl + push de + push bc + ld de, wEnemyMonHP + ld hl, wEnemyMonMaxHP + ; fallthrough + +AICheckMaxHP: +; Return carry if hp at de matches max hp at hl. + + ld a, [de] + inc de + cp [hl] + jr nz, .asm_3922f + + inc hl + ld a, [de] + cp [hl] + jr nz, .asm_3922f + + pop bc + pop de + pop hl + scf + ret + +.asm_3922f + pop bc + pop de + pop hl + and a + ret + +AICheckPlayerHalfHP: + push hl + ld hl, wBattleMonHP + 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 + +AICheckEnemyHalfHP: + push hl + push de + push bc + ld hl, wEnemyMonHP + 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 + +AICheckEnemyQuarterHP: + push hl + push de + push bc + ld hl, wEnemyMonHP + 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 + +AICheckPlayerQuarterHP: + push hl + ld hl, wBattleMonHP + 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 + +AIHasMoveEffect: +; Return carry if the enemy has move b. + + push hl + ld hl, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + +.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 + +AIHasMoveInArray: +; 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, wEnemyMonMovesEnd - wEnemyMonMoves + 1 + ld de, wEnemyMonMoves + +.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 + +INCLUDE "data/battle/ai/useful_moves.asm" + +AI_Opportunist: +; 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_392e8 + +; 50% chance to discourage stall moves if enemy's HP is between 25% and 50%. + call AI_50_50 + ret c + +.asm_392e8 + ld hl, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1 +.checkmove + inc hl + dec c + jr z, .asm_3930d + + ld a, [de] + inc de + and a + jr z, .asm_3930d + + 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_3930d + ret + +INCLUDE "data/battle/ai/stall_moves.asm" + + +AI_Aggressive: +; 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, wEnemyMonMoves + ld bc, 0 + ld de, 0 +.checkmove + inc b + ld a, b + cp wEnemyMonMovesEnd - wEnemyMonMoves + 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, [wCurDamage + 1] + cp e + ld a, [wCurDamage] + sbc d + jr c, .checkmove + + ld a, [wCurDamage + 1] + ld e, a + ld a, [wCurDamage] + 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, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld b, 0 +.checkmove2 + inc b + ld a, b + cp wEnemyMonMovesEnd - wEnemyMonMoves + 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 + +INCLUDE "data/battle/ai/reckless_moves.asm" + +AIDamageCalc: + ld a, 1 + ldh [hBattleTurn], a + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld de, 1 + ld hl, ConstantDamageEffects + call IsInArray + jr nc, .asm_393c6 + callfar BattleCommand_ConstantDamage + ret + +.asm_393c6 + callfar EnemyAttackDamage + callfar BattleCommand_DamageCalc + callfar BattleCommand_Stab + ret + +INCLUDE "data/battle/ai/constant_damage_effects.asm" + +AI_Cautious: +; 90% chance to discourage moves with residual effects after the first turn. + + ld a, [wEnemyTurnsTaken] + and a + ret z + + ld hl, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 1 +.asm_393eb + 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_393eb + + call Random + cp 90 percent + 1 + ret nc + + inc [hl] + jr .asm_393eb + +INCLUDE "data/battle/ai/residual_moves.asm" + + +AI_Status: +; Dismiss status moves that don't affect the player. + + ld hl, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld b, wEnemyMonMovesEnd - wEnemyMonMoves + 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, [wBattleMonType1] + cp POISON + jr z, .immune + ld a, [wBattleMonType2] + cp POISON + jr z, .immune + +.typeimmunity + push hl + push bc + push de + ld a, 1 + ldh [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop de + pop bc + pop hl + + ld a, [wTypeMatchup] + and a + jr nz, .checkmove + +.immune + call AIDiscourageMove + jr .checkmove + + +AI_Risky: +; Use any move that will KO the target. +; Risky moves will often be an exception (see below). + + ld hl, wBuffer1 - 1 + ld de, wEnemyMonMoves + ld c, wEnemyMonMovesEnd - wEnemyMonMoves + 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, RiskyEffects + 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, [wCurDamage + 1] + ld e, a + ld a, [wCurDamage] + ld d, a + ld a, [wBattleMonHP + 1] + cp e + ld a, [wBattleMonHP] + sbc d + jr nc, .nextmove + + pop hl +rept 5 + dec [hl] +endr + push hl + +.nextmove + pop hl + pop bc + pop de + jr .checkmove + +INCLUDE "data/battle/ai/risky_effects.asm" + + +AI_None: + ret + +AIDiscourageMove: + ld a, [hl] + add 10 + ld [hl], a + ret + +AIGetEnemyMove: +; 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 + +AI_80_20: + call Random + cp 20 percent - 1 + ret + +AI_50_50: + call Random + cp 50 percent + 1 + ret diff --git a/engine/battle/ai/switch.asm b/engine/battle/ai/switch.asm new file mode 100644 index 00000000..1998e7ec --- /dev/null +++ b/engine/battle/ai/switch.asm @@ -0,0 +1,658 @@ +CheckPlayerMoveTypeMatchups: +; 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, wPlayerUsedMoves + 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, wEnemyMonType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + 1 ; 1.0 + 0.1 + jr nc, .super_effective + and a + jr z, .next + cp EFFECTIVE ; 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, [wBattleMonType1] + ld b, a + ld hl, wEnemyMonType1 + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + 1 ; 1.0 + 0.1 + jr c, .ok + call .DecreaseScore +.ok + ld a, [wBattleMonType2] + cp b + jr z, .ok2 + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + 1 ; 1.0 + 0.1 + jr c, .ok2 + call .DecreaseScore +.ok2 + +.done + call .CheckEnemyMoveMatchups + pop bc + pop de + pop hl + ret + +.CheckEnemyMoveMatchups: + ld de, wEnemyMonMoves + 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, wBattleMonType1 + call CheckTypeMatchup + + ld a, [wTypeMatchup] + ; immune + and a + jr z, .loop2 + + ; not very effective + inc c + cp EFFECTIVE + jr c, .loop2 + + ; neutral + inc c + inc c + inc c + inc c + inc c + cp EFFECTIVE + 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: + ld a, [wEnemyAISwitchScore] + dec a + ld [wEnemyAISwitchScore], a + ret + +.IncreaseScore: + ld a, [wEnemyAISwitchScore] + inc a + ld [wEnemyAISwitchScore], a + ret + +CheckAbleToSwitch: + xor a + ld [wEnemySwitchMonParam], a + call FindAliveEnemyMons + ret c + + ld a, [wEnemySubStatus1] + bit SUBSTATUS_PERISH, a + jr z, .no_perish + + ld a, [wEnemyPerishCount] + 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, [wLastPlayerCounterMove] + 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 + +FindAliveEnemyMons: + ld a, [wOTPartyCount] + cp 2 + jr c, .only_one + + ld d, a + ld e, 0 + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + ld hl, wOTPartyMon1HP + +.loop + ld a, [wCurOTMon] + 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 + +FindEnemyMonsImmuneToLastCounterMove: + ld hl, wOTPartyMon1 + ld a, [wOTPartyCount] + ld b, a + ld c, 1 << (PARTY_LENGTH - 1) + ld d, 0 + xor a + ld [wEnemyAISwitchScore], a + +.loop + ld a, [wCurOTMon] + 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 [wCurSpecies], a + call GetBaseData + + ; the player's last move is damaging... + ld a, [wLastPlayerCounterMove] + 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, wBaseType + 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 + +FindAliveEnemyMonsWithASuperEffectiveMove: + push bc + ld a, [wOTPartyCount] + ld e, a + ld hl, wOTPartyMon1HP + 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, wPartyMon2HP - (wPartyMon1HP + 1) + add hl, bc + pop bc + dec e + jr nz, .loop + + ld a, c + pop bc + + and c + ld c, a + ; fallthrough + +FindEnemyMonsWithASuperEffectiveMove: + ld a, -1 + ld [wEnemyAISwitchScore], a + ld hl, wOTPartyMon1Moves + 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, wBattleMonType1 + 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 EFFECTIVE + 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 + +FindEnemyMonsThatResistPlayer: + push bc + ld hl, wOTPartyCount + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + +.loop + ld a, [hli] + cp $ff + jr z, .done + + push hl + ld [wCurSpecies], a + call GetBaseData + ld a, [wLastPlayerCounterMove] + 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, [wBattleMonType1] + ld hl, wBaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 + jr nc, .dont_choose_mon + ld a, [wBattleMonType2] + +.check_type + ld hl, wBaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + 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 + +FindEnemyMonsWithAtLeastQuarterMaxHP: + push bc + ld de, wOTPartyCount + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + ld hl, wOTPartyMon1HP + +.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 diff --git a/engine/anim_hp_bar.asm b/engine/battle/anim_hp_bar.asm index 561cba42..9248ad4f 100755 --- a/engine/anim_hp_bar.asm +++ b/engine/battle/anim_hp_bar.asm @@ -1,61 +1,59 @@ -HP_BAR_MAX_PIXELS EQU $30 - -AnimateHPBar_: ; d62d (3:562d) - call Functiond665 - jr c, .asm_d64b - call Functiond676 -.asm_d635 +_AnimateHPBar: + call .IsMaximumMoreThan48Pixels + jr c, .MoreThan48Pixels + call .ComputePixels +.ShortAnimLoop: push bc push hl - call Functiond6e8 + call ShortAnim_UpdateVariables pop hl pop bc push af push bc push hl - call Functiond736 - call Functiond7cf + call ShortHPBarAnim_UpdateTiles + call HPBarAnim_BGMapUpdate pop hl pop bc pop af - jr nc, .asm_d635 + jr nc, .ShortAnimLoop ret -.asm_d64b - call Functiond676 -.asm_d64e +.MoreThan48Pixels: + call .ComputePixels +.LongAnimLoop: push bc push hl - call Functiond6fb + call LongAnim_UpdateVariables pop hl pop bc ret c push af push bc push hl - call Functiond74f - call Functiond7cf + call LongHPBarAnim_UpdateTiles + call HPBarAnim_BGMapUpdate pop hl pop bc pop af - jr nc, .asm_d64e + jr nc, .LongAnimLoop ret -Functiond665: ; d665 (3:5665) +.IsMaximumMoreThan48Pixels: ld a, [wCurHPAnimMaxHP + 1] and a - jr nz, .asm_d674 + jr nz, .player ld a, [wCurHPAnimMaxHP] - cp HP_BAR_MAX_PIXELS - jr nc, .asm_d674 + cp HP_BAR_LENGTH_PX + jr nc, .player and a ret -.asm_d674 +.player scf ret -Functiond676: ; d676 (3:5676) +.ComputePixels: push hl ld hl, wCurHPAnimMaxHP ld a, [hli] @@ -70,6 +68,7 @@ Functiond676: ; d676 (3:5676) call ComputeHPBarPixels ld a, e ld [wCurHPBarPixels], a + ld a, [wCurHPAnimNewHP] ld c, a ld a, [wCurHPAnimNewHP + 1] @@ -81,6 +80,7 @@ Functiond676: ; d676 (3:5676) call ComputeHPBarPixels ld a, e ld [wNewHPBarPixels], a + push hl ld hl, wCurHPAnimOldHP ld a, [hli] @@ -98,15 +98,15 @@ Functiond676: ; d676 (3:5676) ld a, d sbc b ld d, a - jr c, .asm_d6c7 + jr c, .negative ld a, [wCurHPAnimOldHP] ld [wCurHPAnimLowHP], a ld a, [wCurHPAnimNewHP] ld [wCurHPAnimHighHP], a - ld bc, $1 - jr .asm_d6df + ld bc, 1 + jr .got_direction -.asm_d6c7 +.negative ld a, [wCurHPAnimOldHP] ld [wCurHPAnimHighHP], a ld a, [wCurHPAnimNewHP] @@ -118,31 +118,32 @@ Functiond676: ; d676 (3:5676) ld a, d xor $ff ld d, a - ld bc, rIE -.asm_d6df + ld bc, -1 +.got_direction ld a, d ld [wCurHPAnimDeltaHP], a ld a, e ld [wCurHPAnimDeltaHP + 1], a ret -Functiond6e8: ; d6e8 (3:56e8) +ShortAnim_UpdateVariables: ld hl, wCurHPBarPixels ld a, [wNewHPBarPixels] cp [hl] - jr nz, .asm_d6f3 + jr nz, .not_finished scf ret -.asm_d6f3 +.not_finished ld a, c add [hl] ld [hl], a - call Functiond83f + call ShortHPBar_CalcPixelFrame and a ret -Functiond6fb: ; d6fb (3:56fb) +LongAnim_UpdateVariables: +.loop ld hl, wCurHPAnimOldHP ld a, [hli] ld e, a @@ -150,15 +151,15 @@ Functiond6fb: ; d6fb (3:56fb) ld d, a ld a, e cp [hl] - jr nz, .asm_d70d + jr nz, .next inc hl ld a, d cp [hl] - jr nz, .asm_d70d + jr nz, .next scf ret -.asm_d70d +.next ld l, e ld h, d add hl, bc @@ -178,27 +179,26 @@ Functiond6fb: ; d6fb (3:56fb) ld c, a ld a, [hli] ld b, a - ; BUG: This routine is meant to make the HP bar move at - ; the same rate regardless of how many HP the Pokemon has. - ; In actuality, this causes Pokemon with more than 48 HP - ; to gain or lose HP at the rate of 1 HP per BGMap update - ; rather than 1 pixel on the HUD. - ; To fix, move the "ld a, e" above the "pop de". - call ComputeHPBarPixels ; returns to e + ; This routine is buggy. The result from ComputeHPBarPixels is stored + ; in e. However, the pop de opcode deletes this result before it is even + ; used. The game then proceeds as though it never deleted that output. + ; To fix, uncomment the line below. + call ComputeHPBarPixels + ; ld a, e pop bc - pop de ; overloads e + pop de pop hl - ld a, e ; expects result from ComputeHPBarPixels + ld a, e ; Comment or delete this line to fix the above bug. ld hl, wCurHPBarPixels cp [hl] - jr z, Functiond6fb + jr z, .loop ld [hl], a and a ret -Functiond736: ; d736 (3:5736) - call Functiond78a - ld d, $6 +ShortHPBarAnim_UpdateTiles: + call HPBarAnim_UpdateHPRemaining + ld d, HP_BAR_LENGTH ld a, [wWhichHPBar] and $1 ld b, a @@ -206,13 +206,13 @@ Functiond736: ; d736 (3:5736) ld e, a ld c, a push de - call Functiond777 + call HPBarAnim_RedrawHPBar pop de - call Functiond7ba + call HPBarAnim_PaletteUpdate ret -Functiond74f: ; d74f (3:574f) - call Functiond78a +LongHPBarAnim_UpdateTiles: + call HPBarAnim_UpdateHPRemaining ld a, [wCurHPAnimOldHP] ld c, a ld a, [wCurHPAnimOldHP + 1] @@ -223,45 +223,45 @@ Functiond74f: ; d74f (3:574f) ld d, a call ComputeHPBarPixels ld c, e - ld d, $6 + ld d, HP_BAR_LENGTH ld a, [wWhichHPBar] and $1 ld b, a push de - call Functiond777 + call HPBarAnim_RedrawHPBar pop de - call Functiond7ba + call HPBarAnim_PaletteUpdate ret -Functiond777: ; d777 (3:5777) +HPBarAnim_RedrawHPBar: ld a, [wWhichHPBar] cp $2 - jr nz, .asm_d786 - ld a, $28 + jr nz, .skip + ld a, 2 * SCREEN_WIDTH add l ld l, a - ld a, $0 + ld a, 0 adc h ld h, a -.asm_d786 +.skip call DrawBattleHPBar ret -Functiond78a: ; d78a (3:578a) +HPBarAnim_UpdateHPRemaining: ld a, [wWhichHPBar] and a ret z cp $1 - jr z, .asm_d798 - ld de, $16 - jr .asm_d79b + jr z, .load_15 + ld de, SCREEN_WIDTH + 2 + jr .loaded_de -.asm_d798 - ld de, $15 -.asm_d79b +.load_15 + ld de, SCREEN_WIDTH + 1 +.loaded_de push hl add hl, de - ld a, $7f + ld a, " " ld [hli], a ld [hli], a ld [hld], a @@ -276,7 +276,7 @@ Functiond78a: ; d78a (3:578a) pop hl ret -Functiond7ba: ; d7ba (3:57ba) +HPBarAnim_PaletteUpdate: ldh a, [hCGB] and a ret z @@ -284,45 +284,43 @@ Functiond7ba: ; d7ba (3:57ba) call SetHPPal ld a, [wCurHPAnimPal] ld c, a - ld a, $2 - ld hl, $520b - rst FarCall + farcall ApplyHPBarPals ret -Functiond7cf: ; d7cf (3:57cf) +HPBarAnim_BGMapUpdate: ldh a, [hCGB] and a - jr nz, .asm_d7db + jr nz, .cgb call DelayFrame call DelayFrame ret -.asm_d7db +.cgb ld a, [wWhichHPBar] and a - jr z, .asm_d82f + jr z, .load_0 cp $1 - jr z, .asm_d833 + jr z, .load_1 ld a, [wCurPartyMon] cp $3 - jr nc, .asm_d7f0 + jr nc, .bottom_half_of_screen ld c, $0 - jr .asm_d7f2 + jr .got_third -.asm_d7f0 +.bottom_half_of_screen ld c, $1 -.asm_d7f2 +.got_third push af cp $2 - jr z, .asm_d805 + jr z, .skip_delay cp $5 - jr z, .asm_d805 + jr z, .skip_delay ld a, $2 ldh [hBGMapMode], a ld a, c ldh [hBGMapThird], a call DelayFrame -.asm_d805 +.skip_delay ld a, $1 ldh [hBGMapMode], a ld a, c @@ -330,12 +328,12 @@ Functiond7cf: ; d7cf (3:57cf) call DelayFrame pop af cp $2 - jr z, .asm_d819 + jr z, .two_frames cp $5 - jr z, .asm_d819 + jr z, .two_frames ret -.asm_d819 +.two_frames inc c ld a, $2 ldh [hBGMapMode], a @@ -349,73 +347,78 @@ Functiond7cf: ; d7cf (3:57cf) call DelayFrame ret -.asm_d82f +.load_0 ld c, $0 - jr .asm_d835 + jr .finish -.asm_d833 +.load_1 ld c, $1 -.asm_d835 +.finish call DelayFrame ld a, c ldh [hBGMapThird], a call DelayFrame ret -Functiond83f: ; d83f (3:583f) +ShortHPBar_CalcPixelFrame: ld a, [wCurHPAnimMaxHP] ld c, a - ld b, $0 - ld hl, $0 + ld b, 0 + ld hl, 0 ld a, [wCurHPBarPixels] - cp HP_BAR_MAX_PIXELS - jr nc, .asm_d88b + cp HP_BAR_LENGTH_PX + jr nc, .return_max and a - jr z, .asm_d886 + jr z, .return_zero call AddNTimes - ld b, $0 -.asm_d857 + + ld b, 0 +; This routine is buggy. If [wCurHPAnimMaxHP] * [wCurHPBarPixels] is +; divisible by HP_BAR_LENGTH_PX, the loop runs one extra time. +; To fix, uncomment the line below. +.loop ld a, l - sub HP_BAR_MAX_PIXELS % $100 + sub HP_BAR_LENGTH_PX ld l, a ld a, h - sbc HP_BAR_MAX_PIXELS / $100 + sbc $0 ld h, a - jr c, .asm_d864 + ; jr z, .done + jr c, .done inc b - jr .asm_d857 + jr .loop -.asm_d864 +.done push bc ld bc, $80 add hl, bc pop bc ld a, l - sub HP_BAR_MAX_PIXELS % $100 + sub HP_BAR_LENGTH_PX ld l, a ld a, h - sbc HP_BAR_MAX_PIXELS / $100 + sbc $0 ld h, a - jr c, .asm_d875 + jr c, .no_carry inc b -.asm_d875 +.no_carry ld a, [wCurHPAnimLowHP] cp b - jr nc, .asm_d882 + jr nc, .finish ld a, [wCurHPAnimHighHP] cp b - jr c, .asm_d882 + jr c, .finish ld a, b -.asm_d882 +.finish ld [wCurHPAnimOldHP], a ret -.asm_d886 +.return_zero xor a ld [wCurHPAnimOldHP], a ret -.asm_d88b +.return_max ld a, [wCurHPAnimMaxHP] ld [wCurHPAnimOldHP], a ret diff --git a/engine/battle/consume_held_item.asm b/engine/battle/consume_held_item.asm new file mode 100644 index 00000000..c5e3b204 --- /dev/null +++ b/engine/battle/consume_held_item.asm @@ -0,0 +1,57 @@ +ConsumeHeldItem: + push hl + push de + push bc + ldh a, [hBattleTurn] + and a + ld hl, wOTPartyMon1Item + ld de, wEnemyMonItem + ld a, [wCurOTMon] + jr z, .theirturn + ld hl, wPartyMon1Item + ld de, wBattleMonItem + ld a, [wCurBattleMon] + +.theirturn + push hl + push af + ld a, [de] + ld b, a + farcall GetItemHeldEffect + ld hl, ConsumableEffects +.loop + ld a, [hli] + cp b + jr z, .ok + inc a + jr nz, .loop + pop af + pop hl + pop bc + pop de + pop hl + ret + +.ok + xor a + ld [de], a + pop af + pop hl + call GetPartyLocation + ldh a, [hBattleTurn] + and a + jr nz, .ourturn + ld a, [wBattleMode] + dec a + jr z, .done + +.ourturn + ld [hl], NO_ITEM + +.done + pop bc + pop de + pop hl + ret + +INCLUDE "data/battle/held_consumables.asm" diff --git a/engine/battle/core.asm b/engine/battle/core.asm new file mode 100644 index 00000000..512c2598 --- /dev/null +++ b/engine/battle/core.asm @@ -0,0 +1,8732 @@ +; Core components of the battle engine. + +DoBattle: + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wBattlePlayerAction], a + ld [wBattleEnded], a + inc a + ld [wBattleHasJustStarted], a + ld hl, wOTPartyMon1HP + ld bc, PARTYMON_STRUCT_LENGTH - 1 + ld d, BATTLEACTION_SWITCH1 - 1 +.loop + inc d + ld a, [hli] + or [hl] + jr nz, .alive + add hl, bc + jr .loop + +.alive + ld a, d + ld [wBattleAction], a + ld a, [wLinkMode] + and a + jr z, .not_linked + + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .player_2 + +.not_linked + ld a, [wBattleMode] + dec a + jr z, .wild + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + +.wild + ld c, 40 + call DelayFrames + +.player_2 + call LoadTilemapToTempTilemap + call CheckPlayerPartyForFitMon + ld a, d + and a + jp z, LostBattle + call SafeLoadTempTilemapToTilemap + ld a, [wBattleType] + cp BATTLETYPE_DEBUG + jp z, .tutorial_debug + cp BATTLETYPE_TUTORIAL + jp z, .tutorial_debug + xor a + ld [wCurPartyMon], a +.loop2 + call CheckIfCurPartyMonIsFitToFight + jr nz, .alive2 + ld hl, wCurPartyMon + inc [hl] + jr .loop2 + +.alive2 + ld a, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + inc a + ld hl, wPartySpecies - 1 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wCurPartySpecies], a + ld [wTempBattleMonSpecies], a + hlcoord 1, 5 + ld a, 9 + call SlideBattlePicOut + call LoadTilemapToTempTilemap + call ResetBattleParticipants + call InitBattleMon + call ResetPlayerStatLevels + call SendOutMonText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + call SpikesDamage + ld a, [wLinkMode] + and a + jr z, .not_linked_2 + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + 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 + +WildFled_EnemyFled_LinkBattleCanceled: + call SafeLoadTempTilemapToTilemap + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + add DRAW + ld [wBattleResult], a + ld a, [wLinkMode] + and a + ld hl, BattleText_WildFled + jr z, .print_text + + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + ld [wBattleResult], a ; WIN + ld hl, BattleText_EnemyFled + +.print_text + call StdBattleTextbox + call StopDangerSound + ld de, SFX_RUN + call PlaySFX + call SetPlayerTurn + callfar DummyPredef38 + ld a, 1 + ld [wBattleEnded], a + ret + +BattleTurn: +.loop + call CheckContestBattleOver + jr c, .quit + + xor a + ld [wPlayerIsSwitching], a + ld [wEnemyIsSwitching], a + ld [wBattleHasJustStarted], a + ld [wPlayerJustGotFrozen], a + ld [wEnemyJustGotFrozen], a + ld [wCurDamage], a + ld [wCurDamage + 1], a + + call HandleBerserkGene + call UpdateBattleMonInParty + farcall AIChooseMove + call CheckPlayerLockedIn + jr c, .skip_iteration +.loop1 + call BattleMenu + jr c, .quit + ld a, [wBattleEnded] + 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 + ld a, [wForcedSwitch] + and a + jr nz, .quit + + ld a, [wBattleEnded] + and a + jr nz, .quit + + call HandleBetweenTurnEffects + ld a, [wBattleEnded] + and a + jr nz, .quit + jr .loop + +.quit + ret + +HandleBetweenTurnEffects: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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 HandleDefrost + call HandleSafeguard + call HandleScreens + call HandleStatBoostingHeldItems + call HandleHealingItems + call UpdateBattleMonInParty + call LoadTilemapToTempTilemap + jp HandleEncore + +CheckFaint_PlayerThenEnemy: + call HasPlayerFainted + jr nz, .PlayerNotFainted + call HandlePlayerMonFaint + ld a, [wBattleEnded] + and a + jr nz, .BattleIsOver + +.PlayerNotFainted: + call HasEnemyFainted + jr nz, .BattleContinues + call HandleEnemyMonFaint + ld a, [wBattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret + +CheckFaint_EnemyThenPlayer: + call HasEnemyFainted + jr nz, .EnemyNotFainted + call HandleEnemyMonFaint + ld a, [wBattleEnded] + and a + jr nz, .BattleIsOver + +.EnemyNotFainted: + call HasPlayerFainted + jr nz, .BattleContinues + call HandlePlayerMonFaint + ld a, [wBattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret + +HandleBerserkGene: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .reverse + + call .player + jr .enemy + +.reverse + call .enemy + ; fallthrough + +.player + call SetPlayerTurn + ld de, wPartyMon1Item + ld a, [wCurBattleMon] + ld b, a + jr .go + +.enemy + call SetEnemyTurn + ld de, wOTPartyMon1Item + ld a, [wCurOTMon] + ld b, a + ; fallthrough + +.go + push de + push bc + callfar GetUserItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], 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 [wAttackMissed], a + ld [wEffectFailed], 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 + +EnemyTriesToFlee: + 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 + +DetermineMoveOrder: + ld a, [wLinkMode] + and a + jr z, .use_move + ld a, [wBattleAction] + cp BATTLEACTION_STRUGGLE + jr z, .use_move + cp BATTLEACTION_SKIPTURN + jr z, .use_move + sub BATTLEACTION_SWITCH1 + jr c, .use_move + ld a, [wBattlePlayerAction] + cp BATTLEPLAYERACTION_SWITCH + jr nz, .switch + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .player_2 + + call BattleRandom + cp 50 percent + 1 + jp c, .player_first + jp .enemy_first + +.player_2 + call BattleRandom + cp 50 percent + 1 + jp c, .enemy_first + jp .player_first + +.switch + callfar AI_Switch + call SetEnemyTurn + call SpikesDamage + jp .enemy_first + +.use_move + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + 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 + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + 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, wBattleMonSpeed + ld hl, wEnemyMonSpeed + ld c, 2 + call CompareBytes + jr z, .speed_tie + jp nc, .player_first + jp .enemy_first + +.speed_tie + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .player_2c + call BattleRandom + cp 50 percent + 1 + jp c, .player_first + jp .enemy_first + +.player_2c + call BattleRandom + cp 50 percent + 1 + jp c, .enemy_first +.player_first + scf + ret + +.enemy_first + and a + ret + +CheckContestBattleOver: + ld a, [wBattleType] + cp BATTLETYPE_CONTEST + jr nz, .contest_not_over + ld a, [wParkBallsRemaining] + and a + jr nz, .contest_not_over + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + add DRAW + ld [wBattleResult], a + scf + ret + +.contest_not_over + and a + ret + +CheckPlayerLockedIn: + ld a, [wPlayerSubStatus4] + and 1 << SUBSTATUS_RECHARGE + jp nz, .quit + + ld hl, wEnemySubStatus3 + res SUBSTATUS_FLINCHED, [hl] + ld hl, wPlayerSubStatus3 + res SUBSTATUS_FLINCHED, [hl] + + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE + jp nz, .quit + + ld hl, wPlayerSubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + jp nz, .quit + + and a + ret + +.quit + scf + ret + +ParsePlayerAction: + call CheckPlayerLockedIn + jp c, .locked_in + ld hl, wPlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .not_encored + ld a, [wLastPlayerMove] + ld [wCurPlayerMove], a + jr .encored + +.not_encored + ld a, [wBattlePlayerAction] + cp BATTLEPLAYERACTION_SWITCH + jr z, .reset_rage + and a + jr nz, .reset_bide + ld a, [wPlayerSubStatus3] + and 1 << SUBSTATUS_BIDE + jr nz, .locked_in + xor a + ld [wMoveSelectionMenuType], a + inc a ; POUND + ld [wFXAnimID], a + call MoveSelectionScreen + push af + call SafeLoadTempTilemapToTilemap + call UpdateBattleHuds + ld a, [wCurPlayerMove] + cp STRUGGLE + jr z, .struggle + call PlayClickSFX + +.struggle + ld a, $1 + ldh [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 [wPlayerFuryCutterCount], a + +.continue_fury_cutter + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .continue_rage + ld hl, wPlayerSubStatus4 + 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 [wPlayerProtectCount], a + jr .continue_protect + +.reset_bide + ld hl, wPlayerSubStatus3 + res SUBSTATUS_BIDE, [hl] + +.locked_in + xor a + ld [wPlayerFuryCutterCount], a + ld [wPlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, wPlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + +.continue_protect + call ParseEnemyAction + xor a + ret + +.reset_rage + xor a + ld [wPlayerFuryCutterCount], a + ld [wPlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, wPlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ret + +HandleEncore: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .player_1 + call .do_player + jr .do_enemy + +.player_1 + call .do_enemy +.do_player + ld hl, wPlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [wPlayerEncoreCount] + dec a + ld [wPlayerEncoreCount], a + jr z, .end_player_encore + ld hl, wBattleMonPP + ld a, [wCurMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and PP_MASK + ret nz + +.end_player_encore + ld hl, wPlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetEnemyTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextbox + +.do_enemy + ld hl, wEnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [wEnemyEncoreCount] + dec a + ld [wEnemyEncoreCount], a + jr z, .end_enemy_encore + ld hl, wEnemyMonPP + ld a, [wCurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and PP_MASK + ret nz + +.end_enemy_encore + ld hl, wEnemySubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetPlayerTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextbox + +TryEnemyFlee: + ld a, [wBattleMode] + dec a + jr nz, .Stay + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, .Stay + + ld a, [wEnemyWrapCount] + and a + jr nz, .Stay + + ld a, [wEnemyMonStatus] + and 1 << FRZ | SLP + jr nz, .Stay + + ld a, [wTempEnemyMonSpecies] + ld de, 1 + ld hl, AlwaysFleeMons + call IsInArray + jr c, .Flee + + call BattleRandom + ld b, a + cp 50 percent + 1 + jr nc, .Stay + + push bc + ld a, [wTempEnemyMonSpecies] + ld de, 1 + ld hl, OftenFleeMons + call IsInArray + pop bc + jr c, .Flee + + ld a, b + cp 10 percent + 1 + jr nc, .Stay + + ld a, [wTempEnemyMonSpecies] + ld de, 1 + ld hl, SometimesFleeMons + call IsInArray + jr c, .Flee + +.Stay: + and a + ret + +.Flee: + scf + ret + +INCLUDE "data/wild/flee_mons.asm" + +CompareMovePriority: +; Compare the priority of the player and enemy's moves. +; Return carry if the player goes first, or z if they match. + + ld a, [wCurPlayerMove] + call GetMovePriority + ld b, a + push bc + ld a, [wCurEnemyMove] + call GetMovePriority + pop bc + cp b + ret + +GetMovePriority: +; 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, BASE_PRIORITY + ret + +.done + ld a, [hl] + ret + +INCLUDE "data/moves/effects_priorities.asm" + +GetMoveEffect: + 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 + +Battle_EnemyFirst: + 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 + 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 + 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 ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ret + +Battle_PlayerFirst: + 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 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 + 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 ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ret + +PlayerTurn_EndOpponentProtectEndureDestinyBond: + call SetPlayerTurn + call EndUserDestinyBond + callfar DoPlayerTurn + jp EndOpponentProtectEndureDestinyBond + +EnemyTurn_EndOpponentProtectEndureDestinyBond: + call SetEnemyTurn + call EndUserDestinyBond + callfar DoEnemyTurn + jp EndOpponentProtectEndureDestinyBond + +EndOpponentProtectEndureDestinyBond: + 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 + +EndUserDestinyBond: + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret + +HasUserFainted: + ldh a, [hBattleTurn] + and a + jr z, HasPlayerFainted +HasEnemyFainted: + ld hl, wEnemyMonHP + jr CheckIfHPIsZero + +HasPlayerFainted: + ld hl, wBattleMonHP + +CheckIfHPIsZero: + ld a, [hli] + or [hl] + ret + +ResidualDamage: +; 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, wPlayerToxicCount + ldh a, [hBattleTurn] + and a + jr z, .check_toxic + ld de, wEnemyToxicCount +.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 + ldh [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, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .check_fainted + ld hl, wEnemyMonHP + +.check_fainted + ld a, [hli] + or [hl] + ret nz + +.fainted + call RefreshBattleHuds + ld c, 20 + call DelayFrames + xor a + ret + +HandlePerishSong: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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, wPlayerPerishCount + ldh a, [hBattleTurn] + and a + jr z, .got_count + ld hl, wEnemyPerishCount + +.got_count + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_PERISH, a + ret z + dec [hl] + ld a, [hl] + ld [wDeciramBuffer], a + push af + ld hl, PerishCountText + call StdBattleTextbox + pop af + ret nz + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_PERISH, [hl] + ldh a, [hBattleTurn] + and a + jr nz, .kill_enemy + ld hl, wBattleMonHP + xor a + ld [hli], a + ld [hl], a + ld hl, wPartyMon1HP + ld a, [wCurBattleMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret + +.kill_enemy + ld hl, wEnemyMonHP + xor a + ld [hli], a + ld [hl], a + ld a, [wBattleMode] + dec a + ret z + ld hl, wOTPartyMon1HP + ld a, [wCurOTMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret + +HandleWrap: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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 + ldh 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 [wNamedObjectIndexBuffer], a + ld [wFXAnimID], 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 [wFXAnimID + 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 + +SwitchTurnCore: + ldh a, [hBattleTurn] + xor 1 + ldh [hBattleTurn], a + ret + +HandleLeftovers: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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 [wNamedObjectIndexBuffer], a + call GetItemName + ld a, b + cp HELD_LEFTOVERS + ret nz + + ld hl, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wEnemyMonHP + +.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 + +HandleMysteryberry: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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, wPartyMon1PP + ld a, [wCurBattleMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, wPartyMon1Moves + ld a, [wCurBattleMon] + call GetPartyLocation + ldh a, [hBattleTurn] + and a + jr z, .wild + ld de, wWildMonPP + ld hl, wWildMonMoves + ld a, [wBattleMode] + dec a + jr z, .wild + ld hl, wOTPartyMon1PP + ld a, [wCurOTMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, wOTPartyMon1Moves + ld a, [wCurOTMon] + call GetPartyLocation + +.wild + ld c, $0 +.loop + ld a, [hl] + and a + jr z, .quit + ld a, [de] + and PP_MASK + 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 [wTempByteValue], a + ld de, wBattleMonMoves - 1 + ld hl, wBattleMonPP + ldh a, [hBattleTurn] + and a + jr z, .player_pp + ld de, wEnemyMonMoves - 1 + ld hl, wEnemyMonPP +.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, [wTempByteValue] + cp [hl] + jr nz, .skip_checks + ldh a, [hBattleTurn] + and a + ld a, [wPlayerSubStatus5] + jr z, .check_transform + ld a, [wEnemySubStatus5] +.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 [wNamedObjectIndexBuffer], a + xor a + ld [hl], a + call GetPartymonItem + ldh 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 + +HandleFutureSight: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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 + ldh 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 [wAttackMissed], a + ld [wAlreadyDisobeyed], a + ld a, EFFECTIVE + ld [wTypeModifier], a + callfar DoMove + xor a + ld [wCurDamage], a + ld [wCurDamage + 1], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + pop af + ld [hl], a + + call UpdateBattleMonInParty + jp UpdateEnemyMonInParty + +HandleDefrost: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .enemy_first + call .do_player_turn + jr .do_enemy_turn + +.enemy_first + call .do_enemy_turn +.do_player_turn + ld a, [wBattleMonStatus] + bit FRZ, a + ret z + + ld a, [wPlayerJustGotFrozen] + and a + ret nz + + call BattleRandom + cp 10 percent + ret nc + xor a + ld [wBattleMonStatus], a + ld a, [wCurBattleMon] + ld hl, wPartyMon1Status + call GetPartyLocation + ld [hl], 0 + call UpdateBattleHuds + call SetEnemyTurn + ld hl, DefrostedOpponentText + jp StdBattleTextbox + +.do_enemy_turn + ld a, [wEnemyMonStatus] + bit FRZ, a + ret z + ld a, [wEnemyJustGotFrozen] + and a + ret nz + call BattleRandom + cp 10 percent + ret nc + xor a + ld [wEnemyMonStatus], a + + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + call GetPartyLocation + ld [hl], 0 +.wild + + call UpdateBattleHuds + call SetPlayerTurn + ld hl, DefrostedOpponentText + jp StdBattleTextbox + +HandleSafeguard: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .player1 + call .CheckPlayer + jr .CheckEnemy + +.player1 + call .CheckEnemy +.CheckPlayer: + ld a, [wPlayerScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, wPlayerSafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [wPlayerScreens], a + xor a + jr .print + +.CheckEnemy: + ld a, [wEnemyScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, wEnemySafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [wEnemyScreens], a + ld a, $1 + +.print + ldh [hBattleTurn], a + ld hl, BattleText_SafeguardFaded + jp StdBattleTextbox + +HandleScreens: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .Both + call .CheckPlayer + jr .CheckEnemy + +.Both: + call .CheckEnemy + +.CheckPlayer: + call SetPlayerTurn + ld de, .Your + call .Copy + ld hl, wPlayerScreens + ld de, wPlayerLightScreenCount + jr .TickScreens + +.CheckEnemy: + call SetEnemyTurn + ld de, .Enemy + call .Copy + ld hl, wEnemyScreens + ld de, wEnemyLightScreenCount + +.TickScreens: + bit SCREENS_LIGHT_SCREEN, [hl] + call nz, .LightScreenTick + bit SCREENS_REFLECT, [hl] + call nz, .ReflectTick + ret + +.Copy: + ld hl, wStringBuffer1 + jp CopyName2 + +.Your: + db "Your@" +.Enemy: + db "Enemy@" + +.LightScreenTick: + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_LIGHT_SCREEN, [hl] + push hl + push de + ld hl, BattleText_MonsLightScreenFell + call StdBattleTextbox + pop de + pop hl + ret + +.ReflectTick: + inc de + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_REFLECT, [hl] + ld hl, BattleText_MonsReflectFaded + jp StdBattleTextbox + +HandleWeather: + ld a, [wBattleWeather] + cp WEATHER_NONE + ret z + + ld hl, wWeatherCount + dec [hl] + jr z, .ended + + ld hl, .WeatherMessages + call .PrintWeatherMessage + + ld a, [wBattleWeather] + cp WEATHER_SANDSTORM + ret nz + + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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, wBattleMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonType1 +.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 [wBattleWeather], a + ret + +.PrintWeatherMessage: + ld a, [wBattleWeather] + 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 + +.WeatherMessages: +; entries correspond to WEATHER_* constants + dw BattleText_RainContinuesToFall + dw BattleText_TheSunlightIsStrong + dw BattleText_TheSandstormRages + +.WeatherEndedMessages: +; entries correspond to WEATHER_* constants + dw BattleText_TheRainStopped + dw BattleText_TheSunlightFaded + dw BattleText_TheSandstormSubsided + +SubtractHPFromTarget: + call SubtractHP + jp UpdateHPBar + +SubtractHPFromUser: +; Subtract HP from mon + call SubtractHP + jp UpdateHPBarBattleHuds + +SubtractHP: + ld hl, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonHP +.ok + inc hl + ld a, [hl] + ld [wBuffer3], a + sub c + ld [hld], a + ld [wBuffer5], a + ld a, [hl] + ld [wBuffer4], a + sbc b + ld [hl], a + ld [wBuffer6], a + ret nc + + ld a, [wBuffer3] + ld c, a + ld a, [wBuffer4] + ld b, a + xor a + ld [hli], a + ld [hl], a + ld [wBuffer5], a + ld [wBuffer6], a + ret + +GetSixteenthMaxHP: + call GetQuarterMaxHP +; quarter result + srl c + srl c +; at least 1 + ld a, c + and a + jr nz, .ok + inc c +.ok + ret + +GetEighthMaxHP: +; output: bc + call GetQuarterMaxHP +; assumes nothing can have 1024 or more hp +; halve result + srl c +; at least 1 + ld a, c + and a + jr nz, .end + inc c +.end + ret + +GetQuarterMaxHP: +; output: bc + call GetMaxHP + +; quarter result + srl b + rr c + srl b + rr c + +; assumes nothing can have 1024 or more hp +; at least 1 + ld a, c + and a + jr nz, .end + inc c +.end + ret + +GetHalfMaxHP: +; output: bc + call GetMaxHP + +; halve result + srl b + rr c + +; at least 1 + ld a, c + or b + jr nz, .end + inc c +.end + ret + +GetMaxHP: +; output: bc, wBuffer1-2 + + ld hl, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonMaxHP +.ok + ld a, [hli] + ld [wBuffer2], a + ld b, a + + ld a, [hl] + ld [wBuffer1], a + ld c, a + ret + +Unreferenced_GetHalfHP: + ld hl, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonHP +.ok + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + srl b + rr c + ld a, [hli] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + ret + +CheckUserHasEnoughHP: + ld hl, wBattleMonHP + 1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonHP + 1 +.ok + ld a, c + sub [hl] + dec hl + ld a, b + sbc [hl] + ret + +RestoreHP: + ld hl, wEnemyMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wBattleMonMaxHP +.ok + ld a, [hli] + ld [wBuffer2], a + ld a, [hld] + ld [wBuffer1], a + dec hl + ld a, [hl] + ld [wBuffer3], a + add c + ld [hld], a + ld [wBuffer5], a + ld a, [hl] + ld [wBuffer4], a + adc b + ld [hli], a + ld [wBuffer6], a + + ld a, [wBuffer1] + ld c, a + ld a, [hld] + sub c + ld a, [wBuffer2] + ld b, a + ld a, [hl] + sbc b + jr c, .asm_3ccd5 + ld a, b + ld [hli], a + ld [wBuffer6], a + ld a, c + ld [hl], a + ld [wBuffer5], a +.asm_3ccd5 + + call SwitchTurnCore + call UpdateHPBarBattleHuds + jp SwitchTurnCore + +UpdateHPBarBattleHuds: + call UpdateHPBar + jp UpdateBattleHuds + +UpdateHPBar: + hlcoord 10, 9 + ldh a, [hBattleTurn] + and a + ld a, 1 + jr z, .ok + hlcoord 2, 2 + xor a +.ok + push bc + ld [wWhichHPBar], a + predef AnimateHPBar + pop bc + ret + +HandleEnemyMonFaint: + call FaintEnemyPokemon + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + call z, FaintYourPokemon + xor a + ld [wWhichMonFaintedFirst], a + call UpdateBattleStateAndExperienceAfterEnemyFaint + call CheckPlayerPartyForFitMon + ld a, d + and a + jp z, LostBattle + + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + call nz, UpdatePlayerHUD + + ld a, $1 + ldh [hBGMapMode], a + ld c, 60 + call DelayFrames + + ld a, [wBattleMode] + dec a + jr nz, .trainer + + ld a, 1 + ld [wBattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_not_fainted + + call AskUseNextPokemon + jr nc, .dont_flee + + ld a, 1 + ld [wBattleEnded], a + ret + +.dont_flee + call ForcePlayerMonChoice + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jr DoubleSwitch + +.player_mon_not_fainted + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + xor a ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ret + +DoubleSwitch: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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, [wCurPartyMon] + push af + ld a, $1 + call EnemyPartyMonEntrance + call ClearSprites + call LoadTilemapToTempTilemap + pop af + ld [wCurPartyMon], a + call PlayerPartyMonEntrance + +.done + xor a ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ret + +UpdateBattleStateAndExperienceAfterEnemyFaint: + call UpdateBattleMonInParty + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [wCurOTMon] + ld hl, wOTPartyMon1HP + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + +.wild + ld hl, wPlayerSubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld hl, wEnemyDamageTaken + 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 [wBattleLowHealthAlarm], a + +.trainer + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_did_not_faint + ld a, [wWhichMonFaintedFirst] + and a + jr nz, .player_mon_did_not_faint + call UpdateFaintedPlayerMon + +.player_mon_did_not_faint + call CheckPlayerPartyForFitMon + ld a, d + and a + ret z + ld a, [wBattleMode] + dec a + call z, PlayVictoryMusic + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + ld [wBattleResult], a ; WIN + call IsAnyMonHoldingExpShare + jr z, .skip_exp + ld hl, wEnemyMonBaseStats + ld b, wEnemyMonEnd - wEnemyMonBaseStats +.loop + srl [hl] + inc hl + dec b + jr nz, .loop + +.skip_exp + ld hl, wEnemyMonBaseStats + ld de, wBackupEnemyMonBaseStats + ld bc, wEnemyMonEnd - wEnemyMonBaseStats + 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, wEnemyMonBaseStats + ld bc, wEnemyMonEnd - wEnemyMonBaseStats + call CopyBytes + ld a, $1 + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + pop af + ld [wBattleParticipantsNotFainted], a + ret + +IsAnyMonHoldingExpShare: + ld a, [wPartyCount] + ld b, a + ld hl, wPartyMon1 + 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 + +StopDangerSound: + xor a + ld [wLowHealthAlarm], a + ret + +FaintYourPokemon: + call StopDangerSound + call WaitSFX + ld a, $f0 + ld [wCryTracks], a + ld a, [wBattleMonSpecies] + call PlayStereoCry + call PlayerMonFaintedAnimation + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld hl, BattleText_MonFainted + jp StdBattleTextbox + +FaintEnemyPokemon: + 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_EnemyMonFainted + jp StdBattleTextbox + +CheckEnemyTrainerDefeated: + ld a, [wOTPartyCount] + ld b, a + xor a + ld hl, wOTPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + or [hl] + inc hl + or [hl] + dec hl + add hl, de + dec b + jr nz, .loop + + and a + ret + +HandleEnemySwitch: + ld hl, wEnemyHPPal + ld e, HP_BAR_LENGTH_PX + call UpdateHPPal + 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 SafeLoadTempTilemapToTilemap + +.not_linked + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + ld a, $0 + jr nz, EnemyPartyMonEntrance + inc a + ret + +EnemyPartyMonEntrance: + 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 [wBattlePlayerAction], a + inc a + ret + +WinTrainerBattle: +; Player won the battle + call StopDangerSound + ld a, $1 + ld [wBattleLowHealthAlarm], a + ld [wBattleEnded], a + ld a, [wLinkMode] + and a + ld a, b + call z, PlayVictoryMusic + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyWasDefeated + call StdBattleTextbox + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + ret z + + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld a, [wBattleType] + cp BATTLETYPE_CANLOSE + jr nz, .skip_heal + predef HealParty +.skip_heal + ld a, [wDebugFlags] + bit DEBUG_BATTLE_F, a + jr nz, .GiveMoney + call PrintWinLossText + +.GiveMoney: + ld a, [wAmuletCoin] + and a + call nz, .DoubleReward + call .CheckMaxedOutMomMoney + push af + ld a, FALSE + jr nc, .okay + ld a, [wMomSavingMoney] + and MOM_SAVING_MONEY_MASK + cp (1 << MOM_SAVING_SOME_MONEY_F) | (1 << MOM_SAVING_HALF_MONEY_F) + jr nz, .okay + inc a ; TRUE + +.okay + ld b, a + ld c, 4 +.loop + ld a, b + and a + jr z, .loop2 + call .AddMoneyToMom + 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 MOM_SAVING_MONEY_MASK + 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 + +.AddMoneyToMom: + push bc + ld hl, wBattleReward + 2 + ld de, wMomsMoney + 2 + call AddBattleMoneyToAccount + pop bc + ret + +.AddMoneyToWallet: + push bc + ld hl, wBattleReward + 2 + ld de, wMoney + 2 + call AddBattleMoneyToAccount + pop bc + ret + +.DoubleReward: + 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 + +.SentToMomTexts: +; entries correspond to MOM_SAVING_* constants + dw SentSomeToMomText + dw SentHalfToMomText + dw SentAllToMomText + +.CheckMaxedOutMomMoney: + 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 + +AddBattleMoneyToAccount: + ld c, 3 + and a + push de +.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 + +PlayVictoryMusic: + 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 IsGymLeader + jr c, .play_music + ld de, MUSIC_TRAINER_VICTORY + +.play_music + call PlayMusic + +.lost + pop de + ret + +IsKantoGymLeader: + ld hl, KantoGymLeaders + jr IsGymLeaderCommon + +IsGymLeader: + ld hl, GymLeaders +IsGymLeaderCommon: + push de + ld a, [wOtherTrainerClass] + ld de, 1 + call IsInArray + pop de + ret + +INCLUDE "data/trainers/leaders.asm" + +HandlePlayerMonFaint: + call FaintYourPokemon + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + call z, FaintEnemyPokemon + ld a, $1 + ld [wWhichMonFaintedFirst], a + call UpdateFaintedPlayerMon + call CheckPlayerPartyForFitMon + ld a, d + and a + jp z, LostBattle + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + jr nz, .notfainted + call UpdateBattleStateAndExperienceAfterEnemyFaint + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, $1 + ld [wBattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + +.notfainted + call AskUseNextPokemon + jr nc, .switch + ld a, $1 + ld [wBattleEnded], a + ret + +.switch + call ForcePlayerMonChoice + ret nz + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jp DoubleSwitch + +UpdateFaintedPlayerMon: + ld a, [wCurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef SmallFarFlagAction + ld hl, wEnemySubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld [wLowHealthAlarm], a + ld hl, wPlayerDamageTaken + ld [hli], a + ld [hl], a + ld [wBattleMonStatus], a + call UpdateBattleMonInParty + ld c, HAPPINESS_FAINTED + ; If TheirLevel > (YourLevel + 30), use a different parameter + ld a, [wBattleMonLevel] + add 30 + ld b, a + ld a, [wEnemyMonLevel] + cp b + jr c, .got_param + ld c, HAPPINESS_BEATENBYSTRONGFOE + +.got_param + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + callfar ChangeHappiness + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + add LOSE + ld [wBattleResult], a + ld a, [wWhichMonFaintedFirst] + and a + ret z + ret ; ?????????? + +AskUseNextPokemon: + 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, wPartyMon1Speed + ld de, wEnemyMonSpeed + jp TryToRunAwayFromBattle + +ForcePlayerMonChoice: + call EmptyBattleTextbox + call LoadStandardMenuHeader + call SetUpBattlePartyMenu_NoLoop + call ForcePickPartyMonInBattle + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr nz, .skip_link + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], a + call LinkBattleSendReceiveAction + +.skip_link + xor a ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + jr nz, .send_out_pokemon + + call ClearSprites + call ClearBGPalettes + call _LoadHPBar + call ExitMenu + call LoadTilemapToTempTilemap + call WaitBGMap + call GetMemSGBLayout + call SetPalettes + xor a + ret + +.send_out_pokemon + call ClearSprites + ld a, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + call SendOutMonText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + call SpikesDamage + ld a, $1 + and a + ret + +PlayerPartyMonEntrance: + ld a, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutMonText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + jp SpikesDamage + +SetUpBattlePartyMenu_NoLoop: + call ClearBGPalettes +SetUpBattlePartyMenu: ; switch to fullscreen menu? + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + ret + +PickPartyMonInBattle: +.loop + ld a, PARTYMENUACTION_SWITCH + ld [wPartyMenuActionText], a + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + farcall PartyMenuSelect + ret c + call CheckIfCurPartyMonIsFitToFight + jr z, .loop + xor a + ret + +SwitchMonAlreadyOut: + ld hl, wCurBattleMon + ld a, [wCurPartyMon] + cp [hl] + jr nz, .notout + + ld hl, BattleText_MonIsAlreadyOut + call StdBattleTextbox + scf + ret + +.notout + xor a + ret + +ForcePickPartyMonInBattle: +; Can't back out. + +.pick + call PickPartyMonInBattle + ret nc + + ld de, SFX_WRONG + call PlaySFX + call WaitSFX + jr .pick + +PickSwitchMonInBattle: +.pick + call PickPartyMonInBattle + ret c + call SwitchMonAlreadyOut + jr c, .pick + xor a + ret + +ForcePickSwitchMonInBattle: +; Can't back out. + +.pick + call ForcePickPartyMonInBattle + call SwitchMonAlreadyOut + jr c, .pick + + xor a + ret + +LostBattle: + ld a, 1 + ld [wBattleEnded], a + ld a, [wBattleType] + 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, [wDebugFlags] + bit DEBUG_BATTLE_F, a + jr nz, .skip_win_loss_text + call PrintWinLossText +.skip_win_loss_text + 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 BATTLERESULT_BITMASK + add DRAW + ld [wBattleResult], a + jr .text + +.not_tied + ld hl, LostAgainstText + +.text + call StdBattleTextbox + +.end + scf + ret + +EnemyMonFaintedAnimation: + hlcoord 12, 5 + decoord 12, 6 + jp MonFaintedAnimation + +PlayerMonFaintedAnimation: + hlcoord 1, 10 + decoord 1, 11 + jp MonFaintedAnimation + +MonFaintedAnimation: + ld a, [wd8ba] + push af + set 6, a + ld [wd8ba], 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 [wd8ba], a + ret + +.Spaces: + db " @" + +SlideBattlePicOut: + ldh [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 + +.DoFrame: + ldh 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 + +ForceEnemySwitch: + call ResetEnemyBattleVars + ld a, [wEnemySwitchMonIndex] + dec a + ld b, a + call LoadEnemyMonToSwitchTo + call ClearEnemyMonBox + call NewEnemyMonStatus + call ResetEnemyStatLevels + call Function_SetEnemyMonAndSendOutAnimation + call BreakAttraction + call ResetBattleParticipants + ret + +EnemySwitch: + call CheckWhetherToAskSwitch + jr nc, EnemySwitch_SetMode + ; Shift Mode + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindMonInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the mon the AI will switch to + call LoadEnemyMonToSwitchTo + call OfferSwitch + push af + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + call Function_SetEnemyMonAndSendOutAnimation + pop af + ret c + ; If we're here, then we're switching too + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wBattlePlayerAction], a + inc a + ld [wEnemyIsSwitching], a + call LoadTilemapToTempTilemap + jp PlayerSwitch + +EnemySwitch_SetMode: + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindMonInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the mon the AI will switch to + call LoadEnemyMonToSwitchTo + ld a, 1 + ld [wEnemyIsSwitching], a + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + jp Function_SetEnemyMonAndSendOutAnimation + +CheckWhetherSwitchmonIsPredetermined: +; 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 + +ResetEnemyBattleVars: +; and draw empty Textbox + xor a + ld [wLastPlayerCounterMove], a + ld [wLastEnemyCounterMove], a + ld [wLastEnemyMove], a + ld [wCurEnemyMove], a + dec a + ld [wEnemyItemState], a + xor a + ld [wPlayerWrapCount], a + hlcoord 18, 0 + ld a, 8 + call SlideBattlePicOut + call EmptyBattleTextbox + jp LoadStandardMenuHeader + +ResetBattleParticipants: + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a +AddBattleParticipant: + ld a, [wCurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, SET_FLAG + push bc + predef SmallFarFlagAction + pop bc + ld hl, wBattleParticipantsIncludingFainted + predef_jump SmallFarFlagAction + +FindMonInOTPartyToSwitchIntoBattle: + ld b, -1 + ld a, $1 + ld [wBuffer1], a + ld [wBuffer2], a +.loop + ld hl, wBuffer1 + sla [hl] + inc hl + sla [hl] + inc b + ld a, [wOTPartyCount] + cp b + jp z, ScoreMonTypeMatchups + ld a, [wCurOTMon] + cp b + jr z, .discourage + ld hl, wOTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + ld a, [hli] + ld c, a + ld a, [hl] + or c + pop bc + jr z, .discourage + call LookUpTheEffectivenessOfEveryMove + call IsThePlayerMonTypesEffectiveAgainstOTMon + jr .loop + +.discourage + ld hl, wBuffer2 + set 0, [hl] + jr .loop + +LookUpTheEffectivenessOfEveryMove: + push bc + ld hl, wOTPartyMon1Moves + 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, [wTypeMatchup] + cp EFFECTIVE + 1 + jr c, .loop + ld hl, wBuffer1 + set 0, [hl] + ret +.done + ret + +IsThePlayerMonTypesEffectiveAgainstOTMon: +; Calculates the effectiveness of the types of the PlayerMon +; against the OTMon + push bc + ld hl, wOTPartyCount + ld a, b + inc a + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + dec a + ld hl, BaseData + BASE_TYPES + ld bc, BASE_DATA_SIZE + call AddNTimes + ld de, wEnemyMonType + ld bc, BASE_CATCH_RATE - BASE_TYPES + ld a, BANK(BaseData) + call FarCopyBytes + ld a, [wBattleMonType1] + ld [wPlayerMoveStruct + MOVE_TYPE], a + call SetPlayerTurn + callfar BattleCheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + 1 + jr nc, .super_effective + ld a, [wBattleMonType2] + ld [wPlayerMoveStruct + MOVE_TYPE], a + callfar BattleCheckTypeMatchup + ld a, [wTypeMatchup] + cp EFFECTIVE + 1 + jr nc, .super_effective + pop bc + ret + +.super_effective + pop bc + ld hl, wBuffer1 + bit 0, [hl] + jr nz, .reset + inc hl + set 0, [hl] + ret + +.reset + res 0, [hl] + ret + +ScoreMonTypeMatchups: +.loop1 + ld hl, wBuffer1 + sla [hl] + inc hl + sla [hl] + jr nc, .loop1 + ld a, [wOTPartyCount] + ld b, a + ld c, [hl] +.loop2 + sla c + jr nc, .okay + dec b + jr z, .loop5 + jr .loop2 + +.okay + ld a, [wBuffer1] + and a + jr z, .okay2 + ld b, -1 + ld c, a +.loop3 + inc b + sla c + jr nc, .loop3 + jr .quit + +.okay2 + ld b, -1 + ld a, [wBuffer2] + ld c, a +.loop4 + inc b + sla c + jr c, .loop4 + jr .quit + +.loop5 + call BattleRandom + and $7 + cp 6 + jr nc, .loop5 + ld b, a + ld a, [wCurOTMon] + cp b + jr z, .loop5 + ld hl, wOTPartyMon1HP + 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 + +LoadEnemyMonToSwitchTo: + ; 'b' contains the PartyNr of the mon the AI will switch to + ld a, b + ld [wCurPartyMon], a + ld hl, wOTPartyMon1Level + call GetPartyLocation + ld a, [hl] + ld [wCurPartyLevel], a + ld a, [wCurPartyMon] + inc a + ld hl, wOTPartyCount + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wTempEnemyMonSpecies], a + ld [wCurPartySpecies], a + call LoadEnemyMon + + ld a, [wCurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld hl, wEnemyMonDVs + predef GetUnownLetter + ld a, [wUnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + + ld hl, wEnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ret + +CheckWhetherToAskSwitch: + ld a, [wBattleHasJustStarted] + dec a + jp z, .return_nc + ld a, [wPartyCount] + dec a + jp z, .return_nc + ld a, [wLinkMode] + and a + jp nz, .return_nc + ld a, [wOptions] + bit BATTLE_SHIFT, a + jr nz, .return_nc + ld a, [wCurPartyMon] + push af + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + farcall CheckCurPartyMonFainted + pop bc + ld a, b + ld [wCurPartyMon], a + jr c, .return_nc + scf + ret + +.return_nc + and a + ret + +OfferSwitch: + ld a, [wCurPartyMon] + push af + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyIsAboutToUseWillPlayerChangeMon + 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, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + call ClearPalettes + call DelayFrame + call _LoadHPBar + pop af + ld [wCurPartyMon], a + xor a + ld [wCurEnemyMove], a + ld [wCurPlayerMove], a + and a + ret + +.canceled_switch + call ClearPalettes + call DelayFrame + call _LoadHPBar + +.said_no + pop af + ld [wCurPartyMon], a + scf + ret + +ClearEnemyMonBox: + xor a + ldh [hBGMapMode], a + call ExitMenu + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call WaitBGMap + jp FinishBattleAnim + +Function_BattleTextEnemySentOut: + callfar Battle_GetTrainerName + ld hl, BattleText_EnemySentOut + jp StdBattleTextbox + +Function_SetEnemyMonAndSendOutAnimation: + ld a, [wTempEnemyMonSpecies] + ld [wCurPartySpecies], a + ld [wCurSpecies], a + call GetBaseData + ld a, OTPARTYMON + ld [wMonType], a + predef CopyMonToTempMon + 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, .cry_no_anim + + ld a, 1 ; shiny anim + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.cry_no_anim + ld a, $f + ld [wCryTracks], a + ld a, [wTempEnemyMonSpecies] + call PlayStereoCry + call UpdateEnemyHUD + ld a, $1 + ldh [hBGMapMode], a + ret + +NewEnemyMonStatus: + xor a + ld [wLastPlayerCounterMove], a + ld [wLastEnemyCounterMove], a + ld [wLastEnemyMove], a + ld hl, wEnemySubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld [wEnemyDisableCount], a + ld [wEnemyFuryCutterCount], a + ld [wEnemyProtectCount], a + ld [wEnemyRageCounter], a + ld [wEnemyDisabledMove], a + ld [wEnemyMinimized], a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ld [wEnemyTurnsTaken], a + ld hl, wPlayerSubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret + +ResetEnemyStatLevels: + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, wEnemyStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +CheckPlayerPartyForFitMon: +; Has the player any mon in his Party that can fight? + ld a, [wPartyCount] + ld e, a + xor a + ld hl, wPartyMon1HP + ld bc, PARTYMON_STRUCT_LENGTH - 1 +.loop + or [hl] + inc hl ; + 1 + or [hl] + add hl, bc + dec e + jr nz, .loop + ld d, a + ret + +CheckIfCurPartyMonIsFitToFight: + ld a, [wCurPartyMon] + ld hl, wPartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + ret nz + + ld a, [wBattleHasJustStarted] + and a + jr nz, .finish_fail + ld hl, wPartySpecies + ld a, [wCurPartyMon] + 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 + +TryToRunAwayFromBattle: +; Run away from battle, with or without item + ld a, [wBattleType] + cp BATTLETYPE_DEBUG + jp z, .can_escape + cp BATTLETYPE_CONTEST + jp z, .can_escape + cp BATTLETYPE_TRAP + jp z, .cant_escape + cp BATTLETYPE_SHINY + 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, [wEnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jp nz, .cant_escape + + ld a, [wPlayerWrapCount] + and a + jp nz, .cant_escape + + push hl + push de + ld a, [wBattleMonItem] + ld [wNamedObjectIndexBuffer], a + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_ESCAPE + pop de + pop hl + jr nz, .no_flee_item + + call 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] + ldh [hMultiplicand + 1], a + ld a, [hl] + ldh [hMultiplicand + 2], a + ld a, [de] + inc de + ldh [hEnemyMonSpeed + 0], a + ld a, [de] + ldh [hEnemyMonSpeed + 1], a + call SafeLoadTempTilemapToTilemap + ld de, hMultiplicand + 1 + ld hl, hEnemyMonSpeed + ld c, 2 + call CompareBytes + jr nc, .can_escape + + xor a + ldh [hMultiplicand + 0], a + ld a, 32 + ldh [hMultiplier], a + call Multiply + ldh a, [hProduct + 2] + ldh [hDividend + 0], a + ldh a, [hProduct + 3] + ldh [hDividend + 1], a + ldh a, [hEnemyMonSpeed + 0] + ld b, a + ldh a, [hEnemyMonSpeed + 1] + srl b + rr a + srl b + rr a + and a + jr z, .can_escape + ldh [hDivisor], a + ld b, 2 + call Divide + ldh a, [hQuotient + 2] + and a + jr nz, .can_escape + ld a, [wNumFleeAttempts] + ld c, a +.loop + dec c + jr z, .cant_escape_2 + ld b, 30 + ldh a, [hQuotient + 3] + add b + ldh [hQuotient + 3], a + jr c, .can_escape + jr .loop + +.cant_escape_2 + call BattleRandom + ld b, a + ldh a, [hQuotient + 3] + cp b + jr nc, .can_escape + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], 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, TRUE + 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 ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ld a, $f + ld [wCurMoveNum], a + xor a + ld [wCurPlayerMove], a + call LinkBattleSendReceiveAction + call SafeLoadTempTilemapToTilemap + + ; Got away safely + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ld a, DRAW + jr z, .fled + dec a ; LOSE +.fled + ld b, a + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + 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 + +InitBattleMon: + ld a, MON_SPECIES + call GetPartyParamLocation + ld de, wBattleMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, wBattleMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, wBattleMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [wBattleMonSpecies] + ld [wTempBattleMonSpecies], a + ld [wCurPartySpecies], a + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseType1] + ld [wBattleMonType1], a + ld a, [wBaseType2] + ld [wBattleMonType2], a + ld hl, wPartyMonNicknames + ld a, [wCurBattleMon] + call SkipNames + ld de, wBattleMonNick + ld bc, MON_NAME_LENGTH + call CopyBytes + ld hl, wBattleMonAttack + ld de, wPlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnPlayerStats + call BadgeStatBoosts + ret + +BattleCheckPlayerShininess: + call GetPartyMonDVs + jr BattleCheckShininess + +BattleCheckEnemyShininess: + call GetEnemyMonDVs + +BattleCheckShininess: + ld b, h + ld c, l + callfar CheckShininess + ret + +GetPartyMonDVs: + ld hl, wBattleMonDVs + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, wPartyMon1DVs + ld a, [wCurBattleMon] + jp GetPartyLocation + +GetEnemyMonDVs: + ld hl, wEnemyMonDVs + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, wEnemyBackupDVs + ld a, [wBattleMode] + dec a + ret z + ld hl, wOTPartyMon1DVs + ld a, [wCurOTMon] + jp GetPartyLocation + +ResetPlayerStatLevels: + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, wPlayerStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +InitEnemyMon: + ld a, [wCurPartyMon] + ld hl, wOTPartyMon1Species + call GetPartyLocation + ld de, wEnemyMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, wEnemyMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, wEnemyMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [wEnemyMonSpecies] + ld [wCurSpecies], a + call GetBaseData + ld hl, wOTPartyMonNicknames + ld a, [wCurPartyMon] + call SkipNames + ld de, wEnemyMonNick + ld bc, MON_NAME_LENGTH + call CopyBytes + ld hl, wEnemyMonAttack + ld de, wEnemyStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnEnemyStats + ld hl, wBaseType1 + ld de, wEnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, wBaseStats + ld de, wEnemyMonBaseStats + ld b, 5 +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + ld a, [wCurPartyMon] + ld [wCurOTMon], a + ret + +SwitchPlayerMon: + call ClearSprites + ld a, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + ret + +SendOutPlayerMon: + ld hl, wBattleMonDVs + predef GetUnownLetter + hlcoord 1, 5 + ld b, 7 + ld c, 8 + call ClearBox + call WaitBGMap + xor a + ldh [hBGMapMode], a + call GetBattleMonBackpic + xor a + ldh [hGraphicStartTile], a + ld [wBattleMenuCursorBuffer], a + ld [wCurMoveNum], a + ld [wTypeModifier], a + ld [wPlayerMoveStruct + MOVE_ANIM], a + ld [wLastPlayerCounterMove], a + ld [wLastEnemyCounterMove], a + ld [wLastPlayerMove], 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, $f0 + ld [wCryTracks], a + ld a, [wCurPartySpecies] + call PlayStereoCry + call UpdatePlayerHUD + ld a, $1 + ldh [hBGMapMode], a + ret + +NewBattleMonStatus: + xor a + ld [wLastPlayerCounterMove], a + ld [wLastEnemyCounterMove], a + ld [wLastPlayerMove], a + ld hl, wPlayerSubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld hl, wPlayerUsedMoves + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [wPlayerDisableCount], a + ld [wPlayerFuryCutterCount], a + ld [wPlayerProtectCount], a + ld [wPlayerRageCounter], a + ld [wDisabledMove], a + ld [wPlayerMinimized], a + ld [wEnemyWrapCount], a + ld [wPlayerWrapCount], a + ld [wPlayerTurnsTaken], a + ld hl, wEnemySubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret + +BreakAttraction: + ld hl, wPlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, wEnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ret + +SpikesDamage: + ld hl, wPlayerScreens + ld de, wBattleMonType + ld bc, UpdatePlayerHUD + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyScreens + ld de, wEnemyMonType + 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 + +PursuitSwitch: + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld b, a + call GetMoveEffect + ld a, b + cp EFFECT_PURSUIT + jr nz, .done + + ld a, [wCurBattleMon] + push af + + ld hl, DoPlayerTurn + ldh a, [hBattleTurn] + and a + jr z, .do_turn + ld hl, DoEnemyTurn + ld a, [wLastPlayerMon] + ld [wCurBattleMon], a +.do_turn + ld a, BANK(DoPlayerTurn) ; aka BANK(DoEnemyTurn) + rst FarCall + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, $ff + ld [hl], a + + pop af + ld [wCurBattleMon], a + + ldh a, [hBattleTurn] + and a + jr z, .check_enemy_fainted + + ld a, [wLastPlayerMon] + call UpdateBattleMon + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld a, $f0 + ld [wCryTracks], a + ld a, [wBattleMonSpecies] + call PlayStereoCry + ld a, [wLastPlayerMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef SmallFarFlagAction + call PlayerMonFaintedAnimation + ld hl, BattleText_MonFainted + jr .done_fainted + +.check_enemy_fainted + ld hl, wEnemyMonHP + 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_EnemyMonFainted + +.done_fainted + call StdBattleTextbox + scf + ret + +.done + and a + ret + +RecallPlayerMon: + ldh a, [hBattleTurn] + push af + xor a + ldh [hBattleTurn], a + ld [wNumHits], a + ld de, ANIM_RETURN_MON + call Call_PlayBattleAnim + pop af + ldh [hBattleTurn], a + ret + +HandleHealingItems: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + 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 + +HandleHPHealingItem: + callfar GetOpponentItem + ld a, b + cp HELD_BERRY + ret nz + ld de, wEnemyMonHP + 1 + ld hl, wEnemyMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .go + ld de, wBattleMonHP + 1 + ld hl, wBattleMonMaxHP + +.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 [wBuffer3], a + add a + ld c, a + dec de + ld a, [de] + inc de + ld [wBuffer4], 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 wBuffer1/2 + ld a, [hli] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + ld a, [de] + add c + ld [wBuffer5], a + ld c, a + dec de + ld a, [de] + adc 0 + ld [wBuffer6], a + ld b, a + ld a, [hld] + cp c + ld a, [hl] + sbc b + jr nc, .okay + ld a, [hli] + ld [wBuffer6], a + ld a, [hl] + ld [wBuffer5], a + +.okay + ld a, [wBuffer6] + ld [de], a + inc de + ld a, [wBuffer5] + ld [de], a + ldh a, [hBattleTurn] + ld [wWhichHPBar], a + and a + hlcoord 2, 2 + jr z, .got_hp_bar_coords + hlcoord 10, 9 + +.got_hp_bar_coords + ld [wWhichHPBar], a + predef AnimateHPBar +UseOpponentItem: + call RefreshBattleHuds + callfar GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + callfar ConsumeHeldItem + ld hl, RecoveredUsingText + jp StdBattleTextbox + +ItemRecoveryAnim: + push hl + push de + push bc + call EmptyBattleTextbox + ld a, RECOVER + ld [wFXAnimID], a + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [wFXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + pop bc + pop de + pop hl + ret + +UseHeldStatusHealingItem: + callfar GetOpponentItem + ld hl, HeldStatusHealingEffects +.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 + ldh a, [hBattleTurn] + and a + jr z, .got_pointer + ld hl, CalcPlayerStats + +.got_pointer + call SwitchTurnCore + ld a, BANK(CalcPlayerStats) ; aka BANK(CalcEnemyStats) + rst FarCall + call SwitchTurnCore + call ItemRecoveryAnim + call UseOpponentItem + ld a, $1 + and a + ret + +INCLUDE "data/battle/held_heal_status.asm" + +UseConfusionHealingItem: + 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 [wNamedObjectIndexBuffer], a + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + call GetItemName + call ItemRecoveryAnim + ld hl, BattleText_ItemHealedConfusion + call StdBattleTextbox + ldh 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 + +HandleStatBoostingHeldItems: +; The effects handled here are not used in-game. + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .player_1 + call .DoPlayer + jp .DoEnemy + +.player_1 + call .DoEnemy + jp .DoPlayer + +.DoPlayer: + call GetPartymonItem + ld a, $0 + jp .HandleItem + +.DoEnemy: + call GetOTPartymonItem + ld a, $1 +.HandleItem: + ldh [hBattleTurn], a + ld d, h + ld e, l + push de + push bc + ld a, [bc] + ld b, a + callfar GetItemHeldEffect + ld hl, HeldStatUpItems +.loop + ld a, [hli] + cp -1 + jr z, .finish + inc hl + inc hl + cp b + jr nz, .loop + pop bc + ld a, [bc] + ld [wNamedObjectIndexBuffer], 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, [wFailedMessage] + 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 + +INCLUDE "data/battle/held_stat_up.asm" + +GetPartymonItem: + ld hl, wPartyMon1Item + ld a, [wCurBattleMon] + call GetPartyLocation + ld bc, wBattleMonItem + ret + +GetOTPartymonItem: + ld hl, wOTPartyMon1Item + ld a, [wCurOTMon] + call GetPartyLocation + ld bc, wEnemyMonItem + ret + +UpdateBattleHUDs: + push hl + push de + push bc + call DrawPlayerHUD + ld hl, wPlayerHPPal + call SetHPPal + call CheckDanger + call DrawEnemyHUD + ld hl, wEnemyHPPal + call SetHPPal + pop bc + pop de + pop hl + ret + +UpdatePlayerHUD:: + push hl + push de + push bc + call DrawPlayerHUD + call UpdatePlayerHPPal + call CheckDanger + pop bc + pop de + pop hl + ret + +DrawPlayerHUD: + xor a + ldh [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 [wMonType], a + predef DrawPlayerHP + + ; Exp bar + push de + ld a, [wCurBattleMon] + ld hl, wPartyMon1Exp + 2 + call GetPartyLocation + ld d, h + ld e, l + + hlcoord 10, 11 + ld a, [wTempMonLevel] + ld b, a + call FillInExpBar + pop de + ret + +UpdatePlayerHPPal: + ld hl, wPlayerHPPal + jp UpdateHPPal + +CheckDanger: + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + jr z, .no_danger + ld a, [wBattleLowHealthAlarm] + and a + jr nz, .done + ld a, [wPlayerHPPal] + cp HP_RED + jr z, .danger + +.no_danger + ld hl, wLowHealthAlarm + res DANGER_ON_F, [hl] + jr .done + +.danger + ld hl, wLowHealthAlarm + set DANGER_ON_F, [hl] + +.done + ret + +PrintPlayerHUD: + ld de, wBattleMonNick + hlcoord 10, 7 + call ret_3df99 + call PlaceString + + push bc + + ld a, [wCurBattleMon] + ld hl, wPartyMon1DVs + call GetPartyLocation + ld de, wTempMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, wBattleMonLevel + ld de, wTempMonLevel + ld bc, $11 + call CopyBytes + ld a, [wCurBattleMon] + ld hl, wPartyMon1Species + call GetPartyLocation + ld a, [hl] + ld [wCurPartySpecies], a + ld [wCurSpecies], a + call GetBaseData + + pop hl + dec hl + + ld a, TEMPMON + ld [wMonType], 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, wBattleMonStatus + 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, [wBattleMonLevel] + ld [wTempMonLevel], a + jp PrintLevel + +UpdateEnemyHUD:: + push hl + push de + push bc + call DrawEnemyHUD + call UpdateEnemyHPPal + pop bc + pop de + pop hl + ret + +DrawEnemyHUD: + xor a + ldh [hBGMapMode], a + + hlcoord 1, 0 + lb bc, 4, 11 + call ClearBox + + farcall DrawEnemyHUDBorder + + ld a, [wTempEnemyMonSpecies] + ld [wCurSpecies], a + ld [wCurPartySpecies], a + call GetBaseData + ld de, wEnemyMonNick + hlcoord 1, 0 + call ret_3df99 + call PlaceString + ld h, b + ld l, c + dec hl + + ld hl, wEnemyMonDVs + ld de, wTempMonDVs + ld a, [wEnemySubStatus5] + 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 [wMonType], 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, wEnemyMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + jr nz, .skip_level + ld a, b + cp " " + jr nz, .print_level + dec hl +.print_level + ld a, [wEnemyMonLevel] + ld [wTempMonLevel], a + call PrintLevel +.skip_level + + ld hl, wEnemyMonHP + ld a, [hli] + ldh [hMultiplicand + 1], a + ld a, [hld] + ldh [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 + ldh [hMultiplicand + 0], a + ld a, HP_BAR_LENGTH_PX + ldh [hMultiplier], a + call Multiply + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld b, a + ld a, [hl] + ldh [hMultiplier], a + ld a, b + and a + jr z, .less_than_256_max + ldh a, [hMultiplier] + srl b + rr a + srl b + rr a + ldh [hDivisor], a + ldh a, [hProduct + 2] + ld b, a + srl b + ldh a, [hProduct + 3] + rr a + srl b + rr a + ldh [hProduct + 3], a + ld a, b + ldh [hProduct + 2], a + +.less_than_256_max + ldh a, [hProduct + 2] + ldh [hDividend + 0], a + ldh a, [hProduct + 3] + ldh [hDividend + 1], a + ld a, 2 + ld b, a + call Divide + ldh a, [hQuotient + 3] + 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 + +UpdateEnemyHPPal: + ld hl, wEnemyHPPal + call UpdateHPPal + ret + +UpdateHPPal: + ld b, [hl] + call SetHPPal + ld a, [hl] + cp b + ret z + jp FinishBattleAnim + +ret_3df99: + ret + +BattleMenu: + xor a + ldh [hBGMapMode], a + call LoadTempTilemapToTilemap + + ld a, [wBattleType] + cp BATTLETYPE_DEBUG + jr z, .ok + cp BATTLETYPE_TUTORIAL + jr z, .ok + call UpdateBattleHuds + call EmptyBattleTextbox + call LoadTilemapToTempTilemap +.ok + +.loop + ld a, [wBattleType] + cp BATTLETYPE_CONTEST + jr nz, .not_contest + callfar ContestBattleMenu + jr .next +.not_contest + + ; Auto input: choose "ITEM" + ld a, [wInputType] + or a + jr z, .skip_dude_pack_select + farcall _DudeAutoInput_DownA +.skip_dude_pack_select + callfar LoadBattleMenu + +.next + ld a, $1 + ldh [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 + +BattleMenu_Fight: + xor a + ld [wNumFleeAttempts], a + call SafeLoadTempTilemapToTilemap + and a + ret + +BattleMenu_Pack: + ld a, [wLinkMode] + and a + jp nz, .ItemsCantBeUsed + + call LoadStandardMenuHeader + + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial + cp BATTLETYPE_CONTEST + jr z, .contest + + farcall BattlePack + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + jr z, .didnt_use_item + jr .got_item + +.tutorial + farcall TutorialPack + ld a, POKE_BALL + ld [wCurItem], a + call DoItemEffect + jr .got_item + +.contest + ld a, PARK_BALL + ld [wCurItem], 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 + +.ItemsCantBeUsed: + ld hl, BattleText_ItemsCantBeUsedHere + call StdBattleTextbox + jp BattleMenu + +.UseItem: + ld a, [wWildMon] + and a + jr nz, .run + callfar CheckItemPocket + ld a, [wItemAttributeParamBuffer] + cp BALL + jr z, .ball + call ClearBGPalettes + +.ball + xor a + ldh [hBGMapMode], a + call _LoadBattleFontsHPBar + call ClearSprites + ld a, [wBattleType] + 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 BATTLERESULT_BITMASK + ld [wBattleResult], a ; WIN + call ClearWindowData + call SetPalettes + scf + ret + +BattleMenu_PKMN: + call LoadStandardMenuHeader +BattleMenuPKMN_ReturnFromStats: + call ExitMenu + call LoadStandardMenuHeader + call ClearBGPalettes +BattleMenuPKMN_Loop: + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + xor a + ld [wPartyMenuActionText], a + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + farcall PartyMenuSelect + jr c, .Cancel +.loop + callfar FreezeMonIcons + callfar BattleMonMenu + jr c, BattleMenuPKMN_Loop + call PlaceHollowCursor + ld a, [wMenuCursorY] + cp $1 ; SWITCH + jp z, TryPlayerSwitch + cp $2 ; STATS + jr z, .Stats + cp $3 ; CANCEL + jr z, .Cancel + jr .loop + +.Stats: + call Battle_StatsScreen + jp BattleMenuPKMN_ReturnFromStats + +.Cancel: + call ClearSprites + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call LoadTilemapToTempTilemap + call GetMemSGBLayout + call SetPalettes + jp BattleMenu + +Battle_StatsScreen: + 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 [wMonType], a + ld hl, wPartyMons + predef StatsScreenInit + 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 + +TryPlayerSwitch: + ld a, [wCurBattleMon] + ld d, a + ld a, [wCurPartyMon] + cp d + jr nz, .check_trapped + ld hl, BattleText_MonIsAlreadyOut + call StdBattleTextbox + jp BattleMenuPKMN_Loop + +.check_trapped + ld a, [wPlayerWrapCount] + and a + jr nz, .trapped + ld a, [wEnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr z, .try_switch + +.trapped + ld hl, BattleText_MonCantBeRecalled + call StdBattleTextbox + jp BattleMenuPKMN_Loop + +.try_switch + call CheckIfCurPartyMonIsFitToFight + jp z, BattleMenuPKMN_Loop + ld a, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, BATTLEPLAYERACTION_SWITCH + ld [wBattlePlayerAction], a + call ClearPalettes + call DelayFrame + call ClearSprites + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + ld a, [wCurPartyMon] + ld [wCurBattleMon], a +PlayerSwitch: + ld a, 1 + ld [wPlayerIsSwitching], a + ld a, [wLinkMode] + and a + jr z, .not_linked + call LoadStandardMenuHeader + 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_STRUGGLE + jp z, .switch + cp BATTLEACTION_SKIPTURN + jp z, .switch + cp BATTLEACTION_SWITCH1 + jp c, .switch + cp BATTLEACTION_FORFEIT + jr nz, .dont_run + call WildFled_EnemyFled_LinkBattleCanceled + ret + +.dont_run + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .player_1 + call BattleMonEntrance + call EnemyMonEntrance + and a + ret + +.player_1 + call EnemyMonEntrance + call BattleMonEntrance + and a + ret + +EnemyMonEntrance: + callfar AI_Switch + call SetEnemyTurn + jp SpikesDamage + +BattleMonEntrance: + call WithdrawMonText + + ld c, 50 + call DelayFrames + + ld hl, wPlayerSubStatus4 + 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, [wCurBattleMon] + ld [wCurPartyMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutMonText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + call SpikesDamage + ld a, $2 + ld [wMenuCursorY], a + ret + +PassedBattleMonEntrance: + ld c, 50 + call DelayFrames + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + call AddBattleParticipant + call InitBattleMon + xor a ; FALSE + ld [wApplyStatLevelMultipliersToEnemy], a + call ApplyStatLevelMultiplierOnAllStats + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + jp SpikesDamage + +BattleMenu_Run: + call SafeLoadTempTilemapToTilemap + ld a, $3 + ld [wMenuCursorY], a + ld hl, wBattleMonSpeed + ld de, wEnemyMonSpeed + call TryToRunAwayFromBattle + ld a, FALSE + ld [wFailedToFlee], a + ret c + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + ret nz + jp BattleMenu + +CheckAmuletCoin: + ld a, [wBattleMonItem] + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_AMULET_COIN + ret nz + ld a, 1 + ld [wAmuletCoin], a + ret + +MoveSelectionScreen: + ld hl, wEnemyMonMoves + ld a, [wMoveSelectionMenuType] + dec a + jr z, .got_menu_type + dec a + jr z, .ether_elixer_menu + call .CheckPlayerHasUsableMoves + ret z ; use Struggle + ld hl, wBattleMonMoves + 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 + ldh [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 [wBuffer1], 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, [wCurMoveNum] + inc a + +.skip_inc + ld [wMenuCursorY], a + ld a, 1 + ld [wMenuCursorX], a + ld a, [wNumMoves] + inc a + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld c, STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP + ld a, [wMoveSelectionMenuType] + dec a + ld b, D_DOWN | D_UP | A_BUTTON + jr z, .okay + dec a + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON + jr z, .okay + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .okay + ld 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_3e448 + 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 + ldh [hBGMapMode], a + call ScrollingMenuJoypad + bit D_UP_F, a + jp nz, .pressed_up + bit D_DOWN_F, a + jp nz, .pressed_down + bit SELECT_F, a + jp nz, .pressed_select + bit 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 [wCurMoveNum], a + jr nz, .use_move + + pop af + ret + +.use_move + pop af + ret nz + + ld hl, wBattleMonPP + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and PP_MASK + jr z, .no_pp_left + ld a, [wPlayerDisableCount] + swap a + and $f + dec a + cp c + jr z, .move_disabled + ld a, [wUnusedPlayerLockedMove] + and a + jr nz, .skip2 + ld a, [wMenuCursorY] + ld hl, wBattleMonMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + +.skip2 + ld [wCurPlayerMove], a + xor a + ret + +.move_disabled + ld hl, BattleText_TheMoveIsDisabled + jr .place_textbox_start_over + +.no_pp_left + ld hl, BattleText_TheresNoPPLeftForThisMove + +.place_textbox_start_over + call StdBattleTextbox + call SafeLoadTempTilemapToTilemap + jp MoveSelectionScreen + +.string_3e448 + db "@" + +.pressed_up + ld a, [wMenuCursorY] + and a + jp nz, .menu_loop + ld a, [wNumMoves] + inc a + ld [wMenuCursorY], a + jp .menu_loop + +.pressed_down + ld a, [wMenuCursorY] + ld b, a + ld a, [wNumMoves] + inc a + inc a + cp b + jp nz, .menu_loop + ld a, $1 + ld [wMenuCursorY], a + jp .menu_loop + +.CheckPlayerHasUsableMoves: + ld a, STRUGGLE + ld [wCurPlayerMove], a + ld a, [wPlayerDisableCount] + and a + ld hl, wBattleMonPP + jr nz, .disabled + + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and PP_MASK + ret nz + jr .force_struggle + +.disabled + swap a + and $f + ld b, a + ld d, NUM_MOVES + 1 + xor a +.loop + dec d + jr z, .done + ld c, [hl] + inc hl + dec b + jr z, .loop + or c + jr .loop + +.done + ; Bug: this will result in a move with PP Up confusing the game. + and a ; should be "and PP_MASK" + ret nz + +.force_struggle + ld hl, BattleText_MonHasNoMovesLeft + call StdBattleTextbox + ld c, 60 + call DelayFrames + xor a + ret + +.pressed_select + ld a, [wMoveSwapBuffer] + and a + jr z, .start_swap + ld hl, wBattleMonMoves + call .swap_bytes + ld hl, wBattleMonPP + call .swap_bytes + ld hl, wPlayerDisableCount + ld a, [hl] + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_swapping_disabled_move + ld a, [hl] + and $f + ld b, a + ld a, [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, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, wPartyMon1Moves + ld a, [wCurBattleMon] + 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 + +MoveInfoBox: + xor a + ldh [hBGMapMode], a + + hlcoord 0, 8 + ld b, 3 + ld c, 9 + call Textbox + + ld a, [wPlayerDisableCount] + and a + jr z, .not_disabled + + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_disabled + + hlcoord 1, 10 + ld de, .Disabled + call PlaceString + jr .done + +.not_disabled + ld hl, wMenuCursorY + dec [hl] + call SetPlayerTurn + ld hl, wBattleMonMoves + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wCurPlayerMove], a + + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + ld a, WILDMON + ld [wMonType], a + callfar GetMaxPPOfMove + + ld hl, wMenuCursorY + ld c, [hl] + inc [hl] + ld b, 0 + ld hl, wBattleMonPP + add hl, bc + ld a, [hl] + and PP_MASK + ld [wStringBuffer1], a + hlcoord 1, 9 + ld de, .Type + call PlaceString + + hlcoord 7, 11 + ld [hl], "/" + hlcoord 5, 11 + ld de, wStringBuffer1 + lb bc, 1, 2 + call PrintNum + + hlcoord 8, 11 + ld de, wNamedObjectIndexBuffer + lb bc, 1, 2 + call PrintNum + + callfar UpdateMoveData + ld a, [wPlayerMoveStruct + MOVE_ANIM] + ld b, a + hlcoord 2, 10 + predef PrintMoveType + +.done + ret + +.Disabled: + db "Disabled!@" +.Type: + db "TYPE/@" + +ParseEnemyAction: + ld a, [wEnemyIsSwitching] + and a + ret nz + ld a, [wLinkMode] + and a + jr z, .not_linked + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + call z, LinkBattleSendReceiveAction + call SafeLoadTempTilemapToTilemap + ld a, [wBattleAction] + cp BATTLEACTION_STRUGGLE + jp z, .struggle + cp BATTLEACTION_SKIPTURN + jp z, .skip_turn + cp BATTLEACTION_SWITCH1 + jp nc, ResetVarsForSubstatusRage + ld [wCurEnemyMoveNum], a + ld c, a + ld a, [wEnemySubStatus1] + bit SUBSTATUS_ROLLOUT, a + jp nz, .skip_load + ld a, [wEnemySubStatus3] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + jp nz, .skip_load + + ld hl, wEnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ld a, [wLastEnemyMove] + jp nz, .finish + ld hl, wEnemyMonMoves + ld b, 0 + add hl, bc + ld a, [hl] + jp .finish + +.not_linked + ld hl, wEnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .skip_encore + ld a, [wLastEnemyMove] + jp .finish + +.skip_encore + call CheckEnemyLockedIn + jp nz, ResetVarsForSubstatusRage + jr .continue + +.skip_turn + ld a, $ff + jr .finish + +.continue + ld hl, wEnemyMonMoves + ld de, wEnemyMonPP + ld b, NUM_MOVES +.loop + ld a, [hl] + and a + jp z, .struggle + ld a, [wEnemyDisabledMove] + cp [hl] + jr z, .disabled + ld a, [de] + and PP_MASK + 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, wEnemyMonMoves + call BattleRandom + maskbits NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [wEnemyDisableCount] + swap a + and $f + dec a + cp c + jr z, .loop2 + ld a, [hl] + and a + jr z, .loop2 + ld hl, wEnemyMonPP + add hl, bc + ld b, a + ld a, [hl] + and PP_MASK + jr z, .loop2 + ld a, c + ld [wCurEnemyMoveNum], a + ld a, b + +.finish + ld [wCurEnemyMove], 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 [wEnemyFuryCutterCount], a + +.fury_cutter + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .no_rage + ld hl, wEnemySubStatus4 + 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 [wEnemyProtectCount], a + ret + +.struggle + ld a, STRUGGLE + jr .finish + +ResetVarsForSubstatusRage: + xor a + ld [wEnemyFuryCutterCount], a + ld [wEnemyProtectCount], a + ld [wEnemyRageCounter], a + ld hl, wEnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + ret + +CheckEnemyLockedIn: + ld a, [wEnemySubStatus4] + and 1 << SUBSTATUS_RECHARGE + ret nz + + ld hl, wEnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + ld hl, wEnemySubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + ret + +LinkBattleSendReceiveAction: + ld a, $ff + ld [wOtherPlayerLinkAction], a + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + jr nz, .switch + ld a, [wCurPlayerMove] + cp STRUGGLE + ld b, BATTLEACTION_STRUGGLE + jr z, .struggle + dec b + inc a + jr z, .struggle + ld a, [wCurMoveNum] + jr .use_move + +.switch + ld a, [wCurPartyMon] + add BATTLEACTION_SWITCH1 + ld b, a + +.struggle + ld a, b + +.use_move + ld [wPlayerLinkAction], a + callfar PlaceWaitingText + +.waiting + call LinkTransfer + call DelayFrame + ld a, [wOtherPlayerLinkAction] + inc a + jr z, .waiting + + ld b, 10 +.receive + call DelayFrame + call LinkTransfer + dec b + jr nz, .receive + + ld b, 10 +.acknowledge + call DelayFrame + call LinkDataReceived + dec b + jr nz, .acknowledge + + ret + +LoadEnemyMon: +; Initialize enemy monster parameters +; To do this we pull the species from wTempEnemyMonSpecies + +; Notes: +; BattleRandom is used to ensure sync between Game Boys + +; Clear the whole enemy mon struct (wEnemyMon) + xor a + ld hl, wEnemyMonSpecies + ld bc, wEnemyMonEnd - wEnemyMon + call ByteFill + +; We don't need to be here if we're in a link battle + ld a, [wLinkMode] + and a + jp nz, InitEnemyMon + +; Make sure everything knows what species we're working with + ld a, [wTempEnemyMonSpecies] + ld [wEnemyMonSpecies], a + ld [wCurSpecies], a + ld [wCurPartySpecies], a + +; Grab the BaseData for this species + call GetBaseData + +; Let's get the item: + +; Is the item predetermined? + ld a, [wBattleMode] + dec a + jr z, .WildItem + +; If we're in a trainer battle, the item is in the party struct + ld a, [wCurPartyMon] + ld hl, wOTPartyMon1Item + call GetPartyLocation ; bc = PartyMon[wCurPartyMon] - wPartyMons + 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, [wBattleType] + cp BATTLETYPE_FORCEITEM + ld a, [wBaseItem1] + 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 75 percent + 1 + 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, [wBaseItem1] + jr nc, .UpdateItem + ld a, [wBaseItem2] + +.UpdateItem: + ld [wEnemyMonItem], a + +; Initialize DVs + +; If we're in a trainer battle, DVs are predetermined + ld a, [wBattleMode] + and a + jr z, .InitDVs + + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .InitDVs + +; Unknown + ld hl, wEnemyBackupDVs + ld de, wEnemyMonDVs + 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, Suicune) work differently +; They have their own structs, which are shorter than normal + ld a, [wBattleType] + 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 wBattleType + +; 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, wEnemyMonDVs + 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, [wTempEnemyMonSpecies] + cp UNOWN + jr nz, .Magikarp + +; Get letter based on DVs + ld hl, wEnemyMonDVs + 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: +; These filters are untranslated. +; They expect at wMagikarpLength a 2-byte value in mm, +; but the value is in feet and inches (one byte each). + +; The first filter is supposed to make very large Magikarp even rarer, +; by targeting those 1600 mm (= 5'3") or larger. +; After the conversion to feet, it is unable to target any, +; since the largest possible Magikarp is 5'3", and $0503 = 1283 mm. + ld a, [wTempEnemyMonSpecies] + cp MAGIKARP + jr nz, .Happiness + +; Get Magikarp's length + ld de, wEnemyMonDVs + ld bc, wPlayerID + callfar CalcMagikarpLength + +; No reason to keep going if length > 1536 mm (i.e. if HIGH(length) > 6 feet) + ld a, [wMagikarpLength] + cp HIGH(1536) ; should be "cp 5", since 1536 mm = 5'0", but HIGH(1536) = 6 + jr nz, .CheckMagikarpArea + +; 5% chance of skipping both size checks + call Random + cp 5 percent + jr c, .CheckMagikarpArea +; Try again if length >= 1616 mm (i.e. if LOW(length) >= 4 inches) + ld a, [wMagikarpLength + 1] + cp LOW(1616) ; should be "cp 4", since 1616 mm = 5'4", but LOW(1616) = 80 + jr nc, .GenerateDVs + +; 20% chance of skipping this check + call Random + cp 20 percent - 1 + jr c, .CheckMagikarpArea +; Try again if length >= 1600 mm (i.e. if LOW(length) >= 3 inches) + ld a, [wMagikarpLength + 1] + cp LOW(1600) ; should be "cp 3", since 1600 mm = 5'3", but LOW(1600) = 64 + jr nc, .GenerateDVs + +.CheckMagikarpArea: +; The "jr z" checks are supposed to be "jr 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 a minimum size in the Lake of Rage area. + +; Moreover, due to the check not being translated to feet+inches, all Magikarp +; smaller than 4'0" may be caught by the filter, a lot more than intended. + ld a, [wMapGroup] + cp GROUP_LAKE_OF_RAGE + jr z, .Happiness + ld a, [wMapNumber] + cp MAP_LAKE_OF_RAGE + jr z, .Happiness +; 40% chance of not flooring + call Random + cp 40 percent - 2 + jr c, .Happiness +; Try again if length < 1024 mm (i.e. if HIGH(length) < 3 feet) + ld a, [wMagikarpLength] + cp HIGH(1024) ; should be "cp 3", since 1024 mm = 3'4", but HIGH(1024) = 4 + jr c, .GenerateDVs ; try again + +; Finally done with DVs + +.Happiness: +; Set happiness + ld a, BASE_HAPPINESS + ld [wEnemyMonHappiness], a +; Set level + ld a, [wCurPartyLevel] + ld [wEnemyMonLevel], a +; Fill stats + ld de, wEnemyMonMaxHP + ld b, FALSE + ld hl, wEnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1) + predef CalcMonStats + +; 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, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .Moves + +.TreeMon: +; If we're headbutting trees, some monsters enter battle asleep + ld a, [wTempEnemyMonSpecies] + +; Hoothoot/Noctowl are asleep if MORN/DAY + cp HOOTHOOT + jr z, .sleeping_if_not_nite + cp NOCTOWL + jr z, .sleeping_if_not_nite + +; Pidgey/Spearow are asleep if NITE + cp PIDGEY + jr z, .sleeping_if_nite + cp SPEAROW + jr z, .sleeping_if_nite + +; Other species are never asleep + jr .not_sleeping + +.sleeping_if_not_nite + ld a, [wTimeOfDay] + cp NITE_F + jr nz, .sleeping + jr .not_sleeping + +.sleeping_if_nite + ld a, [wTimeOfDay] + cp NITE_F + jr z, .sleeping + jr .not_sleeping + +.sleeping + ld a, TREEMON_SLEEP_TURNS + jr .UpdateStatus + +.not_sleeping + xor a + +.UpdateStatus: + ld hl, wEnemyMonStatus + ld [hli], a + +; Unused byte + xor a + ld [hli], a + +; Full HP.. + ld a, [wEnemyMonMaxHP] + ld [hli], a + ld a, [wEnemyMonMaxHP + 1] + ld [hl], a + +; ..unless it's a RoamMon + ld a, [wBattleType] + 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 [wEnemyMonHP + 1], a + jr .Moves + +.InitRoamHP: +; HP only uses the lo byte in the RoamMon struct since +; Raikou and Entei will have < 256 hp at level 40 + ld a, [wEnemyMonHP + 1] + ld [hl], a + jr .Moves + +.OpponentParty: +; Get HP from the party struct + ld hl, (wOTPartyMon1HP + 1) + ld a, [wCurPartyMon] + call GetPartyLocation + ld a, [hld] + ld [wEnemyMonHP + 1], a + ld a, [hld] + ld [wEnemyMonHP], a + +; Make sure everything knows which monster the opponent is using + ld a, [wCurPartyMon] + ld [wCurOTMon], a + +; Get status from the party struct + dec hl + ld a, [hl] ; OTPartyMonStatus + ld [wEnemyMonStatus], a + +.Moves: + ld hl, wBaseType1 + ld de, wEnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + +; Get moves + ld de, wEnemyMonMoves +; Are we in a trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr nz, .WildMoves +; Then copy moves from the party struct + ld hl, wOTPartyMon1Moves + ld a, [wCurPartyMon] + call GetPartyLocation + ld bc, NUM_MOVES + call CopyBytes + jr .PP + +.WildMoves: +; Clear wEnemyMonMoves + 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, wEnemyMonMoves + ld de, wEnemyMonPP + predef FillPP + jr .Finish + +.TrainerPP: +; Copy PP from the party struct + ld hl, wOTPartyMon1PP + ld a, [wCurPartyMon] + call GetPartyLocation + ld de, wEnemyMonPP + ld bc, NUM_MOVES + call CopyBytes + +.Finish: +; Only the first five base stats are copied.. + ld hl, wBaseStats + ld de, wEnemyMonBaseStats + ld b, wBaseSpecialDefense - wBaseStats +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + + ld a, [wBaseCatchRate] + ld [de], a + inc de + + ld a, [wBaseExp] + ld [de], a + + ld a, [wTempEnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + + call GetPokemonName + +; Did we catch it? + ld a, [wBattleMode] + and a + ret z + +; Update enemy nick + ld hl, wStringBuffer1 + ld de, wEnemyMonNick + ld bc, MON_NAME_LENGTH + call CopyBytes + +; Saw this mon + ld a, [wTempEnemyMonSpecies] + dec a + ld c, a + ld b, SET_FLAG + ld hl, wPokedexSeen + predef SmallFarFlagAction + + ld hl, wEnemyMonStats + ld de, wEnemyStats + ld bc, wEnemyMonStatsEnd - wEnemyMonStats + call CopyBytes + + ret + +CheckUnownLetter: +; Return carry if the Unown letter hasn't been unlocked yet + + ld a, [wUnlockedUnowns] + 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, UnlockedUnownLetterSets + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + push de + ld a, [wUnownLetter] + 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 UnlockedUnownLetterSets.End - UnlockedUnownLetterSets + jr c, .loop + +; Hasn't been unlocked, or the letter is invalid + scf + ret + +.match +; Valid letter + and a + ret + +INCLUDE "data/wild/unlocked_unowns.asm" + +Unreferenced_SwapBattlerLevels: + push bc + ld a, [wBattleMonLevel] + ld b, a + ld a, [wEnemyMonLevel] + ld [wBattleMonLevel], a + ld a, b + ld [wEnemyMonLevel], a + pop bc + ret + +BattleWinSlideInEnemyTrainerFrontpic: + xor a + ld [wTempEnemyMonSpecies], a + call FinishBattleAnim + ld a, [wOtherTrainerClass] + ld [wTrainerClass], 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 + ldh [hBGMapMode], a + ldh [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 + ldh [hBGMapMode], a + ld c, 4 + call DelayFrames + pop hl + pop bc + dec hl + jr .outer_loop + +.CopyColumn: + push hl + push de + push bc + ld e, 7 + +.loop + ld [hl], d + ld bc, SCREEN_WIDTH + add hl, bc + inc d + dec e + jr nz, .loop + + pop bc + pop de + pop hl + ret + +ApplyStatusEffectOnPlayerStats: + ld a, 1 + jr ApplyStatusEffectOnStats + +ApplyStatusEffectOnEnemyStats: + xor a + +ApplyStatusEffectOnStats: + ldh [hBattleTurn], a + call ApplyPrzEffectOnSpeed + jp ApplyBrnEffectOnAttack + +ApplyPrzEffectOnSpeed: + ldh a, [hBattleTurn] + and a + jr z, .enemy + ld a, [wBattleMonStatus] + and 1 << PAR + ret z + ld hl, wBattleMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min speed + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [wEnemyMonStatus] + and 1 << PAR + ret z + ld hl, wEnemyMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min speed + +.enemy_ok + ld [hl], b + ret + +ApplyBrnEffectOnAttack: + ldh a, [hBattleTurn] + and a + jr z, .enemy + ld a, [wBattleMonStatus] + and 1 << BRN + ret z + ld hl, wBattleMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min attack + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [wEnemyMonStatus] + and 1 << BRN + ret z + ld hl, wEnemyMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min attack + +.enemy_ok + ld [hl], b + ret + +ApplyStatLevelMultiplierOnAllStats: +; Apply StatLevelMultipliers on all 5 Stats + ld c, 0 +.stat_loop + call ApplyStatLevelMultiplier + inc c + ld a, c + cp NUM_BATTLE_STATS + jr nz, .stat_loop + ret + +ApplyStatLevelMultiplier: + push bc + push bc + ld a, [wApplyStatLevelMultipliersToEnemy] + and a + ld a, c + ld hl, wBattleMonAttack + ld de, wPlayerStats + ld bc, wPlayerAtkLevel + jr z, .got_pointers + ld hl, wEnemyMonAttack + ld de, wEnemyStats + ld bc, wEnemyAtkLevel + +.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_Applied + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + xor a + ldh [hMultiplicand + 0], a + ld a, [de] + ldh [hMultiplicand + 1], a + inc de + ld a, [de] + ldh [hMultiplicand + 2], a + ld a, [hli] + ldh [hMultiplier], a + call Multiply + ld a, [hl] + ldh [hDivisor], a + ld b, 4 + call Divide + pop hl + +; Cap at 999. + ldh a, [hQuotient + 3] + sub LOW(MAX_STAT_VALUE) + ldh a, [hQuotient + 2] + sbc HIGH(MAX_STAT_VALUE) + jp c, .okay3 + + ld a, HIGH(MAX_STAT_VALUE) + ldh [hQuotient + 2], a + ld a, LOW(MAX_STAT_VALUE) + ldh [hQuotient + 3], a + +.okay3 + ldh a, [hQuotient + 2] + ld [hli], a + ld b, a + ldh a, [hQuotient + 3] + ld [hl], a + or b + jr nz, .okay4 + inc [hl] + +.okay4 + pop bc + ret + +INCLUDE "data/battle/stat_multipliers_2.asm" + +BadgeStatBoosts: +; Raise the stats of the battle mon in wBattleMon +; depending on which badges have been obtained. + +; Every other badge boosts a stat, starting from the first. +; GlacierBadge also boosts Special Defense, although the relevant code is buggy (see below). + +; ZephyrBadge: Attack +; PlainBadge: Speed +; MineralBadge: Defense +; GlacierBadge: Special Attack and 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, [wJohtoBadges] + +; 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, wBattleMonAttack + 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 +; Check GlacierBadge again for Special Defense. +; This check is buggy because it assumes that a is set by the "ld a, b" in the above loop, +; but it can actually be overwritten by the call to BoostStat. + srl a + call c, BoostStat + ret + +BoostStat: +; 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 + +_LoadBattleFontsHPBar: + callfar LoadBattleFontsHPBar + ret + +_LoadHPBar: + callfar LoadHPBar + ret + +Unreferenced_LoadHPExpBarGFX: + 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 + +EmptyBattleTextbox: + ld hl, .empty + jp PrintText + +.empty: + text_end + +_BattleRandom:: +; If the normal RNG is used in a link battle it'll desync. +; To circumvent this a shared PRNG is used instead. + +; But if we're in a non-link battle we're safe to use it + ld a, [wLinkMode] + and a + jp z, Random + +; The PRNG operates in streams of 10 values. + +; Which value are we trying to pull? + push hl + push bc + ld a, [wLinkBattleRNCount] + ld c, a + ld b, 0 + ld hl, wLinkBattleRNs + add hl, bc + inc a + ld [wLinkBattleRNCount], a + +; If we haven't hit the end yet, we're good + cp 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 [wLinkBattleRNCount], a + ld hl, wLinkBattleRNs + 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 + +Call_PlayBattleAnim_OnlyIfVisible: + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz + +Call_PlayBattleAnim: + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 1], a + call WaitBGMap + predef_jump PlayBattleAnim + +FinishBattleAnim: + 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 + +GiveExperiencePoints: +; Give experience. +; Don't give experience if linked or in the Battle Tower. + ld a, [wLinkMode] + and a + ret nz + + call .EvenlyDivideExpAmongParticipants + xor a + ld [wCurPartyMon], a + ld bc, wPartyMon1Species + +.loop + ld hl, MON_HP + add hl, bc + ld a, [hli] + or [hl] + jp z, .next_mon ; fainted + + push bc + ld hl, wBattleParticipantsNotFainted + ld a, [wCurPartyMon] + ld c, a + ld b, CHECK_FLAG + ld d, 0 + predef SmallFarFlagAction + ld a, c + and a + pop bc + jp z, .next_mon + +; give stat exp + ld hl, MON_STAT_EXP + 1 + add hl, bc + ld d, h + ld e, l + ld hl, wEnemyMonBaseStats - 1 + push bc + ld c, NUM_EXP_STATS +.stat_exp_loop + inc hl + ld a, [de] + add [hl] + ld [de], a + jr nc, .no_carry_stat_exp + dec de + ld a, [de] + inc a + jr z, .stat_exp_maxed_out + ld [de], a + inc de + +.no_carry_stat_exp + push hl + push bc + ld a, MON_PKRUS + call GetPartyParamLocation + ld a, [hl] + and a + pop bc + pop hl + jr z, .stat_exp_awarded + ld a, [de] + add [hl] + ld [de], a + jr nc, .stat_exp_awarded + dec de + ld a, [de] + inc a + jr z, .stat_exp_maxed_out + ld [de], a + inc de + jr .stat_exp_awarded + +.stat_exp_maxed_out + ld a, $ff + ld [de], a + inc de + ld [de], a + +.stat_exp_awarded + inc de + inc de + dec c + jr nz, .stat_exp_loop + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, [wEnemyMonBaseExp] + ldh [hMultiplicand + 2], a + ld a, [wEnemyMonLevel] + ldh [hMultiplier], a + call Multiply + ld a, 7 + ldh [hDivisor], a + ld b, 4 + call Divide +; Boost Experience for traded Pokemon + pop bc + ld hl, MON_ID + add hl, bc + ld a, [wPlayerID] + cp [hl] + jr nz, .boosted + inc hl + ld a, [wPlayerID + 1] + cp [hl] + ld a, 0 + jr z, .no_boost + +.boosted + call BoostExp + ld a, 1 + +.no_boost +; Boost experience for a Trainer Battle + ld [wStringBuffer2 + 2], a + ld a, [wBattleMode] + dec a + call nz, BoostExp +; Boost experience for Lucky Egg + push bc + ld a, MON_ITEM + call GetPartyParamLocation + ld a, [hl] + cp LUCKY_EGG + call z, BoostExp + ldh a, [hQuotient + 3] + ld [wStringBuffer2 + 1], a + ldh a, [hQuotient + 2] + ld [wStringBuffer2], a + ld a, [wCurPartyMon] + ld hl, wPartyMonNicknames + call GetNick + ld hl, Text_MonGainedExpPoint + call PrintText + ld a, [wStringBuffer2 + 1] + ldh [hQuotient + 3], a + ld a, [wStringBuffer2] + ldh [hQuotient + 2], a + pop bc + call AnimateExpBar + push bc + call LoadTilemapToTempTilemap + pop bc + ld hl, MON_EXP + 2 + add hl, bc + ld d, [hl] + ldh a, [hQuotient + 3] + add d + ld [hld], a + ld d, [hl] + ldh a, [hQuotient + 2] + adc d + ld [hl], a + jr nc, .no_exp_overflow + dec hl + inc [hl] + +.no_exp_overflow + ld a, [wCurPartyMon] + ld e, a + ld d, 0 + ld hl, wPartySpecies + add hl, de + ld a, [hl] + ld [wCurSpecies], a + call GetBaseData + push bc + ld d, MAX_LEVEL + callfar CalcExpAtLevel + pop bc + ld hl, MON_EXP + 2 + add hl, bc + push bc + ldh a, [hQuotient + 1] + ld b, a + ldh a, [hQuotient + 2] + ld c, a + ldh a, [hQuotient + 3] + ld d, a + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .not_max_exp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.not_max_exp +; Check if the mon leveled up + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + callfar CalcLevel + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + cp d + jp z, .next_mon +; <NICKNAME> grew to level ##! + ld [wTempLevel], a + ld a, [wCurPartyLevel] + push af + ld a, d + ld [wCurPartyLevel], a + ld [hl], a + ld hl, MON_SPECIES + add hl, bc + ld a, [hl] + ld [wCurSpecies], a + ld [wTempSpecies], a ; unused? + call GetBaseData + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + ld e, a + ld d, [hl] + push de + ld hl, MON_MAXHP + add hl, bc + ld d, h + ld e, l + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld b, TRUE + predef CalcMonStats + pop bc + pop de + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + sub e + ld e, a + ld a, [hl] + sbc d + ld d, a + dec hl + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hl], a + ld a, [wCurBattleMon] + ld d, a + ld a, [wCurPartyMon] + cp d + jr nz, .skip_active_mon_update + ld de, wBattleMonHP + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld de, wBattleMonMaxHP + push bc + ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP + call CopyBytes + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [wBattleMonLevel], a + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, MON_ATK + add hl, bc + ld de, wPlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + +.transformed + xor a ; FALSE + ld [wApplyStatLevelMultipliersToEnemy], a + call ApplyStatLevelMultiplierOnAllStats + callfar ApplyStatusEffectOnPlayerStats + callfar BadgeStatBoosts + callfar UpdatePlayerHUD + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + ld a, $1 + ldh [hBGMapMode], a + +.skip_active_mon_update + ; level up happiness mod + ld c, 1 + callfar ChangeHappiness + ld a, [wCurBattleMon] + ld b, a + ld a, [wCurPartyMon] + cp b + jr z, .skip_exp_bar_animation + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextbox + call LoadTilemapToTempTilemap + +.skip_exp_bar_animation + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + hlcoord 9, 0 + ld b, 10 + ld c, 9 + call Textbox + hlcoord 11, 1 + ld bc, 4 + predef PrintTempMonStats + ld c, 30 + call DelayFrames + call WaitPressAorB_BlinkCursor + call SafeLoadTempTilemapToTilemap + xor a ; PARTYMON + ld [wMonType], a + ld a, [wCurSpecies] + ld [wTempSpecies], a ; unused? + ld a, [wCurPartyLevel] + push af + ld c, a + ld a, [wTempLevel] + ld b, a + +.level_loop + inc b + ld a, b + ld [wCurPartyLevel], a + push bc + predef LearnLevelMoves + pop bc + ld a, b + cp c + jr nz, .level_loop + pop af + ld [wCurPartyLevel], a + ld hl, wEvolvableFlags + ld a, [wCurPartyMon] + ld c, a + ld b, SET_FLAG + predef SmallFarFlagAction + pop af + ld [wCurPartyLevel], a + +.next_mon + ld a, [wPartyCount] + ld b, a + ld a, [wCurPartyMon] + inc a + cp b + jr z, .done + ld [wCurPartyMon], a + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + jp .loop + +.done + jp ResetBattleParticipants + +.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 [wTempByteValue], a + ld hl, wEnemyMonBaseStats + ld c, wEnemyMonEnd - wEnemyMonBaseStats +.base_stat_division_loop + xor a + ldh [hDividend + 0], a + ld a, [hl] + ldh [hDividend + 1], a + ld a, [wTempByteValue] + ldh [hDivisor], a + ld b, 2 + call Divide + ldh a, [hQuotient + 3] + ld [hli], a + dec c + jr nz, .base_stat_division_loop + ret + +BoostExp: +; Multiply experience by 1.5x + push bc +; load experience value + ldh a, [hProduct + 2] + ld b, a + ldh a, [hProduct + 3] + ld c, a +; halve it + srl b + rr c +; add it back to the whole exp value + add c + ldh [hProduct + 3], a + ldh a, [hProduct + 2] + adc b + ldh [hProduct + 2], a + pop bc + ret + +Text_MonGainedExpPoint: + text_far Text_Gained + text_asm + ld hl, ExpPointsText + ld a, [wStringBuffer2 + 2] ; IsTradedMon + and a + ret z + + ld hl, BoostedExpPointsText + ret + +BoostedExpPointsText: + text_far _BoostedExpPointsText + text_end + +ExpPointsText: + text_far _ExpPointsText + text_end + +AnimateExpBar: + push bc + + ld hl, wCurPartyMon + ld a, [wCurBattleMon] + cp [hl] + jp nz, .finish + + ld a, [wBattleMonLevel] + cp MAX_LEVEL + jp z, .finish + + ldh a, [hProduct + 3] + ld [wceef], a + push af + ldh a, [hProduct + 2] + ld [wceee], a + push af + xor a + ld [wceed], a + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + ld a, [wTempMonLevel] + ld b, a + ld e, a + push de + ld de, wTempMonExp + 2 + call CalcExpBar + push bc + ld hl, wTempMonExp + 2 + ld a, [wceef] + add [hl] + ld [hld], a + ld a, [wceee] + adc [hl] + ld [hld], a + jr nc, .NoOverflow + inc [hl] + +.NoOverflow: + ld d, MAX_LEVEL + callfar CalcExpAtLevel + ldh a, [hProduct + 1] + ld b, a + ldh a, [hProduct + 2] + ld c, a + ldh a, [hProduct + 3] + ld d, a + ld hl, wTempMonExp + 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 + +.LoopLevels: + ld a, e + cp d + jr z, .FinishExpBar + inc a + ld [wTempMonLevel], a + ld [wCurPartyLevel], a + ld [wBattleMonLevel], a + push de + call .PlayExpBarSound + ld c, $40 + call .LoopBarAnimation + call PrintPlayerHUD + ld hl, wBattleMonNick + ld de, wStringBuffer1 + ld bc, MON_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, wTempMonExp + 2 + call CalcExpBar + ld a, b + pop bc + ld c, a + call .PlayExpBarSound + call .LoopBarAnimation + call TerminateExpBarSound + pop af + ldh [hProduct + 2], a + pop af + ldh [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 + ldh [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ldh [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 + ldh [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ldh [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 + ldh [hBGMapMode], a + ret + +SendOutMonText: + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld hl, JumpText_GoMon ; 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 mon, the game prints a different text + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + ld hl, JumpText_GoMon + jr z, .skip_to_textbox + + ; compute enemy helth remaining as a percentage + xor a + ldh [hMultiplicand + 0], a + ld hl, wEnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ldh [hMultiplicand + 1], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ldh [hMultiplicand + 2], a + ld a, 25 + ldh [hMultiplier], a + call Multiply + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ldh [hDivisor], a + call Divide + + ldh a, [hQuotient + 3] + ld hl, JumpText_GoMon + cp 70 + jr nc, .skip_to_textbox + + ld hl, JumpText_DoItMon + cp 40 + jr nc, .skip_to_textbox + + ld hl, JumpText_GoForItMon + cp 10 + jr nc, .skip_to_textbox + + ld hl, JumpText_YourFoesWeakGetmMon +.skip_to_textbox + jp PrintText + +JumpText_GoMon: + text_far Text_GoMon + text_end + +JumpText_DoItMon: + text_far Text_DoItMon + text_end + +JumpText_GoForItMon: + text_far Text_GoForItMon + text_end + +JumpText_YourFoesWeakGetmMon: + text_far Text_YourFoesWeakGetmMon + text_end + +WithdrawMonText: + ld hl, .WithdrawMonText + jp PrintText + +.WithdrawMonText: + text_far Text_BattleMonNickComma + text_asm +; Print text to withdraw mon +; depending on HP the message is different + push de + push bc + ld hl, wEnemyMonHP + 1 + ld de, wEnemyHPAtTimeOfPlayerSwitch + 1 + ld b, [hl] + dec hl + ld a, [de] + sub b + ldh [hMultiplicand + 2], a + dec de + ld b, [hl] + ld a, [de] + sbc b + ldh [hMultiplicand + 1], a + ld a, 25 + ldh [hMultiplier], a + call Multiply + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ldh [hDivisor], a + call Divide + pop bc + pop de + ldh a, [hQuotient + 3] + ld hl, ThatsEnoughComeBackText + and a + ret z + + ld hl, ComeBackText + cp 30 + ret c + + ld hl, OKComeBackText + cp 70 + ret c + + ld hl, GoodComeBackText + ret + +ThatsEnoughComeBackText: + text_far _ThatsEnoughComeBackText + text_end + +OKComeBackText: + text_far _OKComeBackText + text_end + +GoodComeBackText: + text_far _GoodComeBackText + text_end + +ComeBackText: + text_far _ComeBackText + text_end + +Unreferenced_HandleSafariAngerEatingStatus: + ld hl, wSafariMonEating + ld a, [hl] + and a + jr z, .angry + dec [hl] + ld hl, BattleText_WildMonIsEating + jr .finish + +.angry + dec hl ; wSafariMonAngerCount + ld a, [hl] + and a + ret z + dec [hl] + ld hl, BattleText_WildMonIsAngry + jr nz, .finish + push hl + ld a, [wEnemyMonSpecies] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseCatchRate] + ld [wEnemyMonCatchRate], a + pop hl + +.finish + push hl + call SafeLoadTempTilemapToTilemap + pop hl + jp StdBattleTextbox + +FillInExpBar: + push hl + call CalcExpBar + pop hl + ld de, 7 + add hl, de + jp PlaceExpBar + +CalcExpBar: +; 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] + ldh [hMathBuffer + 2], a + pop bc + sub b + ld [hld], a + ld a, [hl] + ldh [hMathBuffer + 1], a + pop bc + sbc b + ld [hld], a + ld a, [hl] + ldh [hMathBuffer], a + pop bc + sbc b + ld [hl], a + pop de + + ld hl, hMultiplicand + 1 + ld a, [hli] + push af + ld a, [hl] + push af + +; get the amount of exp remaining to the next level + ld a, [de] + dec de + ld c, a + ldh a, [hMathBuffer + 2] + sub c + ld [hld], a + ld a, [de] + dec de + ld b, a + ldh a, [hMathBuffer + 1] + sbc b + ld [hld], a + ld a, [de] + ld c, a + ldh a, [hMathBuffer] + sbc c + ld [hld], a + xor a + ld [hl], a + ld a, 64 + ldh [hMultiplier], a + call Multiply + pop af + ld c, a + pop af + ld b, a +.loop + ld a, b + and a + jr z, .done + srl b + rr c + ld hl, hProduct + srl [hl] + inc hl + rr [hl] + inc hl + rr [hl] + inc hl + rr [hl] + jr .loop + +.done + ld a, c + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld b, a + ld a, $40 + sub b + ld b, a + ret + +PlaceExpBar: + 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 + +GetBattleMonBackpic: + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetBattleMonBackpic_DoAnim ; substitute + +DropPlayerSub: + ld a, [wPlayerMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetBattleMonBackpic_DoAnim + ld a, [wCurPartySpecies] + push af + ld a, [wBattleMonSpecies] + ld [wCurPartySpecies], a + ld hl, wBattleMonDVs + predef GetUnownLetter + ld de, vTiles2 tile $31 + predef GetMonBackpic + pop af + ld [wCurPartySpecies], a + ret + +GetBattleMonBackpic_DoAnim: + ldh a, [hBattleTurn] + push af + xor a + ldh [hBattleTurn], a + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ldh [hBattleTurn], a + ret + +GetEnemyMonFrontpic: + ld a, [wEnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetEnemyMonFrontpic_DoAnim + +DropEnemySub: + ld a, [wEnemyMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetEnemyMonFrontpic_DoAnim + + ld a, [wCurPartySpecies] + push af + ld a, [wEnemyMonSpecies] + ld [wCurSpecies], a + ld [wCurPartySpecies], a + call GetBaseData + ld hl, wEnemyMonDVs + predef GetUnownLetter + ld de, vTiles2 + predef GetMonFrontpic + pop af + ld [wCurPartySpecies], a + ret + +GetEnemyMonFrontpic_DoAnim: + ldh a, [hBattleTurn] + push af + call SetEnemyTurn + ld a, BANK(BattleAnimCmd_MinimizeOpp) + rst FarCall + pop af + ldh [hBattleTurn], a + ret + +StartBattle: +; 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, [wPartyCount] + and a + ret z + + ld a, [wOtherTrainerClass] + and a + jr nz, .battle_intro + + ld a, [wTempWildMonSpecies] + ld [wCurPartySpecies], a + +.battle_intro + ld [wTempEnemyMonSpecies], a + ld a, [wTimeOfDayPal] + push af + xor a + ldh [hMapAnims], a + xor a + ld [wTempBattleMonSpecies], a + ld [wBattleMenuCursorBuffer], a + farcall PlayBattleMusic + ld a, 0 + ld [wSpriteUpdatesEnabled], a + call ShowLinkBattleParticipants + farcall ClearBattleRAM + ld hl, rLCDC + res rLCDC_WINDOW_TILEMAP, [hl] ; select 9800-9BFF + ld a, [wOtherTrainerClass] + and a + jr nz, .trainer + + call InitEnemyWildmon + jr .back_up_bgmap2 + +.trainer + call InitEnemyTrainer + +.back_up_bgmap2 + ld b, 0 + call GetSGBLayout + ld hl, wVramState + res 0, [hl] + call InitBattleDisplay + call BattleStartMessage + xor a + ldh [hBGMapMode], a + ld hl, rLCDC + set rLCDC_WINDOW_TILEMAP, [hl] ; select 9C00-9FFF + call EmptyBattleTextbox + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call ClearSprites + ld a, [wEnemyMonEnd] + cp WILD_BATTLE + call z, UpdateEnemyHUD + ld a, $1 + ldh [hBGMapMode], a + call DoBattle + call ExitBattle + pop af + ld [wTimeOfDayPal], a + scf + ret + +InitEnemyTrainer: + ld [wTrainerClass], a + xor a + ld [wTempEnemyMonSpecies], a + callfar GetTrainerAttributes + callfar ReadTrainerParty + + ; RIVAL1's first mon has no held item + ld a, [wTrainerClass] + cp RIVAL1 + jr nz, .ok + xor a + ld [wOTPartyMon1Item], a + +.ok: + ld de, vTiles2 + callfar GetTrainerPic + xor a + ldh [hGraphicStartTile], a + dec a + ld [wEnemyItemState], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ld a, -1 + ld [wCurOTMon], a + ld a, TRAINER_BATTLE + ld [wBattleMode], a + + call IsGymLeader + jr nc, .done + xor a + ld [wCurPartyMon], a + ld a, [wPartyCount] + 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, wCurPartyMon + inc [hl] + jr .partyloop +.done + ret + +InitEnemyWildmon: + ld a, WILD_BATTLE + ld [wBattleMode], a + call LoadEnemyMon + ld hl, wEnemyMonMoves + ld de, wWildMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld hl, wEnemyMonPP + ld de, wWildMonPP + ld bc, NUM_MOVES + call CopyBytes + ld hl, wEnemyMonDVs + predef GetUnownLetter + ld a, [wCurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld a, [wUnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + ld de, vTiles2 + predef GetMonFrontpic + xor a + ld [wTrainerClass], a + ldh [hGraphicStartTile], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ret + +Unreferenced_Function3f41a: + ld hl, wEnemyMonMoves + 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, wEnemyMonPP - (wEnemyMonMoves + 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, wEnemyMonPP - (wEnemyMonMoves + 1) + add hl, bc + xor a + ld [hl], a + pop hl + pop bc + dec b + jr nz, .clear + ret + +ExitBattle: + call IsLinkBattle + jr nz, .handle_end_of_battle + call ShowLinkBattleParticipantsAfterEnd + jr .clean_up_battle_ram + +.handle_end_of_battle + ld a, [wBattleResult] + and $f + jr nz, .clean_up_battle_ram + ; WIN + call CheckPayDay + xor a + ld [wForceEvolution], a + predef EvolveAfterBattle + farcall GivePokerusAndConvertBerries + +.clean_up_battle_ram + call BattleEnd_HandleRoamMons + xor a + ld [wLowHealthAlarm], a + ld [wBattleMode], a + ld [wBattleType], a + ld [wAttackMissed], a + ld [wTempWildMonSpecies], a + ld [wOtherTrainerClass], a + ld [wFailedToFlee], a + ld [wNumFleeAttempts], a + ld [wForcedSwitch], a + ld [wPartyMenuCursor], a + ld [wKeyItemsPocketCursor], a + ld [wItemsPocketCursor], a + ld [wBattleMenuCursorBuffer], a + ld [wCurMoveNum], a + ld [wBallsPocketCursor], a + ld [wLastPocket], a + ld [wMenuScrollPosition], a + ld [wKeyItemsPocketScrollPosition], a + ld [wItemsPocketScrollPosition], a + ld [wBallsPocketScrollPosition], a + ld hl, wPlayerSubStatus1 + ld b, wEnemyFuryCutterCount - wPlayerSubStatus1 +.loop + ld [hli], a + dec b + jr nz, .loop + call WaitSFX + ret + +CheckPayDay: + 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, wMoney + 2 + call AddBattleMoneyToAccount + ld hl, BattleText_PlayerPickedUpPayDayMoney + call StdBattleTextbox + ret + +PlayerPickedUpPayDayMoney: + text_far _PlayerPickedUpPayDayMoney + text_end + +ShowLinkBattleParticipantsAfterEnd: + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + call GetPartyLocation + ld a, [wEnemyMonStatus] + ld [hl], a + call ClearTilemap + farcall _ShowLinkBattleParticipants + ld a, [wBattleResult] + and $f + cp LOSE + ld de, .Win + jr c, .store_result + ld de, .Lose + jr z, .store_result + ; DRAW + ld de, .Draw + +.store_result + hlcoord 6, 8 + call PlaceString + ld c, 200 + call DelayFrames + + ld a, BANK(sLinkBattleStats) + call OpenSRAM + + call AddLastLinkBattleToLinkRecord + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + + call WaitPressAorB_BlinkCursor + call ClearTilemap + ret + +.Win: + db "YOU WIN@" +.Lose: + db "YOU LOSE@" +.Draw: + db " DRAW@" + +LINK_BATTLE_RECORD_LENGTH EQUS "(sLinkBattleRecord1End - sLinkBattleRecord1)" ; 18 +NUM_LINK_BATTLE_RECORDS EQUS "((sLinkBattleStatsEnd - sLinkBattleRecord) / LINK_BATTLE_RECORD_LENGTH)" ; 5 + +_DisplayLinkRecord: + ld a, BANK(sLinkBattleStats) + call OpenSRAM + + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + hlcoord 0, 0, wAttrmap + 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 + +ReadAndPrintLinkBattleRecord: + call ClearTilemap + call ClearSprites + call .PrintBattleRecord + hlcoord 0, 8 + ld b, NUM_LINK_BATTLE_RECORDS + 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, wceed + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld a, "@" + ld [de], a + inc de + ld bc, 6 + call CopyBytes + ld de, wceed + pop hl + call PlaceString + pop hl + ld de, 26 + add hl, de + push hl + ld de, wcef8 + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + push hl + ld de, wcefa + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + ld de, wcefc + lb bc, 2, 4 + call PrintNum + jr .next + +.PrintFormatString: + ld de, .Format + call PlaceString +.next + pop hl + ld bc, LINK_BATTLE_RECORD_LENGTH + 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 + + 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 + ret + +.Scores: + db "<NULL><NULL>" +.Format: + db " --- <LF>" + db " - - -@" +.Record: + db "<PLAYER>'s RECORD@" +.Result: + db "RESULT WIN LOSE DRAW@" +.Total: + db "TOTAL WIN LOSE DRAW@" + +BattleEnd_HandleRoamMons: + ld a, [wBattleType] + cp BATTLETYPE_ROAMING + jr nz, .not_roaming + ld a, [wBattleResult] + and $f + jr z, .caught_or_defeated_roam_mon ; WIN + call GetRoamMonHP + ld a, [wEnemyMonHP + 1] + ld [hl], a + jr .update_roam_mons + +.caught_or_defeated_roam_mon + call GetRoamMonHP + ld [hl], 0 + call GetRoamMonMapGroup + ld [hl], GROUP_N_A + call GetRoamMonMapNumber + ld [hl], MAP_N_A + call GetRoamMonSpecies + ld [hl], 0 + ret + +.not_roaming + call BattleRandom + and $f + ret nz + +.update_roam_mons + callfar UpdateRoamMons + ret + +GetRoamMonMapGroup: + ld a, [wTempEnemyMonSpecies] + 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 + +GetRoamMonMapNumber: + ld a, [wTempEnemyMonSpecies] + 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 + +GetRoamMonHP: +; output: hl = wRoamMonHP + ld a, [wTempEnemyMonSpecies] + 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 + +GetRoamMonDVs: +; output: hl = wRoamMonDVs + ld a, [wTempEnemyMonSpecies] + 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 + +GetRoamMonSpecies: + ld a, [wTempEnemyMonSpecies] + ld hl, wRoamMon1Species + cp [hl] + ret z + ld hl, wRoamMon2Species + cp [hl] + ret z + ld hl, wRoamMon3Species + ret + +AddLastLinkBattleToLinkRecord: + ld hl, wOTPlayerID + ld de, wStringBuffer1 + ld bc, 2 + call CopyBytes + ld hl, wOTPlayerName + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld hl, sLinkBattleStats - (LINK_BATTLE_RECORD_LENGTH - 6) + call .StoreResult + ld hl, sLinkBattleRecord + ld d, NUM_LINK_BATTLE_RECORDS +.loop + push hl + inc hl + inc hl + ld a, [hl] + dec hl + dec hl + and a + jr z, .copy + push de + ld bc, LINK_BATTLE_RECORD_LENGTH - 6 + ld de, wStringBuffer1 + call CompareBytesLong + pop de + pop hl + jr c, .done + ld bc, LINK_BATTLE_RECORD_LENGTH + add hl, bc + dec d + jr nz, .loop + ld bc, -LINK_BATTLE_RECORD_LENGTH + add hl, bc + push hl + +.copy + ld d, h + ld e, l + ld hl, wStringBuffer1 + ld bc, LINK_BATTLE_RECORD_LENGTH - 6 + 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 +.StoreResult: + ld a, [wBattleResult] + and $f + cp LOSE + ld bc, (sLinkBattleRecord1Wins - sLinkBattleRecord1) + 1 + jr c, .okay ; WIN + ld bc, (sLinkBattleRecord1Losses - sLinkBattleRecord1) + 1 + jr z, .okay ; LOSE + ; DRAW + ld bc, (sLinkBattleRecord1Draws - sLinkBattleRecord1) + 1 +.okay + add hl, bc + call .CheckOverflow + ret nc + inc [hl] + ret nz + dec hl + inc [hl] + ret + +.CheckOverflow: + dec hl + ld a, [hl] + inc hl + cp HIGH(MAX_LINK_RECORD) + ret c + ld a, [hl] + cp LOW(MAX_LINK_RECORD) + ret + +.FindOpponentAndAppendRecord: + ld b, NUM_LINK_BATTLE_RECORDS + ld hl, sLinkBattleRecord1End - 1 + ld de, wceed +.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, LINK_BATTLE_RECORD_LENGTH + 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, wceed + add hl, de + push hl + ld a, c + add c + add c + ld e, a + ld d, $0 + ld hl, wceed + add hl, de + ld d, h + ld e, l + pop hl + push bc + ld c, 3 + call CompareBytes + 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, LINK_BATTLE_RECORD_LENGTH + ld hl, sLinkBattleRecord + call AddNTimes + push hl + ld de, wceed + ld bc, LINK_BATTLE_RECORD_LENGTH + call CopyBytes + pop hl + pop bc + push hl + ld a, c + ld bc, LINK_BATTLE_RECORD_LENGTH + ld hl, sLinkBattleRecord + call AddNTimes + pop de + push hl + ld bc, LINK_BATTLE_RECORD_LENGTH + call CopyBytes + ld hl, wceed + ld bc, LINK_BATTLE_RECORD_LENGTH + pop de + call CopyBytes + ret + +.LoadPointer: + 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 + +InitBattleDisplay: + call InitBackPic + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call Textbox + hlcoord 1, 5 + lb bc, 3, 7 + call ClearBox + call LoadStandardFont + call _LoadBattleFontsHPBar + call .BlankBGMap + xor a + ldh [hMapAnims], a + ldh [hSCY], a + ld a, $90 + ldh [hWY], a + ldh [rWY], a + call WaitBGMap + xor a + ldh [hBGMapMode], a + call BattleIntroSlidingPics + ld a, $1 + ldh [hBGMapMode], a + ld a, $31 + ldh [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + xor a + ldh [hWY], a + ldh [rWY], a + call WaitBGMap + call HideSprites + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + ld a, $90 + ldh [hWY], a + xor a + ldh [hSCX], a + ret + +.BlankBGMap: + ld a, BANK(sDecompressScratch) + call OpenSRAM + + ld hl, sDecompressScratch + ld bc, sScratchAttrmap - sDecompressScratch + ld a, " " + call ByteFill + + ld de, sDecompressScratch + hlbgcoord 0, 0 + lb bc, BANK(.BlankBGMap), $40 + call Request2bpp + call CloseSRAM + ret + +INCLUDE "engine/battle/sliding_intro.asm" + +InitBackPic: + call GetTrainerBackpic + call CopyBackpic + ret + +GetTrainerBackpic: + ld hl, ChrisBackpic + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jr nz, .ok + ld hl, DudeBackpic + +.ok: + ld de, vTiles2 tile $31 + ld b, BANK(ChrisBackpic) + ld c, 7 * 7 + predef DecompressGet2bpp + ret + +CopyBackpic: + ld a, BANK(sDecompressBuffer) + call OpenSRAM + ld hl, vTiles3 + ld de, sDecompressBuffer + ldh a, [hROMBank] + ld b, a + ld c, 7 * 7 + call Request2bpp + call CloseSRAM + call .LoadTrainerBackpicAsOAM + ld a, 7 * 7 + ldh [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + ret + +.LoadTrainerBackpicAsOAM: + ld hl, wVirtualOAMSprite00 + xor a + ldh [hMapObjectIndexBuffer], a + ld b, 6 + ld e, (SCREEN_WIDTH + 1) * TILE_WIDTH +.outer_loop + ld c, 3 + ld d, 8 * TILE_WIDTH +.inner_loop + ld [hl], d ; y + inc hl + ld [hl], e ; x + inc hl + ldh a, [hMapObjectIndexBuffer] + ld [hli], a ; tile id + inc a + ldh [hMapObjectIndexBuffer], a + ld a, PAL_BATTLE_OB_PLAYER + ld [hli], a ; attributes + ld a, d + add 1 * TILE_WIDTH + ld d, a + dec c + jr nz, .inner_loop + ldh a, [hMapObjectIndexBuffer] + add $3 + ldh [hMapObjectIndexBuffer], a + ld a, e + add 1 * TILE_WIDTH + ld e, a + dec b + jr nz, .outer_loop + ret + +ChrisBackpic: +INCBIN "gfx/player/chris_back.2bpp.lz" + +DudeBackpic: +INCBIN "gfx/battle/dude.2bpp.lz" + +BattleStartMessage: + ld a, [wBattleMode] + dec a + jr z, .wild + + ld de, SFX_SHINE + call PlaySFX + call WaitSFX + + ld c, 20 + call DelayFrames + + callfar Battle_GetTrainerName + + ld hl, WantsToBattleText + jr .PlaceBattleStartText + +.wild + call BattleCheckEnemyShininess + jr nc, .not_shiny + + xor a + ld [wNumHits], a + ld a, 1 + ldh [hBattleTurn], a + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + ld a, $f + ld [wCryTracks], a + ld a, [wTempEnemyMonSpecies] + call PlayStereoCry + ld hl, HookedPokemonAttackedText + ld a, [wBattleType] + cp BATTLETYPE_FISH + jr z, .PlaceBattleStartText + ld hl, PokemonFellFromTreeText + cp BATTLETYPE_TREE + jr z, .PlaceBattleStartText + ld hl, WildPokemonAppearedText + +.PlaceBattleStartText: + push hl + farcall BattleStart_TrainerHuds + pop hl + call StdBattleTextbox + ret + +ShowLinkBattleParticipants: + call IsLinkBattle + jr nz, .ok + farcall _ShowLinkBattleParticipants + call ClearTilemap + call ClearSprites + +.ok + xor a + ldh [hMapAnims], a + call DelayFrame + predef DoBattleTransition + call _LoadBattleFontsHPBar + ld a, $1 + ldh [hBGMapMode], a + call ClearSprites + call ClearTilemap + xor a + ldh [hBGMapMode], a + ldh [hWY], a + ldh [rWY], a + ldh [hMapAnims], a + ret + +IsLinkBattle: + push bc + push af + ld a, [wLinkMode] + cp LINK_COLOSSEUM + pop bc + ld a, b + pop bc + ret diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm new file mode 100644 index 00000000..815cc17d --- /dev/null +++ b/engine/battle/effect_commands.asm @@ -0,0 +1,6865 @@ +DoPlayerTurn: +; Read in and execute the player's move effects for this turn. + call SetPlayerTurn + + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + ret nz + + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData + jr DoMove + +DoEnemyTurn: +; Read in and execute the enemy's move effects for this turn. + call SetEnemyTurn + + ld a, [wLinkMode] + and a + jr z, .do_it + + ld a, [wBattleAction] + cp BATTLEACTION_STRUGGLE + jr z, .do_it + cp BATTLEACTION_SWITCH1 + ret nc + +.do_it + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData + + ; fallthrough + +DoMove: +; 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, wBattleScriptBuffer + +.GetMoveEffect: + ld a, BANK(MoveEffects) + call GetFarByte + inc hl + ld [de], a + inc de + cp endmove_command + jr nz, .GetMoveEffect + +; Start at the first command. + ld hl, wBattleScriptBuffer + ld a, l + ld [wBattleScriptBufferAddress], a + ld a, h + ld [wBattleScriptBufferAddress + 1], a + +.ReadMoveEffectCommand: +; ld a, [wBattleScriptBufferAddress++] + ld a, [wBattleScriptBufferAddress] + ld l, a + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + + ld a, [hli] + + push af + ld a, l + ld [wBattleScriptBufferAddress], a + ld a, h + ld [wBattleScriptBufferAddress + 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 + +CheckTurn: +BattleCommand_CheckTurn: +; 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 [wAttackMissed], a + ld [wEffectFailed], a + ld [wKickCounter], a + ld [wAlreadyDisobeyed], a + ld [wAlreadyFailed], a + ld [wSomeoneIsRampaging], a + + ld a, EFFECTIVE + ld [wTypeModifier], a + + ldh a, [hBattleTurn] + and a + jp nz, CheckEnemyTurn + +CheckPlayerTurn: + ld hl, wPlayerSubStatus4 + 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, wBattleMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [wBattleMonStatus], 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 + ldh [hBGMapMode], a + ld hl, wPlayerSubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ld hl, FastAsleepText + call StdBattleTextbox + + ; Snore and Sleep Talk bypass sleep. + ld a, [wCurPlayerMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + + call CantMove + jp EndTurn + +.not_asleep + + ld hl, wBattleMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [wCurPlayerMove] + 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, wPlayerSubStatus3 + 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, wPlayerDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [wDisabledMove], a + ld hl, DisabledNoMoreText + call StdBattleTextbox + +.not_disabled + + ld a, [wPlayerSubStatus3] + add a + jr nc, .not_confused + ld hl, wPlayerConfuseCount + dec [hl] + jr nz, .confused + + ld hl, wPlayerSubStatus3 + 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 50 percent + 1 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, wPlayerSubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + call HitConfusion + call CantMove + jp EndTurn + +.not_confused + + ld a, [wPlayerSubStatus1] + 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 50 percent + 1 + 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, [wDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, wCurPlayerMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + call CantMove + jp EndTurn + +.no_disabled_move + + ld hl, wBattleMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp 25 percent + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextbox + call CantMove + jp EndTurn + +CantMove: + 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 + +OpponentCantMove: + call BattleCommand_SwitchTurn + call CantMove + jp BattleCommand_SwitchTurn + +CheckEnemyTurn: + ld hl, wEnemySubStatus4 + 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, wEnemyMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [wEnemyMonStatus], 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 + ldh [hBGMapMode], a + ld hl, wEnemySubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ; Snore and Sleep Talk bypass sleep. + ld a, [wCurEnemyMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + call CantMove + jp EndTurn + +.not_asleep + + ld hl, wEnemyMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [wCurEnemyMove] + 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, wEnemySubStatus3 + 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, wEnemyDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [wEnemyDisabledMove], a + + ld hl, DisabledNoMoreText + call StdBattleTextbox + +.not_disabled + + ld a, [wEnemySubStatus3] + add a ; bit SUBSTATUS_CONFUSED + jr nc, .not_confused + + ld hl, wEnemyConfuseCount + dec [hl] + jr nz, .confused + + ld hl, wEnemySubStatus3 + 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 50 percent + 1 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, wEnemySubStatus3 + 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, TRUE + call DoEnemyDamage + call BattleCommand_RaiseSub + call CantMove + jp EndTurn + +.not_confused + + ld a, [wEnemySubStatus1] + 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 50 percent + 1 + 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, [wEnemyDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, wCurEnemyMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + + call CantMove + jp EndTurn + +.no_disabled_move + + ld hl, wEnemyMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp 25 percent + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextbox + call CantMove + + ; fallthrough + +EndTurn: + ld a, $1 + ld [wTurnEnded], a + jp ResetDamage + +MoveDisabled: + ; 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 + +HitConfusion: + ld hl, HurtItselfText + call StdBattleTextbox + + xor a + ld [wCriticalHit], 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 + ldh [hBGMapMode], a + ld c, TRUE + call DoPlayerDamage + jp BattleCommand_RaiseSub + +BattleCommand_CheckObedience: +; checkobedience + + ; Enemy can't disobey + ldh a, [hBattleTurn] + and a + ret nz + + call CheckUserIsCharging + ret nz + + ; If we've already checked this turn + ld a, [wAlreadyDisobeyed] + and a + ret nz + + xor a + ld [wAlreadyDisobeyed], a + + ; No obedience in link battles + ; (since no handling exists for enemy) + ld a, [wLinkMode] + 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, [wPlayerID] + cp [hl] + jr nz, .obeylevel + inc hl + ld a, [wPlayerID + 1] + cp [hl] + ret z + +.obeylevel + ; The maximum obedience level is constrained by owned badges: + ld hl, wJohtoBadges + + ; 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, [wBattleMonLevel] + 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 [wBattleMonStatus], a + + ld hl, BeganToNapText + jr .Print + +.DoNothing: + ; 4 random choices + call BattleRandom + and %11 + + ld hl, LoafingAroundText + and a ; 0 + jr z, .Print + + ld hl, WontObeyText + dec a ; 1 + jr z, .Print + + ld hl, TurnedAwayText + dec a ; 2 + 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, [wBattleMonMoves + 1] + and a + jr z, .DoNothing + +; Don't bother trying to handle Disable. + ld a, [wDisabledMove] + and a + jr nz, .DoNothing + + ld hl, wBattleMonPP + ld de, wBattleMonMoves + ld b, 0 + ld c, NUM_MOVES + +.GetTotalPP: + ld a, [hli] + and PP_MASK + 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, wBattleMonPP + ld a, [wCurMoveNum] + ld e, a + ld d, 0 + add hl, de + +; Can't use another move if only one move has PP. + ld a, [hl] + and PP_MASK + cp b + jr z, .DoNothing + +; Make sure we can actually use the move once we get there. + ld a, 1 + ld [wAlreadyDisobeyed], a + + ld a, [w2DMenuNumRows] + ld b, a + +; Save the move we originally picked for afterward. + ld a, [wCurMoveNum] + ld c, a + push af + +.RandomMove: + call BattleRandom + maskbits 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 [wCurMoveNum], a + ld hl, wBattleMonPP + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + and PP_MASK + jr z, .RandomMove + +; Use it. + ld a, [wCurMoveNum] + ld c, a + ld b, 0 + ld hl, wBattleMonMoves + add hl, bc + ld a, [hl] + ld [wCurPlayerMove], a + + call SetPlayerTurn + call UpdateMoveData + call DoMove + +; Restore original move choice. + pop af + ld [wCurMoveNum], a + +.EndDisobedience: + xor a + ld [wLastPlayerMove], a + ld [wLastPlayerCounterMove], a + + ; Break Encore too. + ld hl, wPlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + xor a + ld [wPlayerEncoreCount], a + + jp EndMoveEffect + +IgnoreSleepOnly: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + ; Snore and Sleep Talk bypass sleep. + 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 + +INCLUDE "engine/battle/used_move_text.asm" + +BattleCommand_DoTurn: + call CheckUserIsCharging + ret nz + + ld hl, wBattleMonPP + ld de, wPlayerSubStatus3 + ld bc, wPlayerTurnsTaken + + ldh a, [hBattleTurn] + and a + jr z, .proceed + + ld hl, wEnemyMonPP + ld de, wEnemySubStatus3 + ld bc, wEnemyTurnsTaken + +.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 + + ldh a, [hBattleTurn] + and a + + ld hl, wPartyMon1PP + ld a, [wCurBattleMon] + jr z, .player + +; mimic this part entirely if wildbattle + ld a, [wBattleMode] + dec a + jr z, .wild + + ld hl, wOTPartyMon1PP + ld a, [wCurOTMon] + +.player + call GetPartyLocation + push hl + call CheckMimicUsed + pop hl + ret c + +.consume_pp + ldh a, [hBattleTurn] + and a + ld a, [wCurMoveNum] + jr z, .okay + ld a, [wCurEnemyMoveNum] + +.okay + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and PP_MASK + jr z, .out_of_pp + dec [hl] + ld b, 0 + ret + +.wild + ld hl, wEnemyMonMoves + ld a, [wCurEnemyMoveNum] + 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 +; 'has no pp left for [move]' + ld hl, HasNoPPLeftText +; get move effect + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar +; continuous? + cp EFFECT_RAZOR_WIND + jr z, .print + + cp EFFECT_SKY_ATTACK + jr z, .print + + cp EFFECT_SKULL_BASH + jr z, .print + + cp EFFECT_SOLARBEAM + jr z, .print + + cp EFFECT_FLY + jr z, .print + + cp EFFECT_ROLLOUT + jr z, .print + + cp EFFECT_BIDE + jr z, .print + + cp EFFECT_RAMPAGE + jr z, .print + +; 'but no pp is left for the move' + ld hl, NoPPLeftText +.print + call StdBattleTextbox + ld b, 1 + ret + +CheckMimicUsed: + ldh a, [hBattleTurn] + and a + ld a, [wCurMoveNum] + jr z, .player + ld a, [wCurEnemyMoveNum] + +.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 + +BattleCommand_Critical: +; critical + +; Determine whether this attack's hit will be critical. + + xor a + ld [wCriticalHit], a + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + and a + ret z + + ldh a, [hBattleTurn] + and a + ld hl, wEnemyMonItem + ld a, [wEnemyMonSpecies] + jr nz, .Item + ld hl, wBattleMonItem + ld a, [wBattleMonSpecies] + +.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, CriticalHitMoves + 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, CriticalHitChances + ld b, 0 + add hl, bc + call BattleRandom + cp [hl] + ret nc + ld a, 1 + ld [wCriticalHit], a + ret + +INCLUDE "data/moves/critical_hit_moves.asm" + +INCLUDE "data/battle/critical_hit_chances.asm" + +INCLUDE "engine/battle/move_effects/triple_kick.asm" + +BattleCommand_Stab: +; STAB = Same Type Attack Bonus + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp STRUGGLE + ret z + + ld hl, wBattleMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wEnemyMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + + ldh a, [hBattleTurn] + and a + jr z, .go ; Who Attacks and who Defends + + ld hl, wEnemyMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wBattleMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + +.go + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + ld [wCurType], 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, [wCurType] + cp b + jr z, .stab + cp c + jr z, .stab + + jr .SkipStab + +.stab + ld hl, wCurDamage + 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 [wCurDamage], a + ld a, l + ld [wCurDamage + 1], a + + ld hl, wTypeModifier + set 7, [hl] + +.SkipStab: + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld b, a + ld hl, TypeMatchups + +.TypesLoop: + ld a, [hli] + + cp -1 + jr z, .end + + ; foresight + cp -2 + 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, [wTypeModifier] + 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 [wAttackMissed], a + xor a +.NotImmune: + ldh [hMultiplier], a + add b + ld [wTypeModifier], a + + xor a + ldh [hMultiplicand + 0], a + + ld hl, wCurDamage + ld a, [hli] + ldh [hMultiplicand + 1], a + ld a, [hld] + ldh [hMultiplicand + 2], a + + call Multiply + + ldh a, [hProduct + 1] + ld b, a + ldh a, [hProduct + 2] + or b + ld b, a + ldh 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 + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 2] + ld b, a + ldh a, [hQuotient + 3] + or b + jr nz, .ok + + ld a, 1 + ldh [hMultiplicand + 2], a + +.ok + ldh a, [hMultiplicand + 1] + ld [hli], a + ldh 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, [wTypeModifier] + and %10000000 + or b + ld [wTypeModifier], a + ret + +BattleCheckTypeMatchup: + ld hl, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, CheckTypeMatchup + ld hl, wBattleMonType1 +CheckTypeMatchup: +; 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 -1 + jr z, .End + cp -2 + 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 + ldh [hDividend + 0], a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, [hli] + ldh [hMultiplicand + 2], a + ld a, [wTypeMatchup] + ldh [hMultiplier], a + call Multiply + ld a, 10 + ldh [hDivisor], a + push bc + ld b, 4 + call Divide + pop bc + ldh a, [hQuotient + 3] + ld [wTypeMatchup], a + jr .TypesLoop + +.End: + pop bc + pop de + pop hl + ret + +BattleCommand_ResetTypeMatchup: +; 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 [wTypeModifier], a + inc a + ld [wAttackMissed], a + ret + +.reset + ld [wTypeMatchup], a + ret + +INCLUDE "engine/battle/ai/switch.asm" + +INCLUDE "data/types/type_matchups.asm" + +BattleCommand_DamageVariation: +; 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, wCurDamage + ld a, [hli] + and a + jr nz, .go + ld a, [hl] + cp 2 + ret c + +.go +; Start with the maximum damage. + xor a + ldh [hMultiplicand + 0], a + dec hl + ld a, [hli] + ldh [hMultiplicand + 1], a + ld a, [hl] + ldh [hMultiplicand + 2], a + +; Multiply by 85-100%... +.loop + call BattleRandom + rrca + cp 85 percent + 1 + jr c, .loop + + ldh [hMultiplier], a + call Multiply + +; ...divide by 100%... + ld a, $ff ; 100% + ldh [hDivisor], a + ld b, $4 + call Divide + +; ...to get .85-1.00x damage. + ldh a, [hQuotient + 2] + ld hl, wCurDamage + ld [hli], a + ldh a, [hQuotient + 3] + ld [hl], a + ret + +BattleCommand_CheckHit: +; 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 + ldh 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 -1 + 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 [wAttackMissed], 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, [wBattleWeather] + cp WEATHER_RAIN + ret + +.XAccuracy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_X_ACCURACY, a + ret + +.StatModifiers: + ldh 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, [wPlayerAccLevel] + ld b, a + ld a, [wEnemyEvaLevel] + ld c, a + + jr z, .got_acc_eva + + ld hl, wEnemyMoveStruct + MOVE_ACC + ld a, [wEnemyAccLevel] + ld b, a + ld a, [wPlayerEvaLevel] + 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, MAX_STAT_LEVEL + 1 + sub c + ld c, a + ; store the base move accuracy for math ops + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, [hl] + ldh [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, AccuracyLevelMultipliers + 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] + ldh [hMultiplier], a + call Multiply + ; ... and divide by the second byte + ld a, [hl] + ldh [hDivisor], a + ld b, 4 + call Divide + ; minimum accuracy is $0001 + ldh a, [hQuotient + 3] + ld b, a + ldh a, [hQuotient + 2] + or b + jr nz, .min_accuracy + ldh [hQuotient + 2], a + ld a, 1 + ldh [hQuotient + 3], 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% + ldh a, [hQuotient + 2] + and a + ldh a, [hQuotient + 3] + jr z, .finish_accuracy + ld a, $ff + +.finish_accuracy + pop hl + ld [hl], a + ret + +INCLUDE "data/battle/accuracy_multipliers.asm" + +BattleCommand_EffectChance: +; effectchance + + xor a + ld [wEffectFailed], a + call CheckSubstituteOpp + jr nz, .failed + + push hl + ld hl, wPlayerMoveStruct + MOVE_CHANCE + ldh a, [hBattleTurn] + and a + jr z, .got_move_chance + ld hl, wEnemyMoveStruct + MOVE_CHANCE +.got_move_chance + + ; BUG: 1/256 chance to fail even for a 100% effect chance, + ; since carry is not set if BattleRandom == [hl] == 255 + call BattleRandom + cp [hl] + pop hl + ret c + +.failed + ld a, 1 + ld [wEffectFailed], a + and a + ret + +BattleCommand_LowerSub: +; 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 + ; check battle scene + ld a, [wOptions] + add a + jr c, .mimic_anims + + xor a + ld [wNumHits], a + ld [wFXAnimID + 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 + +BattleCommand_MoveAnim: +; moveanim + call BattleCommand_LowerSub + call BattleCommand_MoveAnimNoSub + jp BattleCommand_RaiseSub + +BattleCommand_MoveAnimNoSub: + ld a, [wAttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ldh a, [hBattleTurn] + and a + ld de, wPlayerRolloutCount + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .got_rollout_count + ld de, wEnemyRolloutCount + 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, .alternate_anim + cp EFFECT_CONVERSION + jr z, .alternate_anim + cp EFFECT_DOUBLE_HIT + jr z, .alternate_anim + cp EFFECT_POISON_MULTI_HIT + jr z, .alternate_anim + 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, .clear_sprite + cp DIG + ret nz +.clear_sprite + jp AppearUserLowerSub + +.alternate_anim + 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 + +BattleCommand_StatUpAnim: + ld a, [wAttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + xor a + jr BattleCommand_StatUpDownAnim + +BattleCommand_StatDownAnim: + ld a, [wAttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ldh a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_STAT_DOWN + jr z, BattleCommand_StatUpDownAnim + ld a, BATTLEANIM_WOBBLE + + ; fallthrough + +BattleCommand_StatUpDownAnim: + ld [wNumHits], a + xor a + ld [wKickCounter], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + jp PlayFXAnimID + +BattleCommand_SwitchTurn: +; switchturn + + ldh a, [hBattleTurn] + xor 1 + ldh [hBattleTurn], a + ret + +BattleCommand_RaiseSub: +; raisesub + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret z + + ; check battle scene + ld a, [wOptions] + add a + jp c, BattleCommand_RaiseSubNoAnim + + xor a + ld [wNumHits], a + ld [wFXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + ld a, SUBSTITUTE + jp LoadAnim + +BattleCommand_FailureText: +; failuretext +; If the move missed or failed, load the appropriate +; text, and end the effects of multi-turn or multi- +; hit moves. + ld a, [wAttackMissed] + 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 + +BattleCommand_ApplyDamage: +; applydamage + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_ENDURE, a + jr z, .focus_band + + call BattleCommand_FalseSwipe + ld b, 0 + jr nc, .damage + ld b, 1 + jr .damage + +.focus_band + call GetOpponentItem + ld a, b + cp HELD_FOCUS_BAND + ld b, 0 + jr nz, .damage + + call BattleRandom + cp c + jr nc, .damage + call BattleCommand_FalseSwipe + ld b, 0 + jr nc, .damage + ld b, 2 + +.damage + push bc + call .update_damage_taken + ld c, FALSE + ldh a, [hBattleTurn] + and a + jr nz, .damage_player + call DoEnemyDamage + jr .done_damage + +.damage_player + call DoPlayerDamage + +.done_damage + pop bc + ld a, b + and a + ret z + + dec a + jr nz, .focus_band_text + ld hl, EnduredText + jp StdBattleTextbox + +.focus_band_text + call GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, HungOnText + jp StdBattleTextbox + +.update_damage_taken + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld de, wPlayerDamageTaken + 1 + ldh a, [hBattleTurn] + and a + jr nz, .got_damage_taken + ld de, wEnemyDamageTaken + 1 + +.got_damage_taken + ld a, [wCurDamage + 1] + ld b, a + ld a, [de] + add b + ld [de], a + dec de + ld a, [wCurDamage] + 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 + +GetFailureResultText: + ld hl, DoesntAffectText + ld de, DoesntAffectText + ld a, [wTypeModifier] + 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, [wCriticalHit] + cp -1 + jr nz, .got_text + ld hl, UnaffectedText +.got_text + call FailText_CheckOpponentProtect + xor a + ld [wCriticalHit], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_JUMP_KICK + ret nz + + ld a, [wTypeModifier] + and $7f + ret z + + ld hl, wCurDamage + 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, TRUE + ldh a, [hBattleTurn] + and a + jp nz, DoEnemyDamage + jp DoPlayerDamage + +FailText_CheckOpponentProtect: + 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 + +BattleCommand_BideFailText: + ld a, [wAttackMissed] + and a + ret z + + ld a, [wTypeModifier] + and $7f + jp z, PrintDoesntAffect + jp PrintButItFailed + +BattleCommand_CriticalText: +; criticaltext +; Prints the message for critical hits or one-hit KOs. + +; If there is no message to be printed, wait 20 frames. + ld a, [wCriticalHit] + 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 [wCriticalHit], a + +.wait + ld c, 20 + jp DelayFrames + +.texts + dw CriticalHitText + dw OneHitKOText + +BattleCommand_StartLoop: +; startloop + + ld hl, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyRolloutCount +.ok + xor a + ld [hl], a + ret + +BattleCommand_SuperEffectiveLoopText: +; supereffectivelooptext + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, a + ret nz + + ; fallthrough + +BattleCommand_SuperEffectiveText: +; supereffectivetext + + ld a, [wTypeModifier] + and $7f + cp 10 ; 1.0 + ret z + ld hl, SuperEffectiveText + jr nc, .print + ld hl, NotVeryEffectiveText +.print + jp StdBattleTextbox + +BattleCommand_CheckFaint: +; checkfaint + +; Faint the opponent if its HP reached zero +; and faint the user along with it if it used Destiny Bond. +; Ends the move effect if the opponent faints. + + ld hl, wEnemyMonHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wBattleMonHP + +.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 + + ldh a, [hBattleTurn] + and a + ld hl, wEnemyMonMaxHP + 1 + bccoord 2, 2 ; hp bar + ld a, 0 + jr nz, .got_max_hp + ld hl, wBattleMonMaxHP + 1 + bccoord 10, 9 ; hp bar + ld a, 1 + +.got_max_hp + ld [wWhichHPBar], a + ld a, [hld] + ld [wBuffer1], a + ld a, [hld] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer3], a + xor a + ld [hld], a + ld a, [hl] + ld [wBuffer4], a + xor a + ld [hl], a + ld [wBuffer5], a + ld [wBuffer6], a + ld h, b + ld l, c + predef AnimateHPBar + call RefreshBattleHuds + + call BattleCommand_SwitchTurn + xor a + ld [wNumHits], a + ld [wFXAnimID + 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 + +BattleCommand_BuildOpponentRage: +; buildopponentrage + + jp .start + +.start + ld a, [wAttackMissed] + and a + ret nz + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_RAGE, a + ret z + + ld de, wEnemyRageCounter + ldh 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 + +BattleCommand_RageDamage: +; ragedamage + + ld a, [wCurDamage] + ld h, a + ld b, a + ld a, [wCurDamage + 1] + ld l, a + ld c, a + ldh 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, $ffff +.done + ld a, h + ld [wCurDamage], a + ld a, l + ld [wCurDamage + 1], a + ret + +EndMoveEffect: + ld a, [wBattleScriptBufferAddress] + ld l, a + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret + +DittoMetalPowder: + ld a, MON_SPECIES + call BattlePartyAttr + ldh a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .Ditto + ld a, [wTempEnemyMonSpecies] + +.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 + +BattleCommand_DamageStats: +; damagestats + + ldh a, [hBattleTurn] + and a + jp nz, EnemyAttackDamage + + ; fallthrough + +PlayerAttackDamage: +; 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, wEnemyMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [wEnemyScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, wBattleMonAttack + call CheckDamageStatsCritical + jr c, .thickclub + + ld hl, wEnemyDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wPlayerAttack + jr .thickclub + +.special + ld hl, wEnemyMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [wEnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, wBattleMonSpclAtk + call CheckDamageStatsCritical + jr c, .lightball + + ld hl, wEnemySpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wPlayerSpAtk + +.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, [wBattleMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +TruncateHL_BC: +.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, .done + + 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, .done + inc l + +.done + ld b, l + ret + +CheckDamageStatsCritical: +; Return carry if boosted stats should be used in damage calculations. +; Unboosted stats should be used if the attack is a critical hit, +; and the stage of the opponent's defense is higher than the user's attack. + + ld a, [wCriticalHit] + and a + scf + ret z + + push hl + push bc + ldh a, [hBattleTurn] + and a + jr nz, .enemy + ld a, [wPlayerMoveStructType] + cp SPECIAL +; special + ld a, [wPlayerSAtkLevel] + ld b, a + ld a, [wEnemySDefLevel] + jr nc, .end +; physical + ld a, [wPlayerAtkLevel] + ld b, a + ld a, [wEnemyDefLevel] + jr .end + +.enemy + ld a, [wEnemyMoveStructType] + cp SPECIAL +; special + ld a, [wEnemySAtkLevel] + ld b, a + ld a, [wPlayerSDefLevel] + jr nc, .end +; physical + ld a, [wEnemyAtkLevel] + ld b, a + ld a, [wPlayerDefLevel] +.end + cp b + pop bc + pop hl + ret + +ThickClubBoost: +; 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 + +LightBallBoost: +; 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 + +SpeciesItemBoost: +; 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 + + ldh a, [hBattleTurn] + and a + ld a, [hl] + jr z, .CompareSpecies + ld a, [wTempEnemyMonSpecies] +.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 + +EnemyAttackDamage: + 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, wBattleMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [wPlayerScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, wEnemyMonAttack + call CheckDamageStatsCritical + jr c, .thickclub + + ld hl, wPlayerDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wEnemyAttack + jr .thickclub + +.Special: + ld hl, wBattleMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [wPlayerScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, wEnemyMonSpclAtk + call CheckDamageStatsCritical + jr c, .lightball + ld hl, wPlayerSpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wEnemySpAtk + +.lightball + call LightBallBoost + jr .done + +.thickclub + call ThickClubBoost + +.done + call TruncateHL_BC + + ld a, [wEnemyMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +INCLUDE "engine/battle/move_effects/beat_up.asm" + +BattleCommand_ClearMissDamage: +; clearmissdamage + ld a, [wAttackMissed] + and a + ret z + + jp ResetDamage + +HitSelfInConfusion: + call ResetDamage + ldh a, [hBattleTurn] + and a + ld hl, wBattleMonDefense + ld de, wPlayerScreens + ld a, [wBattleMonLevel] + jr z, .got_it + + ld hl, wEnemyMonDefense + ld de, wEnemyScreens + ld a, [wEnemyMonLevel] +.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 + +BattleCommand_DamageCalc: +; 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 -1 + 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 + ldh [hMultiplier], a + call Multiply + +; / 100 + ld a, 100 + ldh [hDivisor], a + ld b, 4 + call Divide + +.DoneItem: +; Critical hits + call .CriticalMultiplier + +; Update wCurDamage (capped at 997). + ld hl, wCurDamage + ld b, [hl] + ldh a, [hProduct + 3] + add b + ldh [hProduct + 3], a + jr nc, .dont_cap_1 + + ldh a, [hProduct + 2] + inc a + ldh [hProduct + 2], a + and a + jr z, .Cap + +.dont_cap_1 + ldh a, [hProduct] + ld b, a + ldh a, [hProduct + 1] + or a + jr nz, .Cap + + ldh 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 + + ldh a, [hProduct + 3] + cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr nc, .Cap + +.dont_cap_2 + inc hl + + ldh a, [hProduct + 3] + ld b, [hl] + add b + ld [hld], a + + ldh 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, [wCriticalHit] + and a + ret z + +; x2 + ldh a, [hQuotient + 3] + sla a + ldh [hProduct + 3], a + + ldh a, [hQuotient + 2] + rl a + ldh [hProduct + 2], a + +; Cap at $ffff. + ret nc + + ld a, $ff + ldh [hProduct + 2], a + ldh [hProduct + 3], a + + ret + +INCLUDE "data/types/type_boost_items.asm" + +BattleCommand_ConstantDamage: +; constantdamage + + ld hl, wBattleMonLevel + ldh a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, wEnemyMonLevel + +.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, wEnemyMonHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wBattleMonHP +.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, wCurDamage + ld [hli], a + ld [hl], b + ret + +.reversal + ld hl, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .reversal_got_hp + ld hl, wEnemyMonHP +.reversal_got_hp + xor a + ldh [hDividend], a + ldh [hMultiplicand + 0], a + ld a, [hli] + ldh [hMultiplicand + 1], a + ld a, [hli] + ldh [hMultiplicand + 2], a + ld a, 48 + ldh [hMultiplier], a + call Multiply + ld a, [hli] + ld b, a + ld a, [hl] + ldh [hDivisor], a + ld a, b + and a + jr z, .skip_to_divide + + ldh a, [hProduct + 4] + srl b + rr a + srl b + rr a + ldh [hDivisor], a + ldh a, [hProduct + 2] + ld b, a + srl b + ldh a, [hProduct + 3] + rr a + srl b + rr a + ldh [hDividend + 3], a + ld a, b + ldh [hDividend + 2], a + +.skip_to_divide + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld b, a + ld hl, FlailReversalPower + +.reversal_loop + ld a, [hli] + cp b + jr nc, .break_loop + inc hl + jr .reversal_loop + +.break_loop + ldh 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 + +INCLUDE "data/moves/flail_reversal_power.asm" + +INCLUDE "engine/battle/move_effects/counter.asm" + +INCLUDE "engine/battle/move_effects/encore.asm" + +INCLUDE "engine/battle/move_effects/pain_split.asm" + +INCLUDE "engine/battle/move_effects/snore.asm" + +INCLUDE "engine/battle/move_effects/conversion2.asm" + +INCLUDE "engine/battle/move_effects/lock_on.asm" + +INCLUDE "engine/battle/move_effects/sketch.asm" + +BattleCommand_DefrostOpponent: +; 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 + +INCLUDE "engine/battle/move_effects/sleep_talk.asm" + +INCLUDE "engine/battle/move_effects/destiny_bond.asm" + +INCLUDE "engine/battle/move_effects/spite.asm" + +INCLUDE "engine/battle/move_effects/false_swipe.asm" + +INCLUDE "engine/battle/move_effects/heal_bell.asm" + +FarPlayBattleAnimation: +; play animation de + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz + + ; fallthrough + +PlayFXAnimID: + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 1], a + + ld c, 3 + call DelayFrames + callfar PlayBattleAnim + ret + +DoEnemyDamage: + ld hl, wCurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .ignore_substitute + ld a, [wEnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, DoSubstituteDamage + +.ignore_substitute + ; Substract wCurDamage from wEnemyMonHP. + ; store original HP in little endian wBuffer3/4 + ld a, [hld] + ld b, a + ld a, [wEnemyMonHP + 1] + ld [wBuffer3], a + sub b + ld [wEnemyMonHP + 1], a + ld a, [hl] + ld b, a + ld a, [wEnemyMonHP] + ld [wBuffer4], a + sbc b + ld [wEnemyMonHP], a + jr nc, .no_underflow + + ld a, [wBuffer4] + ld [hli], a + ld a, [wBuffer3] + ld [hl], a + xor a + ld hl, wEnemyMonHP + ld [hli], a + ld [hl], a + +.no_underflow + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + ld hl, wEnemyMonHP + ld a, [hli] + ld [wBuffer6], a + ld a, [hl] + ld [wBuffer5], a + + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +DoPlayerDamage: + ld hl, wCurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .ignore_substitute + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, DoSubstituteDamage + +.ignore_substitute + ; Substract wCurDamage from wBattleMonHP. + ; store original HP in little endian wBuffer3/4 + ; store new HP in little endian wBuffer5/6 + ld a, [hld] + ld b, a + ld a, [wBattleMonHP + 1] + ld [wBuffer3], a + sub b + ld [wBattleMonHP + 1], a + ld [wBuffer5], a + ld b, [hl] + ld a, [wBattleMonHP] + ld [wBuffer4], a + sbc b + ld [wBattleMonHP], a + ld [wBuffer6], a + jr nc, .no_underflow + + ld a, [wBuffer4] + ld [hli], a + ld a, [wBuffer3] + ld [hl], a + xor a + ld hl, wBattleMonHP + ld [hli], a + ld [hl], a + ld hl, wBuffer5 + ld [hli], a + ld [hl], a + +.no_underflow + ld hl, wBattleMonMaxHP + ld a, [hli] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + + hlcoord 10, 9 + ld a, 1 + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +DoSubstituteDamage: + ld hl, SubTookDamageText + call StdBattleTextbox + + ld de, wEnemySubstituteHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld de, wPlayerSubstituteHP +.got_hp + + ld hl, wCurDamage + 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 + +UpdateMoveData: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [wCurSpecies], a + ld [wNamedObjectIndexBuffer], a + + dec a + call GetMoveData + call GetMoveName + jp CopyName1 + +BattleCommand_SleepTarget: +; 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, [wAttackMissed] + 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 + +.random_loop + call BattleRandom + and 7 + 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 + ret nz + + call OpponentCantMove + ret + +.fail + call AnimateFailedMove + jp StdBattleTextbox + +.CheckAIRandomFail: + ; Enemy turn + ldh a, [hBattleTurn] + and a + jr z, .dont_fail + + ; Not in link battle + ld a, [wLinkMode] + and a + jr nz, .dont_fail + + ; Not locked-on by the enemy + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_fail + + call BattleRandom + cp 25 percent + 1 ; 25% chance AI fails + ret c + +.dont_fail + xor a + ret + +BattleCommand_PoisonTarget: +; poisontarget + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [wTypeModifier] + and $7f + ret z + call CheckIfTargetIsPoisonType + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + ret z + ld a, [wEffectFailed] + 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 + +BattleCommand_Poison: +; poison + + ld hl, DoesntAffectText + ld a, [wTypeModifier] + 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 + + ldh a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 25 percent + 1 ; 25% chance AI fails + jr c, .failed + +.dont_sample_failure + call CheckSubstituteOpp + jr nz, .failed + ld a, [wAttackMissed] + 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 + call AnimateFailedMove + jp StdBattleTextbox + +.apply_poison + call AnimateCurrentMove + call PoisonOpponent + jp RefreshBattleHuds + +.check_toxic + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + ldh a, [hBattleTurn] + and a + ld de, wEnemyToxicCount + jr z, .ok + ld de, wPlayerToxicCount +.ok + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_TOXIC + ret + +CheckIfTargetIsPoisonType: + ld de, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wBattleMonType1 +.ok + ld a, [de] + inc de + cp POISON + ret z + ld a, [de] + cp POISON + ret + +PoisonOpponent: + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PSN, [hl] + jp UpdateOpponentInParty + +BattleCommand_DrainTarget: +; draintarget + call SapHealth + ld hl, SuckedHealthText + jp StdBattleTextbox + +BattleCommand_EatDream: +; eatdream + call SapHealth + ld hl, DreamEatenText + jp StdBattleTextbox + +SapHealth: + ; Divide damage by 2, store it in hDividend + ld hl, wCurDamage + ld a, [hli] + srl a + ldh [hDividend], a + ld b, a + ld a, [hl] + rr a + ldh [hDividend + 1], a + or b + jr nz, .at_least_one + ld a, 1 + ldh [hDividend + 1], a +.at_least_one + + ld hl, wBattleMonHP + ld de, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .battlemonhp + ld hl, wEnemyMonHP + ld de, wEnemyMonMaxHP +.battlemonhp + + ; Store current HP in little endian wBuffer3/4 + ld bc, wBuffer4 + ld a, [hli] + ld [bc], a + ld a, [hl] + dec bc + ld [bc], a + + ; Store max HP in little endian wBuffer1/2 + ld a, [de] + dec bc + ld [bc], a + inc de + ld a, [de] + dec bc + ld [bc], a + + ; Add hDividend to current HP and copy it to little endian wBuffer5/6 + ldh a, [hDividend + 1] + ld b, [hl] + add b + ld [hld], a + ld [wBuffer5], a + ldh a, [hDividend] + ld b, [hl] + adc b + ld [hli], a + ld [wBuffer6], a + jr c, .max_hp + + ; Substract current HP from max HP (to see if we have more than max HP) + 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, .finish + +.max_hp + ; Load max HP into current HP and copy it to little endian wBuffer5/6 + ld a, [de] + ld [hld], a + ld [wBuffer5], a + dec de + ld a, [de] + ld [hli], a + ld [wBuffer6], a + inc de + +.finish + ldh 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 + +BattleCommand_BurnTarget: +; 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, [wTypeModifier] + 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, [wEffectFailed] + 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 + +Defrost: + ld a, [hl] + and 1 << FRZ + ret z + + xor a + ld [hl], a + + ldh a, [hBattleTurn] + and a + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + jr z, .ok + ld hl, wPartyMon1Status + ld a, [wCurBattleMon] +.ok + + call GetPartyLocation + xor a + ld [hl], a + call UpdateOpponentInParty + + ld hl, DefrostedOpponentText + jp StdBattleTextbox + +BattleCommand_FreezeTarget: +; freezetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [wTypeModifier] + and $7f + ret z + ld a, [wBattleWeather] + 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, [wEffectFailed] + 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 + ldh a, [hBattleTurn] + and a + jr z, .finish + ld hl, wPlayerJustGotFrozen +.finish + ld [hl], $1 + ret + +BattleCommand_ParalyzeTarget: +; paralyzetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [wTypeModifier] + and $7f + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + ret z + ld a, [wEffectFailed] + 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 + +BattleCommand_AttackUp: +; attackup + ld b, ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp: +; defenseup + ld b, DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp: +; speedup + ld b, SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp: +; specialattackup + ld b, SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp: +; specialdefenseup + ld b, SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp: +; accuracyup + ld b, ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp: +; evasionup + ld b, EVASION + jr BattleCommand_StatUp + +BattleCommand_AttackUp2: +; attackup2 + ld b, $10 | ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp2: +; defenseup2 + ld b, $10 | DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp2: +; speedup2 + ld b, $10 | SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp2: +; specialattackup2 + ld b, $10 | SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp2: +; specialdefenseup2 + ld b, $10 | SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp2: +; accuracyup2 + ld b, $10 | ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp2: +; evasionup2 + ld b, $10 | EVASION + jr BattleCommand_StatUp + +BattleCommand_StatUp: +; statup + call RaiseStat + ld a, [wFailedMessage] + and a + ret nz + jp MinimizeDropSub + +RaiseStat: + ld a, b + ld [wLoweredStat], a + ld hl, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .got_stat_levels + ld hl, wEnemyStatLevels +.got_stat_levels + ld a, [wAttackMissed] + and a + jp nz, .stat_raise_failed + ld a, [wEffectFailed] + and a + jp nz, .stat_raise_failed + ld a, [wLoweredStat] + 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, [wLoweredStat] + 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, wBattleMonStats + 1 + ld de, wPlayerStats + ldh a, [hBattleTurn] + and a + jr z, .got_stats_pointer + ld hl, wEnemyMonStats + 1 + ld de, wEnemyStats +.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 + ldh 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 [wFailedMessage], a + ret + +.stats_already_max + pop hl + dec [hl] + ; fallthrough + +.cant_raise_stat + ld a, $2 + ld [wFailedMessage], a + ld a, $1 + ld [wAttackMissed], a + ret + +.stat_raise_failed + ld a, $1 + ld [wFailedMessage], a + ret + +MinimizeDropSub: +; Lower the substitute if we're minimizing + + ld bc, wPlayerMinimized + ld hl, DropPlayerSub + ldh 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 + ; check battle scene + ld a, [wOptions] + add a + ret nc + + xor a + ldh [hBGMapMode], a + call CallBattleCore + call WaitBGMap + jp BattleCommand_MoveDelay + +BattleCommand_AttackDown: +; attackdown + ld a, ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown: +; defensedown + ld a, DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown: +; speeddown + ld a, SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown: +; specialattackdown + ld a, SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown: +; specialdefensedown + ld a, SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown: +; accuracydown + ld a, ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown: +; evasiondown + ld a, EVASION + jr BattleCommand_StatDown + +BattleCommand_AttackDown2: +; attackdown2 + ld a, $10 | ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown2: +; defensedown2 + ld a, $10 | DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown2: +; speeddown2 + ld a, $10 | SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown2: +; specialattackdown2 + ld a, $10 | SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown2: +; specialdefensedown2 + ld a, $10 | SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown2: +; accuracydown2 + ld a, $10 | ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown2: +; evasiondown2 + ld a, $10 | EVASION + +BattleCommand_StatDown: +; statdown + + ld [wLoweredStat], a + + call CheckMist + jp nz, .Mist + + ld hl, wEnemyStatLevels + ldh a, [hBattleTurn] + and a + jr z, .GetStatLevel + ld hl, wPlayerStatLevels + +.GetStatLevel: +; Attempt to lower the stat. + ld a, [wLoweredStat] + 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, [wLoweredStat] + and $f0 + jr z, .ComputerMiss + dec b + jr nz, .ComputerMiss + inc b + +.ComputerMiss: +; Computer opponents have a 25% chance of failing. + ldh a, [hBattleTurn] + and a + jr z, .DidntMiss + + ld a, [wLinkMode] + and a + jr nz, .DidntMiss + +; Lock-On still always works. + ld a, [wPlayerSubStatus5] + 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 25 percent + 1 ; 25% chance AI fails + jr c, .Failed + +.DidntMiss: + call CheckSubstituteOpp + jr nz, .Failed + + ld a, [wAttackMissed] + and a + jr nz, .Failed + + ld a, [wEffectFailed] + 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, wEnemyMonAttack + 1 + ld de, wEnemyStats + ldh a, [hBattleTurn] + and a + jr z, .do_enemy + ld hl, wBattleMonAttack + 1 + ld de, wPlayerStats +.do_enemy + call TryLowerStat + pop hl + jr z, .CouldntLower + +.Hit: + xor a + ld [wFailedMessage], a + ret + +.CouldntLower: + inc [hl] +.CantLower: + ld a, 3 + ld [wFailedMessage], a + ld a, 1 + ld [wAttackMissed], a + ret + +.Failed: + ld a, 1 + ld [wFailedMessage], a + ld [wAttackMissed], a + ret + +.Mist: + ld a, 2 + ld [wFailedMessage], a + ld a, 1 + ld [wAttackMissed], a + ret + +CheckMist: + 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 + +BattleCommand_StatUpMessage: + ld a, [wFailedMessage] + and a + ret nz + ld a, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp PrintText + +.stat + text_far Text_BattleEffectActivate + text_asm + ld hl, .BattleStatWentUpText + ld a, [wLoweredStat] + and $f0 + ret z + ld hl, .BattleStatWentWayUpText + ret + +.BattleStatWentWayUpText: + text_far _BattleStatWentWayUpText + text_end + +.BattleStatWentUpText: + text_far _BattleStatWentUpText + text_end + +BattleCommand_StatDownMessage: + ld a, [wFailedMessage] + and a + ret nz + ld a, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp PrintText + +.stat + text_far Text_BattleFoeEffectActivate + text_asm + ld hl, .BattleStatFellText + ld a, [wLoweredStat] + and $f0 + ret z + ld hl, .BattleStatSharplyFellText + ret + +.BattleStatSharplyFellText: + text_far _BattleStatSharplyFellText + text_end + +.BattleStatFellText: + text_far _BattleStatFellText + text_end + +TryLowerStat: +; 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 + ldh 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 + +BattleCommand_StatUpFailText: +; statupfailtext + ld a, [wFailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + ld a, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontRiseAnymoreText + jp StdBattleTextbox + +BattleCommand_StatDownFailText: +; statdownfailtext + ld a, [wFailedMessage] + 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, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontDropAnymoreText + jp StdBattleTextbox + +GetStatName: + ld hl, StatNames + ld c, "@" +.CheckName: + dec b + jr z, .Copy +.GetName: + ld a, [hli] + cp c + jr z, .CheckName + jr .GetName + +.Copy: + ld de, wStringBuffer2 + ld bc, 10 + jp CopyBytes + +INCLUDE "data/battle/stat_names.asm" + +INCLUDE "data/battle/stat_multipliers.asm" + +BattleCommand_AllStatsUp: +; 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 + +ResetMiss: + xor a + ld [wAttackMissed], a + ret + +LowerStat: + ld [wLoweredStat], a + + ld hl, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .got_target + ld hl, wEnemyStatLevels + +.got_target + ld a, [wLoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jr z, .cant_lower_anymore + + ld a, [wLoweredStat] + 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, wBattleMonStats + 1 + ld de, wPlayerStats + ldh a, [hBattleTurn] + and a + jr z, .got_target_2 + ld hl, wEnemyMonStats + 1 + ld de, wEnemyStats + +.got_target_2 + call TryLowerStat + pop hl + jr z, .failed + +.accuracy_evasion + ldh a, [hBattleTurn] + and a + jr z, .player + + call CalcEnemyStats + + jr .finish + +.player + call CalcPlayerStats + +.finish + xor a + ld [wFailedMessage], a + ret + +.failed + inc [hl] + +.cant_lower_anymore + ld a, 2 + ld [wFailedMessage], a + ret + +BattleCommand_TriStatusChance: +; tristatuschance + + call BattleCommand_EffectChance + +.loop + ; 1/3 chance of each status + call BattleRandom + swap a + and %11 + jr z, .loop + dec a + ld hl, .ptrs + rst JumpTable + ret + +.ptrs + dw BattleCommand_ParalyzeTarget ; paralyze + dw BattleCommand_FreezeTarget ; freeze + dw BattleCommand_BurnTarget ; burn + +BattleCommand_Curl: +; curl + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVarAddr + set SUBSTATUS_CURLED, [hl] + ret + +BattleCommand_RaiseSubNoAnim: + ld hl, GetBattleMonBackpic + ldh a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, GetEnemyMonFrontpic +.PlayerTurn: + xor a + ldh [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +BattleCommand_LowerSubNoAnim: + ld hl, DropPlayerSub + ldh a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, DropEnemySub +.PlayerTurn: + xor a + ldh [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +CalcPlayerStats: + ld hl, wPlayerAtkLevel + ld de, wPlayerStats + ld bc, wBattleMonAttack + + ld a, 5 + call CalcBattleStats + + ld hl, BadgeStatBoosts + call CallBattleCore + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +CalcEnemyStats: + ld hl, wEnemyAtkLevel + ld de, wEnemyStats + ld bc, wEnemyMonAttack + + ld a, 5 + call CalcBattleStats + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +CalcBattleStats: +.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 + ldh [hMultiplicand + 0], a + ld a, [de] + ldh [hMultiplicand + 1], a + inc de + ld a, [de] + ldh [hMultiplicand + 2], a + inc de + + ld a, [hli] + ldh [hMultiplier], a + call Multiply + + ld a, [hl] + ldh [hDivisor], a + ld b, 4 + call Divide + + ldh a, [hQuotient + 2] + ld b, a + ldh a, [hQuotient + 3] + or b + jr nz, .check_maxed_out + + ld a, 1 + ldh [hQuotient + 3], a + jr .not_maxed_out + +.check_maxed_out + ldh a, [hQuotient + 3] + cp LOW(MAX_STAT_VALUE) + ld a, b + sbc HIGH(MAX_STAT_VALUE) + jr c, .not_maxed_out + + ld a, LOW(MAX_STAT_VALUE) + ldh [hQuotient + 3], a + ld a, HIGH(MAX_STAT_VALUE) + ldh [hQuotient + 2], a + +.not_maxed_out + pop bc + ldh a, [hQuotient + 2] + ld [bc], a + inc bc + ldh a, [hQuotient + 3] + ld [bc], a + inc bc + pop hl + pop af + dec a + jr nz, .loop + + ret + +INCLUDE "engine/battle/move_effects/bide.asm" + +BattleCommand_CheckRampage: +; checkrampage + + ld de, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .player + ld de, wEnemyRolloutCount +.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 + +BattleCommand_Rampage: +; rampage + +; No rampage during Sleep Talk. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld de, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wEnemyRolloutCount +.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 + +INCLUDE "engine/battle/move_effects/teleport.asm" + +BattleCommand_ForceSwitch: +; forceswitch + + ld a, [wBattleType] + cp BATTLETYPE_SHINY + jp z, .fail + cp BATTLETYPE_TRAP + jp z, .fail + ldh a, [hBattleTurn] + and a + jp nz, .force_player_switch + ld a, [wAttackMissed] + and a + jr nz, .missed + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, [wCurPartyLevel] + ld b, a + ld a, [wBattleMonLevel] + 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 + ; set battle draw + inc a + ld [wBattleResult], a + 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, [wOTPartyCount] + ld b, a + ld a, [wCurOTMon] + 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, wOTPartyMon1HP + 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, [wAttackMissed] + and a + jr nz, .player_miss + + ld a, [wBattleMode] + dec a + jr nz, .vs_trainer + + ld a, [wBattleMonLevel] + ld b, a + ld a, [wCurPartyLevel] + 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 + jp .fail + +.wild_succeed_playeristarget + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + ; set battle draw + inc a + ld [wBattleResult], a + ld a, [wEnemyMoveStructAnimation] + jr .succeed + +.vs_trainer + call CheckPlayerHasMonToSwitchTo + jr c, .switch_fail2 + + 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, [wPartyCount] + ld b, a + ld a, [wCurBattleMon] + 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, wPartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer_playeristarget + + ld a, d + ld [wCurPartyMon], a + ld hl, SwitchPlayerMon + call CallBattleCore + + ld hl, DraggedOutText + call StdBattleTextbox + + ld hl, SpikesDamage + jp CallBattleCore + +.switch_fail2 + jr .fail + +.succeed + push af + ld a, DRAW + ld [wBattleResult], a + 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 + +.fail + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + jp PrintButItFailed + +CheckPlayerHasMonToSwitchTo: + ld a, [wPartyCount] + ld d, a + ld e, 0 + ld bc, PARTYMON_STRUCT_LENGTH +.loop + ld a, [wCurBattleMon] + cp e + jr z, .next + + ld a, e + ld hl, wPartyMon1HP + 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 + +BattleCommand_EndLoop: +; endloop + +; Loop back to 'critical'. + + ld de, wPlayerRolloutCount + ld bc, wPlayerDamageTaken + ldh a, [hBattleTurn] + and a + jr z, .got_addrs + ld de, wEnemyRolloutCount + ld bc, wEnemyDamageTaken +.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 + ldh a, [hBattleTurn] + and a + jr nz, .check_ot_beat_up + ld a, [wPartyCount] + 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, [wOTPartyCount] + 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 BattleCommand_BeatUpFailText + 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 + ldh 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_critical + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + ld a, [wBattleScriptBufferAddress] + ld l, a +.not_critical + ld a, [hld] + cp critical_command + jr nz, .not_critical + inc hl + ld a, h + ld [wBattleScriptBufferAddress + 1], a + ld a, l + ld [wBattleScriptBufferAddress], a + ret + +BattleCommand_FakeOut: + ld a, [wAttackMissed] + 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 [wAttackMissed], a + ret + +BattleCommand_FlinchTarget: + call CheckSubstituteOpp + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + ret nz + + call CheckOpponentWentFirst + ret nz + + ld a, [wEffectFailed] + and a + ret nz + + ; fallthrough + +FlinchTarget: + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + jp EndRechargeOpp + +CheckOpponentWentFirst: +; 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 + ldh a, [hBattleTurn] ; 0 if it's the player's turn + xor b ; 1 if opponent went first + pop bc + ret + +BattleCommand_HeldFlinch: +; kingsrock + + ld a, [wAttackMissed] + 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 + +BattleCommand_OHKO: +; ohko + + call ResetDamage + ld a, [wTypeModifier] + and $7f + jr z, .no_effect + ld hl, wEnemyMonLevel + ld de, wBattleMonLevel + ld bc, wPlayerMoveStruct + MOVE_ACC + ldh 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, wCurDamage + ld a, $ff + ld [hli], a + ld [hl], a + ld a, $2 + ld [wCriticalHit], a + ret + +.no_effect + ld a, $ff + ld [wCriticalHit], a + ld a, $1 + ld [wAttackMissed], a + ret + +BattleCommand_CheckCharge: +; 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 + +BattleCommand_Charge: +; 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, [wAlreadyDisobeyed] + 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 PrintText + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_SKULL_BASH + ld b, endturn_command + jp z, SkipToBattleCommand + jp EndMoveEffect + +.UsedText: + text_far Text_BattleUser ; "<USER>" + text_asm + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp RAZOR_WIND + ld hl, .BattleMadeWhirlwindText + jr z, .done + + cp SOLARBEAM + ld hl, .BattleTookSunlightText + jr z, .done + + cp SKULL_BASH + ld hl, .BattleLoweredHeadText + jr z, .done + + cp SKY_ATTACK + ld hl, .BattleGlowingText + jr z, .done + + cp FLY + ld hl, .BattleFlewText + jr z, .done + + cp DIG + ld hl, .BattleDugText + +.done + ret + +.BattleMadeWhirlwindText: + text_far _BattleMadeWhirlwindText + text_end + +.BattleTookSunlightText: + text_far _BattleTookSunlightText + text_end + +.BattleLoweredHeadText: + text_far _BattleLoweredHeadText + text_end + +.BattleGlowingText: + text_far _BattleGlowingText + text_end + +.BattleFlewText: + text_far _BattleFlewText + text_end + +.BattleDugText: + text_far _BattleDugText + text_end + +BattleCommand3c: +; unused + ret + +BattleCommand_TrapTarget: +; traptarget + + ld a, [wAttackMissed] + and a + ret nz + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + ldh 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 + ; trapped for 2-5 turns + and %11 + 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, WasTrappedText ; 'was trapped!' + dbw CLAMP, ClampedByText ; 'was CLAMPED by' + dbw WHIRLPOOL, WasTrappedText ; 'was trapped!' + +INCLUDE "engine/battle/move_effects/mist.asm" + +INCLUDE "engine/battle/move_effects/focus_energy.asm" + +BattleCommand_Recoil: +; recoil + + ld hl, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wEnemyMonMaxHP +.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, [wCurDamage] + ld b, a + ld a, [wCurDamage + 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 [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + dec hl + dec hl + ld a, [hl] + ld [wBuffer3], a + sub c + ld [hld], a + ld [wBuffer5], a + ld a, [hl] + ld [wBuffer4], a + sbc b + ld [hl], a + ld [wBuffer6], a + jr nc, .dont_ko + xor a + ld [hli], a + ld [hl], a + ld hl, wBuffer5 + ld [hli], a + ld [hl], a +.dont_ko + hlcoord 10, 9 + ldh 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 + +BattleCommand_ConfuseTarget: +; confusetarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + ret z + ld a, [wEffectFailed] + 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: +; 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, [wAttackMissed] + and a + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit +BattleCommand_FinishConfusingTarget: + ld bc, wEnemyConfuseCount + ldh a, [hBattleTurn] + and a + jr z, .got_confuse_count + ld bc, wPlayerConfuseCount + +.got_confuse_count + set SUBSTATUS_CONFUSED, [hl] + ; confused for 2-5 turns + call BattleRandom + and %11 + 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 + +BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit: + 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 + +BattleCommand_Paralyze: +; paralyze + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + bit PAR, a + jr nz, .paralyzed + ld a, [wTypeModifier] + 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 + ldh a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 25 percent + 1 ; 25% chance AI fails + jr c, .failed + +.dont_sample_failure + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jr nz, .failed + ld a, [wAttackMissed] + and a + jr nz, .failed + call CheckSubstituteOpp + jr nz, .failed + ld c, 30 + call DelayFrames + call AnimateCurrentMove + ld a, $1 + ldh [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 + +CheckMoveTypeMatchesTarget: +; Compare move type to opponent type. +; Return z if matching the opponent type, +; unless the move is Normal (Tri Attack). + + push hl + + ld hl, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wBattleMonType1 +.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 + +INCLUDE "engine/battle/move_effects/substitute.asm" + +BattleCommand_RechargeNextTurn: +; rechargenextturn + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RECHARGE, [hl] + ret + +EndRechargeOpp: + push hl + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_RECHARGE, [hl] + pop hl + ret + +INCLUDE "engine/battle/move_effects/rage.asm" + +BattleCommand_DoubleFlyingDamage: +; doubleflyingdamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + ret z + jr DoubleDamage + +BattleCommand_DoubleUndergroundDamage: +; doubleundergrounddamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret z + + ; fallthrough + +DoubleDamage: + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .quit + + ld a, $ff + ld [hli], a + ld [hl], a +.quit + ret + +INCLUDE "engine/battle/move_effects/mimic.asm" + +INCLUDE "engine/battle/move_effects/leech_seed.asm" + +INCLUDE "engine/battle/move_effects/splash.asm" + +INCLUDE "engine/battle/move_effects/disable.asm" + +INCLUDE "engine/battle/move_effects/pay_day.asm" + +INCLUDE "engine/battle/move_effects/conversion.asm" + +BattleCommand_ResetStats: +; resetstats + + ld a, 7 ; neutral + ld hl, wPlayerStatLevels + call .Fill + ld hl, wEnemyStatLevels + call .Fill + + ldh a, [hBattleTurn] + push af + + call SetPlayerTurn + call CalcPlayerStats + call SetEnemyTurn + call CalcEnemyStats + + pop af + ldh [hBattleTurn], a + + call AnimateCurrentMove + + ld hl, EliminatedStatsText + jp StdBattleTextbox + +.Fill: + ld b, wPlayerStatLevelsEnd - wPlayerStatLevels +.next + ld [hli], a + dec b + jr nz, .next + ret + +BattleCommand_Heal: +; heal + + ld de, wBattleMonHP + ld hl, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld de, wEnemyMonHP + ld hl, wEnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + push hl + push de + push bc + ld c, 2 + call CompareBytes + 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 + ldh 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 + +INCLUDE "engine/battle/move_effects/transform.asm" + +BattleEffect_ButItFailed: + call AnimateFailedMove + jp PrintButItFailed + +ClearLastMove: + 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 + +ResetActorDisable: + ldh a, [hBattleTurn] + and a + jr z, .player + + xor a + ld [wEnemyDisableCount], a + ld [wEnemyDisabledMove], a + ret + +.player + xor a + ld [wPlayerDisableCount], a + ld [wDisabledMove], a + ret + +BattleCommand_Screen: +; screen + + ld hl, wPlayerScreens + ld bc, wPlayerLightScreenCount + ldh a, [hBattleTurn] + and a + jr z, .got_screens_pointer + ld hl, wEnemyScreens + ld bc, wEnemyLightScreenCount + +.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 + +PrintDoesntAffect: +; 'it doesn't affect' + ld hl, DoesntAffectText + jp StdBattleTextbox + +PrintNothingHappened: +; 'but nothing happened!' + ld hl, NothingHappenedText + jp StdBattleTextbox + +TryPrintButItFailed: + ld a, [wAlreadyFailed] + and a + ret nz + + ; fallthrough + +PrintButItFailed: +; 'but it failed!' + ld hl, ButItFailedText + jp StdBattleTextbox + +FailMove: + call AnimateFailedMove + ; fallthrough + +FailMimic: + ld hl, ButItFailedText ; 'but it failed!' + ld de, ItFailedText ; 'it failed!' + jp FailText_CheckOpponentProtect + +PrintDidntAffect: +; 'it didn't affect' + ld hl, DidntAffect1Text + jp StdBattleTextbox + +PrintDidntAffect2: + call AnimateFailedMove + ld hl, DidntAffect1Text ; 'it didn't affect' + ld de, DidntAffect2Text ; 'it didn't affect' + jp FailText_CheckOpponentProtect + +PrintParalyze: +; 'paralyzed! maybe it can't attack!' + ld hl, ParalyzedText + jp StdBattleTextbox + +CheckSubstituteOpp: + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret + +INCLUDE "engine/battle/move_effects/selfdestruct.asm" + +INCLUDE "engine/battle/move_effects/mirror_move.asm" + +INCLUDE "engine/battle/move_effects/metronome.asm" + +CheckUserMove: +; Return z if the user has move a. + ld b, a + ld de, wBattleMonMoves + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wEnemyMonMoves +.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 + +ResetTurn: + ld hl, wPlayerCharging + ldh a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyCharging + +.player + ld [hl], 1 + xor a + ld [wAlreadyDisobeyed], a + call DoMove + jp EndMoveEffect + +INCLUDE "engine/battle/move_effects/thief.asm" + +BattleCommand_ArenaTrap: +; 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 + +INCLUDE "engine/battle/move_effects/nightmare.asm" + +BattleCommand_Defrost: +; 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. + + ldh 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 + +INCLUDE "engine/battle/move_effects/curse.asm" + +INCLUDE "engine/battle/move_effects/protect.asm" + +INCLUDE "engine/battle/move_effects/endure.asm" + +INCLUDE "engine/battle/move_effects/spikes.asm" + +INCLUDE "engine/battle/move_effects/foresight.asm" + +INCLUDE "engine/battle/move_effects/perish_song.asm" + +INCLUDE "engine/battle/move_effects/sandstorm.asm" + +INCLUDE "engine/battle/move_effects/rollout.asm" + +BattleCommand5d: +; unused + ret + +INCLUDE "engine/battle/move_effects/fury_cutter.asm" + +INCLUDE "engine/battle/move_effects/attract.asm" + +INCLUDE "engine/battle/move_effects/return.asm" + +INCLUDE "engine/battle/move_effects/present.asm" + +INCLUDE "engine/battle/move_effects/frustration.asm" + +INCLUDE "engine/battle/move_effects/safeguard.asm" + +SafeCheckSafeguard: + push hl + ld hl, wEnemyScreens + ldh a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, wPlayerScreens + +.got_turn + bit SCREENS_SAFEGUARD, [hl] + pop hl + ret + +BattleCommand_CheckSafeguard: +; checksafeguard + ld hl, wEnemyScreens + ldh a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, wPlayerScreens +.got_turn + bit SCREENS_SAFEGUARD, [hl] + ret z + ld a, 1 + ld [wAttackMissed], a + call BattleCommand_MoveDelay + ld hl, SafeguardProtectText + call StdBattleTextbox + jp EndMoveEffect + +INCLUDE "engine/battle/move_effects/magnitude.asm" + +INCLUDE "engine/battle/move_effects/baton_pass.asm" + +INCLUDE "engine/battle/move_effects/pursuit.asm" + +INCLUDE "engine/battle/move_effects/rapid_spin.asm" + +BattleCommand_HealMorn: +; healmorn + ld b, MORN_F + jr BattleCommand_TimeBasedHealContinue + +BattleCommand_HealDay: +; healday + ld b, DAY_F + jr BattleCommand_TimeBasedHealContinue + +BattleCommand_HealNite: +; healnite + ld b, NITE_F + ; fallthrough + +BattleCommand_TimeBasedHealContinue: +; Time- and weather-sensitive heal. + + ld hl, wBattleMonMaxHP + ld de, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .start + ld hl, wEnemyMonMaxHP + ld de, wEnemyMonHP + +.start +; Index for .Multipliers +; Default restores half max HP. + ld c, 2 + +; Don't bother healing if HP is already full. + push bc + call CompareBytes + 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, [wTimeOfDay] + cp b + jr z, .Weather + dec c ; double + +.Weather: + ld a, [wBattleWeather] + 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 + +INCLUDE "engine/battle/move_effects/hidden_power.asm" + +INCLUDE "engine/battle/move_effects/rain_dance.asm" + +INCLUDE "engine/battle/move_effects/sunny_day.asm" + +INCLUDE "engine/battle/move_effects/belly_drum.asm" + +INCLUDE "engine/battle/move_effects/psych_up.asm" + +INCLUDE "engine/battle/move_effects/mirror_coat.asm" + +BattleCommand_DoubleMinimizeDamage: +; doubleminimizedamage + + ld hl, wEnemyMinimized + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerMinimized +.ok + ld a, [hl] + and a + ret z + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hl], a + ret + +BattleCommand_SkipSunCharge: +; mimicsuncharge + ld a, [wBattleWeather] + cp WEATHER_SUN + ret nz + ld b, charge_command + jp SkipToBattleCommand + +INCLUDE "engine/battle/move_effects/future_sight.asm" + +INCLUDE "engine/battle/move_effects/thunder.asm" + +CheckHiddenOpponent: +; BUG: This routine is completely redundant and introduces a bug, since BattleCommand_CheckHit does these checks properly. + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +GetUserItem: +; Return the effect of the user's item in bc, and its id at hl. + ld hl, wBattleMonItem + ldh a, [hBattleTurn] + and a + jr z, .go + ld hl, wEnemyMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +GetOpponentItem: +; Return the effect of the opponent's item in bc, and its id at hl. + ld hl, wEnemyMonItem + ldh a, [hBattleTurn] + and a + jr z, .go + ld hl, wBattleMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +GetItemHeldEffect: +; 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 + +AnimateCurrentMoveEitherSide: + 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 + +AnimateCurrentMove: + 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 + +PlayDamageAnim: + xor a + ld [wFXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ld [wFXAnimID], a + + ldh a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .player + ld a, BATTLEANIM_PLAYER_DAMAGE + +.player + ld [wNumHits], a + + jp PlayUserBattleAnim + +LoadMoveAnim: + xor a + ld [wNumHits], a + ld [wFXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ; fallthrough + +LoadAnim: + ld [wFXAnimID], a + + ; fallthrough + +PlayUserBattleAnim: + push hl + push de + push bc + callfar PlayBattleAnim + pop bc + pop de + pop hl + ret + +PlayOpponentBattleAnim: + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 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 + +CallBattleCore: + ld a, BANK("Battle Core") + rst FarCall + ret + +AnimateFailedMove: + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + jp BattleCommand_RaiseSub + +BattleCommand_MoveDelay: +; movedelay +; Wait 40 frames. + ld c, 40 + jp DelayFrames + +BattleCommand_ClearText: +; cleartext + +; Used in multi-hit moves. + ld hl, .text + jp PrintText + +.text: + text_end + +SkipToBattleCommand: +; Skip over commands until reaching command b. + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + ld a, [wBattleScriptBufferAddress] + ld l, a +.loop + ld a, [hli] + cp b + jr nz, .loop + + ld a, h + ld [wBattleScriptBufferAddress + 1], a + ld a, l + ld [wBattleScriptBufferAddress], a + ret + +GetMoveAttr: +; Assuming hl = Moves + x, return attribute x of move a. + push bc + ld bc, MOVE_LENGTH + call AddNTimes + call GetMoveByte + pop bc + ret + +GetMoveData: +; Copy move struct a to de. + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + jp FarCopyBytes + +GetMoveByte: + ld a, BANK(Moves) + jp GetFarByte + +DisappearUser: + farcall _DisappearUser + ret + +AppearUserLowerSub: + farcall _AppearUserLowerSub + ret + +AppearUserRaiseSub: + farcall _AppearUserRaiseSub + ret diff --git a/engine/battle/menu.asm b/engine/battle/menu.asm new file mode 100644 index 00000000..f75d4114 --- /dev/null +++ b/engine/battle/menu.asm @@ -0,0 +1,94 @@ +LoadBattleMenu: + ld hl, BattleMenuHeader + call LoadMenuHeader + jr Function24e78 + +SafariBattleMenu: + ; untranslated + ld hl, MenuHeader_0x24eae + call LoadMenuHeader + jr Function24e78 + +ContestBattleMenu: + ld hl, MenuHeader_0x24ee9 + call LoadMenuHeader +; fallthrough +Function24e78: + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + call _2DMenu + ld a, [wMenuCursorBuffer] + ld [wBattleMenuCursorBuffer], a + call ExitMenu + ret + +BattleMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 8, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw MenuData_0x24e93 + db 1 ; default option + +MenuData_0x24e93: + db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags + dn 2, 2 ; rows, columns + db 6 ; spacing + dba Strings24e9c + dbw BANK(MenuData_0x24e93), 0 + +Strings24e9c: + db "FIGHT@" + db "<PK><MN>@" + db "PACK@" + db "RUN@" + +MenuHeader_0x24eae: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw MenuData_0x24eb6 + db 1 ; default option + +MenuData_0x24eb6: + db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags + dn 2, 2 ; rows, columns + db 11 ; spacing + dba Strings24ebf + dba Function24edc + +Strings24ebf: + db "サファりボール× @" ; "SAFARI BALL× @" + db "エサをなげる@" ; "THROW BAIT" + db "いしをなげる@" ; "THROW ROCK" + db "にげる@" ; "RUN" + +Function24edc: + hlcoord 17, 13 + ld de, wSafariBallsRemaining + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret + +MenuHeader_0x24ee9: + db MENU_BACKUP_TILES ; flags + menu_coords 2, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw MenuData_0x24ef1 + db 1 ; default option + +MenuData_0x24ef1: + db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags + dn 2, 2 ; rows, columns + db 12 ; spacing + dba Strings24efa + dba Strings24f13 + +Strings24efa: + db "FIGHT@" + db "<PK><MN>@" + db "PARKBALL× @" + db "RUN@" + +Strings24f13: + hlcoord 13, 16 + ld de, wParkBallsRemaining + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret diff --git a/engine/battle/move_effects/attract.asm b/engine/battle/move_effects/attract.asm new file mode 100644 index 00000000..5eb82d65 --- /dev/null +++ b/engine/battle/move_effects/attract.asm @@ -0,0 +1,76 @@ +BattleCommand_Attract: +; attract + ld a, [wAttackMissed] + 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 FailMove + +CheckOppositeGender: + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hl] + ld [wCurPartySpecies], a + + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + xor a + ld [wMonType], a + + farcall GetGender + jr c, .genderless_samegender + + ld b, 1 + jr nz, .got_gender + dec b + +.got_gender + push bc + ld a, [wTempEnemyMonSpecies] + ld [wCurPartySpecies], a + ld hl, wEnemyMonDVs + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .not_transformed + ld hl, wEnemyBackupDVs +.not_transformed + ld a, [hli] + ld [wTempMonDVs], a + ld a, [hl] + ld [wTempMonDVs + 1], a + ld a, 3 + ld [wMonType], 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 diff --git a/engine/battle/move_effects/baton_pass.asm b/engine/battle/move_effects/baton_pass.asm new file mode 100644 index 00000000..bf9e3235 --- /dev/null +++ b/engine/battle/move_effects/baton_pass.asm @@ -0,0 +1,194 @@ +BattleCommand_BatonPass: +; batonpass + + ldh 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 LoadStandardMenuHeader + 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 + + 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 + +; Passed enemy PartyMon entrance + xor a + ld [wEnemySwitchMonIndex], a + ld hl, EnemySwitch_SetMode + call CallBattleCore + ld hl, ResetBattleParticipants + call CallBattleCore + ld a, TRUE + ld [wApplyStatLevelMultipliersToEnemy], a + ld hl, ApplyStatLevelMultiplierOnAllStats + call CallBattleCore + + ld hl, SpikesDamage + call CallBattleCore + + jr ResetBatonPassStatus + +BatonPass_LinkPlayerSwitch: + ld a, [wLinkMode] + and a + ret z + + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], a + + call LoadStandardMenuHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + call CloseWindow + + xor a ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ret + +BatonPass_LinkEnemySwitch: + ld a, [wLinkMode] + and a + ret z + + call LoadStandardMenuHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + jp CloseWindow + +FailedBatonPass: + call AnimateFailedMove + jp PrintButItFailed + +ResetBatonPassStatus: +; 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, wPlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, wEnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, wPlayerSubStatus5 + + 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 + +CheckAnyOtherAlivePartyMons: + ld hl, wPartyMon1HP + ld a, [wPartyCount] + ld d, a + ld a, [wCurBattleMon] + ld e, a + jr CheckAnyOtherAliveMons + +CheckAnyOtherAliveEnemyMons: + ld hl, wOTPartyMon1HP + ld a, [wOTPartyCount] + ld d, a + ld a, [wCurOTMon] + ld e, a + + ; fallthrough + +CheckAnyOtherAliveMons: +; 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 diff --git a/engine/battle/move_effects/beat_up.asm b/engine/battle/move_effects/beat_up.asm new file mode 100644 index 00000000..8546c37d --- /dev/null +++ b/engine/battle/move_effects/beat_up.asm @@ -0,0 +1,220 @@ +BattleCommand_BeatUp: +; beatup + + call ResetDamage + ldh a, [hBattleTurn] + and a + jp nz, .enemy_beats_up + + ld a, [wPlayerSubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .next_mon + + ld c, 20 + call DelayFrames + xor a + ld [wPlayerRolloutCount], a + ld [wceed], a + ld [wBeatUpHitAtLeastOnce], a + jr .got_mon + +.next_mon + ld a, [wPlayerRolloutCount] + ld b, a + ld a, [wPartyCount] + sub b + ld [wceed], a + +.got_mon + ld a, [wceed] + ld hl, wPartyMonNicknames + call GetNick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail ; fainted + ld a, [wceed] + ld c, a + ld a, [wCurBattleMon] + ; BUG: this can desynchronize link battles + ; Change "cp [hl]" to "cp c" to fix + cp [hl] + ld hl, wBattleMonStatus + 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, [wEnemyMonSpecies] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseDefense] + ld c, a + + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseAttack] + 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, [wEnemySubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .enemy_next_mon + + xor a + ld [wEnemyRolloutCount], a + ld [wceed], a + ld [wBeatUpHitAtLeastOnce], a + jr .enemy_got_mon + +.enemy_next_mon + ld a, [wEnemyRolloutCount] + ld b, a + ld a, [wOTPartyCount] + sub b + ld [wceed], a + +.enemy_got_mon + ld a, [wBattleMode] + dec a + jr z, .wild + + ld a, [wLinkMode] + and a + jr nz, .linked + + ld a, [wceed] + ld c, a + ld b, 0 + ld hl, wOTPartySpecies + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + jr .got_enemy_nick + +.linked + ld a, [wceed] + ld hl, wOTPartyMonNicknames + ld bc, NAME_LENGTH + call AddNTimes + ld de, wStringBuffer1 + call CopyBytes + +.got_enemy_nick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail + + ld a, [wceed] + ld b, a + ld a, [wCurOTMon] + cp b + ld hl, wEnemyMonStatus + 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, [wEnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BeatUpAttackText + call StdBattleTextbox + jp EnemyAttackDamage + +.finish_beatup + ld hl, BeatUpAttackText + call StdBattleTextbox + + ld a, [wBattleMonSpecies] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseDefense] + ld c, a + + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseAttack] + 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 + +.beatup_fail + ld b, buildopponentrage_command + jp SkipToBattleCommand + +BattleCommand_BeatUpFailText: +; beatupfailtext + + ld a, [wBeatUpHitAtLeastOnce] + and a + ret nz + + jp PrintButItFailed + +GetBeatupMonLocation: + push bc + ld c, a + ld b, 0 + ldh a, [hBattleTurn] + and a + ld hl, wPartyMon1Species + jr z, .got_species + ld hl, wOTPartyMon1Species + +.got_species + ld a, [wceed] + add hl, bc + call GetPartyLocation + pop bc + ret diff --git a/engine/battle/move_effects/belly_drum.asm b/engine/battle/move_effects/belly_drum.asm new file mode 100644 index 00000000..5b1361f2 --- /dev/null +++ b/engine/battle/move_effects/belly_drum.asm @@ -0,0 +1,30 @@ +BattleCommand_BellyDrum: +; 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, [wAttackMissed] + and a + jr nz, .failed + + callfar GetHalfMaxHP + callfar CheckUserHasEnoughHP + jr nc, .failed + + push bc + call AnimateCurrentMove + pop bc + callfar SubtractHPFromUser + call UpdateUserInParty + +rept 5 + call BattleCommand_AttackUp2 +endr + + ld hl, BellyDrumText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/bide.asm b/engine/battle/move_effects/bide.asm new file mode 100644 index 00000000..74f7c9cf --- /dev/null +++ b/engine/battle/move_effects/bide.asm @@ -0,0 +1,100 @@ +BattleCommand_StoreEnergy: +; storeenergy + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_BIDE, a + ret z + + ld hl, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .check_still_storing_energy + ld hl, wEnemyRolloutCount +.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, wPlayerDamageTaken + 1 + ld de, wPlayerCharging ; player + ldh a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyDamageTaken + 1 + ld de, wEnemyCharging ; enemy +.player + ld a, [hld] + add a + ld b, a + ld [wCurDamage + 1], a + ld a, [hl] + rl a + ld [wCurDamage], a + jr nc, .not_maxed + ld a, $ff + ld [wCurDamage], a + ld [wCurDamage + 1], a +.not_maxed + or b + jr nz, .built_up_something + ld a, 1 + ld [wAttackMissed], 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 + +BattleCommand_UnleashEnergy: +; unleashenergy + + ld de, wPlayerDamageTaken + ld bc, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .got_damage + ld de, wEnemyDamageTaken + ld bc, wEnemyRolloutCount +.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 diff --git a/engine/battle/move_effects/conversion.asm b/engine/battle/move_effects/conversion.asm new file mode 100644 index 00000000..b6081a6b --- /dev/null +++ b/engine/battle/move_effects/conversion.asm @@ -0,0 +1,96 @@ +BattleCommand_Conversion: +; conversion + + ld hl, wBattleMonMoves + ld de, wBattleMonType1 + ldh a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, wEnemyMonMoves + ld de, wEnemyMonType1 +.got_moves + push de + ld c, 0 + ld de, wStringBuffer1 +.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, wStringBuffer1 +.loop2 + ld a, [hl] + cp -1 + jr z, .fail + cp CURSE_TYPE + 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 + maskbits NUM_MOVES + ld c, a + ld b, 0 + ld hl, wStringBuffer1 + add hl, bc + ld a, [hl] + cp -1 + jr z, .loop3 + cp CURSE_TYPE + 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 diff --git a/engine/battle/move_effects/conversion2.asm b/engine/battle/move_effects/conversion2.asm new file mode 100644 index 00000000..bc866727 --- /dev/null +++ b/engine/battle/move_effects/conversion2.asm @@ -0,0 +1,64 @@ +BattleCommand_Conversion2: +; conversion2 + + ld a, [wAttackMissed] + and a + jr nz, .failed + ld hl, wBattleMonType1 + ldh a, [hBattleTurn] + and a + jr z, .got_type + ld hl, wEnemyMonType1 +.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_TYPE + jr z, .failed + call AnimateCurrentMove + call BattleCommand_SwitchTurn + +.loop + call BattleRandom + maskbits NUM_TYPES + 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 EFFECTIVE + jr nc, .loop + call BattleCommand_SwitchTurn + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + predef GetTypeName + ld hl, TransformedTypeText + jp StdBattleTextbox + +.failed + jp FailMove diff --git a/engine/battle/move_effects/counter.asm b/engine/battle/move_effects/counter.asm new file mode 100644 index 00000000..031c399a --- /dev/null +++ b/engine/battle/move_effects/counter.asm @@ -0,0 +1,59 @@ +BattleCommand_Counter: +; counter + + ld a, 1 + ld [wAttackMissed], 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, wStringBuffer1 + call GetMoveData + + ld a, [wStringBuffer1 + MOVE_POWER] + and a + ret z + + ld a, [wStringBuffer1 + MOVE_TYPE] + cp SPECIAL + ret nc + + ; BUG: Move should fail with all non-damaging battle actions + ld hl, wCurDamage + 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 [wAttackMissed], a + ret diff --git a/engine/battle/move_effects/curse.asm b/engine/battle/move_effects/curse.asm new file mode 100644 index 00000000..3507c668 --- /dev/null +++ b/engine/battle/move_effects/curse.asm @@ -0,0 +1,93 @@ +BattleCommand_Curse: +; curse + + ld de, wBattleMonType1 + ld bc, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .go + ld de, wEnemyMonType1 + ld bc, wEnemyStatLevels + +.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 diff --git a/engine/battle/move_effects/destiny_bond.asm b/engine/battle/move_effects/destiny_bond.asm new file mode 100644 index 00000000..6a03b9a7 --- /dev/null +++ b/engine/battle/move_effects/destiny_bond.asm @@ -0,0 +1,9 @@ +BattleCommand_DestinyBond: +; destinybond + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_DESTINY_BOND, [hl] + call AnimateCurrentMove + ld hl, DestinyBondEffectText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/disable.asm b/engine/battle/move_effects/disable.asm new file mode 100644 index 00000000..de6dbc60 --- /dev/null +++ b/engine/battle/move_effects/disable.asm @@ -0,0 +1,72 @@ +BattleCommand_Disable: +; disable + + ld a, [wAttackMissed] + and a + jr nz, .failed + + ld de, wEnemyDisableCount + ld hl, wEnemyMonMoves + ldh a, [hBattleTurn] + and a + jr z, .got_moves + ld de, wPlayerDisableCount + ld hl, wBattleMonMoves +.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 + + ldh a, [hBattleTurn] + and a + ld hl, wEnemyMonPP + jr z, .got_pp + ld hl, wBattleMonPP +.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, wDisabledMove + ldh 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 FailMove diff --git a/engine/battle/move_effects/encore.asm b/engine/battle/move_effects/encore.asm new file mode 100644 index 00000000..8ca3595f --- /dev/null +++ b/engine/battle/move_effects/encore.asm @@ -0,0 +1,120 @@ +BattleCommand_Encore: +; encore + + ld hl, wEnemyMonMoves + ld de, wEnemyEncoreCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wBattleMonMoves + ld de, wPlayerEncoreCount +.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, wBattleMonPP - wBattleMonMoves - 1 + add hl, bc + ld a, [hl] + and PP_MASK + jp z, .failed + ld a, [wAttackMissed] + 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 + ldh a, [hBattleTurn] + and a + jr z, .force_last_enemy_move + + push hl + ld a, [wLastPlayerMove] + ld b, a + ld c, 0 + ld hl, wBattleMonMoves +.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 [wCurMoveNum], a + ld a, b + ld [wCurPlayerMove], a + dec a + ld de, wPlayerMoveStruct + call GetMoveData + jr .finish_move + +.force_last_enemy_move + push hl + ld a, [wLastEnemyMove] + ld b, a + ld c, 0 + ld hl, wEnemyMonMoves +.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 [wCurEnemyMoveNum], a + ld a, b + ld [wCurEnemyMove], a + dec a + ld de, wEnemyMoveStruct + call GetMoveData + +.finish_move + call AnimateCurrentMove + ld hl, GotAnEncoreText + jp StdBattleTextbox + +.failed + jp PrintDidntAffect2 diff --git a/engine/battle/move_effects/endure.asm b/engine/battle/move_effects/endure.asm new file mode 100644 index 00000000..00ccb130 --- /dev/null +++ b/engine/battle/move_effects/endure.asm @@ -0,0 +1,16 @@ +BattleCommand_Endure: +; 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 diff --git a/engine/battle/move_effects/false_swipe.asm b/engine/battle/move_effects/false_swipe.asm new file mode 100644 index 00000000..e2e0c6f1 --- /dev/null +++ b/engine/battle/move_effects/false_swipe.asm @@ -0,0 +1,48 @@ +BattleCommand_FalseSwipe: +; falseswipe + +; Makes sure wCurDamage < MonHP + + ld hl, wEnemyMonHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wBattleMonHP +.got_hp + ld de, wCurDamage + ld c, 2 + push hl + push de + call CompareBytes + 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, [wCriticalHit] + cp 2 + jr nz, .carry + xor a + ld [wCriticalHit], a + +.carry + scf + ret + +.done + and a + ret diff --git a/engine/battle/move_effects/focus_energy.asm b/engine/battle/move_effects/focus_energy.asm new file mode 100644 index 00000000..c4eb1f33 --- /dev/null +++ b/engine/battle/move_effects/focus_energy.asm @@ -0,0 +1,15 @@ +BattleCommand_FocusEnergy: +; 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 diff --git a/engine/battle/move_effects/foresight.asm b/engine/battle/move_effects/foresight.asm new file mode 100644 index 00000000..ff25b04e --- /dev/null +++ b/engine/battle/move_effects/foresight.asm @@ -0,0 +1,22 @@ +BattleCommand_Foresight: +; foresight + + ld a, [wAttackMissed] + 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 FailMove diff --git a/engine/battle/move_effects/frustration.asm b/engine/battle/move_effects/frustration.asm new file mode 100644 index 00000000..b07942c7 --- /dev/null +++ b/engine/battle/move_effects/frustration.asm @@ -0,0 +1,27 @@ +BattleCommand_FrustrationPower: +; frustrationpower + + push bc + ld hl, wBattleMonHappiness + ldh a, [hBattleTurn] + and a + jr z, .got_happiness + ld hl, wEnemyMonHappiness +.got_happiness + ld a, $ff + sub [hl] + ldh [hMultiplicand + 2], a + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, 10 + ldh [hMultiplier], a + call Multiply + ld a, 25 + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld d, a + pop bc + ret diff --git a/engine/battle/move_effects/fury_cutter.asm b/engine/battle/move_effects/fury_cutter.asm new file mode 100644 index 00000000..a1284849 --- /dev/null +++ b/engine/battle/move_effects/fury_cutter.asm @@ -0,0 +1,55 @@ +BattleCommand_FuryCutter: +; furycutter + + ld hl, wPlayerFuryCutterCount + ldh a, [hBattleTurn] + and a + jr z, .go + ld hl, wEnemyFuryCutterCount + +.go + ld a, [wAttackMissed] + 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, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .checkdouble + +; No overflow + ld a, $ff + ld [hli], a + ld [hl], a + ret + +ResetFuryCutterCount: + push hl + + ld hl, wPlayerFuryCutterCount + ldh a, [hBattleTurn] + and a + jr z, .reset + ld hl, wEnemyFuryCutterCount + +.reset + xor a + ld [hl], a + + pop hl + ret diff --git a/engine/battle/move_effects/future_sight.asm b/engine/battle/move_effects/future_sight.asm new file mode 100644 index 00000000..129a9e08 --- /dev/null +++ b/engine/battle/move_effects/future_sight.asm @@ -0,0 +1,81 @@ +BattleCommand_CheckFutureSight: +; checkfuturesight + + ld hl, wPlayerFutureSightCount + ld de, wPlayerFutureSightDamage + ldh 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 [wCurDamage], a + ld a, [de] + ld [wCurDamage + 1], a + ld b, futuresight_command + jp SkipToBattleCommand + +BattleCommand_FutureSight: +; 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 + ldh 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 + ldh a, [hBattleTurn] + and a + jr z, .StoreDamage + ld de, wEnemyFutureSightDamage +.StoreDamage: + ld hl, wCurDamage + 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 diff --git a/engine/battle/move_effects/heal_bell.asm b/engine/battle/move_effects/heal_bell.asm new file mode 100644 index 00000000..62309f1d --- /dev/null +++ b/engine/battle/move_effects/heal_bell.asm @@ -0,0 +1,34 @@ +BattleCommand_HealBell: +; healbell + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] + ld de, wPartyMon1Status + ldh a, [hBattleTurn] + and a + jr z, .got_status + ld de, wOTPartyMon1Status +.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 + + ldh a, [hBattleTurn] + and a + jp z, CalcPlayerStats + jp CalcEnemyStats diff --git a/engine/battle/move_effects/hidden_power.asm b/engine/battle/move_effects/hidden_power.asm new file mode 100644 index 00000000..3b40a6c3 --- /dev/null +++ b/engine/battle/move_effects/hidden_power.asm @@ -0,0 +1,8 @@ +BattleCommand_HiddenPower: +; hiddenpower + + ld a, [wAttackMissed] + and a + ret nz + farcall HiddenPowerDamage + ret diff --git a/engine/battle/move_effects/leech_seed.asm b/engine/battle/move_effects/leech_seed.asm new file mode 100644 index 00000000..bb17ee00 --- /dev/null +++ b/engine/battle/move_effects/leech_seed.asm @@ -0,0 +1,40 @@ +BattleCommand_LeechSeed: +; leechseed + ld a, [wAttackMissed] + and a + jr nz, .evaded + call CheckSubstituteOpp + jr nz, .evaded + + ld de, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wBattleMonType1 +.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 diff --git a/engine/battle/move_effects/lock_on.asm b/engine/battle/move_effects/lock_on.asm new file mode 100644 index 00000000..1de3e14b --- /dev/null +++ b/engine/battle/move_effects/lock_on.asm @@ -0,0 +1,21 @@ +BattleCommand_LockOn: +; lockon + + call CheckSubstituteOpp + jr nz, .fail + + ld a, [wAttackMissed] + 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 diff --git a/engine/battle/move_effects/magnitude.asm b/engine/battle/move_effects/magnitude.asm new file mode 100644 index 00000000..f8961b66 --- /dev/null +++ b/engine/battle/move_effects/magnitude.asm @@ -0,0 +1,29 @@ +BattleCommand_GetMagnitude: +; getmagnitude + + push bc + call BattleRandom + ld b, a + ld hl, MagnitudePower +.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 [wDeciramBuffer], a + call BattleCommand_MoveDelay + ld hl, MagnitudeText + call StdBattleTextbox + pop de + pop bc + ret + +INCLUDE "data/moves/magnitude_power.asm" diff --git a/engine/battle/move_effects/metronome.asm b/engine/battle/move_effects/metronome.asm new file mode 100644 index 00000000..02766c16 --- /dev/null +++ b/engine/battle/move_effects/metronome.asm @@ -0,0 +1,43 @@ +BattleCommand_Metronome: +; metronome + + call ClearLastMove + call CheckUserIsCharging + jr nz, .asm_3752a + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.asm_3752a + 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 + +INCLUDE "data/moves/metronome_exception_moves.asm" diff --git a/engine/battle/move_effects/mimic.asm b/engine/battle/move_effects/mimic.asm new file mode 100644 index 00000000..71eb72c6 --- /dev/null +++ b/engine/battle/move_effects/mimic.asm @@ -0,0 +1,50 @@ +BattleCommand_Mimic: +; mimic + + call ClearLastMove + call BattleCommand_MoveDelay + ld a, [wAttackMissed] + and a + jr nz, .fail + ld hl, wBattleMonMoves + ldh a, [hBattleTurn] + and a + jr z, .player_turn + ld hl, wEnemyMonMoves +.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, wBattleMonPP - wBattleMonMoves + add hl, bc + ld [hl], 5 + call GetMoveName + call AnimateCurrentMove + ld hl, MimicLearnedMoveText + jp StdBattleTextbox + +.fail + jp FailMimic diff --git a/engine/battle/move_effects/mirror_coat.asm b/engine/battle/move_effects/mirror_coat.asm new file mode 100644 index 00000000..96afa317 --- /dev/null +++ b/engine/battle/move_effects/mirror_coat.asm @@ -0,0 +1,60 @@ +BattleCommand_MirrorCoat: +; mirrorcoat + + ld a, 1 + ld [wAttackMissed], 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, wStringBuffer1 + call GetMoveData + + ld a, [wStringBuffer1 + MOVE_POWER] + and a + ret z + + ld a, [wStringBuffer1 + MOVE_TYPE] + cp SPECIAL + ret c + + ; BUG: Move should fail with all non-damaging battle actions + ld hl, wCurDamage + 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 [wAttackMissed], a + ret diff --git a/engine/battle/move_effects/mirror_move.asm b/engine/battle/move_effects/mirror_move.asm new file mode 100644 index 00000000..98e8aacc --- /dev/null +++ b/engine/battle/move_effects/mirror_move.asm @@ -0,0 +1,51 @@ +BattleCommand_MirrorMove: +; 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 [wNamedObjectIndexBuffer], 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 diff --git a/engine/battle/move_effects/mist.asm b/engine/battle/move_effects/mist.asm new file mode 100644 index 00000000..26fafdd2 --- /dev/null +++ b/engine/battle/move_effects/mist.asm @@ -0,0 +1,15 @@ +BattleCommand_Mist: +; 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 diff --git a/engine/battle/move_effects/nightmare.asm b/engine/battle/move_effects/nightmare.asm new file mode 100644 index 00000000..9354b15b --- /dev/null +++ b/engine/battle/move_effects/nightmare.asm @@ -0,0 +1,37 @@ +BattleCommand_Nightmare: +; 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 diff --git a/engine/battle/move_effects/pain_split.asm b/engine/battle/move_effects/pain_split.asm new file mode 100644 index 00000000..68d7cfb4 --- /dev/null +++ b/engine/battle/move_effects/pain_split.asm @@ -0,0 +1,92 @@ +BattleCommand_PainSplit: +; painsplit + + ld a, [wAttackMissed] + and a + jp nz, .ButItFailed + call CheckSubstituteOpp + jp nz, .ButItFailed + call AnimateCurrentMove + ld hl, wBattleMonMaxHP + 1 + ld de, wEnemyMonMaxHP + 1 + call .PlayerShareHP + ld a, $1 + ld [wWhichHPBar], a + hlcoord 10, 9 + predef AnimateHPBar + ld hl, wEnemyMonHP + ld a, [hli] + ld [wBuffer4], a + ld a, [hli] + ld [wBuffer3], a + ld a, [hli] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + call .EnemyShareHP + xor a + ld [wWhichHPBar], a + call ResetDamage + hlcoord 2, 2 + predef AnimateHPBar + + ld hl, SharedPainText + jp StdBattleTextbox + +.PlayerShareHP: + ld a, [hld] + ld [wBuffer1], a + ld a, [hld] + ld [wBuffer2], a + ld a, [hld] + ld b, a + ld [wBuffer3], a + ld a, [hl] + ld [wBuffer4], a + dec de + dec de + ld a, [de] + dec de + add b + ld [wCurDamage + 1], a + ld b, [hl] + ld a, [de] + adc b + srl a + ld [wCurDamage], a + ld a, [wCurDamage + 1] + rr a + ld [wCurDamage + 1], a + inc hl + inc hl + inc hl + inc de + inc de + inc de + +.EnemyShareHP: + ld c, [hl] + dec hl + ld a, [wCurDamage + 1] + sub c + ld b, [hl] + dec hl + ld a, [wCurDamage] + sbc b + jr nc, .skip + + ld a, [wCurDamage] + ld b, a + ld a, [wCurDamage + 1] + ld c, a +.skip + ld a, c + ld [hld], a + ld [wBuffer5], a + ld a, b + ld [hli], a + ld [wBuffer6], a + ret + +.ButItFailed: + jp PrintDidntAffect2 diff --git a/engine/battle/move_effects/pay_day.asm b/engine/battle/move_effects/pay_day.asm new file mode 100644 index 00000000..5f857aea --- /dev/null +++ b/engine/battle/move_effects/pay_day.asm @@ -0,0 +1,26 @@ +BattleCommand_PayDay: +; payday + + xor a + ld hl, wStringBuffer1 + ld [hli], a + + ldh a, [hBattleTurn] + and a + ld a, [wBattleMonLevel] + jr z, .ok + ld a, [wEnemyMonLevel] +.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 diff --git a/engine/battle/move_effects/perish_song.asm b/engine/battle/move_effects/perish_song.asm new file mode 100644 index 00000000..1758b65a --- /dev/null +++ b/engine/battle/move_effects/perish_song.asm @@ -0,0 +1,38 @@ +BattleCommand_PerishSong: +; perishsong + + ld hl, wPlayerSubStatus1 + ld de, wEnemySubStatus1 + 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 [wPlayerPerishCount], a + +.enemy + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .done + + set SUBSTATUS_PERISH, a + ld [de], a + ld a, 4 + ld [wEnemyPerishCount], a + +.done + call AnimateCurrentMove + ld hl, StartPerishText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/present.asm b/engine/battle/move_effects/present.asm new file mode 100644 index 00000000..360a4172 --- /dev/null +++ b/engine/battle/move_effects/present.asm @@ -0,0 +1,75 @@ +BattleCommand_Present: +; present + + call BattleCommand_Stab + ld a, [wTypeMatchup] + and a + jp z, AnimateFailedMove + ld a, [wAttackMissed] + and a + jp nz, AnimateFailedMove + + push bc + call BattleRandom + ld b, a + ld hl, PresentPower + ld c, 0 +.next + ld a, [hli] + cp -1 + jr z, .heal_effect + cp b + jr nc, .got_power + inc c + inc hl + jr .next + +.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 + ldh a, [hBattleTurn] + and a + jr z, .got_hp_fn_pointer + ld hl, AICheckEnemyMaxHP +.got_hp_fn_pointer + ld a, BANK(AICheckPlayerMaxHP) ; aka BANK(AICheckEnemyMaxHP) + rst FarCall + jr c, .already_fully_healed + + 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 + +.already_fully_healed + call BattleCommand_SwitchTurn + ; check battle scene + ld a, [wOptions] + add a + jr nc, .do_animation + call AnimateFailedMove + ld hl, CantReceiveGiftText + call StdBattleTextbox +.do_animation + jp EndMoveEffect + +INCLUDE "data/moves/present_power.asm" diff --git a/engine/battle/move_effects/protect.asm b/engine/battle/move_effects/protect.asm new file mode 100644 index 00000000..9f3899a9 --- /dev/null +++ b/engine/battle/move_effects/protect.asm @@ -0,0 +1,75 @@ +BattleCommand_Protect: +; protect + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_PROTECT, [hl] + + call AnimateCurrentMove + + ld hl, ProtectedItselfText + jp StdBattleTextbox + +ProtectChance: + ld de, wPlayerProtectCount + ldh a, [hBattleTurn] + and a + jr z, .asm_37736 + ld de, wEnemyProtectCount +.asm_37736 + + 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 diff --git a/engine/battle/move_effects/psych_up.asm b/engine/battle/move_effects/psych_up.asm new file mode 100644 index 00000000..3473b9db --- /dev/null +++ b/engine/battle/move_effects/psych_up.asm @@ -0,0 +1,47 @@ +BattleCommand_PsychUp: +; psychup + + ld hl, wEnemyStatLevels + ld de, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .pointers_correct +; It's the enemy's turn, so swap the pointers. + ld hl, wPlayerStatLevels + ld de, wEnemyStatLevels +.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 + ldh 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 diff --git a/engine/battle/move_effects/pursuit.asm b/engine/battle/move_effects/pursuit.asm new file mode 100644 index 00000000..f8979fb9 --- /dev/null +++ b/engine/battle/move_effects/pursuit.asm @@ -0,0 +1,24 @@ +BattleCommand_Pursuit: +; pursuit +; Double damage if the opponent is switching. + + ld hl, wEnemyIsSwitching + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerIsSwitching +.ok + ld a, [hl] + and a + ret z + + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + + ld a, $ff + ld [hli], a + ld [hl], a + ret diff --git a/engine/battle/move_effects/rage.asm b/engine/battle/move_effects/rage.asm new file mode 100644 index 00000000..df206a6b --- /dev/null +++ b/engine/battle/move_effects/rage.asm @@ -0,0 +1,6 @@ +BattleCommand_Rage: +; rage + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RAGE, [hl] + ret diff --git a/engine/battle/move_effects/rain_dance.asm b/engine/battle/move_effects/rain_dance.asm new file mode 100644 index 00000000..c22fb9fd --- /dev/null +++ b/engine/battle/move_effects/rain_dance.asm @@ -0,0 +1,9 @@ +BattleCommand_StartRain: +; startrain + ld a, WEATHER_RAIN + ld [wBattleWeather], a + ld a, 5 + ld [wWeatherCount], a + call AnimateCurrentMove + ld hl, DownpourText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/rapid_spin.asm b/engine/battle/move_effects/rapid_spin.asm new file mode 100644 index 00000000..eb396a35 --- /dev/null +++ b/engine/battle/move_effects/rapid_spin.asm @@ -0,0 +1,36 @@ +BattleCommand_ClearHazards: +; 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, wPlayerScreens + ld de, wPlayerWrapCount + ldh a, [hBattleTurn] + and a + jr z, .got_screens_wrap + ld hl, wEnemyScreens + 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 diff --git a/engine/battle/move_effects/return.asm b/engine/battle/move_effects/return.asm new file mode 100644 index 00000000..7c7c5fcb --- /dev/null +++ b/engine/battle/move_effects/return.asm @@ -0,0 +1,25 @@ +BattleCommand_HappinessPower: +; happinesspower + push bc + ld hl, wBattleMonHappiness + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonHappiness +.ok + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, [hl] + ldh [hMultiplicand + 2], a + ld a, 10 + ldh [hMultiplier], a + call Multiply + ld a, 25 + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld d, a + pop bc + ret diff --git a/engine/battle/move_effects/rollout.asm b/engine/battle/move_effects/rollout.asm new file mode 100644 index 00000000..e2f810e6 --- /dev/null +++ b/engine/battle/move_effects/rollout.asm @@ -0,0 +1,95 @@ +MAX_ROLLOUT_COUNT EQU 5 + +BattleCommand_CheckCurl: +; checkcurl + + ld de, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wEnemyRolloutCount +.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 + +BattleCommand_RolloutPower: +; rolloutpower + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld hl, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .got_rollout_count + ld hl, wEnemyRolloutCount + +.got_rollout_count + ld a, [hl] + and a + jr nz, .skip_set_rampage + ld a, 1 + ld [wSomeoneIsRampaging], a + +.skip_set_rampage + ld a, [wAttackMissed] + 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, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .loop + + ld a, $ff + ld [hli], a + ld [hl], a + +.done_damage + ret diff --git a/engine/battle/move_effects/safeguard.asm b/engine/battle/move_effects/safeguard.asm new file mode 100644 index 00000000..e64e8092 --- /dev/null +++ b/engine/battle/move_effects/safeguard.asm @@ -0,0 +1,23 @@ +BattleCommand_Safeguard: +; safeguard + + ld hl, wPlayerScreens + ld de, wPlayerSafeguardCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyScreens + ld de, wEnemySafeguardCount +.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 diff --git a/engine/battle/move_effects/sandstorm.asm b/engine/battle/move_effects/sandstorm.asm new file mode 100644 index 00000000..c88529fb --- /dev/null +++ b/engine/battle/move_effects/sandstorm.asm @@ -0,0 +1,18 @@ +BattleCommand_StartSandstorm: +; startsandstorm + + ld a, [wBattleWeather] + cp WEATHER_SANDSTORM + jr z, .failed + + ld a, WEATHER_SANDSTORM + ld [wBattleWeather], a + ld a, 5 + ld [wWeatherCount], a + call AnimateCurrentMove + ld hl, SandstormBrewedText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/selfdestruct.asm b/engine/battle/move_effects/selfdestruct.asm new file mode 100644 index 00000000..b4967b03 --- /dev/null +++ b/engine/battle/move_effects/selfdestruct.asm @@ -0,0 +1,30 @@ +BattleCommand_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] + ; check battle scene + ld a, [wOptions] + add a + ret nc + farcall DrawPlayerHUD + farcall DrawEnemyHUD + call WaitBGMap + jp RefreshBattleHuds diff --git a/engine/battle/move_effects/sketch.asm b/engine/battle/move_effects/sketch.asm new file mode 100644 index 00000000..654fb3f5 --- /dev/null +++ b/engine/battle/move_effects/sketch.asm @@ -0,0 +1,117 @@ +BattleCommand_Sketch: +; 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, wBattleMonMoves + ldh a, [hBattleTurn] + and a + jr z, .get_last_move + ld hl, wEnemyMonMoves +.get_last_move + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [wNamedObjectIndexBuffer], 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, wBattleMonPP - wBattleMonMoves + add hl, bc + ld [hl], a + pop bc + + ldh 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 diff --git a/engine/battle/move_effects/sleep_talk.asm b/engine/battle/move_effects/sleep_talk.asm new file mode 100644 index 00000000..92bff260 --- /dev/null +++ b/engine/battle/move_effects/sleep_talk.asm @@ -0,0 +1,143 @@ +BattleCommand_SleepTalk: +; sleeptalk + + call ClearLastMove + ld a, [wAttackMissed] + and a + jr nz, .fail + ldh a, [hBattleTurn] + and a + ld hl, wBattleMonMoves + 1 + ld a, [wDisabledMove] + ld d, a + jr z, .got_moves + ld hl, wEnemyMonMoves + 1 + ld a, [wEnemyDisabledMove] + 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 + maskbits 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 + ldh a, [hBattleTurn] + and a + ld a, [wDisabledMove] + jr z, .got_move_2 + + ld a, [wEnemyDisabledMove] +.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 diff --git a/engine/battle/move_effects/snore.asm b/engine/battle/move_effects/snore.asm new file mode 100644 index 00000000..e2432c59 --- /dev/null +++ b/engine/battle/move_effects/snore.asm @@ -0,0 +1,11 @@ +BattleCommand_Snore: +; snore + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + call ResetDamage + ld a, $1 + ld [wAttackMissed], a + call FailMove + jp EndMoveEffect diff --git a/engine/battle/move_effects/spikes.asm b/engine/battle/move_effects/spikes.asm new file mode 100644 index 00000000..06aa35e8 --- /dev/null +++ b/engine/battle/move_effects/spikes.asm @@ -0,0 +1,26 @@ +BattleCommand_Spikes: +; spikes + + ld hl, wEnemyScreens + ldh a, [hBattleTurn] + and a + jr z, .asm_3778d + ld hl, wPlayerScreens +.asm_3778d + +; 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 FailMove diff --git a/engine/battle/move_effects/spite.asm b/engine/battle/move_effects/spite.asm new file mode 100644 index 00000000..06627268 --- /dev/null +++ b/engine/battle/move_effects/spite.asm @@ -0,0 +1,86 @@ +BattleCommand_Spite: +; spite + + ld a, [wAttackMissed] + and a + jp nz, .failed + ld bc, PARTYMON_STRUCT_LENGTH ; ???? + ld hl, wEnemyMonMoves + ldh a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, wBattleMonMoves +.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 [wNamedObjectIndexBuffer], a + dec hl + ld b, 0 + push bc + ld c, wBattleMonPP - wBattleMonMoves + add hl, bc + pop bc + ld a, [hl] + and PP_MASK + jr z, .failed + push bc + call GetMoveName + ; lose 2-5 PP + call BattleRandom + and %11 + inc a + inc a + ld b, a + ld a, [hl] + and PP_MASK + 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 + ldh 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 [wDeciramBuffer], a + ld hl, SpiteEffectText + jp StdBattleTextbox + +.failed + jp PrintDidntAffect2 diff --git a/engine/battle/move_effects/splash.asm b/engine/battle/move_effects/splash.asm new file mode 100644 index 00000000..1be307f8 --- /dev/null +++ b/engine/battle/move_effects/splash.asm @@ -0,0 +1,3 @@ +BattleCommand_Splash: + call AnimateCurrentMove + jp PrintNothingHappened diff --git a/engine/battle/move_effects/substitute.asm b/engine/battle/move_effects/substitute.asm new file mode 100644 index 00000000..c5ab8741 --- /dev/null +++ b/engine/battle/move_effects/substitute.asm @@ -0,0 +1,90 @@ +BattleCommand_Substitute: +; substitute + + call BattleCommand_MoveDelay + ld hl, wBattleMonMaxHP + ld de, wPlayerSubstituteHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wEnemyMonMaxHP + ld de, wEnemySubstituteHP +.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 + ldh a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove +.player + + xor a + ld [hl], a + ld [de], a + ; check battle scene + ld a, [wOptions] + add a + jr c, .no_anim + + xor a + ld [wNumHits], a + ld [wFXAnimID + 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 diff --git a/engine/battle/move_effects/sunny_day.asm b/engine/battle/move_effects/sunny_day.asm new file mode 100644 index 00000000..0edc38e4 --- /dev/null +++ b/engine/battle/move_effects/sunny_day.asm @@ -0,0 +1,9 @@ +BattleCommand_StartSun: +; startsun + ld a, WEATHER_SUN + ld [wBattleWeather], a + ld a, 5 + ld [wWeatherCount], a + call AnimateCurrentMove + ld hl, SunGotBrightText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/teleport.asm b/engine/battle/move_effects/teleport.asm new file mode 100644 index 00000000..7d866ccf --- /dev/null +++ b/engine/battle/move_effects/teleport.asm @@ -0,0 +1,87 @@ +BattleCommand_Teleport: +; teleport + + ld a, [wBattleType] + cp BATTLETYPE_SHINY + jr z, .failed + cp BATTLETYPE_TRAP + 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 + ldh 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, [wCurPartyLevel] + ld b, a + ld a, [wBattleMonLevel] + 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, [wBattleMonLevel] + ld b, a + ld a, [wCurPartyLevel] + 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 should be jr c, .failed + ; As written, it 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 + ; set battle draw + inc a + ld [wBattleResult], a + ld a, 1 + ld [wKickCounter], a + call BattleCommand_LowerSub + call LoadMoveAnim + ld c, 20 + call DelayFrames + ld a, DRAW + ld [wBattleResult], a + + ld hl, FledFromBattleText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/thief.asm b/engine/battle/move_effects/thief.asm new file mode 100644 index 00000000..e588c5ff --- /dev/null +++ b/engine/battle/move_effects/thief.asm @@ -0,0 +1,112 @@ +BattleCommand_Thief: +; thief + + ldh 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 [wNamedObjectIndexBuffer], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [wEffectFailed] + 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, [wNamedObjectIndexBuffer] + 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 [wNamedObjectIndexBuffer], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [wEffectFailed] + 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, [wNamedObjectIndexBuffer] + 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, wBattleMonItem + ret + +.enemyitem + ld a, 1 + call OTPartyAttr + ld d, h + ld e, l + ld hl, wEnemyMonItem + ret diff --git a/engine/battle/move_effects/thunder.asm b/engine/battle/move_effects/thunder.asm new file mode 100644 index 00000000..b2a64378 --- /dev/null +++ b/engine/battle/move_effects/thunder.asm @@ -0,0 +1,18 @@ +BattleCommand_ThunderAccuracy: +; thunderaccuracy + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + inc hl + ld a, [wBattleWeather] + 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 diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm new file mode 100644 index 00000000..0247d8bb --- /dev/null +++ b/engine/battle/move_effects/transform.asm @@ -0,0 +1,155 @@ +BattleCommand_Transform: +; 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 [wFXAnimID + 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, wBattleMonSpecies + ld de, wEnemyMonSpecies + ldh a, [hBattleTurn] + and a + jr nz, .got_mon_species + ld hl, wEnemyMonSpecies + ld de, wBattleMonSpecies + xor a + ld [wCurMoveNum], a +.got_mon_species + push hl + ld a, [hli] + ld [de], a + inc hl + inc de + inc de + ld bc, NUM_MOVES + call CopyBytes + ldh 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, wBattleMonStats - wBattleMonPP + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, wBattleMonStructEnd - wBattleMonStats + call CopyBytes +; init the power points + ld bc, wBattleMonMoves - wBattleMonStructEnd + add hl, bc + push de + ld d, h + ld e, l + pop hl + ld bc, wBattleMonPP - wBattleMonStructEnd + 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, wEnemyStats + ld de, wPlayerStats + ld bc, 2 * 5 + call BattleSideCopy + ld hl, wEnemyStatLevels + ld de, wPlayerStatLevels + ld bc, 8 + call BattleSideCopy + ; check battle scene + ld a, [wOptions] + add a + jr c, .mimic_anims + ldh 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 [wFXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + pop af + ld a, SUBSTITUTE + call nz, LoadAnim + ld hl, TransformedText + jp StdBattleTextbox + +BattleSideCopy: +; 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. + ldh a, [hBattleTurn] + and a + jr z, .copy + +; Swap hl and de + push hl + ld h, d + ld l, e + pop de +.copy + jp CopyBytes diff --git a/engine/battle/move_effects/triple_kick.asm b/engine/battle/move_effects/triple_kick.asm new file mode 100644 index 00000000..e41044c9 --- /dev/null +++ b/engine/battle/move_effects/triple_kick.asm @@ -0,0 +1,34 @@ +BattleCommand_TripleKick: +; triplekick + + ld a, [wKickCounter] + ld b, a + inc b + ld hl, wCurDamage + 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 + +BattleCommand_KickCounter: +; kickcounter + + ld hl, wKickCounter + inc [hl] + ret diff --git a/engine/battle/read_trainer_attributes.asm b/engine/battle/read_trainer_attributes.asm new file mode 100644 index 00000000..3f4d4a98 --- /dev/null +++ b/engine/battle/read_trainer_attributes.asm @@ -0,0 +1,66 @@ +GetTrainerClassName: + ld hl, wRivalName + ld a, c + cp RIVAL1 + jr z, .rival + + ld [wCurSpecies], a + ld a, TRAINER_NAME + ld [wNamedObjectTypeBuffer], a + call GetName + ld de, wStringBuffer1 + ret + +.rival + ld de, wStringBuffer1 + push de + ld bc, TRAINER_CLASS_NAME_LENGTH + call CopyBytes + pop de + ret + +GetOTName: + ld hl, wOTPlayerName + ld a, [wLinkMode] + and a + jr nz, .ok + + ld hl, wRivalName + ld a, c + cp RIVAL1 + jr z, .ok + + ld [wCurSpecies], a + ld a, TRAINER_NAME + ld [wNamedObjectTypeBuffer], a + call GetName + ld hl, wStringBuffer1 + +.ok + ld bc, TRAINER_CLASS_NAME_LENGTH + ld de, wOTClassName + push de + call CopyBytes + pop de + ret + +GetTrainerAttributes: + ld a, [wTrainerClass] + ld c, a + call GetOTName + ld a, [wTrainerClass] + dec a + ld hl, TrainerClassAttributes + TRNATTR_ITEM1 + ld bc, NUM_TRAINER_ATTRIBUTES + call AddNTimes + ld de, wEnemyTrainerItem1 + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld a, [hl] + ld [wEnemyTrainerBaseReward], a + ret + +INCLUDE "data/trainers/attributes.asm" diff --git a/engine/battle/read_trainer_party.asm b/engine/battle/read_trainer_party.asm new file mode 100644 index 00000000..18e23f13 --- /dev/null +++ b/engine/battle/read_trainer_party.asm @@ -0,0 +1,374 @@ +ReadTrainerParty: + ld a, [wLinkMode] + and a + ret nz + + ld hl, wOTPartyCount + xor a + ld [hli], a + dec a + ld [hl], a + + ld hl, wOTPartyMons + ld bc, wOTPartyMonsEnd - wOTPartyMons + xor a + call ByteFill + + ld a, [wOtherTrainerClass] + cp CAL + jr nz, .not_cal2 + ld a, [wOtherTrainerID] + cp CAL2 + jr z, .cal2 + ld a, [wOtherTrainerClass] +.not_cal2 + + dec a + ld c, a + ld b, 0 + ld hl, TrainerGroups + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + + ld a, [wOtherTrainerID] + ld b, a +.skip_trainer + dec b + jr z, .got_trainer +.loop + ld a, [hli] + cp -1 + jr nz, .loop + jr .skip_trainer +.got_trainer + +.skip_name + ld a, [hli] + cp "@" + jr nz, .skip_name + + ld a, [hli] + ld c, a + ld b, 0 + ld d, h + ld e, l + ld hl, TrainerTypes + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld bc, .done + push bc + jp hl + +.done + jp ComputeTrainerReward + +.cal2 + ld a, BANK(sMysteryGiftTrainer) + call OpenSRAM + ld de, sMysteryGiftTrainer + call TrainerType2 + call CloseSRAM + jr .done + +TrainerTypes: +; entries correspond to TRAINERTYPE_* constants + dw TrainerType1 ; level, species + dw TrainerType2 ; level, species, moves + dw TrainerType3 ; level, species, item + dw TrainerType4 ; level, species, item, moves + +TrainerType1: +; normal (level, species) + ld h, d + ld l, e +.loop + ld a, [hli] + cp $ff + ret z + + ld [wCurPartyLevel], a + ld a, [hli] + ld [wCurPartySpecies], a + ld a, OTPARTYMON + ld [wMonType], a + push hl + predef TryAddMonToParty + pop hl + jr .loop + +TrainerType2: +; moves + ld h, d + ld l, e +.loop + ld a, [hli] + cp $ff + ret z + + ld [wCurPartyLevel], a + ld a, [hli] + ld [wCurPartySpecies], a + ld a, OTPARTYMON + ld [wMonType], a + + push hl + predef TryAddMonToParty + ld a, [wOTPartyCount] + dec a + ld hl, wOTPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + pop hl + + ld b, NUM_MOVES +.copy_moves + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .copy_moves + + push hl + + ld a, [wOTPartyCount] + dec a + ld hl, wOTPartyMon1Species + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, MON_PP + add hl, de + push hl + ld hl, MON_MOVES + add hl, de + pop de + + ld b, NUM_MOVES +.copy_pp + ld a, [hli] + and a + jr z, .copied_pp + + push hl + push bc + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + pop bc + pop hl + + ld [de], a + inc de + dec b + jr nz, .copy_pp +.copied_pp + + pop hl + jr .loop + +TrainerType3: +; item + ld h, d + ld l, e +.loop + ld a, [hli] + cp $ff + ret z + + ld [wCurPartyLevel], a + ld a, [hli] + ld [wCurPartySpecies], a + ld a, OTPARTYMON + ld [wMonType], a + push hl + predef TryAddMonToParty + ld a, [wOTPartyCount] + dec a + ld hl, wOTPartyMon1Item + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + pop hl + ld a, [hli] + ld [de], a + jr .loop + +TrainerType4: +; item + moves + ld h, d + ld l, e +.loop + ld a, [hli] + cp $ff + ret z + + ld [wCurPartyLevel], a + ld a, [hli] + ld [wCurPartySpecies], a + + ld a, OTPARTYMON + ld [wMonType], a + + push hl + predef TryAddMonToParty + ld a, [wOTPartyCount] + dec a + ld hl, wOTPartyMon1Item + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + pop hl + + ld a, [hli] + ld [de], a + + push hl + ld a, [wOTPartyCount] + dec a + ld hl, wOTPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + pop hl + + ld b, NUM_MOVES +.copy_moves + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .copy_moves + + push hl + + ld a, [wOTPartyCount] + dec a + ld hl, wOTPartyMon1 + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, MON_PP + add hl, de + + push hl + ld hl, MON_MOVES + add hl, de + pop de + + ld b, NUM_MOVES +.copy_pp + ld a, [hli] + and a + jr z, .copied_pp + + push hl + push bc + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + pop bc + pop hl + + ld [de], a + inc de + dec b + jr nz, .copy_pp +.copied_pp + + pop hl + jr .loop + +ComputeTrainerReward: + ld hl, hProduct + xor a + ld [hli], a + ld [hli], a ; hMultiplicand + 0 + ld [hli], a ; hMultiplicand + 1 + ld a, [wEnemyTrainerBaseReward] + ld [hli], a ; hMultiplicand + 2 + ld a, [wCurPartyLevel] + ld [hl], a ; hMultiplier + call Multiply + ld hl, wBattleReward + xor a + ld [hli], a + ldh a, [hProduct + 2] + ld [hli], a + ldh a, [hProduct + 3] + ld [hl], a + ret + +Battle_GetTrainerName:: + ld a, [wOtherTrainerID] + ld b, a + ld a, [wOtherTrainerClass] + ld c, a + +GetTrainerName:: + ld a, c + cp CAL + jr nz, .not_cal2 + + ld a, BANK(sMysteryGiftTrainerHouseFlag) + call OpenSRAM + ld a, [sMysteryGiftTrainerHouseFlag] + and a + call CloseSRAM + jr z, .not_cal2 + + ld a, BANK(sMysteryGiftPartnerName) + call OpenSRAM + ld hl, sMysteryGiftPartnerName + call CopyTrainerName + jp CloseSRAM + +.not_cal2 + dec c + push bc + ld b, 0 + ld hl, TrainerGroups + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + pop bc + +.loop + dec b + jr z, CopyTrainerName + +.skip + ld a, [hli] + cp $ff + jr nz, .skip + jr .loop + +CopyTrainerName: + ld de, wStringBuffer1 + push de + ld bc, NAME_LENGTH + call CopyBytes + pop de + ret + +INCLUDE "data/trainers/parties.asm" diff --git a/engine/battle/returntobattle_useball.asm b/engine/battle/returntobattle_useball.asm new file mode 100644 index 00000000..fd138ae6 --- /dev/null +++ b/engine/battle/returntobattle_useball.asm @@ -0,0 +1,19 @@ +_ReturnToBattle_UseBall: + call ClearBGPalettes + call ClearTilemap + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jr z, .gettutorialbackpic + farcall GetBattleMonBackpic + jr .continue + +.gettutorialbackpic + farcall GetTrainerBackpic +.continue + farcall GetEnemyMonFrontpic + farcall _LoadBattleFontsHPBar + call GetMemSGBLayout + call CloseWindow + call LoadStandardMenuHeader + call WaitBGMap + jp SetPalettes diff --git a/engine/battle/sliding_intro.asm b/engine/battle/sliding_intro.asm new file mode 100644 index 00000000..f872a8de --- /dev/null +++ b/engine/battle/sliding_intro.asm @@ -0,0 +1,57 @@ +BattleIntroSlidingPics: + ld b, $70 + ld c, $90 + ld a, c + ldh [hSCX], a + call DelayFrame + ld a, %11100100 + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + +.loop1 + push bc + ld h, b + ld l, $40 + call .subfunction2 + ld h, $00 + ld l, $60 + call .subfunction2 + call .subfunction1 + pop bc + ld a, c + ldh [hSCX], a + inc b + inc b + dec c + dec c + jr nz, .loop1 + ret + +.subfunction1 + push bc + ld hl, wVirtualOAMSprite00XCoord + ld c, $12 ; 18 + ld de, SPRITEOAMSTRUCT_LENGTH +.loop2 + dec [hl] + dec [hl] + add hl, de + dec c + jr nz, .loop2 + pop bc + ret + +.subfunction2 +.loop3 + ldh a, [rLY] + cp l + jr nz, .loop3 + ld a, h + ldh [rSCX], a + +.loop4 + ldh a, [rLY] + cp h + jr z, .loop4 + ret diff --git a/engine/battle/trainer_huds.asm b/engine/battle/trainer_huds.asm new file mode 100644 index 00000000..7fd57571 --- /dev/null +++ b/engine/battle/trainer_huds.asm @@ -0,0 +1,257 @@ +BattleStart_TrainerHuds: + ld a, $e4 + ldh [rOBP0], a + call LoadBallIconGFX + call ShowPlayerMonsRemaining + ld a, [wBattleMode] + dec a + ret z + jp ShowOTTrainerMonsRemaining + +EnemySwitch_TrainerHud: + ld a, $e4 + ldh [rOBP0], a + call LoadBallIconGFX + jp ShowOTTrainerMonsRemaining + +ShowPlayerMonsRemaining: + call DrawPlayerPartyIconHUDBorder + ld hl, wPartyMon1HP + ld de, wPartyCount + 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, wVirtualOAMSprite00 + jp LoadTrainerHudOAM + +ShowOTTrainerMonsRemaining: + call DrawEnemyHUDBorder + ld hl, wOTPartyMon1HP + ld de, wOTPartyCount + 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, wVirtualOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH + jp LoadTrainerHudOAM + +StageBallTilesData: + ld a, [de] + push af + ld de, wBuffer1 + ld c, PARTY_LENGTH + ld a, $34 ; empty slot +.loop1 + ld [de], a + inc de + dec c + jr nz, .loop1 + pop af + ld de, wBuffer1 +.loop2 + push af + call .GetHUDTile + inc de + pop af + dec a + jr nz, .loop2 + ret + +.GetHUDTile: + 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 + +DrawPlayerHUDBorder: + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, .tiles_end - .tiles + 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 +.tiles_end + +DrawPlayerPartyIconHUDBorder: + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, .tiles_end - .tiles + 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 +.tiles_end + +DrawEnemyHUDBorder: + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, .tiles_end - .tiles + call CopyBytes + hlcoord 1, 2 + ld de, 1 ; start on left + call PlaceHUDBorderTiles + ld a, [wBattleMode] + dec a + ret nz + ld a, [wTempEnemyMonSpecies] + 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 +.tiles_end + +PlaceHUDBorderTiles: + ld a, [wTrainerHUDTiles + 0] + ld [hl], a + ld bc, SCREEN_WIDTH + add hl, bc + ld a, [wTrainerHUDTiles + 1] + ld [hl], a + ld b, 8 +.loop + add hl, de + ld a, [wTrainerHUDTiles + 3] + ld [hl], a + dec b + jr nz, .loop + add hl, de + ld a, [wTrainerHUDTiles + 2] + ld [hl], a + ret + +LinkBattle_TrainerHuds: + call LoadBallIconGFX + ld hl, wPartyMon1HP + ld de, wPartyCount + call StageBallTilesData + ld hl, wPlaceBallsX + ld a, 10 * 8 + ld [hli], a + ld [hl], 8 * 8 + ld a, 8 + ld [wPlaceBallsDirection], a + ld hl, wVirtualOAMSprite00 + call LoadTrainerHudOAM + + ld hl, wOTPartyMon1HP + ld de, wOTPartyCount + call StageBallTilesData + ld hl, wPlaceBallsX + ld a, 10 * 8 + ld [hli], a + ld [hl], 13 * 8 + ld hl, wVirtualOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH + jp LoadTrainerHudOAM + +LoadTrainerHudOAM: + ld de, wBuffer1 + ld c, PARTY_LENGTH +.loop + ld a, [wPlaceBallsY] + ld [hli], a ; y + ld a, [wPlaceBallsX] + ld [hli], a ; x + ld a, [de] + ld [hli], a ; tile id + ld a, PAL_BATTLE_OB_YELLOW + ld [hli], a ; attributes + ld a, [wPlaceBallsX] + ld b, a + ld a, [wPlaceBallsDirection] + add b + ld [wPlaceBallsX], a + inc de + dec c + jr nz, .loop + ret + +LoadBallIconGFX: + ld de, .gfx + ld hl, vTiles0 tile $31 + lb bc, BANK(LoadBallIconGFX), 4 + jp Request2bpp + +.gfx +INCBIN "gfx/battle/balls.2bpp" + +_ShowLinkBattleParticipants: + call ClearBGPalettes + call LoadFontsExtra + hlcoord 3, 3 + ld b, 9 + ld c, 12 + call Textbox + hlcoord 4, 5 + ld de, wPlayerName + call PlaceString + hlcoord 4, 10 + ld de, wOTPlayerName + 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 + ldh [rOBP0], a + ld c, 150 + jp DelayFrames diff --git a/engine/battle/used_move_text.asm b/engine/battle/used_move_text.asm new file mode 100644 index 00000000..5b148ab5 --- /dev/null +++ b/engine/battle/used_move_text.asm @@ -0,0 +1,235 @@ +BattleCommand_UsedMoveText: +; battle command 03 + ld hl, UsedMoveText + call PrintText + jp WaitBGMap + +UsedMoveText: +; this is a stream of text and asm from 105db9 to 105ef6 + text_far _ActorNameText + text_asm + ldh 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 [wMoveGrammar], a + + call CheckUserIsCharging + jr nz, .grammar + + ; update last move + ld a, [wMoveGrammar] + ld [hl], a + ld [de], a + +.grammar + call GetMoveGrammar ; convert move id to grammar index + +; everything except 'CheckObedience' made redundant in localization + + ; check obedience + ld a, [wAlreadyDisobeyed] + and a + ld hl, UsedMove2Text + ret nz + + ; check move grammar + ld a, [wMoveGrammar] + cp $3 + ld hl, UsedMove2Text + ret c + ld hl, UsedMove1Text + ret + +UsedMove1Text: + text_far _UsedMove1Text + text_asm + jr UsedMoveText_CheckObedience + +UsedMove2Text: + text_far _UsedMove2Text + text_asm +UsedMoveText_CheckObedience: +; check obedience + ld a, [wAlreadyDisobeyed] + and a + jr z, .GetMoveNameText +; print "instead," + ld hl, .UsedInsteadText + ret + +.UsedInsteadText: + text_far _UsedInsteadText + text_asm +.GetMoveNameText: + ld hl, MoveNameText + ret + +MoveNameText: + text_far _MoveNameText + text_asm +; get start address + ld hl, .endusedmovetexts + +; get move id + ld a, [wMoveGrammar] + +; 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 + +.endusedmovetexts +; entries correspond to MoveGrammar sets + dw EndUsedMove1Text + dw EndUsedMove2Text + dw EndUsedMove3Text + dw EndUsedMove4Text + dw EndUsedMove5Text + +EndUsedMove1Text: + text_far _EndUsedMove1Text + text_end + +EndUsedMove2Text: + text_far _EndUsedMove2Text + text_end + +EndUsedMove3Text: + text_far _EndUsedMove3Text + text_end + +EndUsedMove4Text: + text_far _EndUsedMove4Text + text_end + +EndUsedMove5Text: + text_far _EndUsedMove5Text + text_end + +GetMoveGrammar: +; store move grammar type in wMoveGrammar + + push bc +; wMoveGrammar contains move id + ld a, [wMoveGrammar] + ld c, a ; move id + ld b, 0 ; grammar index + +; read grammar table + ld hl, MoveGrammar +.loop + ld a, [hli] +; end of table? + cp -1 + jr z, .end +; match? + cp c + jr z, .end +; advance grammar type at 0 + and a + jr nz, .loop +; next grammar type + inc b + jr .loop + +.end +; wMoveGrammar now contains move grammar + ld a, b + ld [wMoveGrammar], a + +; we're done + pop bc + ret + +INCLUDE "data/moves/grammar.asm" + +CheckUserIsCharging: + ldh a, [hBattleTurn] + and a + ld a, [wPlayerCharging] ; player + jr z, .end + ld a, [wEnemyCharging] ; enemy +.end + and a + ret + +UpdateUsedMoves: +; append move a to wPlayerUsedMoves unless it has already been used + + push bc +; start of list + ld hl, wPlayerUsedMoves +; 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, wPlayerUsedMoves + 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 [wPlayerUsedMoves + 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 diff --git a/engine/battle_anims/pokeball_wobble.asm b/engine/battle_anims/pokeball_wobble.asm new file mode 100644 index 00000000..c430e513 --- /dev/null +++ b/engine/battle_anims/pokeball_wobble.asm @@ -0,0 +1,45 @@ +GetPokeBallWobble: +; Returns whether a Poke Ball will wobble in the catch animation. +; Whether a Pokemon is caught is determined beforehand. + + ld a, [wBuffer2] + inc a + ld [wBuffer2], a + +; Wobble up to 3 times. + cp 3 + 1 + jr z, .finished + + ld a, [wWildMon] + and a + ld c, 0 ; next + ret nz + + ld hl, WobbleProbabilities + ld a, [wBuffer1] + ld b, a +.loop + ld a, [hli] + cp b + jr nc, .checkwobble + inc hl + jr .loop + +.checkwobble + ld b, [hl] + call Random + cp b + ld c, 0 ; next + ret c + ld c, 2 ; escaped + ret + +.finished + ld a, [wWildMon] + and a + ld c, 1 ; caught + ret nz + ld c, 2 ; escaped + ret + +INCLUDE "data/battle/wobble_probabilities.asm" diff --git a/engine/color.asm b/engine/color.asm deleted file mode 100755 index 05c13b2b..00000000 --- a/engine/color.asm +++ /dev/null @@ -1,1903 +0,0 @@ -PALPACKET_LENGTH EQU $10 -INCLUDE "predef/sgb.asm" - -SHINY_ATK_BIT EQU 5 -SHINY_DEF_VAL EQU 10 -SHINY_SPD_VAL EQU 10 -SHINY_SPC_VAL EQU 10 - -CheckShininess: - ld l, c - ld h, b - ld a, [hl] - and $20 - jr z, .asm_9070 - ld a, [hli] - and $f - cp $a - jr nz, .asm_9070 - ld a, [hl] - and $f0 - cp $a0 - jr nz, .asm_9070 - ld a, [hl] - and $f - cp $a - jr nz, .asm_9070 - scf - ret - -.asm_9070 - and a - ret - -Unused_CheckShininess: ; 9072 (2:5072) - ld a, [hl] - cp $a0 - jr c, .asm_908c - ld a, [hli] - and $f - cp $a - jr c, .asm_908c - ld a, [hl] - cp $a0 - jr c, .asm_908c - ld a, [hl] - and $f - cp $a - jr c, .asm_908c - scf - ret - -.asm_908c - and a - ret - -Function908e: - push de - push bc - ld hl, PalPacket_a155 - ld de, wcca9 - ld bc, $10 - call CopyBytes - pop bc - pop de - ld a, c - ld [wccac], a - ld a, b - ld [wccad], a - ld a, e - ld [wccae], a - ld a, d - ld [wccaf], a - ld hl, wcca9 - call PushSGBPals_ - ld hl, BlkPacket_9ee5 - call PushSGBPals_ - ret - -InitPartyMenuPalettes: - call CheckCGB - jr nz, .asm_90cc - ld hl, BlkPacket_9fa5 - ld de, wccaa - ld bc, $30 - jp CopyBytes - -.asm_90cc - ld hl, PalPacket_a0c5 + 1 - call Function9ab2 - call Function9b9c - call Function9b1d - ret - -SGB_ApplyPartyMenuHPPals: - ld hl, wcc9b - ld a, [wcca9] - ld e, a - ld d, $0 - add hl, de - ld e, l - ld d, h - ld a, [de] - and a - ld e, $5 - jr z, .asm_90f2 - dec a - ld e, $a - jr z, .asm_90f2 - ld e, $f -.asm_90f2 - push de - ld hl, wccb3 - ld bc, $6 - ld a, [wcca9] - call AddNTimes - pop de - ld [hl], e - ret - -Function9102: - call CheckCGB - ret z - ld hl, .BGPal - ld de, wTempBGPals - ld bc, $8 - call CopyBytes - ld hl, .OBPal - ld de, wTempOBPals - ld bc, $8 - call CopyBytes - call Function9b28 - ld a, $1 - ldh [hCGBPalUpdate], a - ret - -.BGPal: - RGB 31, 31, 31 - RGB 18, 23, 31 - RGB 15, 20, 31 - RGB 00, 00, 00 - -.OBPal: - RGB 31, 31, 31 - RGB 31, 31, 12 - RGB 08, 16, 28 - RGB 00, 00, 00 - -Function9136: - call CheckCGB - ret nz - ldh a, [hSGB] - and a - ret z - ld hl, BlkPacket_9ee5 - jp PushSGBPals_ - -Function9144: - call CheckCGB - jr nz, .asm_9153 - ldh a, [hSGB] - and a - ret z - ld hl, PalPacket_a095 - jp PushSGBPals_ - -.asm_9153 - ld de, wTempOBPals - ld a, $3b - call Function9ac7 - jp Function9ad2 - -Function915e: - call CheckCGB - jr nz, .asm_916d - ldh a, [hSGB] - and a - ret z - ld hl, PalPacket_a0a5 - jp PushSGBPals_ - -.asm_916d - ld de, wTempOBPals - ld a, $3c - call Function9ac7 - jp Function9ad2 - -Function9178: - call CheckCGB - jr nz, .asm_91a9 - ldh a, [hSGB] - and a - ret z - ld a, c - push af - ld hl, PalPacket_a155 - ld de, wcca9 - ld bc, $10 - call CopyBytes - pop af - call Function9be4 - ld a, [hli] - ld [wccac], a - ld a, [hli] - ld [wccad], a - ld a, [hli] - ld [wccae], a - ld a, [hl] - ld [wccaf], a - ld hl, wcca9 - jp PushSGBPals_ - -.asm_91a9 - ld de, wTempOBPals - ld a, c - call Function9be4 - call Function9adb - ret - -Function91b4: - ldh a, [hCGB] - and a - jr nz, .asm_91bf - ld hl, wc602 - jp PushSGBPals_ - -.asm_91bf - ld a, [wc606] - ld c, a - ld a, [wc607] - ld hl, wAttrmap - ld de, $14 -.asm_91cc - and a - jr z, .asm_91d3 - add hl, de - dec a - jr .asm_91cc - -.asm_91d3 - ld b, $0 - add hl, bc - lb bc, 6, 4 - ld a, [wc605] - and $3 - call Function9af1 - call CopyTilemapAtOnce - ret - -ApplyMonOrTrainerPals: ; 91e5 (2:51e5) - call CheckCGB - ret z - ld a, e - and a - jr z, .asm_91f5 - ld a, [wCurPartySpecies] - call Function9be4 - jr .asm_91fb - -.asm_91f5 - ld a, [wTrainerClass] - call Function9bda -.asm_91fb - ld de, wTempBGPals - call Function9adb - call Function9b1d - call Function9b35 - call Function9b28 - ret - -ApplyHPBarPals: - ld a, [wWhichHPBar] - and a - jr z, .asm_921a - cp $1 - jr z, .asm_921f - cp $2 - jr z, .asm_9236 - ret - -.asm_921a - ld de, $c292 - jr .asm_9222 - -.asm_921f - ld de, $c29a -.asm_9222 - ld l, c - ld h, $0 - add hl, hl - add hl, hl - ld bc, $6d2d - add hl, bc - ld bc, $4 - call CopyBytes - ld a, $1 - ldh [hCGBPalUpdate], a - ret - -.asm_9236 - ld e, c - inc e - hlcoord 11, 1, wAttrmap - ld bc, 2 * SCREEN_WIDTH - ld a, [wCurPartyMon] -.asm_9241 - and a - jr z, .asm_9248 - add hl, bc - dec a - jr .asm_9241 - -.asm_9248 - lb bc, 2, 8 - ld a, e - call Function9af1 - ret - -LoadStatsScreenPals: - call CheckCGB - ret z - ld hl, StatsScreenPals ; $54eb - ld b, $0 - dec c - add hl, bc - add hl, bc - ld a, [hli] - ld [wTempBGPals], a - ld [wTempBGPals + $10], a - ld a, [hl] - ld [wTempBGPals + 1], a - ld [wTempBGPals + $11], a - call Function9b28 - ld a, $1 - ldh [hCGBPalUpdate], a - ret - -LoadMailPalettes: - ld l, e - ld h, $0 - add hl, hl - add hl, hl - add hl, hl - ld de, .MailPals - add hl, de - call CheckCGB - jr nz, .asm_92ae - push hl - ld hl, PalPacket_a155 - ld de, wcca9 - ld bc, $10 - call CopyBytes - pop hl - inc hl - inc hl - ld a, [hli] - ld [wccac], a - ld a, [hli] - ld [wccad], a - ld a, [hli] - ld [wccae], a - ld a, [hli] - ld [wccaf], a - ld hl, wcca9 - call PushSGBPals_ - ld hl, BlkPacket_9ee5 - call PushSGBPals_ - ret - -.asm_92ae - ld de, wTempBGPals - ld bc, $8 - call CopyBytes - call Function9b28 - call Function9b1d - call Function9b35 - ret - -.MailPals: - RGB 20, 31, 11 - RGB 31, 19, 00 - RGB 31, 10, 09 - RGB 00, 00, 00 - - RGB 15, 20, 31 - RGB 30, 26, 00 - RGB 31, 12, 00 - RGB 00, 00, 00 - - RGB 24, 17, 31 - RGB 30, 26, 00 - RGB 08, 11, 31 - RGB 00, 00, 00 - - RGB 31, 25, 17 - RGB 31, 18, 04 - RGB 28, 12, 05 - RGB 00, 00, 00 - - RGB 19, 26, 31 - RGB 31, 05, 08 - RGB 31, 09, 31 - RGB 00, 00, 00 - - RGB 31, 19, 28 - RGB 31, 21, 00 - RGB 12, 22, 00 - RGB 00, 00, 00 - - RGB 19, 17, 23 - RGB 30, 26, 00 - RGB 31, 12, 00 - RGB 00, 00, 00 - - RGB 07, 26, 31 - RGB 26, 26, 27 - RGB 31, 11, 11 - RGB 00, 00, 00 - - RGB 21, 31, 21 - RGB 30, 26, 00 - RGB 31, 12, 00 - RGB 00, 00, 00 - - RGB 07, 26, 31 - RGB 31, 31, 00 - RGB 00, 21, 00 - RGB 00, 00, 00 - -INCLUDE "predef/cgb.asm" - -Function9a94: ; 9a94 (2:5a94) - ld hl, Palettes_9aaa - ld de, wTempBGPals - ld bc, $8 - call CopyBytes - call Function9b28 - call Function9b1d - call Function9b35 - ret - -Palettes_9aaa: - RGB 31, 31, 31 - RGB 9, 31, 31 - RGB 10, 12, 31 - RGB 0, 3, 19 - -Function9ab2: ; 9ab2 (2:5ab2) - ld de, wTempBGPals - ld c, $4 -Function9ab7: ; 9ab7 (2:5ab7) - push bc - ld a, [hli] - push hl - call Function9ac7 - call Function9ad2 - pop hl - inc hl - pop bc - dec c - jr nz, Function9ab7 - ret - -Function9ac7: ; 9ac7 (2:5ac7) - ld l, a - ld h, $0 - add hl, hl - add hl, hl - add hl, hl - ld bc, Palettes_a265 - add hl, bc - ret - -Function9ad2: ; 9ad2 (2:5ad2) - ld c, $8 -.asm_9ad4 - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .asm_9ad4 - ret - -Function9adb: ; 9adb (2:5adb) - ld a, $ff - ld [de], a - inc de - ld a, $7f - ld [de], a - inc de - ld c, $4 -.asm_9ae5 - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .asm_9ae5 - xor a - ld [de], a - inc de - ld [de], a - inc de - ret - -Function9af1: ; 9af1 (2:5af1) - push bc - push hl -.asm_9af3 - ld [hli], a - dec c - jr nz, .asm_9af3 - pop hl - ld bc, $14 - add hl, bc - pop bc - dec b - jr nz, Function9af1 - ret - -Function9b01: ; 9b01 (2:5b01) - push af - push bc - push de - push hl - ld hl, wTempBGPals - ld c, $8 -.asm_9b0a - ld a, $ff - ld [hli], a - ld [hli], a - ld [hli], a - ld [hli], a - xor a - ld [hli], a - ld [hli], a - ld [hli], a - ld [hli], a - dec c - jr nz, .asm_9b0a - pop hl - pop de - pop bc - pop af - ret - -Function9b1d: ; 9b1d (2:5b1d) - hlcoord 0, 0, wAttrmap - ld bc, SCREEN_HEIGHT * SCREEN_WIDTH - xor a - call ByteFill - ret - -Function9b28: ; 9b28 (2:5b28) - ld hl, wTempBGPals - ld de, wBGPals - ld bc, $80 - call CopyBytes - ret - -Function9b35: ; 9b35 (2:5b35) - ldh a, [rLCDC] - bit 7, a - jr z, .asm_9b52 - ldh a, [hBGMapMode] - push af - ld a, $2 - ldh [hBGMapMode], a - call DelayFrame - call DelayFrame - call DelayFrame - call DelayFrame - pop af - ldh [hBGMapMode], a - ret - -.asm_9b52 - hlcoord 0, 0, wAttrmap - ld de, $9800 - ld b, $12 - ld a, $1 - ldh [rVBK], a -.asm_9b5e - ld c, $14 -.asm_9b60 - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .asm_9b60 - ld a, $c - add e - jr nc, .asm_9b6c - inc d -.asm_9b6c - ld e, a - dec b - jr nz, .asm_9b5e - ld a, $0 - ldh [rVBK], a - ret - -Function9b75: ; 9b75 (2:5b75) - ld hl, wcc9b - ld a, [wcca9] - ld e, a - ld d, $0 - add hl, de - ld e, l - ld d, h - ld a, [de] - inc a - ld e, a - hlcoord 11, 2, wAttrmap - ld bc, $28 - ld a, [wcca9] -.asm_9b8d - and a - jr z, .asm_9b94 - add hl, bc - dec a - jr .asm_9b8d - -.asm_9b94 - lb bc, 2, 8 - ld a, e - call Function9af1 - ret - -Function9b9c: ; 9b9c (2:5b9c) - ld hl, Palettes_bac6 - ld de, wTempOBPal0 - ld bc, $10 - call CopyBytes - ret - -Function9ba9: ; 9ba9 (2:5ba9) - push de - farcall Function3d8f5 - ld c, l - ld b, h - ld a, [wd0ee] - call Function9bcb - pop de - ret - -Function9bba: ; 9bba (2:5bba) - push de - farcall Function3d907 - ld c, l - ld b, h - ld a, [wTempEnemyMonSpecies] - call Function9bd3 - pop de - ret - -Function9bcb: ; 9bcb (2:5bcb) - and a - jp nz, Function9c66 - ld hl, TrainerPalettes - ret - -Function9bd3: ; 9bd3 (2:5bd3) - and a - jp nz, Function9c66 - ld a, [wTrainerClass] -Function9bda: ; 9bda (2:5bda) - ld l, a - ld h, $0 - add hl, hl - add hl, hl - ld bc, TrainerPalettes - add hl, bc - ret - -Function9be4: ; 9be4 (2:5be4) - call Function9c5b - ret - -Function9be8: - ret - -Function9be9: - call CheckCGB - ret z - ld hl, Palettes_9c09 - ld a, $90 - ldh [rOBPI], a - ld c, $30 -.asm_9bf6 - ld a, [hli] - ldh [rOBPD], a - dec c - jr nz, .asm_9bf6 - ld hl, Palettes_9c09 - ld de, wTempOBPal2 - ld bc, $10 - call CopyBytes - ret - -Palettes_9c09: - RGB 31, 31, 31 - RGB 25, 25, 25 - RGB 13, 13, 13 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 31, 7 - RGB 31, 16, 1 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 19, 24 - RGB 30, 10, 6 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 12, 25, 1 - RGB 5, 14, 0 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 8, 12, 31 - RGB 1, 4, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 24, 18, 7 - RGB 20, 15, 3 - RGB 0, 0, 0 - -Function9c39: - call CheckCGB - ret z - ld a, $90 - ldh [rOBPI], a - ld a, $1c - call Function9ac7 - call Function9c52 - ld a, $21 - call Function9ac7 - call Function9c52 - ret - -Function9c52: ; 9c52 (2:5c52) - ld c, $8 -.asm_9c54 - ld a, [hli] - ldh [rOBPD], a - dec c - jr nz, .asm_9c54 - ret - -Function9c5b: ; 9c5b (2:5c5b) - ld l, a - ld h, $0 - add hl, hl - add hl, hl - add hl, hl - ld bc, PokemonPalettes - add hl, bc - ret - -Function9c66: ; 9c66 (2:5c66) - push bc - call Function9c5b - pop bc - push hl - call CheckShininess - pop hl - ret nc - inc hl - inc hl - inc hl - inc hl - ret - -PushSGBPals_: ; 9c76 (2:5c76) - ld a, [wd8ba] - push af - set 7, a - ld [wd8ba], a - call Function9c87 - pop af - ld [wd8ba], a - ret - -Function9c87: ; 9c87 (2:5c87) - ld a, [hl] - and $7 - ret z - ld b, a -.asm_9c8c - push bc - xor a - ldh [rJOYP], a - ld a, $30 - ldh [rJOYP], a - ld b, $10 -.asm_9c96 - ld e, $8 - ld a, [hli] - ld d, a -.asm_9c9a - bit 0, d - ld a, $10 - jr nz, .asm_9ca2 - ld a, $20 -.asm_9ca2 - ldh [rJOYP], a - ld a, $30 - ldh [rJOYP], a - rr d - dec e - jr nz, .asm_9c9a - dec b - jr nz, .asm_9c96 - ld a, $20 - ldh [rJOYP], a - ld a, $30 - ldh [rJOYP], a - call Function9ed9 - pop bc - dec b - jr nz, .asm_9c8c - ret - -InitSGBBorder: ; 9cc0 (2:5cc0) - call CheckCGB - ret nz - di - ld a, [wd8ba] - push af - set 7, a - ld [wd8ba], a - xor a - ldh [rJOYP], a - ldh [hSGB], a - call Function9da9 - jr nc, .asm_9cf7 - ld a, $1 - ldh [hSGB], a - call Function9d4a - call Function9e13 - call Function9ed9 - call Function9d9e - call Function9d8b - call Function9ed9 - call Function9d9e - ld hl, PalPacket_a1d5 - call Function9c87 -.asm_9cf7 - pop af - ld [wd8ba], a - ei - ret - -InitCGBPals:: ; 9cfd (2:5cfd) - call CheckCGB - ret z - ld a, $1 - ldh [rVBK], a - ld hl, $8000 - ld bc, $2000 - xor a - call ByteFill - ld a, $0 - ldh [rVBK], a - ld a, $80 - ldh [rBGPI], a - ld c, $20 -.asm_9d19 - ld a, $ff - ldh [rBGPD], a - ld a, $7f - ldh [rBGPD], a - dec c - jr nz, .asm_9d19 - ld a, $80 - ldh [rOBPI], a - ld c, $20 -.asm_9d2a - ld a, $ff - ldh [rOBPD], a - ld a, $7f - ldh [rOBPD], a - dec c - jr nz, .asm_9d2a - ld hl, wTempBGPals - call Function9d3e - ld hl, wBGPals -Function9d3e: ; 9d3e (2:5d3e) - ld c, $40 -.asm_9d40 - ld a, $ff - ld [hli], a - ld a, $7f - ld [hli], a - dec c - jr nz, .asm_9d40 - ret - -Function9d4a: ; 9d4a (2:5d4a) - ld hl, .Pointers - ld c, $9 -.asm_9d4f - push bc - ld a, [hli] - push hl - ld h, [hl] - ld l, a - call Function9c87 - pop hl - inc hl - pop bc - dec c - jr nz, .asm_9d4f - ret - -.Pointers: - dw PalPacket_a1c5 - dw PalPacket_a1e5 - dw PalPacket_a1f5 - dw PalPacket_a205 - dw PalPacket_a215 - dw PalPacket_a225 - dw PalPacket_a235 - dw PalPacket_a245 - dw PalPacket_a255 - -Function9d70: - di - xor a - ldh [rJOYP], a - ld hl, PalPacket_a1c5 - call Function9c87 - call Function9d8b - call Function9ed9 - call Function9d9e - ld hl, PalPacket_a1d5 - call Function9c87 - ei - ret - -Function9d8b: ; 9d8b (2:5d8b) - call Function9d97 - push de - call Function9e83 - pop hl - call Function9e37 - ret - -Function9d97: ; 9d97 (2:5d97) - ld hl, SGBBorder - ld de, SGBBorderMap - ret - -Function9d9e: ; 9d9e (2:5d9e) - ld hl, $8000 - ld bc, $2000 - xor a - call ByteFill - ret - -Function9da9: ; 9da9 (2:5da9) - ld hl, PalPacket_a195 - call Function9c87 - call Function9ed9 - ldh a, [rJOYP] - and $3 - cp $3 - jr nz, .asm_9e05 - ld a, $20 - ldh [rJOYP], a - ldh a, [rJOYP] - ldh a, [rJOYP] - call Function9ed9 - call Function9ed9 - ld a, $30 - ldh [rJOYP], a - call Function9ed9 - call Function9ed9 - ld a, $10 - ldh [rJOYP], a - ldh a, [rJOYP] - ldh a, [rJOYP] - ldh a, [rJOYP] - ldh a, [rJOYP] - ldh a, [rJOYP] - ldh a, [rJOYP] - call Function9ed9 - call Function9ed9 - ld a, $30 - ldh [rJOYP], a - ldh a, [rJOYP] - ldh a, [rJOYP] - ldh a, [rJOYP] - call Function9ed9 - call Function9ed9 - ldh a, [rJOYP] - and $3 - cp $3 - jr nz, .asm_9e05 - call Function9e0a - and a - ret - -.asm_9e05 - call Function9e0a - scf - ret - -Function9e0a: ; 9e0a (2:5e0a) - ld hl, PalPacket_a185 - call Function9c87 - jp Function9ed9 - -Function9e13: ; 9e13 (2:5e13) - call DisableLCD - ld a, $e4 - ldh [rBGP], a - ld hl, Palettes_a265 - ld de, $8800 - ld bc, $1000 - call Function9eb1 - call Function9ec3 - ld a, $e3 - ldh [rLCDC], a - ld hl, PalPacket_a175 - call Function9c87 - xor a - ldh [rBGP], a - ret - -Function9e37: ; 9e37 (2:5e37) - call DisableLCD - ld a, $e4 - ldh [rBGP], a - ld de, $8800 - ld bc, $140 - call Function9eb1 - ld b, $12 -.asm_9e49 - push bc - ld bc, $c - call Function9eb1 - ld bc, $28 - call Function9eba - ld bc, $c - call Function9eb1 - pop bc - dec b - jr nz, .asm_9e49 - ld bc, $140 - call Function9eb1 - ld bc, $100 - call Function9eba - ld bc, $80 - call Function9eb1 - call Function9ec3 - ld a, $e3 - ldh [rLCDC], a - ld hl, PalPacket_a1b5 - call Function9c87 - xor a - ldh [rBGP], a - ret - -Function9e83: ; 9e83 (2:5e83) - call DisableLCD - ld a, $e4 - ldh [rBGP], a - ld de, $8800 - ld b, $80 -.asm_9e8f - push bc - ld bc, $10 - call Function9eb1 - ld bc, $10 - call Function9eba - pop bc - dec b - jr nz, .asm_9e8f - call Function9ec3 - ld a, $e3 - ldh [rLCDC], a - ld hl, PalPacket_a1a5 - call Function9c87 - xor a - ldh [rBGP], a - ret - -Function9eb1: ; 9eb1 (2:5eb1) - ld a, [hli] - ld [de], a - inc de - dec bc - ld a, c - or b - jr nz, Function9eb1 - ret - -Function9eba: ; 9eba (2:5eba) - xor a - ld [de], a - inc de - dec bc - ld a, c - or b - jr nz, Function9eba - ret - -Function9ec3: ; 9ec3 (2:5ec3) - ld hl, $9800 - ld de, $c - ld a, $80 - ld c, $d -.asm_9ecd - ld b, $14 -.asm_9ecf - ld [hli], a - inc a - dec b - jr nz, .asm_9ecf - add hl, de - dec c - jr nz, .asm_9ecd - ret - -Function9ed9: ; 9ed9 (2:5ed9) - ld de, 7000 -.asm_9edc - nop - nop - nop - dec de - ld a, d - or e - jr nz, .asm_9edc - ret - -BlkPacket_9ee5: db $21, $01, $03, $00, $00, $00, $13, $11, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9ef5: db $21, $01, $07, $05, $00, $0a, $13, $0d, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f05: db $22, $05, $07, $0a, $00, $0c, $13, $11, $03, $05, $01, $00, $0a, $03, $03, $00 -BlkPacket_9f15: db $0a, $08, $13, $0a, $03, $0a, $00, $04, $08, $0b, $03, $0f, $0b, $00, $13, $07 -BlkPacket_9f25: db $21, $01, $07, $05, $00, $00, $06, $06, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f35: db $21, $01, $06, $05, $0b, $01, $13, $02, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f45: db $21, $01, $07, $05, $00, $01, $07, $07, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f55: db $21, $01, $07, $05, $01, $04, $07, $0a, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f65: db $21, $01, $07, $05, $01, $01, $05, $05, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f75: db $21, $01, $07, $05, $07, $05, $0d, $0b, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9f85: db $22, $05, $03, $05, $00, $00, $13, $0b, $03, $0a, $00, $04, $13, $09, $02, $0f -BlkPacket_9f95: db $00, $06, $13, $07, $03, $00, $04, $04, $0f, $09, $03, $00, $00, $0c, $13, $11 -BlkPacket_9fa5: db $23, $07, $07, $10, $00, $00, $02, $0c, $02, $00, $0c, $01, $12, $02, $02, $00 -BlkPacket_9fb5: db $0c, $03, $12, $04, $02, $00, $0c, $05, $12, $06, $02, $00, $0c, $07, $12, $08 -BlkPacket_9fc5: db $02, $00, $0c, $09, $12, $0a, $02, $00, $0c, $0b, $12, $0c, $00, $00, $00, $00 -BlkPacket_9fd5: db $21, $02, $07, $30, $00, $00, $13, $06, $02, $04, $05, $06, $0e, $06, $00, $00 -BlkPacket_9fe5: db $21, $01, $07, $10, $00, $00, $13, $05, $00, $00, $00, $00, $00, $00, $00, $00 -BlkPacket_9ff5: db $21, $02, $07, $0a, $00, $04, $13, $0d, $03, $05, $00, $06, $13, $0b, $00, $00 - -PalPacket_a005: - db $51 - RGB 8, 2, 0 - RGB 9, 2, 0 - RGB 10, 2, 0 - RGB 11, 2, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a015: - db $51 - RGB 11, 1, 0 - RGB 4, 1, 0 - RGB 0, 1, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a025: - db $51 - RGB 1, 2, 0 - RGB 2, 2, 0 - RGB 3, 2, 0 - RGB 4, 2, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a035: - db $51 - RGB 12, 2, 0 - RGB 12, 2, 0 - RGB 12, 2, 0 - RGB 12, 2, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a045: - db $51 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a055: - db $51 - RGB 22, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a065: - db $51 - RGB 23, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a075: - db $51 - RGB 24, 1, 0 - RGB 25, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a085: - db $51 - RGB 26, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a095: - db $51 - RGB 27, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a0a5: - db $51 - RGB 28, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a0b5: - db $51 - RGB 25, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a0c5: - db $51 - RGB 14, 1, 0 - RGB 15, 1, 0 - RGB 16, 1, 0 - RGB 17, 1, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a0d5: - db $51 - RGB 26, 0, 0 - RGB 26, 0, 0 - RGB 26, 0, 0 - RGB 26, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a0e5: - db $51 - RGB 18, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a0f5: - db $51 - RGB 28, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a105: - db $51 - RGB 29, 1, 0 - RGB 30, 1, 0 - RGB 31, 1, 0 - RGB 0, 2, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a115: - db $51 - RGB 19, 1, 0 - RGB 20, 1, 0 - RGB 27, 0, 0 - RGB 31, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a125: - db $51 - RGB 27, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a135: - db $51 - RGB 28, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a145: - db $51 - RGB 21, 1, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - RGB 0, 0, 0 - db $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a155: db $01, $ff, $7f, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a165: db $09, $ff, $7f, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a175: db $59, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a185: db $89, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a195: db $89, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a1a5: db $99, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a1b5: db $a1, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 - -PalPacket_a1c5: db $b9, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a1d5: db $b9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a1e5: db $79, $5d, $08, $00, $0b, $8c, $d0, $f4, $60, $00, $00, $00, $00, $00, $00, $00 -PalPacket_a1f5: db $79, $52, $08, $00, $0b, $a9, $e7, $9f, $01, $c0, $7e, $e8, $e8, $e8, $e8, $e0 -PalPacket_a205: db $79, $47, $08, $00, $0b, $c4, $d0, $16, $a5, $cb, $c9, $05, $d0, $10, $a2, $28 -PalPacket_a215: db $79, $3c, $08, $00, $0b, $f0, $12, $a5, $c9, $c9, $c8, $d0, $1c, $a5, $ca, $c9 -PalPacket_a225: db $79, $31, $08, $00, $0b, $0c, $a5, $ca, $c9, $7e, $d0, $06, $a5, $cb, $c9, $7e -PalPacket_a235: db $79, $26, $08, $00, $0b, $39, $cd, $48, $0c, $d0, $34, $a5, $c9, $c9, $80, $d0 -PalPacket_a245: db $79, $1b, $08, $00, $0b, $ea, $ea, $ea, $ea, $ea, $a9, $01, $cd, $4f, $0c, $d0 -PalPacket_a255: db $79, $10, $08, $00, $0b, $4c, $20, $08, $ea, $ea, $ea, $ea, $ea, $60, $ea, $ea - -IF DEF(GOLD) -Palettes_a265: INCLUDE "gfx/pals/gold_a265.pal" -ENDC -IF DEF(SILVER) -Palettes_a265: INCLUDE "gfx/pals/silver_a265.pal" -ENDC - -IF DEF(GOLD) -SGBBorderMap: INCBIN "gfx/sgb_border/gold.map" -SGBBorderPalettes: INCLUDE "gfx/sgb_border/pals/gold.pal" -SGBBorder: INCBIN "gfx/sgb_border/gold.2bpp" -ENDC - -IF DEF(SILVER) -SGBBorderMap: INCBIN "gfx/sgb_border/silver.map" -SGBBorderPalettes: INCLUDE "gfx/sgb_border/pals/silver.pal" -SGBBorder: INCBIN "gfx/sgb_border/silver.2bpp" -ENDC - -Palettes_ad2d: - RGB 30, 26, 15 - RGB 00, 23, 00 - - RGB 30, 26, 15 - RGB 31, 21, 00 - - RGB 30, 26, 15 - RGB 31, 00, 00 - -Palettes_ad39: - RGB 30, 26, 15 - RGB 04, 17, 31 - -INCLUDE "gfx/pics/palette_pointers.asm" -INCLUDE "gfx/trainers/palette_pointers.asm" - -Functionb649: ; b649 (2:7649) - ld a, [wPermission] - and $7 - ld e, a - ld d, $0 - ld hl, Pointers_b6ce - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wTimeOfDayPal] - and $3 - add a - add a - add a - ld e, a - ld d, $0 - add hl, de - ld e, l - ld d, h - ld hl, wTempBGPals - ld b, $8 -.asm_b66c - ld a, [de] - push de - push hl - ld l, a - ld h, $0 - add hl, hl - add hl, hl - add hl, hl - ld de, $775e - add hl, de - ld e, l - ld d, h - pop hl - ld c, $8 -.asm_b67e - ld a, [de] - inc de - ld [hli], a - dec c - jr nz, .asm_b67e - pop de - inc de - dec b - jr nz, .asm_b66c - ld a, [wTimeOfDayPal] - and $3 - ld bc, $40 - ld hl, MapObjectPals - call AddNTimes - ld de, wTempOBPal0 - ld bc, $40 - call CopyBytes - ld a, [wPermission] - cp $1 - jr z, .asm_b6aa - cp $2 - ret nz -.asm_b6aa - ld a, [wMapGroup] - ld l, a - ld h, $0 - add hl, hl - add hl, hl - add hl, hl - ld de, RoofPals - add hl, de - ld a, [wTimeOfDayPal] - and $3 - cp $2 - jr c, .asm_b6c4 - inc hl - inc hl - inc hl - inc hl -.asm_b6c4 - ld de, wTempBGPal6 + 2 - ld bc, $4 - call CopyBytes - ret - -Pointers_b6ce: - dw .OutdoorColors ; unused - dw .OutdoorColors ; TOWN - dw .OutdoorColors ; ROUTE - dw .IndoorColors ; INDOOR - dw .DungeonColors ; CAVE - dw .Perm5Colors ; ENVIRONMENT_5 - dw .IndoorColors ; GATE - dw .DungeonColors ; DUNGEON - -; Valid indices: $00 - $29 -.OutdoorColors: - db $00, $01, $02, $28, $04, $05, $06, $07 ; morn - db $08, $09, $0a, $28, $0c, $0d, $0e, $0f ; day - db $10, $11, $12, $29, $14, $15, $16, $17 ; nite - db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; dark - -.IndoorColors: - db $20, $21, $22, $23, $24, $25, $26, $07 ; morn - db $20, $21, $22, $23, $24, $25, $26, $07 ; day - db $10, $11, $12, $13, $14, $15, $16, $07 ; nite - db $18, $19, $1a, $1b, $1c, $1d, $1e, $07 ; dark - -.DungeonColors: - db $00, $01, $02, $03, $04, $05, $06, $07 ; morn - db $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ; day - db $10, $11, $12, $13, $14, $15, $16, $17 ; nite - db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; dark - -.Perm5Colors: - db $00, $01, $02, $03, $04, $05, $06, $07 ; morn - db $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ; day - db $10, $11, $12, $13, $14, $15, $16, $17 ; nite - db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; dark - -TilesetBGPalette: ; b75e -INCLUDE "gfx/tilesets/bg.pal" - -MapObjectPals:: ; b8ae -INCLUDE "gfx/tilesets/ob.pal" - -RoofPals: ; b9ae -INCLUDE "gfx/tilesets/roof.pal" - -Palettes_ba86: - RGB 27, 31, 27 - RGB 21, 21, 21 - RGB 13, 13, 13 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 07, 06 - RGB 20, 02, 03 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 10, 31, 09 - RGB 04, 14, 01 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 08, 12, 31 - RGB 01, 04, 31 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 31, 07 - RGB 31, 16, 01 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 22, 16, 08 - RGB 13, 07, 01 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 15, 31, 31 - RGB 05, 17, 31 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 11, 11, 19 - RGB 07, 07, 12 - RGB 00, 00, 00 - -Palettes_bac6: - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 10, 14, 20 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 27, 31, 27 - RGB 31, 19, 10 - RGB 31, 07, 04 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 21, 21, 21 - RGB 13, 13, 13 - RGB 07, 07, 07 - - RGB 31, 31, 31 - RGB 31, 31, 07 - RGB 31, 16, 01 - RGB 07, 07, 07 - - RGB 31, 31, 31 - RGB 31, 19, 24 - RGB 30, 10, 06 - RGB 07, 07, 07 - - RGB 31, 31, 31 - RGB 12, 25, 01 - RGB 05, 14, 00 - RGB 07, 07, 07 - - RGB 31, 31, 31 - RGB 08, 12, 31 - RGB 01, 04, 31 - RGB 07, 07, 07 - - RGB 31, 31, 31 - RGB 24, 18, 07 - RGB 20, 15, 03 - RGB 07, 07, 07 - -Palettes_bb36: -IF DEF(GOLD) - RGB 31, 31, 31 - RGB 18, 23, 31 - RGB 15, 20, 31 - RGB 0, 0, 0 - - RGB 31, 21, 0 - RGB 12, 14, 12 - RGB 15, 20, 31 - RGB 0, 0, 17 - - RGB 31, 31, 31 - RGB 31, 0, 0 - RGB 15, 20, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 29, 25, 0 - RGB 15, 20, 31 - RGB 17, 10, 1 - - RGB 31, 31, 31 - RGB 23, 26, 31 - RGB 18, 23, 31 - RGB 0, 0, 0 -ENDC - -IF DEF(SILVER) - RGB 31, 31, 31 - RGB 0, 12, 15 - RGB 4, 8, 21 - RGB 0, 0, 0 - - RGB 31, 21, 0 - RGB 15, 17, 15 - RGB 4, 8, 21 - RGB 0, 0, 17 - - RGB 31, 31, 31 - RGB 31, 0, 0 - RGB 4, 8, 21 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 24, 23, 25 - RGB 4, 8, 21 - RGB 8, 8, 9 - - RGB 31, 31, 31 - RGB 5, 10, 11 - RGB 0, 12, 15 - RGB 0, 0, 0 -ENDC - -Palettes_bb5e: - RGB 31, 31, 31 - RGB 07, 06, 03 - RGB 07, 06, 03 - RGB 07, 06, 03 - - RGB 31, 31, 31 - RGB 31, 31, 00 - RGB 26, 22, 00 - RGB 00, 00, 00 - -Palettes_bb6e: - RGB 28, 31, 20 - RGB 21, 21, 21 - RGB 13, 13, 13 - RGB 00, 00, 00 - - RGB 28, 31, 20 - RGB 00, 31, 00 - RGB 00, 00, 31 - RGB 00, 00, 00 - - RGB 28, 31, 20 - RGB 00, 31, 00 - RGB 15, 07, 00 - RGB 00, 00, 00 - - RGB 28, 31, 20 - RGB 31, 15, 00 - RGB 15, 07, 00 - RGB 00, 00, 00 - - RGB 28, 31, 20 - RGB 00, 31, 00 - RGB 00, 00, 31 - RGB 31, 00, 00 - - RGB 28, 31, 20 - RGB 00, 31, 00 - RGB 15, 07, 00 - RGB 31, 00, 00 - -Palettes_bb9e: - RGB 31, 31, 31 - RGB 30, 22, 24 - RGB 18, 18, 18 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 10, 11, 31 - RGB 18, 18, 18 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 12, 31, 11 - RGB 18, 18, 18 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 29, 26, 05 - RGB 18, 18, 18 - RGB 00, 00, 00 - -Palettes_bbbe: -IF DEF(GOLD) - RGB 31, 31, 31 - RGB 24, 25, 28 - RGB 24, 24, 09 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 30, 10, 06 - RGB 24, 24, 09 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 15, 31, 00 - RGB 24, 24, 09 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 31, 15, 31 - RGB 24, 24, 09 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 15, 21, 31 - RGB 24, 24, 09 - RGB 00, 00, 00 - - RGB 31, 31, 11 - RGB 31, 31, 06 - RGB 24, 24, 09 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 16, 19, 29 - RGB 25, 22, 00 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 21, 21, 21 - RGB 13, 13, 13 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 30, 10, 06 - RGB 31, 00, 00 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 12, 25, 01 - RGB 05, 14, 00 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 12, 25, 01 - RGB 30, 10, 06 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 31, 31, 06 - RGB 20, 15, 03 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 31, 31, 06 - RGB 15, 21, 31 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 31, 31, 06 - RGB 20, 15, 03 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 31, 24, 21 - RGB 31, 13, 31 - RGB 00, 00, 00 - - RGB 31, 31, 31 - RGB 31, 31, 31 - RGB 00, 00, 00 - RGB 00, 00, 00 -ENDC - -IF DEF(SILVER) - RGB 31, 31, 31 - RGB 25, 26, 14 - RGB 20, 17, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 30, 10, 6 - RGB 20, 17, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 15, 31, 0 - RGB 20, 17, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 15, 31 - RGB 20, 17, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 15, 21, 31 - RGB 20, 17, 31 - RGB 0, 0, 0 - - RGB 31, 31, 11 - RGB 31, 31, 6 - RGB 20, 17, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 16, 19, 29 - RGB 25, 22, 0 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 21, 21, 21 - RGB 13, 13, 13 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 30, 10, 6 - RGB 31, 0, 0 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 12, 25, 1 - RGB 5, 14, 0 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 12, 25, 1 - RGB 30, 10, 6 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 31, 6 - RGB 20, 15, 3 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 31, 6 - RGB 15, 21, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 31, 6 - RGB 20, 15, 3 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 24, 21 - RGB 31, 13, 31 - RGB 0, 0, 0 - - RGB 31, 31, 31 - RGB 31, 31, 31 - RGB 0, 0, 0 - RGB 0, 0, 0 -ENDC diff --git a/engine/engine_flags.asm b/engine/engine_flags.asm deleted file mode 100755 index 9fa5f8c0..00000000 --- a/engine/engine_flags.asm +++ /dev/null @@ -1,195 +0,0 @@ -EngineFlagAction:: ; c01b -; Do action b on engine flag de -; -; b = 0: reset flag -; = 1: set flag -; > 1: check flag, result in c -; -; Setting/resetting does not return a result. - - -; 16-bit flag ids are considered invalid, but it's nice -; to know that the infrastructure is there. - - ld a, d - cp 0 - jr z, .ceiling - jr c, .read ; cp 0 can't set carry! - jr .invalid - -; There are only $a2 engine flags, so -; anything beyond that is invalid too. - -.ceiling - ld a, e - cp NUM_ENGINE_FLAGS - jr c, .read - -; Invalid flags are treated as flag 00. - -.invalid - xor a - ld e, a - ld d, a - -; Get this flag's location. - -.read - ld hl, EngineFlags -; location - add hl, de - add hl, de -; bit - add hl, de - -; location - ld e, [hl] - inc hl - ld d, [hl] - inc hl -; bit - ld c, [hl] - -; What are we doing with this flag? - - ld a, b - cp 1 - jr c, .reset ; b = 0 - jr z, .set ; b = 1 - -; Return the given flag in c. -.check - ld a, [de] - and c - ld c, a - ret - -; Set the given flag. -.set - ld a, [de] - or c - ld [de], a - ret - -; Reset the given flag. -.reset - ld a, c - cpl ; AND all bits except the one in question - ld c, a - ld a, [de] - and c - ld [de], a - ret - -; 404d -EngineFlags: -; All locations are in WRAM bank 1. - - ; location, bit - engine_flag ENGINE_RADIO_CARD - engine_flag ENGINE_MAP_CARD - engine_flag ENGINE_PHONE_CARD - engine_flag ENGINE_EXPN_CARD - engine_flag ENGINE_POKEGEAR - - engine_flag ENGINE_DAY_CARE_MAN_HAS_EGG - engine_flag ENGINE_DAY_CARE_MAN_HAS_MON - - engine_flag ENGINE_DAY_CARE_LADY_HAS_MON - - engine_flag ENGINE_MOM_SAVING_MONEY - engine_flag ENGINE_DST - - engine_flag ENGINE_0A - - engine_flag ENGINE_POKEDEX - engine_flag ENGINE_UNOWN_DEX - engine_flag ENGINE_POKERUS - engine_flag ENGINE_ROCKET_SIGNAL_ON_CH20 - engine_flag ENGINE_CREDITS_SKIP - engine_flag ENGINE_BUG_CONTEST_TIMER - engine_flag ENGINE_SAFARI_ZONE - engine_flag ENGINE_ROCKETS_IN_RADIO_TOWER - engine_flag ENGINE_BIKE_SHOP_CALL_ENABLED - engine_flag ENGINE_GIVE_POKERUS - engine_flag ENGINE_REACHED_GOLDENROD - engine_flag ENGINE_ROCKETS_IN_MAHOGANY - - engine_flag ENGINE_STRENGTH_ACTIVE - engine_flag ENGINE_ALWAYS_ON_BIKE - engine_flag ENGINE_DOWNHILL - - engine_flag ENGINE_ZEPHYRBADGE - engine_flag ENGINE_HIVEBADGE - engine_flag ENGINE_PLAINBADGE - engine_flag ENGINE_FOGBADGE - engine_flag ENGINE_MINERALBADGE - engine_flag ENGINE_STORMBADGE - engine_flag ENGINE_GLACIERBADGE - engine_flag ENGINE_RISINGBADGE - - engine_flag ENGINE_BOULDERBADGE - engine_flag ENGINE_CASCADEBADGE - engine_flag ENGINE_THUNDERBADGE - engine_flag ENGINE_RAINBOWBADGE - engine_flag ENGINE_SOULBADGE - engine_flag ENGINE_MARSHBADGE - engine_flag ENGINE_VOLCANOBADGE - engine_flag ENGINE_EARTHBADGE - - engine_flag ENGINE_UNLOCKED_UNOWNS_A_TO_K - engine_flag ENGINE_UNLOCKED_UNOWNS_L_TO_R - engine_flag ENGINE_UNLOCKED_UNOWNS_S_TO_W - engine_flag ENGINE_UNLOCKED_UNOWNS_X_TO_Z - engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_4 - engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_5 - engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_6 - engine_flag ENGINE_UNLOCKED_UNOWNS_UNUSED_7 - - engine_flag ENGINE_FLYPOINT_PLAYERS_HOUSE - engine_flag ENGINE_FLYPOINT_VIRIDIAN_POKECENTER - engine_flag ENGINE_FLYPOINT_PALLET - engine_flag ENGINE_FLYPOINT_VIRIDIAN - engine_flag ENGINE_FLYPOINT_PEWTER - engine_flag ENGINE_FLYPOINT_CERULEAN - engine_flag ENGINE_FLYPOINT_ROCK_TUNNEL - engine_flag ENGINE_FLYPOINT_VERMILION - engine_flag ENGINE_FLYPOINT_LAVENDER - engine_flag ENGINE_FLYPOINT_SAFFRON - engine_flag ENGINE_FLYPOINT_CELADON - engine_flag ENGINE_FLYPOINT_FUCHSIA - engine_flag ENGINE_FLYPOINT_CINNABAR - engine_flag ENGINE_FLYPOINT_INDIGO_PLATEAU - engine_flag ENGINE_FLYPOINT_NEW_BARK - engine_flag ENGINE_FLYPOINT_CHERRYGROVE - engine_flag ENGINE_FLYPOINT_VIOLET - - engine_flag ENGINE_FLYPOINT_AZALEA - engine_flag ENGINE_FLYPOINT_CIANWOOD - engine_flag ENGINE_FLYPOINT_GOLDENROD - engine_flag ENGINE_FLYPOINT_OLIVINE - engine_flag ENGINE_FLYPOINT_ECRUTEAK - engine_flag ENGINE_FLYPOINT_MAHOGANY - engine_flag ENGINE_FLYPOINT_LAKE_OF_RAGE - engine_flag ENGINE_FLYPOINT_BLACKTHORN - engine_flag ENGINE_FLYPOINT_SILVER_CAVE - - engine_flag ENGINE_FLYPOINT_UNUSED - engine_flag ENGINE_LUCKY_NUMBER_SHOW - engine_flag ENGINE_4E - - engine_flag ENGINE_KURT_MAKING_BALLS - engine_flag ENGINE_DAILY_BUG_CONTEST - engine_flag ENGINE_SPECIAL_WILDDATA - engine_flag ENGINE_TIME_CAPSULE - engine_flag ENGINE_ALL_FRUIT_TREES - engine_flag ENGINE_GOT_SHUCKIE_TODAY - engine_flag ENGINE_GOLDENROD_UNDERGROUND_MERCHANT_CLOSED - engine_flag ENGINE_FOUGHT_IN_TRAINER_HALL_TODAY - - engine_flag ENGINE_MT_MOON_SQUARE_CLEFAIRY - engine_flag ENGINE_UNION_CAVE_LAPRAS - engine_flag ENGINE_GOLDENROD_UNDERGROUND_GOT_HAIRCUT - engine_flag ENGINE_GOLDENROD_DEPT_STORE_TM27_RETURN - engine_flag ENGINE_DAISYS_GROOMING - engine_flag ENGINE_INDIGO_PLATEAU_RIVAL_FIGHT diff --git a/engine/events/bug_contest/caught_mon.asm b/engine/events/bug_contest/caught_mon.asm new file mode 100644 index 00000000..b2cc044a --- /dev/null +++ b/engine/events/bug_contest/caught_mon.asm @@ -0,0 +1,37 @@ +BugContest_SetCaughtContestMon: + ld a, [wContestMon] + and a + jr z, .firstcatch + ld [wNamedObjectIndexBuffer], a + farcall DisplayAlreadyCaughtText + farcall DisplayCaughtContestMonStats + lb bc, 14, 7 + call PlaceYesNoBox + ret c + +.firstcatch + call .generatestats + ld a, [wTempEnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, .ContestCaughtMonText + call PrintText + ret + +.generatestats + ld a, [wTempEnemyMonSpecies] + ld [wCurSpecies], a + ld [wCurPartySpecies], a + call GetBaseData + xor a + ld bc, PARTYMON_STRUCT_LENGTH + ld hl, wContestMon + call ByteFill + xor a + ld [wMonType], a + ld hl, wContestMon + jp GeneratePartyMonStats + +.ContestCaughtMonText: + text_far _ContestCaughtMonText + text_end diff --git a/engine/events/bug_contest/contest.asm b/engine/events/bug_contest/contest.asm index 88c300e9..6a3f7799 100755 --- a/engine/events/bug_contest/contest.asm +++ b/engine/events/bug_contest/contest.asm @@ -2,16 +2,16 @@ GiveParkBalls: xor a ld [wContestMon], a ld a, 20 - ld [wParkBalls], a + ld [wParkBallsRemaining], a farcall StartBugContestTimer ret BugCatchingContestBattleScript:: - writecode VAR_BATTLETYPE, BATTLETYPE_CONTEST + loadvar VAR_BATTLETYPE, BATTLETYPE_CONTEST randomwildmon startbattle reloadmapafterbattle - copybytetovar wParkBalls + readmem wParkBallsRemaining iffalse BugCatchingContestOutOfBallsScript end @@ -20,22 +20,22 @@ BugCatchingContestOverScript:: opentext writetext BugCatchingContestTimeUpText waitbutton - jump $79CD - + sjump BugCatchingContestReturnToGateScript + BugCatchingContestOutOfBallsScript: playsound SFX_ELEVATOR_END opentext writetext BugCatchingContestIsOverText waitbutton - + BugCatchingContestReturnToGateScript: closetext jumpstd bugcontestresultswarp - + BugCatchingContestTimeUpText: text_far _BugCatchingContestTimeUpText - db "@" + text_end BugCatchingContestIsOverText: text_far _BugCatchingContestIsOverText - db "@"
\ No newline at end of file + text_end diff --git a/engine/events/bug_contest/contest_2.asm b/engine/events/bug_contest/contest_2.asm new file mode 100644 index 00000000..ddfad864 --- /dev/null +++ b/engine/events/bug_contest/contest_2.asm @@ -0,0 +1,116 @@ +SelectRandomBugContestContestants: +; 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, NUM_BUG_CONTESTANTS + 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 $ff / NUM_BUG_CONTESTANTS * NUM_BUG_CONTESTANTS + jr nc, .next + ld c, $ff / NUM_BUG_CONTESTANTS + 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 + +CheckBugContestContestantFlag: +; Checks the flag of the Bug Catching Contestant whose index is loaded in a. + + 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 + +INCLUDE "data/events/bug_contest_flags.asm" + +ContestDropOffMons: + ld hl, wPartyMon1HP + ld a, [hli] + or [hl] + jr z, .fainted +; Mask the rest of your party by setting the count to 1... + ld hl, wPartyCount + 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], -1 + xor a + ld [wScriptVar], a + ret + +.fainted + ld a, $1 + ld [wScriptVar], a + ret + +ContestReturnMons: +; Restore the species of the second mon. + ld hl, wPartySpecies + 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 [wPartyCount], a + ret diff --git a/engine/events/bug_contest/judging.asm b/engine/events/bug_contest/judging.asm new file mode 100644 index 00000000..4f55fd78 --- /dev/null +++ b/engine/events/bug_contest/judging.asm @@ -0,0 +1,373 @@ +_BugContestJudging: + call ContestScore + call BugContest_JudgeContestants + ld a, [wBugContestThirdPlaceWinnerID] + call LoadContestantName + ld a, [wBugContestThirdPlaceMon] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, ContestJudging_ThirdPlaceText + call PrintText + ld a, [wBugContestSecondPlaceWinnerID] + call LoadContestantName + ld a, [wBugContestSecondPlaceMon] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, ContestJudging_SecondPlaceText + call PrintText + ld a, [wBugContestFirstPlaceWinnerID] + call LoadContestantName + ld a, [wBugContestFirstPlaceMon] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, ContestJudging_FirstPlaceText + call PrintText + jp BugContest_GetPlayersResult + +ContestJudging_FirstPlaceText: + text_far _ContestJudging_FirstPlaceText + text_asm + ld de, SFX_1ST_PLACE + call PlaySFX + call WaitSFX + ld hl, ContestJudging_FirstPlaceScoreText + ret + +ContestJudging_FirstPlaceScoreText: + text_far _ContestJudging_FirstPlaceScoreText + text_end + +ContestJudging_SecondPlaceText: + ; Placing second was @ , who caught a @ !@ @ + text_far _ContestJudging_SecondPlaceText + text_asm + ld de, SFX_2ND_PLACE + call PlaySFX + call WaitSFX + ld hl, ContestJudging_SecondPlaceScoreText + ret + +ContestJudging_SecondPlaceScoreText: + text_far _ContestJudging_SecondPlaceScoreText + text_end + +ContestJudging_ThirdPlaceText: + ; Placing third was @ , who caught a @ !@ @ + text_far _ContestJudging_ThirdPlaceText + text_asm + ld de, SFX_3RD_PLACE + call PlaySFX + call WaitSFX + ld hl, ContestJudging_ThirdPlaceScoreText + ret + +ContestJudging_ThirdPlaceScoreText: + text_far _ContestJudging_ThirdPlaceScoreText + text_end + +LoadContestantName: +; If a = 1, get your name. + dec a ; BUG_CONTEST_PLAYER + 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, wStringBuffer1 + 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, wStringBuffer1 + pop de + ld bc, NAME_LENGTH - 1 + jp CopyBytes + +.player + ld hl, wPlayerName + ld de, wBugContestWinnerName + ld bc, NAME_LENGTH + jp CopyBytes + +INCLUDE "data/events/bug_contest_winners.asm" + +BugContest_GetPlayersResult: + ld hl, wBugContestThirdPlaceWinnerID + ld de, -BUG_CONTESTANT_SIZE + ld b, 3 ; 3rd, 2nd, or 1st +.loop + ld a, [hl] + cp BUG_CONTEST_PLAYER + jr z, .done + add hl, de + dec b + jr nz, .loop + +.done + ret + +BugContest_JudgeContestants: + call ClearContestResults + call ComputeAIContestantScores + ld hl, wBugContestTempWinnerID + ld a, BUG_CONTEST_PLAYER + ld [hli], a + ld a, [wContestMon] + ld [hli], a + ldh a, [hProduct] + ld [hli], a + ldh a, [hProduct + 1] + ld [hl], a + call DetermineContestWinners + ret + +ClearContestResults: + ld hl, wBugContestResults + ld b, wBugContestWinnersEnd - wBugContestResults + xor a +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +DetermineContestWinners: + ld de, wBugContestTempScore + ld hl, wBugContestFirstPlaceScore + ld c, 2 + call CompareBytes + jr c, .not_first_place + ld hl, wBugContestSecondPlaceWinnerID + ld de, wBugContestThirdPlaceWinnerID + ld bc, BUG_CONTESTANT_SIZE + call CopyBytes + ld hl, wBugContestFirstPlaceWinnerID + ld de, wBugContestSecondPlaceWinnerID + ld bc, BUG_CONTESTANT_SIZE + call CopyBytes + ld hl, wBugContestFirstPlaceWinnerID + call CopyTempContestant + jr .done + +.not_first_place + ld de, wBugContestTempScore + ld hl, wBugContestSecondPlaceScore + ld c, 2 + call CompareBytes + jr c, .not_second_place + ld hl, wBugContestSecondPlaceWinnerID + ld de, wBugContestThirdPlaceWinnerID + ld bc, BUG_CONTESTANT_SIZE + call CopyBytes + ld hl, wBugContestSecondPlaceWinnerID + call CopyTempContestant + jr .done + +.not_second_place + ld de, wBugContestTempScore + ld hl, wBugContestThirdPlaceScore + ld c, 2 + call CompareBytes + jr c, .done + ld hl, wBugContestThirdPlaceWinnerID + call CopyTempContestant + +.done + ret + +CopyTempContestant: +; Could've just called CopyBytes. + ld de, wBugContestTempWinnerID +rept BUG_CONTESTANT_SIZE - 1 + ld a, [de] + inc de + ld [hli], a +endr + ld a, [de] + inc de + ld [hl], a + ret + +ComputeAIContestantScores: + ld e, 0 +.loop + push de + call 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 + ; 0, 1, or 2 for 1st, 2nd, or 3rd + 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 + ; randomly perturb score + call Random + and %111 + 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 NUM_BUG_CONTESTANTS + jr nz, .loop + ret + +ContestScore: +; Determine the player's score in the Bug Catching Contest. + + xor a + ldh [hProduct], a + ldh [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 %0010 + add a + add a + ld c, a + + swap b + ld a, b + and %0010 + add a + add c + ld d, a + + ld a, [wContestMonDVs + 1] + ld b, a + and %0010 + ld c, a + + swap b + ld a, b + and %0010 + 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 + +.AddContestStat: + ld hl, hMultiplicand + add [hl] + ld [hl], a + ret nc + dec hl + inc [hl] + ret diff --git a/engine/events/checkforhiddenitems.asm b/engine/events/checkforhiddenitems.asm new file mode 100644 index 00000000..c71bd290 --- /dev/null +++ b/engine/events/checkforhiddenitems.asm @@ -0,0 +1,83 @@ +CheckForHiddenItems: +; Checks to see if there are hidden items on the screen that have not yet been found. If it finds one, returns carry. + call GetMapScriptsBank + ld [wBuffer1], a +; Get the coordinate of the bottom right corner of the screen, and load it in wBuffer3/wBuffer4. + ld a, [wXCoord] + add SCREEN_WIDTH / 4 + ld [wBuffer4], a + ld a, [wYCoord] + add SCREEN_HEIGHT / 4 + ld [wBuffer3], a +; Get the pointer for the first bg_event in the map... + ld hl, wCurMapBGEventsPointer + ld a, [hli] + ld h, [hl] + ld l, a +; ... before even checking to see if there are any BG events on this map. + ld a, [wCurMapBGEventCount] + and a + jr z, .nobgeventitems +; For i = 1:wCurMapBGEventCount... +.loop +; Store the counter in wBuffer2, and store the bg_event pointer in the stack. + ld [wBuffer2], a + push hl +; Get the Y coordinate of the BG event. + call .GetFarByte + ld e, a +; Is the Y coordinate of the BG event on the screen? If not, go to the next BG event. + ld a, [wBuffer3] + sub e + jr c, .next + cp SCREEN_HEIGHT / 2 + jr nc, .next +; Is the X coordinate of the BG event on the screen? If not, go to the next BG event. + call .GetFarByte + ld d, a + ld a, [wBuffer4] + sub d + jr c, .next + cp SCREEN_WIDTH / 2 + jr nc, .next +; Is this BG event a hidden item? If not, go to the next BG event. + call .GetFarByte + cp BGEVENT_ITEM + jr nz, .next +; Has this item already been found? If not, set off the Itemfinder. + ld a, [wBuffer1] + call GetFarHalfword + ld a, [wBuffer1] + call GetFarHalfword + ld d, h + ld e, l + ld b, CHECK_FLAG + call EventFlagAction + ld a, c + and a + jr z, .itemnearby + +.next +; Restore the bg_event pointer and increment it by the length of a bg_event. + pop hl + ld bc, BG_EVENT_SIZE + add hl, bc +; Restore the BG event counter and decrement it. If it hits zero, there are no hidden items in range. + ld a, [wBuffer2] + dec a + jr nz, .loop + +.nobgeventitems + xor a + ret + +.itemnearby + pop hl + scf + ret + +.GetFarByte: + ld a, [wBuffer1] + call GetFarByte + inc hl + ret diff --git a/engine/events/checktime.asm b/engine/events/checktime.asm new file mode 100644 index 00000000..6e470e88 --- /dev/null +++ b/engine/events/checktime.asm @@ -0,0 +1,19 @@ +CheckTime:: + ld a, [wTimeOfDay] + ld hl, .TimeOfDayTable + ld de, 2 + call IsInArray + inc hl + ld c, [hl] + ret c + + xor a + ld c, a + ret + +.TimeOfDayTable: + db MORN_F, MORN + db DAY_F, DAY + db NITE_F, NITE + db NITE_F, NITE + db -1 diff --git a/engine/events/daycare.asm b/engine/events/daycare.asm index 4cd12087..9cbe61ce 100644 --- a/engine/events/daycare.asm +++ b/engine/events/daycare.asm @@ -321,7 +321,7 @@ PrintDayCareText: .CantAcceptEgg: ; Sorry, but I can't accept an EGG. - text_far _CantRaiseEggText + text_far _CantAcceptEggText db "@" .RemoveMail: @@ -376,7 +376,7 @@ PrintDayCareText: .NotEnoughMoney: ; You don't have enough money. - text_far _DCNotEnoughMoneyText + text_far _NotEnoughMoneyText db "@" .OhFineThen: @@ -456,7 +456,7 @@ DayCareManOutside: .IllKeepItThanksText: ; Well then, I'll keep it. Thanks! - text_far _RefuseEggText + text_far _IllKeepItThanksText db "@" .PartyFullText: diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm new file mode 100644 index 00000000..e51b6be1 --- /dev/null +++ b/engine/events/elevator.asm @@ -0,0 +1,215 @@ +Elevator:: + 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 + +.LoadPointer: + ld a, b + ld [wElevatorPointerBank], a + ld a, e + ld [wElevatorPointer], a + ld a, d + ld [wElevatorPointer + 1], a + call .LoadFloors + ret + +.LoadFloors: + ld de, wCurElevator + ld bc, wElevatorDataEnd - wElevatorData + 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 + +.FindCurrentFloor: + ld hl, wElevatorPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wElevatorPointerBank] + call GetFarByte + ld c, a + inc hl + ld a, [wBackupMapGroup] + ld d, a + ld a, [wBackupMapNumber] + 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 + +Elevator_GoToFloor: + push af + ld hl, wElevatorPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + pop af + ld bc, wElevatorDataEnd - wElevatorData + call AddNTimes + inc hl + ld de, wBackupWarpNumber + ld a, [wElevatorPointerBank] + ld bc, wElevatorDataEnd - wElevatorData - 1 + call FarCopyBytes + ret + +Elevator_AskWhichFloor: + call LoadStandardMenuHeader + ld hl, AskFloorElevatorText + call PrintText + call Elevator_GetCurrentFloorText + ld hl, Elevator_MenuHeader + call CopyMenuHeader + 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 + +AskFloorElevatorText: + text_far _AskFloorElevatorText + text_end + +Elevator_GetCurrentFloorText: + ld hl, wOptions + 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 [wOptions], a + ret + +Elevator_CurrentFloorText: + db "Now on:@" + +Elevator_GetCurrentFloorString: + push hl + ld a, [wElevatorOriginFloor] + ld e, a + ld d, 0 + ld hl, wCurElevatorFloors + add hl, de + ld a, [hl] + pop de + call GetFloorString + ret + +Elevator_MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 12, 1, 18, 9 + dw Elevator_MenuData + db 1 ; default option + +Elevator_MenuData: + db SCROLLINGMENU_DISPLAY_ARROWS ; flags + db 4, 0 ; rows, columns + db SCROLLINGMENU_ITEMS_NORMAL ; item format + dbw 0, wCurElevator + dba GetElevatorFloorStrings + dba NULL + dba NULL + +GetElevatorFloorStrings: + ld a, [wMenuSelection] +GetFloorString: + push de + call FloorToString + ld d, h + ld e, l + pop hl + jp PlaceString + +FloorToString: + push de + ld e, a + ld d, 0 + ld hl, ElevatorFloorNames + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + pop de + ret + +INCLUDE "data/events/elevator_floors.asm" diff --git a/engine/events/engine_flags.asm b/engine/events/engine_flags.asm new file mode 100755 index 00000000..4099dfda --- /dev/null +++ b/engine/events/engine_flags.asm @@ -0,0 +1,83 @@ +EngineFlagAction:: +; Do action b on engine flag de +; +; b = 0: reset flag +; = 1: set flag +; > 1: check flag, result in c +; +; Setting/resetting does not return a result. + +; 16-bit flag ids are considered invalid, but it's nice +; to know that the infrastructure is there. + + ld a, d + cp HIGH(NUM_ENGINE_FLAGS) + jr z, .ceiling + jr c, .read ; cp 0 can't set carry! + jr .invalid + +; There are only NUM_ENGINE_FLAGS engine flags, so +; anything beyond that is invalid too. + +.ceiling + ld a, e + cp LOW(NUM_ENGINE_FLAGS) + jr c, .read + +; Invalid flags are treated as flag 00. + +.invalid + xor a + ld e, a + ld d, a + +; Get this flag's location. + +.read + ld hl, EngineFlags +; location + add hl, de + add hl, de +; bit + add hl, de + +; location + ld e, [hl] + inc hl + ld d, [hl] + inc hl +; bit + ld c, [hl] + +; What are we doing with this flag? + + ld a, b + cp 1 + jr c, .reset ; b = 0 + jr z, .set ; b = 1 + +; Return the given flag in c. +.check + ld a, [de] + and c + ld c, a + ret + +; Set the given flag. +.set + ld a, [de] + or c + ld [de], a + ret + +; Reset the given flag. +.reset + ld a, c + cpl ; AND all bits except the one in question + ld c, a + ld a, [de] + and c + ld [de], a + ret + +INCLUDE "data/engine_flags.asm" diff --git a/engine/events/fish.asm b/engine/events/fish.asm new file mode 100644 index 00000000..8cdcd3f2 --- /dev/null +++ b/engine/events/fish.asm @@ -0,0 +1,121 @@ +Fish: +; Using a fishing rod. +; Fish for monsters with rod e in encounter group d. +; Return monster d at level e. + + push af + push bc + push hl + + ld b, e + call GetFishGroupIndex + + ld hl, FishGroups +rept FISHGROUP_DATA_LENGTH + add hl, de +endr + call .Fish + + pop hl + pop bc + pop af + ret + +.Fish: +; Fish for monsters with rod b from encounter data in FishGroup at hl. +; Return monster d at level e. + + call Random + cp [hl] + jr nc, .no_bite + + ; Get encounter data by rod: + ; 0: Old + ; 1: Good + ; 2: Super + inc hl + ld e, b + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + ; Compare the encounter chance to select a Pokemon. + call Random +.loop + cp [hl] + jr z, .ok + jr c, .ok + inc hl + inc hl + inc hl + jr .loop +.ok + inc hl + + ; Species 0 reads from a time-based encounter table. + ld a, [hli] + ld d, a + and a + call z, .TimeEncounter + + ld e, [hl] + ret + +.no_bite + ld de, 0 + ret + +.TimeEncounter: + ; The level byte is repurposed as the index for the new table. + ld e, [hl] + ld d, 0 + ld hl, TimeFishGroups +rept 4 + add hl, de +endr + + ld a, [wTimeOfDay] + maskbits NUM_DAYTIMES + cp NITE_F + jr c, .time_species + inc hl + inc hl + +.time_species + ld d, [hl] + inc hl + ret + +GetFishGroupIndex: +; Return the index of fishgroup d in de. + + ld a, d + cp FISHGROUP_QWILFISH + jr z, .qwilfish + cp FISHGROUP_REMORAID + jr z, .remoraid + +.done + dec d + ld e, d + ld d, 0 + ret + +.qwilfish + ld a, [wFishingSwarmFlag] + cp FISHSWARM_QWILFISH + jr nz, .done + ld d, FISHGROUP_QWILFISH_SWARM + jr .done + +.remoraid + ld a, [wFishingSwarmFlag] + cp FISHSWARM_REMORAID + jr nz, .done + ld d, FISHGROUP_REMORAID_SWARM + jr .done + +INCLUDE "data/wild/fish.asm" diff --git a/engine/events/forced_movement.asm b/engine/events/forced_movement.asm index 69f27bfe..fcd2793f 100755 --- a/engine/events/forced_movement.asm +++ b/engine/events/forced_movement.asm @@ -1,5 +1,5 @@ Script_ForcedMovement:: - checkcode VAR_FACING + readvar VAR_FACING ifequal DOWN, .down ifequal UP, .up ifequal LEFT, .left diff --git a/engine/events/haircut.asm b/engine/events/haircut.asm index 55718beb..32043af1 100755 --- a/engine/events/haircut.asm +++ b/engine/events/haircut.asm @@ -12,14 +12,14 @@ BillsGrandfather: ld [wScriptVar], a ret -YoungerHaircutBrother: - ld hl, HappinessData_YoungerHaircutBrother - jr HaircutOrGrooming - OlderHaircutBrother: ld hl, HappinessData_OlderHaircutBrother jr HaircutOrGrooming +YoungerHaircutBrother: + ld hl, HappinessData_YoungerHaircutBrother + jr HaircutOrGrooming + DaisysGrooming: ld hl, HappinessData_DaisysGrooming ; fallthrough diff --git a/engine/events/happiness_egg.asm b/engine/events/happiness_egg.asm index 6c8b918c..bb2e949c 100755 --- a/engine/events/happiness_egg.asm +++ b/engine/events/happiness_egg.asm @@ -1,17 +1,17 @@ GetFirstPokemonHappiness: ld hl, wPartyMon1Happiness - ld bc, $30 + ld bc, PARTYMON_STRUCT_LENGTH ld de, wPartySpecies -.asm_7275 +.loop ld a, [de] cp EGG - jr nz, .asm_727e + jr nz, .done inc de add hl, bc - jr .asm_7275 + jr .loop -.asm_727e - ld [wd151], a +.done + ld [wNamedObjectIndexBuffer], a ld a, [hl] ld [wScriptVar], a call GetPokemonName @@ -19,67 +19,76 @@ GetFirstPokemonHappiness: CheckFirstMonIsEgg: ld a, [wPartySpecies] - ld [wd151], a + ld [wNamedObjectIndexBuffer], a cp EGG - ld a, $1 - jr z, .asm_7298 + ld a, TRUE + jr z, .egg xor a -.asm_7298 + +.egg ld [wScriptVar], a call GetPokemonName jp CopyPokemonName_Buffer1_Buffer3 -ChangeHappiness: ; 72a1 (1:72a1) +ChangeHappiness: +; Perform happiness action c on wCurPartyMon + ld a, [wCurPartyMon] inc a ld e, a - ld d, $0 - ld hl, wPartyCount + ld d, 0 + ld hl, wPartySpecies - 1 add hl, de ld a, [hl] - cp $fd + cp EGG ret z + push bc ld hl, wPartyMon1Happiness - ld bc, $30 + ld bc, PARTYMON_STRUCT_LENGTH ld a, [wCurPartyMon] call AddNTimes pop bc + ld d, h ld e, l + push de ld a, [de] - cp $64 - ld e, $0 - jr c, .asm_72ce + cp HAPPINESS_THRESHOLD_1 + ld e, 0 + jr c, .ok inc e - cp $c8 - jr c, .asm_72ce + cp HAPPINESS_THRESHOLD_2 + jr c, .ok inc e -.asm_72ce + +.ok dec c - ld b, $0 - ld hl, .Actions + ld b, 0 + ld hl, HappinessChanges add hl, bc add hl, bc add hl, bc - ld d, $0 + ld d, 0 add hl, de ld a, [hl] - cp $64 + cp $64 ; why not $80? pop de + ld a, [de] - jr nc, .asm_72e8 + jr nc, .negative add [hl] - jr nc, .asm_72ec - ld a, $ff - jr .asm_72ec + jr nc, .done + ld a, -1 + jr .done -.asm_72e8 +.negative add [hl] - jr c, .asm_72ec + jr c, .done xor a -.asm_72ec + +.done ld [de], a ld a, [wBattleMode] and a @@ -93,84 +102,76 @@ ChangeHappiness: ; 72a1 (1:72a1) ld [wBattleMonHappiness], a ret -.Actions: - db +5, +3, +2 ; Gained a level - db +5, +3, +2 ; Vitamin - db +1, +1, +0 ; X Item - db +3, +2, +1 ; Battled a Gym Leader - db +1, +1, +0 ; Learned a move - db -1, -1, -1 ; Lost to an enemy - db -5, -5, -10 ; Fainted due to poison - db -5, -5, -10 ; Lost to a much stronger enemy - db +1, +1, +1 ; Haircut (Y1) - db +3, +3, +1 ; Haircut (Y2) - db +5, +5, +2 ; Haircut (Y3) - db +1, +1, +1 ; Haircut (O1) - db +3, +3, +1 ; Haircut (O2) - db +10, +10, +4 ; Haircut (O3) - db -5, -5, -10 ; Used Heal Powder or Energypowder (bitter) - db -10, -10, -15 ; Used Energy Root (bitter) - db -15, -15, -20 ; Used Revival Herb (bitter) - db +3, +3, +1 ; Grooming +INCLUDE "data/events/happiness_changes.asm" StepHappiness:: - ld hl, wd9c1 +; Raise the party's happiness by 1 point every other step cycle. + + ld hl, wHappinessStepCount ld a, [hl] inc a - and $1 + and 1 ld [hl], a ret nz + ld de, wPartyCount ld a, [de] and a ret z + ld c, a ld hl, wPartyMon1Happiness -.asm_7349 +.loop inc de ld a, [de] cp EGG - jr z, .asm_7354 + jr z, .next inc [hl] - jr nz, .asm_7354 + jr nz, .next ld [hl], $ff -.asm_7354 + +.next push de - ld de, $30 + ld de, PARTYMON_STRUCT_LENGTH add hl, de pop de dec c - jr nz, .asm_7349 + jr nz, .loop ret -MAX_EXP EQU 5242880 +DayCareStep:: +; Raise the experience of Day-Care Pokémon every step cycle. + + ld a, [wDayCareMan] + bit DAYCAREMAN_HAS_MON_F, a + jr z, .day_care_lady -DaycareStep:: - CheckFlag ENGINE_DAY_CARE_MAN_HAS_MON - jr z, .daycare_lady - ld a, [wBreedMon1Level] + ld a, [wBreedMon1Level] ; level cp MAX_LEVEL - jr nc, .daycare_lady - ld hl, wBreedMon1Exp + 2 + jr nc, .day_care_lady + ld hl, wBreedMon1Exp + 2 ; exp inc [hl] - jr nz, .daycare_lady + jr nz, .day_care_lady dec hl inc [hl] - jr nz, .daycare_lady + jr nz, .day_care_lady dec hl inc [hl] ld a, [hl] - cp MAX_EXP / $10000 - jr c, .daycare_lady - ld a, MAX_EXP / $10000 + cp HIGH(MAX_DAY_CARE_EXP >> 8) + jr c, .day_care_lady + ld a, HIGH(MAX_DAY_CARE_EXP >> 8) ld [hl], a -.daycare_lady - CheckFlag ENGINE_DAY_CARE_LADY_HAS_MON + +.day_care_lady + ld a, [wDayCareLady] + bit DAYCARELADY_HAS_MON_F, a jr z, .check_egg - ld a, [wBreedMon2Level] + + ld a, [wBreedMon2Level] ; level cp MAX_LEVEL jr nc, .check_egg - ld hl, wBreedMon2Exp + 2 + ld hl, wBreedMon2Exp + 2 ; exp inc [hl] jr nz, .check_egg dec hl @@ -179,13 +180,14 @@ DaycareStep:: dec hl inc [hl] ld a, [hl] - cp MAX_EXP / $10000 + cp HIGH(MAX_DAY_CARE_EXP >> 8) jr c, .check_egg - ld a, MAX_EXP / $10000 + ld a, HIGH(MAX_DAY_CARE_EXP >> 8) ld [hl], a + .check_egg ld hl, wDayCareMan - bit 5, [hl] + bit DAYCAREMAN_MONS_COMPATIBLE_F, [hl] ret z ld hl, wStepsToEgg dec [hl] @@ -194,24 +196,25 @@ DaycareStep:: call Random ld [hl], a callfar CheckBreedmonCompatibility - ld a, [wd151] + ld a, [wBreedingCompatibility] cp 230 - ld b, -1 + 32 percent + ld b, 31 percent + 1 jr nc, .okay - ld a, [wd151] + ld a, [wBreedingCompatibility] cp 170 ld b, 16 percent jr nc, .okay - ld a, [wd151] + ld a, [wBreedingCompatibility] 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] - SetFlagForceReuseHL ENGINE_DAY_CARE_MAN_HAS_EGG + res DAYCAREMAN_MONS_COMPATIBLE_F, [hl] + set DAYCAREMAN_HAS_EGG_F, [hl] ret diff --git a/engine/events/heal_machine_anim.asm b/engine/events/heal_machine_anim.asm index 9770c35b..002d4ad4 100755 --- a/engine/events/heal_machine_anim.asm +++ b/engine/events/heal_machine_anim.asm @@ -134,25 +134,25 @@ ENDM ret .PC_ElmsLab_OAM: - 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 + dbsprite 4, 4, 2, 0, $7c, PAL_OW_TREE | OBP_NUM + dbsprite 4, 4, 6, 0, $7c, PAL_OW_TREE | OBP_NUM + dbsprite 4, 4, 0, 6, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 5, 4, 0, 6, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP + dbsprite 4, 5, 0, 3, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 5, 5, 0, 3, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP + dbsprite 4, 6, 0, 0, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 5, 6, 0, 0, $7d, PAL_OW_TREE | OBP_NUM | X_FLIP .HealMachineGFX: INCBIN "gfx/overworld/heal_machine.2bpp" .HOF_OAM: - 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 + dbsprite 10, 7, 1, 4, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 10, 7, 6, 4, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 9, 7, 5, 3, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 11, 7, 2, 3, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 9, 7, 1, 1, $7d, PAL_OW_TREE | OBP_NUM + dbsprite 11, 7, 5, 1, $7d, PAL_OW_TREE | OBP_NUM .LoadPalettes: call IsCGB @@ -163,7 +163,7 @@ INCBIN "gfx/overworld/heal_machine.2bpp" .cgb ld hl, .palettes - ld de, wOBPal6 + ld de, wOBPals2 palette PAL_OW_TREE ld bc, 1 palettes call CopyBytes ld a, $1 @@ -171,15 +171,7 @@ INCBIN "gfx/overworld/heal_machine.2bpp" ret .palettes - rst $38 - ld a, a - ld a, a - ld a, [hl+] - rst $38 - inc b - nop - nop -;INCLUDE "gfx/overworld/heal_machine.pal" +INCLUDE "gfx/overworld/heal_machine.pal" .FlashPalettes8Times: ld c, 8 @@ -202,7 +194,7 @@ INCBIN "gfx/overworld/heal_machine.2bpp" ret .go - ld hl, wOBPal6 + ld hl, wOBPals2 palette PAL_OW_TREE ld a, [hli] ld e, a ld a, [hli] diff --git a/engine/events/misc_scripts_2.asm b/engine/events/hidden_item.asm index 4a9e9484..b61a6205 100755..100644 --- a/engine/events/misc_scripts_2.asm +++ b/engine/events/hidden_item.asm @@ -1,28 +1,17 @@ -RepelWoreOffScript:: - opentext - writetext .RepelWoreOffText - waitbutton - closetext - end - -.RepelWoreOffText: - text_far _RepelWoreOffText - db "@" - HiddenItemScript:: opentext - copybytetovar wcf2b - itemtotext STRING_BUFFER_3, USE_SCRIPT_VAR + readmem wHiddenItemID + getitemname STRING_BUFFER_3, USE_SCRIPT_VAR writetext .PlayerFoundItemText giveitem ITEM_FROM_MEM iffalse .bag_full callasm SetMemEvent specialsound itemnotify - jump .finish + sjump .finish .bag_full - buttonsound + promptbutton writetext .ButNoSpaceText waitbutton @@ -32,14 +21,14 @@ HiddenItemScript:: .PlayerFoundItemText: text_far _PlayerFoundItemText - db "@" + text_end .ButNoSpaceText: text_far _ButNoSpaceText - db "@" + text_end SetMemEvent: - ld hl, wcf29 + ld hl, wHiddenItemEvent ld a, [hli] ld d, [hl] ld e, a diff --git a/engine/events/itemfinder.asm b/engine/events/itemfinder.asm new file mode 100644 index 00000000..3665187c --- /dev/null +++ b/engine/events/itemfinder.asm @@ -0,0 +1,50 @@ +ItemFinder: + 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 + +.ItemfinderSound: + 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 + +.Script_FoundSomething: + reloadmappart + special UpdateTimePals + callasm .ItemfinderSound + writetext .ItemfinderItemNearbyText + closetext + end + +.Script_FoundNothing: + reloadmappart + special UpdateTimePals + writetext .ItemfinderNopeText + closetext + end + +.ItemfinderItemNearbyText: + text_far _ItemfinderItemNearbyText + text_end + +.ItemfinderNopeText: + text_far _ItemfinderNopeText + text_end diff --git a/engine/events/misc_scripts.asm b/engine/events/misc_scripts.asm index f9ba459f..e9006332 100755 --- a/engine/events/misc_scripts.asm +++ b/engine/events/misc_scripts.asm @@ -29,27 +29,27 @@ FindItemInBallScript:: .FoundItemText: text_far _FoundItemText - db "@" + text_end .CantCarryItemText: text_far _CantCarryItemText - db "@" + text_end .TryReceiveItem: xor a ld [wScriptVar], a - ld a, [wcf29] - ld [wDeciramBuffer], a + ld a, [wItemBallItemID] + ld [wNamedObjectIndexBuffer], a call GetItemName ld hl, wStringBuffer3 call CopyName2 - ld a, [wcf29] - ld [wd002], a - ld a, [wcf2a] + ld a, [wItemBallItemID] + ld [wCurItem], a + ld a, [wItemBallQuantity] ld [wItemQuantityChangeBuffer], a ld hl, wNumItems call ReceiveItem ret nc ld a, $1 ld [wScriptVar], a - ret
\ No newline at end of file + ret diff --git a/engine/events/mom.asm b/engine/events/mom.asm new file mode 100644 index 00000000..18572296 --- /dev/null +++ b/engine/events/mom.asm @@ -0,0 +1,676 @@ +BankOfMom: + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + xor a + ld [wJumptableIndex], a +.loop + ld a, [wJumptableIndex] + bit 7, a + jr nz, .done + call .RunJumptable + jr .loop + +.done + pop af + ldh [hInMenu], a + ret + +.RunJumptable: + 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 + +.dw + + dw .CheckIfBankInitialized + dw .InitializeBank + dw .IsThisAboutYourMoney + dw .AccessBankOfMom + dw .StoreMoney + dw .TakeMoney + dw .StopOrStartSavingMoney + dw .JustDoWhatYouCan + dw .AskDST + +.CheckIfBankInitialized: + ld a, [wMomSavingMoney] + bit MOM_ACTIVE_F, a + jr nz, .savingmoneyalready + set MOM_ACTIVE_F, a + ld [wMomSavingMoney], a + ld a, $1 + jr .done_0 + +.savingmoneyalready + ld a, $2 + +.done_0 + ld [wJumptableIndex], a + ret + +.InitializeBank: + ld hl, MomLeavingText1 + call PrintText + call YesNoBox + jr c, .DontSaveMoney + ld hl, MomLeavingText2 + call PrintText + ld a, (1 << MOM_ACTIVE_F) | (1 << MOM_SAVING_SOME_MONEY_F) + jr .done_1 + +.DontSaveMoney: + ld a, 1 << MOM_ACTIVE_F + +.done_1 + ld [wMomSavingMoney], a + ld hl, MomLeavingText3 + call PrintText + ld a, $8 + ld [wJumptableIndex], a + ret + +.IsThisAboutYourMoney: + ld hl, MomIsThisAboutYourMoneyText + 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 + +.AccessBankOfMom: + ld hl, MomBankWhatDoYouWantToDoText + call PrintText + call LoadStandardMenuHeader + ld hl, MenuHeader_0x16914 + call CopyMenuHeader + 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 + +.StoreMoney: + ld hl, MomStoreMoneyText + call PrintText + xor a + ld hl, wStringBuffer2 + ld [hli], a + ld [hli], a + ld [hl], a + ld a, 5 + ld [wMomBankDigitCursorPosition], a + call LoadStandardMenuHeader + call Mom_SetUpDepositMenu + call Mom_Wait10Frames + call Mom_WithdrawDepositMenuJoypad + call CloseWindow + jr c, .CancelDeposit + ld hl, wStringBuffer2 + ld a, [hli] + or [hl] + inc hl + or [hl] + jr z, .CancelDeposit + ld de, wMoney + ld bc, wStringBuffer2 + farcall CompareMoney + jr c, .InsufficientFundsInWallet + ld hl, wStringBuffer2 + ld de, wStringBuffer2 + 3 + ld bc, 3 + call CopyBytes + ld bc, wMomsMoney + ld de, wStringBuffer2 + farcall GiveMoney + jr c, .NotEnoughRoomInBank + ld bc, wStringBuffer2 + 3 + ld de, wMoney + farcall TakeMoney + ld hl, wStringBuffer2 + ld de, wMomsMoney + ld bc, 3 + call CopyBytes + ld de, SFX_TRANSACTION + call PlaySFX + call WaitSFX + ld hl, MomStoredMoneyText + call PrintText + ld a, $8 + jr .done_4 + +.InsufficientFundsInWallet: + ld hl, MomInsufficientFundsInWalletText + call PrintText + ret + +.NotEnoughRoomInBank: + ld hl, MomNotEnoughRoomInBankText + call PrintText + ret + +.CancelDeposit: + ld a, $7 + +.done_4 + ld [wJumptableIndex], a + ret + +.TakeMoney: + ld hl, MomTakeMoneyText + call PrintText + xor a + ld hl, wStringBuffer2 + ld [hli], a + ld [hli], a + ld [hl], a + ld a, 5 + ld [wMomBankDigitCursorPosition], a + call LoadStandardMenuHeader + call Mom_SetUpWithdrawMenu + call Mom_Wait10Frames + call Mom_WithdrawDepositMenuJoypad + call CloseWindow + jr c, .CancelWithdraw + ld hl, wStringBuffer2 + ld a, [hli] + or [hl] + inc hl + or [hl] + jr z, .CancelWithdraw + ld hl, wStringBuffer2 + ld de, wStringBuffer2 + 3 + ld bc, 3 + call CopyBytes + ld de, wMomsMoney + ld bc, wStringBuffer2 + farcall CompareMoney + jr c, .InsufficientFundsInBank + ld bc, wMoney + ld de, wStringBuffer2 + farcall GiveMoney + jr c, .NotEnoughRoomInWallet + ld bc, wStringBuffer2 + 3 + ld de, wMomsMoney + farcall TakeMoney + ld hl, wStringBuffer2 + ld de, wMoney + ld bc, 3 + call CopyBytes + ld de, SFX_TRANSACTION + call PlaySFX + call WaitSFX + ld hl, MomTakenMoneyText + call PrintText + ld a, $8 + jr .done_5 + +.InsufficientFundsInBank: + ld hl, MomHaventSavedThatMuchText + call PrintText + ret + +.NotEnoughRoomInWallet: + ld hl, MomNotEnoughRoomInWalletText + call PrintText + ret + +.CancelWithdraw: + ld a, $7 + +.done_5 + ld [wJumptableIndex], a + ret + +.StopOrStartSavingMoney: + ld hl, MomSaveMoneyText + call PrintText + call YesNoBox + jr c, .StopSavingMoney + ld a, (1 << MOM_ACTIVE_F) | (1 << MOM_SAVING_SOME_MONEY_F) + ld [wMomSavingMoney], a + ld hl, MomStartSavingMoneyText + call PrintText + ld a, $8 + ld [wJumptableIndex], a + ret + +.StopSavingMoney: + ld a, 1 << MOM_ACTIVE_F + ld [wMomSavingMoney], a + ld a, $7 + ld [wJumptableIndex], a + ret + +.JustDoWhatYouCan: + ld hl, MomJustDoWhatYouCanText + call PrintText + +.AskDST: + ld hl, wJumptableIndex + set 7, [hl] + ret + +DSTChecks: +; check the time; avoid changing DST if doing so would change the current day + ld a, [wDST] + bit 7, a + ldh 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, .TimesetAskAdjustDSTText + call PlaceHLTextAtBC + call YesNoBox + ret c + call .ClearBox + bccoord 1, 14 + ld hl, .MomLostGearBookletText + call PlaceHLTextAtBC + ret + +.loop + call .ClearBox + bccoord 1, 14 + ld a, [wDST] + bit 7, a + jr z, .SetDST + ld hl, .TimesetAskNotDSTText + call PlaceHLTextAtBC + call YesNoBox + ret c + ld a, [wDST] + res 7, a + ld [wDST], a + call .SetClockBack + predef UpdateTimePredef + call .ClearBox + bccoord 1, 14 + ld hl, .TimesetNotDSTText + call PlaceHLTextAtBC + ret + +.SetDST: + ld hl, .TimesetAskDSTText + call PlaceHLTextAtBC + call YesNoBox + ret c + ld a, [wDST] + set 7, a + ld [wDST], a + call .SetClockForward + predef UpdateTimePredef + call .ClearBox + bccoord 1, 14 + ld hl, .TimesetDSTText + call PlaceHLTextAtBC + ret + +.SetClockForward: + ld a, [wStartHour] + add 1 + sub 24 + jr nc, .DontLoopHourForward + add 24 +.DontLoopHourForward: + ld [wStartHour], a + ccf + ld a, [wStartDay] + adc 0 + ld [wStartDay], a + ret + +.SetClockBack: + ld a, [wStartHour] + sub 1 + jr nc, .DontLoopHourBack + add 24 +.DontLoopHourBack: + ld [wStartHour], a + ld a, [wStartDay] + sbc 0 + jr nc, .DontLoopDayBack + add 7 +.DontLoopDayBack: + ld [wStartDay], a + ret + +.ClearBox: + hlcoord 1, 14 + lb bc, 3, 18 + call ClearBox + ret + +.TimesetAskAdjustDSTText: + text_far _TimesetAskAdjustDSTText + text_end + +.MomLostGearBookletText: + text_far _MomLostGearBookletText + text_end + +.TimesetAskDSTText: + text_far _TimesetAskDSTText + text_end + +.TimesetDSTText: + text_far _TimesetDSTText + text_end + +.TimesetAskNotDSTText: + text_far _TimesetAskNotDSTText + text_end + +.TimesetNotDSTText: + text_far _TimesetNotDSTText + text_end + +Mom_SetUpWithdrawMenu: + ld de, Mon_WithdrawString + jr Mom_ContinueMenuSetup + +Mom_SetUpDepositMenu: + ld de, Mom_DepositString +Mom_ContinueMenuSetup: + push de + xor a + ldh [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, wMoney + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + hlcoord 1, 6 + pop de + call PlaceString + hlcoord 12, 6 + ld de, wStringBuffer2 + lb bc, PRINTNUM_MONEY | PRINTNUM_LEADINGZEROS | 3, 6 + call PrintNum + call UpdateSprites + call CGBOnly_CopyTilemapAtOnce + ret + +Mom_Wait10Frames: + ld c, 10 + call DelayFrames + ret + +Mom_WithdrawDepositMenuJoypad: +.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 + ldh [hBGMapMode], a + hlcoord 12, 6 + ld bc, 7 + ld a, " " + call ByteFill + hlcoord 12, 6 + ld de, wStringBuffer2 + lb bc, PRINTNUM_MONEY | PRINTNUM_LEADINGZEROS | 3, 6 + call PrintNum + ldh 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, wStringBuffer2 + farcall GiveMoney + ret + +.decrementdigit + ld hl, .DigitQuantities + call .getdigitquantity + ld c, l + ld b, h + ld de, wStringBuffer2 + 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 + +.DigitQuantities: + 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 + +MomLeavingText1: + text_far _MomLeavingText1 + text_end + +MomLeavingText2: + text_far _MomLeavingText2 + text_end + +MomLeavingText3: + text_far _MomLeavingText3 + text_end + +MomIsThisAboutYourMoneyText: + text_far _MomIsThisAboutYourMoneyText + text_end + +MomBankWhatDoYouWantToDoText: + text_far _MomBankWhatDoYouWantToDoText + text_end + +MomStoreMoneyText: + text_far _MomStoreMoneyText + text_end + +MomTakeMoneyText: + text_far _MomTakeMoneyText + text_end + +MomSaveMoneyText: + text_far _MomSaveMoneyText + text_end + +MomHaventSavedThatMuchText: + text_far _MomHaventSavedThatMuchText + text_end + +MomNotEnoughRoomInWalletText: + text_far _MomNotEnoughRoomInWalletText + text_end + +MomInsufficientFundsInWalletText: + text_far _MomInsufficientFundsInWalletText + text_end + +MomNotEnoughRoomInBankText: + text_far _MomNotEnoughRoomInBankText + text_end + +MomStartSavingMoneyText: + text_far _MomStartSavingMoneyText + text_end + +MomStoredMoneyText: + text_far _MomStoredMoneyText + text_end + +MomTakenMoneyText: + text_far _MomTakenMoneyText + text_end + +MomJustDoWhatYouCanText: + text_far _MomJustDoWhatYouCanText + text_end + +Mom_SavedString: + db "SAVED@" + +Mon_WithdrawString: + db "WITHDRAW@" + +Mom_DepositString: + db "DEPOSIT@" + +Mom_HeldString: + db "HELD@" + +MenuHeader_0x16914: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 10, 10 + dw MenuData_0x1691c + db 1 ; default option + +MenuData_0x1691c: + db STATICMENU_CURSOR ; flags + db 4 ; items + db "GET@" + db "SAVE@" + db "CHANGE@" + db "CANCEL@" diff --git a/engine/events/money.asm b/engine/events/money.asm new file mode 100644 index 00000000..c8f9d058 --- /dev/null +++ b/engine/events/money.asm @@ -0,0 +1,209 @@ +GiveMoney:: + ld a, 3 + call AddMoney + ld bc, MaxMoney + ld a, 3 + call CompareMoney + jr z, .not_maxed_out + jr c, .not_maxed_out + ld hl, MaxMoney + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + scf + ret + +.not_maxed_out + and a + ret + +MaxMoney: + dt MAX_MONEY + +TakeMoney:: + ld a, 3 + call SubtractMoney + jr nc, .okay + ; leave with 0 money + xor a + ld [de], a + inc de + ld [de], a + inc de + ld [de], a + scf + ret + +.okay + and a + ret + +CompareMoney:: + ld a, 3 +CompareFunds: +; a: number of bytes +; bc: start addr of amount (big-endian) +; de: start addr of account (big-endian) + push hl + push de + push bc + ld h, b + ld l, c + ld c, 0 + ld b, a +.loop1 + dec a + jr z, .done + inc de + inc hl + jr .loop1 + +.done + and a +.loop2 + ld a, [de] + sbc [hl] + jr z, .okay + inc c + +.okay + dec de + dec hl + dec b + jr nz, .loop2 + jr c, .set_carry + ld a, c + and a + jr .skip_carry + +.set_carry + ld a, 1 + and a + scf +.skip_carry + pop bc + pop de + pop hl + ret + +SubtractMoney: + ld a, 3 +SubtractFunds: +; a: number of bytes +; bc: start addr of amount (big-endian) +; de: start addr of account (big-endian) + push hl + push de + push bc + ld h, b + ld l, c + ld b, a + ld c, 0 +.loop + dec a + jr z, .done + inc de + inc hl + jr .loop + +.done + and a +.loop2 + ld a, [de] + sbc [hl] + ld [de], a + dec de + dec hl + dec b + jr nz, .loop2 + pop bc + pop de + pop hl + ret + +AddMoney: + ld a, 3 +AddFunds: +; a: number of bytes +; bc: start addr of amount (big-endian) +; de: start addr of account (big-endian) + push hl + push de + push bc + + ld h, b + ld l, c + ld b, a +.loop1 + dec a + jr z, .done + inc de + inc hl + jr .loop1 + +.done + and a +.loop2 + ld a, [de] + adc [hl] + ld [de], a + dec de + dec hl + dec b + jr nz, .loop2 + + pop bc + pop de + pop hl + ret + +GiveCoins:: + ld a, 2 + ld de, wCoins + call AddFunds + ld a, 2 + ld bc, .maxcoins + call CompareFunds + jr c, .not_maxed + ld hl, .maxcoins + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + scf + ret + +.not_maxed + and a + ret + +.maxcoins + bigdw MAX_COINS + +TakeCoins:: + ld a, 2 + ld de, wCoins + call SubtractFunds + jr nc, .okay + ; leave with 0 coins + xor a + ld [de], a + inc de + ld [de], a + scf + ret + +.okay + and a + ret + +CheckCoins:: + ld a, 2 + ld de, wCoins + jp CompareFunds diff --git a/engine/events/move_deleter.asm b/engine/events/move_deleter.asm new file mode 100644 index 00000000..f9f83fab --- /dev/null +++ b/engine/events/move_deleter.asm @@ -0,0 +1,150 @@ +MoveDeletion: + ld hl, .DeleterIntroText + call PrintText + call YesNoBox + jr c, .declined + ld hl, .DeleterAskWhichMonText + call PrintText + farcall SelectMonFromParty + jr c, .declined + ld a, [wCurPartySpecies] + cp EGG + jr z, .egg + ld a, [wCurPartyMon] + ld hl, wPartyMon1Moves + 1 + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld a, [hl] + and a + jr z, .onlyonemove + ld hl, .DeleterAskWhichMoveText + call PrintText + call LoadStandardMenuHeader + farcall ChooseMoveToDelete + push af + call ReturnToMapWithSpeechTextbox + pop af + jr c, .declined + ld a, [wMenuCursorY] + push af + ld a, [wCurSpecies] + ld [wNamedObjectIndexBuffer], a + call GetMoveName + ld hl, .AskDeleteMoveText + call PrintText + call YesNoBox + pop bc + jr c, .declined + call .DeleteMove + call WaitSFX + ld de, SFX_MOVE_DELETED + call PlaySFX + call WaitSFX + ld hl, .DeleterForgotMoveText + call PrintText + ret + +.egg + ld hl, .MailEggText + call PrintText + ret + +.declined + ld hl, .DeleterNoComeAgainText + call PrintText + ret + +.onlyonemove + ld hl, .MoveKnowsOneText + call PrintText + ret + +.MoveKnowsOneText: + text_far _MoveKnowsOneText + text_end + +.AskDeleteMoveText: + text_far _AskDeleteMoveText + text_end + +.DeleterForgotMoveText: + text_far _DeleterForgotMoveText + text_end + +.MailEggText: + text_far _DeleterEggText + text_end + +.DeleterNoComeAgainText: + text_far _DeleterNoComeAgainText + text_end + +.DeleterAskWhichMoveText: + text_far _DeleterAskWhichMoveText + text_end + +.DeleterIntroText: + text_far _DeleterIntroText + text_end + +.DeleterAskWhichMonText: + text_far _DeleterAskWhichMonText + text_end + +.DeleteMove: + ld a, b + push bc + dec a + ld c, a + ld b, 0 + ld hl, wPartyMon1Moves + add hl, bc + ld a, [wCurPartyMon] + 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, wPartyMon1PP + add hl, bc + ld a, [wCurPartyMon] + 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/overworld.asm b/engine/events/overworld.asm index 0787d094..4f2ba801 100755 --- a/engine/events/overworld.asm +++ b/engine/events/overworld.asm @@ -1,407 +1,390 @@ -FieldMoveBufferReset: ; c72f (3:472f) +FieldMoveJumptableReset: xor a ld hl, wBuffer1 - ld bc, $7 + ld bc, 7 call ByteFill ret -DoFieldMoveAction: ; c73a (3:473a) +FieldMoveJumptable: ld a, [wBuffer1] rst JumpTable ld [wBuffer1], a bit 7, a - jr nz, .asm_c747 + jr nz, .okay and a ret -.asm_c747 +.okay and $7f scf ret -FieldMoveGetPartyNick: ; c74b (3:474b) - ld hl, wPartyMon1Nickname - ld a, $2 +GetPartyNick: +; write wCurPartyMon nickname to wStringBuffer1-3 + ld hl, wPartyMonNicknames + ld a, BOXMON ld [wMonType], a ld a, [wCurPartyMon] call GetNick call CopyName1 +; copy text from wStringBuffer2 to wStringBuffer3 ld de, wStringBuffer2 ld hl, wStringBuffer3 call CopyName2 ret -FieldMoveEngineFlagCheck: ; c766 (3:4766) +CheckEngineFlag: +; Check engine flag de +; Return carry if flag is not set ld b, CHECK_FLAG - farcall EngineFlagAction ; same bank + farcall EngineFlagAction ld a, c and a - jr nz, .asm_c774 + jr nz, .isset scf ret - -.asm_c774 +.isset xor a ret -FieldMoveBadgeCheck: ; c776 (3:4776) - call FieldMoveEngineFlagCheck +CheckBadge: +; 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 + call MenuTextboxBackup ; push text to queue scf ret .BadgeRequiredText: - text_far BadgeRequiredText_ - db "@" + text_far _BadgeRequiredText + text_end -FieldMovePartyCheck: ; c787 (3:4787) - ld e, $0 +CheckPartyMove: +; Check if a monster in your party has move d. + + ld e, 0 xor a ld [wCurPartyMon], a -.asm_c78d +.loop ld c, e - ld b, $0 + ld b, 0 ld hl, wPartySpecies add hl, bc ld a, [hl] and a - jr z, .asm_c7bc + jr z, .no cp -1 - jr z, .asm_c7bc + jr z, .no cp EGG - jr z, .asm_c7b3 + jr z, .next + ld bc, PARTYMON_STRUCT_LENGTH ld hl, wPartyMon1Moves ld a, e call AddNTimes ld b, NUM_MOVES -.asm_c7ac +.check ld a, [hli] cp d - jr z, .asm_c7b6 + jr z, .yes dec b - jr nz, .asm_c7ac -.asm_c7b3 + jr nz, .check + +.next inc e - jr .asm_c78d + jr .loop -.asm_c7b6 +.yes ld a, e - ld [wCurPartyMon], a + ld [wCurPartyMon], a ; which mon has the move xor a ret - -.asm_c7bc +.no scf ret -FieldMoveFailed: ; c7be (3:47be) - ld hl, .CantUseHereText +FieldMoveFailed: + ld hl, .CantUseItemText call MenuTextboxBackup ret -.CantUseHereText: - text_far CantUseFieldMoveHereText_ - db "@" +.CantUseItemText: + text_far _CantUseItemText + text_end -CutFunction:: - call FieldMoveBufferReset -.asm_c7cd +CutFunction: + call FieldMoveJumptableReset +.loop ld hl, .Jumptable - call DoFieldMoveAction - jr nc, .asm_c7cd + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret .Jumptable: - dw CheckAbleToCut - dw CutTreeOrGrass - dw FailToCut + dw .CheckAble + dw .DoCut + dw .FailCut -CheckAbleToCut: +.CheckAble: ld de, ENGINE_HIVEBADGE - call FieldMoveBadgeCheck - jr c, .asm_c7f1 + call CheckBadge + jr c, .nohivebadge call CheckMapForSomethingToCut - jr c, .asm_c7f4 + jr c, .nothingtocut ld a, $1 ret -.asm_c7f1 +.nohivebadge ld a, $80 ret -.asm_c7f4 +.nothingtocut ld a, $2 ret -CutTreeOrGrass: +.DoCut: ld hl, Script_CutFromMenu call QueueScript ld a, $81 ret -FailToCut: - ld hl, Text_NothingToCut +.FailCut: + ld hl, CutNothingText call MenuTextboxBackup ld a, $80 ret -Text_UsedCut: - text_far Text_UsedCut_ - db "@" +UseCutText: + text_far _UseCutText + text_end -Text_NothingToCut: - text_far Text_NothingToCut_ - db "@" +CutNothingText: + text_far _CutNothingText + text_end -CheckMapForSomethingToCut: ; c813 (3:4813) +CheckMapForSomethingToCut: + ; Does the collision data of the facing tile permit cutting? call GetFacingTileCoord ld c, a push de farcall CheckCutCollision pop de - jr nc, .asm_c841 + jr nc, .fail + ; Get the location of the current block in wOverworldMapBlocks. 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, .asm_c841 + jr nc, .fail + ; Back up the wOverworldMapBlocks address to wBuffer3 ld a, l ld [wBuffer3], a ld a, h ld [wBuffer4], a + ; Back up the replacement tile to wBuffer5 ld a, b ld [wBuffer5], a + ; Back up the animation index to wBuffer6 ld a, c ld [wBuffer6], a xor a ret -.asm_c841 +.fail scf ret Script_CutFromMenu: reloadmappart special UpdateTimePals + Script_Cut: - callasm FieldMoveGetPartyNick - writetext Text_UsedCut + callasm GetPartyNick + writetext UseCutText reloadmappart callasm CutDownTreeOrGrass closetext end CutDownTreeOrGrass: - ld hl, wBuffer3 + ld hl, wBuffer3 ; OverworldMapTile ld a, [hli] ld h, [hl] ld l, a - ld a, [wBuffer5] + ld a, [wBuffer5] ; ReplacementTile ld [hl], a xor a ldh [hBGMapMode], a call OverworldTextModeSwitch call UpdateSprites call DelayFrame - ld a, [wBuffer6] + ld a, [wBuffer6] ; Animation type ld e, a farcall OWCutAnimation call BufferScreen call GetMovementPermissions ret -CheckOverworldTileArrays: ; c87c (3:487c) +CheckOverworldTileArrays: + ; 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, [wd082] - ld de, $3 + ld a, [wMapTileset] + ld de, 3 call IsInArray pop bc - jr nc, .asm_c89c + jr nc, .nope + ; Load the pointer inc hl ld a, [hli] ld h, [hl] ld l, a - ld de, $3 + ; Look up the tile you're facing + ld de, 3 ld a, c call IsInArray - jr nc, .asm_c89c + 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 -.asm_c89c +.nope xor a ret -CutTreeBlockPointers: - dbw TILESET_JOHTO, .johto1 - dbw TILESET_JOHTO_MODERN, .johto2 - dbw TILESET_KANTO, .kanto - dbw TILESET_PARK, .park - dbw TILESET_FOREST, .ilex - db -1 - -.johto1 - db $03, $02, $01 ; grass - db $5b, $3c, $00 ; tree - db $5f, $3d, $00 ; tree - db $63, $3f, $00 ; tree - db $67, $3e, $00 ; tree - db -1 - -.johto2 - db $03, $02, $01 ; grass - db -1 - -.kanto - db $0b, $0a, $01 ; grass - db $32, $6d, $00 ; tree - db $33, $6c, $00 ; tree - db $34, $6f, $00 ; tree - db $35, $4c, $00 ; tree - db $60, $6e, $00 ; tree - db -1 - -.park - db $13, $03, $01 ; grass - db $03, $04, $01 ; grass - db -1 - -.ilex - db $0f, $17, $00 - db -1 - -WhirlpoolBlockPointers: - dbw TILESET_JOHTO, .johto - db -1 - -.johto - db $07, $36, $00 - db -1 +INCLUDE "data/events/field_move_blocks.asm" FlashFunction: - call CheckUseFlash + call .CheckUseFlash and $7f ld [wFieldMoveSucceeded], a ret -CheckUseFlash: ; c8f1 (3:48f1) +.CheckUseFlash: +; Flash ld de, ENGINE_ZEPHYRBADGE - farcall FieldMoveBadgeCheck ; same bank - jr c, .asm_c90f - ld a, [wd56e] - cp $ff - jr nz, .asm_c909 + farcall CheckBadge + jr c, .nozephyrbadge + ld a, [wTimeOfDayPalset] + cp %11111111 ; 3, 3, 3, 3 + jr nz, .notadarkcave +.useflash call UseFlash ld a, $81 ret -.asm_c909 +.notadarkcave call FieldMoveFailed ld a, $80 ret -.asm_c90f +.nozephyrbadge ld a, $80 ret -UseFlash: ; c912 (3:4912) +UseFlash: ld hl, Script_UseFlash jp QueueScript Script_UseFlash: reloadmappart special UpdateTimePals - writetext Text_UsedFlash + writetext UseFlashTextScript callasm BlindingFlash closetext end -Text_UsedFlash: - text_far Text_UsedFlash_ +UseFlashTextScript: + text_far _BlindingFlashText text_asm call WaitSFX ld de, SFX_FLASH call PlaySFX call WaitSFX - ld hl, .end + ld hl, .BlankText ret -.end db "@" + +.BlankText: + text_end SurfFunction: - call FieldMoveBufferReset -.asm_c93e + call FieldMoveJumptableReset +.loop ld hl, .Jumptable - call DoFieldMoveAction - jr nc, .asm_c93e + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret .Jumptable: - dw CheckAbleToSurf - dw StartSurfing - dw CantSurf - dw AlreadySurfing + dw .TrySurf + dw .DoSurf + dw .FailSurf + dw .AlreadySurfing -CheckAbleToSurf: +.TrySurf: ld de, ENGINE_FOGBADGE - call FieldMoveBadgeCheck + call CheckBadge jr c, .asm_c980 - CheckFlagHL ENGINE_ALWAYS_ON_BIKE - jr nz, .asm_c986 + ld hl, wBikeFlags + bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl] + jr nz, .cannotsurf ld a, [wPlayerState] cp PLAYER_SURF - jr z, .asm_c983 + jr z, .alreadyfail cp PLAYER_SURF_PIKA - jr z, .asm_c983 + jr z, .alreadyfail call GetFacingTileCoord call GetTileCollision - cp $1 - jr nz, .asm_c986 - call GetSurfDirection - jr c, .asm_c986 + cp WATER_TILE + jr nz, .cannotsurf + call CheckDirection + jr c, .cannotsurf ld a, $1 ret - .asm_c980 ld a, $80 ret - -.asm_c983 +.alreadyfail ld a, $3 ret - -.asm_c986 +.cannotsurf ld a, $2 ret -StartSurfing: +.DoSurf: call GetSurfType ld [wBuffer2], a - call FieldMoveGetPartyNick + call GetPartyNick ld hl, SurfFromMenuScript call QueueScript ld a, $81 ret -CantSurf: +.FailSurf: ld hl, CantSurfText call MenuTextboxBackup ld a, $80 ret -AlreadySurfing: +.AlreadySurfing: ld hl, AlreadySurfingText call MenuTextboxBackup ld a, $80 @@ -409,36 +392,44 @@ AlreadySurfing: SurfFromMenuScript: special UpdateTimePals + UsedSurfScript: - writetext UsedSurfText + writetext UsedSurfText ; "used SURF!" waitbutton closetext - copybytetovar wBuffer2 - writevarcode VAR_MOVEMENT - special ReplacePlayerSprite + + readmem wBuffer2 + writevar VAR_MOVEMENT + + special ReplaceChrisSprite special PlayMapMusic +; step into the water (slow_step DIR, step_end) special SurfStartStep - applymovement 0, wMovementBuffer + applymovement PLAYER, wMovementBuffer end UsedSurfText: - text_far UsedSurfText_ - db "@" + text_far _UsedSurfText + text_end CantSurfText: - text_far CantSurfText_ - db "@" + text_far _CantSurfText + text_end AlreadySurfingText: - text_far AlreadySurfingText_ - db "@" + text_far _AlreadySurfingText + text_end + +GetSurfType: +; Surfing on Pikachu uses an alternate sprite. +; This is done by using a separate movement type. -GetSurfType: ; c9d7 (3:49d7) ld a, [wCurPartyMon] ld e, a - ld d, $0 + ld d, 0 ld hl, wPartySpecies add hl, de + ld a, [hl] cp PIKACHU ld a, PLAYER_SURF_PIKA @@ -446,22 +437,28 @@ GetSurfType: ; c9d7 (3:49d7) ld a, PLAYER_SURF ret -GetSurfDirection: ; c9ea (3:49ea) +CheckDirection: +; Return carry if a tile permission prevents you +; from moving in the direction you're facing. + +; Get player direction ld a, [wPlayerDirection] - and $c + and %00001100 ; bits 2 and 3 contain direction rrca rrca ld e, a - ld d, $0 + ld d, 0 ld hl, .Directions add hl, de + +; Can you walk in this direction? ld a, [wTilePermissions] and [hl] - jr nz, .asm_ca00 + jr nz, .quit xor a ret -.asm_ca00 +.quit scf ret @@ -472,31 +469,46 @@ GetSurfDirection: ; c9ea (3:49ea) db FACE_RIGHT TrySurfOW:: +; Checking a tile in the overworld. +; Return carry if fail is allowed. + +; Don't ask to surf if already fail. ld a, [wPlayerState] cp PLAYER_SURF_PIKA jr z, .quit cp PLAYER_SURF jr z, .quit - ld a, [wcf29] + +; Must be facing water. + ld a, [wFacingTileID] call GetTileCollision - cp $1 + cp WATER_TILE jr nz, .quit - call GetSurfDirection + +; Check tile permissions. + call CheckDirection jr c, .quit + ld de, ENGINE_FOGBADGE - call FieldMoveEngineFlagCheck + call CheckEngineFlag jr c, .quit + ld d, SURF - call FieldMovePartyCheck + call CheckPartyMove jr c, .quit - CheckFlagHL ENGINE_ALWAYS_ON_BIKE + + ld hl, wBikeFlags + bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl] jr nz, .quit + call GetSurfType ld [wBuffer2], a - call FieldMoveGetPartyNick + call GetPartyNick + ld a, BANK(AskSurfScript) ld hl, AskSurfScript call CallScript + scf ret @@ -513,150 +525,152 @@ AskSurfScript: end AskSurfText: - text_far AskSurfText_ - db "@" + text_far _AskSurfText + text_end FlyFunction: - call FieldMoveBufferReset -.asm_ca5d + call FieldMoveJumptableReset +.loop ld hl, .Jumptable - call DoFieldMoveAction - jr nc, .asm_ca5d + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret -.Jumptable - dw TryToFly - dw RunFlyScript - dw FailToFly +.Jumptable: + dw .TryFly + dw .DoFly + dw .FailFly -TryToFly: +.TryFly: +; Fly ld de, ENGINE_STORMBADGE - call FieldMoveBadgeCheck - jr c, .asm_caa4 - call GetMapPermission + call CheckBadge + jr c, .nostormbadge + call GetMapEnvironment call CheckOutdoorMap - jr z, .asm_ca83 - jr .asm_caa7 + jr z, .outdoors + jr .indoors -.asm_ca83 +.outdoors xor a ldh [hMapAnims], a call LoadStandardMenuHeader call ClearSprites - ld a, $24 - ld hl, $5a61 - rst FarCall + farcall _FlyMap ld a, e - cp $ff - jr z, .asm_caaa - cp $1c - jr nc, .asm_caaa - ld [wceec], a + cp -1 + jr z, .illegal + cp NUM_SPAWNS + jr nc, .illegal + + ld [wDefaultSpawnpoint], a call CloseWindow ld a, $1 ret -.asm_caa4 +.nostormbadge ld a, $82 ret -.asm_caa7 +.indoors ld a, $2 ret -.asm_caaa +.illegal call CloseWindow call WaitBGMap ld a, $80 ret -RunFlyScript: - ld hl, FlyScript +.DoFly: + ld hl, .FlyScript call QueueScript ld a, $81 ret -FailToFly: +.FailFly: call FieldMoveFailed ld a, $82 ret -FlyScript: +.FlyScript: reloadmappart callasm HideSprites special UpdateTimePals - callasm FlyFromAnimation + callasm FlyFromAnim farscall Script_AbortBugContest special WarpToSpawnPoint - callasm DelayLoadingNewSprites ; 1560c - writecode VAR_MOVEMENT, PLAYER_NORMAL + callasm SkipUpdateMapSprites + loadvar VAR_MOVEMENT, PLAYER_NORMAL newloadmap MAPSETUP_TELEPORT - callasm FlyToAnimation + callasm FlyToAnim special WaitSFX - special ReplacePlayerSprite - callasm Function1415c + special ReplaceChrisSprite + callasm _ClearSprites end -WaterfallFunction: ; caed - call TryWaterfall +WaterfallFunction: + call .TryWaterfall and $7f ld [wFieldMoveSucceeded], a ret -TryWaterfall: ; caf6 (3:4af6) +.TryWaterfall: +; Waterfall ld de, ENGINE_RISINGBADGE - farcall FieldMoveBadgeCheck ; same bank + farcall CheckBadge ld a, $80 ret c call CheckMapCanWaterfall - jr c, .asm_cb10 + jr c, .failed ld hl, Script_WaterfallFromMenu call QueueScript ld a, $81 ret -.asm_cb10 +.failed call FieldMoveFailed ld a, $80 ret -CheckMapCanWaterfall: ; cb16 (3:4b16) +CheckMapCanWaterfall: ld a, [wPlayerDirection] and $c cp FACE_UP - jr nz, .asm_cb29 + jr nz, .failed ld a, [wTileUp] call CheckWaterfallTile - jr nz, .asm_cb29 + jr nz, .failed xor a ret -.asm_cb29 +.failed scf ret -Script_WaterfallFromMenu: ;cb2b +Script_WaterfallFromMenu: reloadmappart special UpdateTimePals + Script_UsedWaterfall: - callasm FieldMoveGetPartyNick - writetext Text_UsedWaterfall + callasm GetPartyNick + writetext .UseWaterfallText waitbutton closetext playsound SFX_BUBBLEBEAM .loop - applymovement 0, WaterfallStep - callasm CheckContinueWaterfall + applymovement PLAYER, .WaterfallStep + callasm .CheckContinueWaterfall iffalse .loop end -WaterfallStep: +.WaterfallStep: turn_waterfall UP step_end -CheckContinueWaterfall: ;cb49 +.CheckContinueWaterfall: xor a ld [wScriptVar], a ld a, [wPlayerStandingTile] @@ -666,440 +680,450 @@ CheckContinueWaterfall: ;cb49 ld [wScriptVar], a ret -Text_UsedWaterfall: - text_far Text_UsedWaterfall_ - db "@" +.UseWaterfallText: + text_far _UseWaterfallText + text_end -TryWaterfallOW: +TryWaterfallOW:: ld d, WATERFALL - call FieldMovePartyCheck - jr c, .asm_cb7d + call CheckPartyMove + jr c, .failed ld de, ENGINE_RISINGBADGE - call FieldMoveEngineFlagCheck - jr c, .asm_cb7d + call CheckEngineFlag + jr c, .failed call CheckMapCanWaterfall - jr c, .asm_cb7d + jr c, .failed ld a, BANK(Script_AskWaterfall) ld hl, Script_AskWaterfall call CallScript scf ret -.asm_cb7d +.failed ld a, BANK(Script_CantDoWaterfall) ld hl, Script_CantDoWaterfall call CallScript scf ret -Script_CantDoWaterfall:;cb87 - jumptext Text_CantDoWaterfall +Script_CantDoWaterfall: + jumptext .HugeWaterfallText -Text_CantDoWaterfall: - text_far Text_CantDoWaterfall_ - db "@" +.HugeWaterfallText: + text_far _HugeWaterfallText + text_end Script_AskWaterfall: opentext - writetext Text_AskUseWaterfall + writetext .AskWaterfallText yesorno iftrue Script_UsedWaterfall closetext end -Text_AskUseWaterfall: - text_far Text_AskUseWaterfall_ - db "@" +.AskWaterfallText: + text_far _AskWaterfallText + text_end EscapeRopeFunction: - call FieldMoveBufferReset + call FieldMoveJumptableReset ld a, $1 - jr asm_cbaa + jr EscapeRopeOrDig DigFunction: - call FieldMoveBufferReset + call FieldMoveJumptableReset ld a, $2 -asm_cbaa + +EscapeRopeOrDig: ld [wBuffer2], a -.asm_cbad - ld hl, .Jumptable - call DoFieldMoveAction - jr nc, .asm_cbad +.loop + ld hl, .DigTable + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret -.Jumptable: - dw TryEscapeFromDungeon - dw EscapeFromDungeon - dw FailToEscapeFromDungeon +.DigTable: + dw .CheckCanDig + dw .DoDig + dw .FailDig -TryEscapeFromDungeon: - call GetMapPermission +.CheckCanDig: + call GetMapEnvironment cp CAVE - jr z, .asm_cbcf + jr z, .incave cp DUNGEON - jr z, .asm_cbcf -.asm_cbcc + jr z, .incave +.fail ld a, $2 ret -.asm_cbcf +.incave ld hl, wDigWarpNumber ld a, [hli] and a - jr z, .asm_cbcc + jr z, .fail ld a, [hli] and a - jr z, .asm_cbcc + jr z, .fail ld a, [hl] and a - jr z, .asm_cbcc + jr z, .fail ld a, $1 ret -EscapeFromDungeon: +.DoDig: ld hl, wDigWarpNumber - ld de, wNextWarpNumber - ld bc, $3 + ld de, wNextWarp + ld bc, 3 call CopyBytes - call FieldMoveGetPartyNick + call GetPartyNick ld a, [wBuffer2] cp $2 - jr nz, .asm_cc00 - ld hl, UsedDigScript + jr nz, .escaperope + ld hl, .UsedDigScript call QueueScript ld a, $81 ret -.asm_cc00 - ld hl, UsedEscapeRopeScript +.escaperope + ld hl, .UsedEscapeRopeScript call QueueScript ld a, $81 ret -FailToEscapeFromDungeon: +.FailDig: ld a, [wBuffer2] cp $2 - jr nz, .asm_cc1c - ld hl, Text_CantUseDigEscapeRopeHere ; $4c29 + jr nz, .failescaperope + ld hl, .CantUseDigText call MenuTextbox call WaitPressAorB_BlinkCursor call CloseWindow -.asm_cc1c + +.failescaperope ld a, $80 ret -Text_UsedDig: ; cc1f - text_far Text_UsedDig_ - db "@" +.UseDigText: + text_far _UseDigText + text_end -Text_UsedEscapeRope: - text_far Text_UsedEscapeRope_ - db "@" +.UseEscapeRopeText: + text_far _UseEscapeRopeText + text_end -Text_CantUseDigEscapeRopeHere: - text_far Text_CantUseDigEscapeRopeHere_ - db "@" +.CantUseDigText: + text_far _CantUseDigText + text_end -UsedEscapeRopeScript: ; cc2e reloadmappart +.UsedEscapeRopeScript: reloadmappart special UpdateTimePals - writetext Text_UsedEscapeRope ; cc24 - jump ContinueDigEscapeRopeScript + writetext .UseEscapeRopeText + sjump .UsedDigOrEscapeRopeScript -UsedDigScript: +.UsedDigScript: reloadmappart special UpdateTimePals - writetext Text_UsedDig -ContinueDigEscapeRopeScript: + writetext .UseDigText + +.UsedDigOrEscapeRopeScript: waitbutton closetext playsound SFX_WARP_TO - applymovement PLAYER, DigOutMovementData + applymovement PLAYER, .DigOut farscall Script_AbortBugContest special WarpToSpawnPoint - writecode VAR_MOVEMENT, PLAYER_NORMAL + loadvar VAR_MOVEMENT, PLAYER_NORMAL newloadmap MAPSETUP_DOOR playsound SFX_WARP_FROM - applymovement PLAYER, DigReturnMovementData + applymovement PLAYER, .DigReturn end -DigOutMovementData: +.DigOut: step_dig 32 - hide_person + hide_object step_end -DigReturnMovementData: - show_person +.DigReturn: + show_object return_dig 32 step_end - call FieldMoveBufferReset -.asm_cc67 +TeleportFunction: + call FieldMoveJumptableReset +.loop ld hl, .Jumptable - call DoFieldMoveAction - jr nc, .asm_cc67 + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret .Jumptable: - dw TryTeleport - dw DoTeleport - dw FailTeleport + dw .TryTeleport + dw .DoTeleport + dw .FailTeleport -TryTeleport: - call GetMapPermission +.TryTeleport: + call GetMapEnvironment call CheckOutdoorMap - jr z, .asm_cc85 - jr .asm_cc9c + jr z, .CheckIfSpawnPoint + jr .nope -.asm_cc85 - ld a, [wd9fb] +.CheckIfSpawnPoint: + ld a, [wLastSpawnMapGroup] ld d, a - ld a, [wd9fc] + ld a, [wLastSpawnMapNumber] ld e, a - ld a, $5 - ld hl, $5465 - rst FarCall - jr nc, .asm_cc9c + farcall IsSpawnPoint + jr nc, .nope ld a, c - ld [wceec], a + ld [wDefaultSpawnpoint], a ld a, $1 ret -.asm_cc9c +.nope ld a, $2 ret -DoTeleport: - call FieldMoveGetPartyNick - ld hl, TeleportScript +.DoTeleport: + call GetPartyNick + ld hl, .TeleportScript call QueueScript ld a, $81 ret -FailTeleport: - ld hl, Text_CantUseTeleportHere +.FailTeleport: + ld hl, .CantUseTeleportText call MenuTextboxBackup ld a, $80 ret -Text_ReturnToLastMonCenter: - text_far Text_ReturnToLastMonCenter_ - db "@" +.TeleportReturnText: + text_far _TeleportReturnText + text_end -Text_CantUseTeleportHere: - text_far Text_CantUseTeleportHere_ - db "@" +.CantUseTeleportText: + text_far _CantUseTeleportText + text_end -TeleportScript: ; ccbe +.TeleportScript: reloadmappart special UpdateTimePals - writetext Text_ReturnToLastMonCenter + writetext .TeleportReturnText pause 60 reloadmappart closetext playsound SFX_WARP_TO - applymovement PLAYER, TeleportFromMovementData + applymovement PLAYER, .TeleportFrom farscall Script_AbortBugContest special WarpToSpawnPoint - writecode VAR_MOVEMENT, PLAYER_NORMAL + loadvar VAR_MOVEMENT, PLAYER_NORMAL newloadmap MAPSETUP_TELEPORT playsound SFX_WARP_FROM - applymovement PLAYER, TeleportToMovementData + applymovement PLAYER, .TeleportTo end -TeleportFromMovementData: ; cce4 +.TeleportFrom: teleport_from step_end -TeleportToMovementData: +.TeleportTo: teleport_to step_end StrengthFunction: - call Functionccf1 + call .TryStrength and $7f ld [wFieldMoveSucceeded], a ret -Functionccf1: ; ccf1 (3:4cf1) +.TryStrength: +; Strength ld de, ENGINE_PLAINBADGE - call FieldMoveBadgeCheck - jr c, asm_cd09 - jr asm_cd0c + call CheckBadge + jr c, .Failed + jr .UseStrength - ld hl, Text_AlreadyUsingStrength +.Unreferenced_AlreadyUsing: + ld hl, .AlreadyUsingStrengthText call MenuTextboxBackup ld a, $80 ret -Text_AlreadyUsingStrength: - text_far Text_AlreadyUsingStrength_ - db "@" +.AlreadyUsingStrengthText: + text_far _AlreadyUsingStrengthText + text_end -asm_cd09 +.Failed: ld a, $80 ret -asm_cd0c +.UseStrength: ld hl, Script_StrengthFromMenu call QueueScript ld a, $81 ret -GetStrengthUserSpeciesAndSetFlag: - SetFlag ENGINE_STRENGTH_ACTIVE +SetStrengthFlag: + ld hl, wBikeFlags + set BIKEFLAGS_STRENGTH_ACTIVE_F, [hl] ld a, [wCurPartyMon] ld e, a - ld d, $0 + ld d, 0 ld hl, wPartySpecies add hl, de ld a, [hl] ld [wBuffer6], a - call FieldMoveGetPartyNick + call GetPartyNick ret -Script_StrengthFromMenu: ; cd2c +Script_StrengthFromMenu: reloadmappart special UpdateTimePals + Script_UsedStrength: - callasm GetStrengthUserSpeciesAndSetFlag - writetext Text_UsedStrength - copybytetovar wBuffer6 + callasm SetStrengthFlag + writetext .UseStrengthText + readmem wBuffer6 cry 0 pause 3 - writetext Text_AllowedToMoveBoulders + writetext .MoveBoulderText closetext end -Text_UsedStrength: ; cd44 - text_far Text_UsedStrength_ - db "@" +.UseStrengthText: + text_far _UseStrengthText + text_end -Text_AllowedToMoveBoulders: - text_far Text_AllowedToMoveBoulders_ - db "@" +.MoveBoulderText: + text_far _MoveBoulderText + text_end -AskStrengthScript: ; cd4e +AskStrengthScript: callasm TryStrengthOW - iffalse .ask - ifequal 1, .not_able - jump .already_active + iffalse .AskStrength + ifequal $1, .DontMeetRequirements + sjump .AlreadyUsedStrength -.not_able - jumptext Text_MonMayBeAbleToMove +.DontMeetRequirements: + jumptext BouldersMayMoveText -.already_active - jumptext Text_BouldersMayNowBeMoved +.AlreadyUsedStrength: + jumptext BouldersMoveText -.ask +.AskStrength: opentext - writetext Text_AskStrength + writetext AskStrengthText yesorno iftrue Script_UsedStrength closetext end -Text_AskStrength: - text_far Text_AskStrength_ - db "@" +AskStrengthText: + text_far _AskStrengthText + text_end -Text_BouldersMayNowBeMoved: - text_far Text_BouldersMayNowBeMoved_ - db "@" +BouldersMoveText: + text_far _BouldersMoveText + text_end -Text_MonMayBeAbleToMove: - text_far Text_MonMayBeAbleToMove_ - db "@" +BouldersMayMoveText: + text_far _BouldersMayMoveText + text_end TryStrengthOW: ld d, STRENGTH - call FieldMovePartyCheck - jr c, .asm_cd95 + call CheckPartyMove + jr c, .nope + ld de, ENGINE_PLAINBADGE - call FieldMoveEngineFlagCheck - jr c, .asm_cd95 - CheckFlagHL ENGINE_STRENGTH_ACTIVE - jr z, .asm_cd99 - ld a, $2 - jr .asm_cd9c + call CheckEngineFlag + jr c, .nope -.asm_cd95 - ld a, $1 - jr .asm_cd9c + ld hl, wBikeFlags + bit BIKEFLAGS_STRENGTH_ACTIVE_F, [hl] + jr z, .already_using + + ld a, 2 + jr .done + +.nope + ld a, 1 + jr .done -.asm_cd99 +.already_using xor a - jr .asm_cd9c + jr .done -.asm_cd9c +.done ld [wScriptVar], a ret WhirlpoolFunction: - call FieldMoveBufferReset -.asm_cda3 - ld hl, .Jumptable - call DoFieldMoveAction - jr nc, .asm_cda3 + call FieldMoveJumptableReset +.loop + ld hl, Jumptable_cdae + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret -.Jumptable - dw TryWhirlpool - dw DoWhirlpool - dw FailWhirlpool +Jumptable_cdae: + dw .TryWhirlpool + dw .DoWhirlpool + dw .FailWhirlpool -TryWhirlpool: +.TryWhirlpool: ld de, ENGINE_GLACIERBADGE - call FieldMoveBadgeCheck - jr c, .asm_cdca + call CheckBadge + jr c, .noglacierbadge call TryWhirlpoolMenu - jr c, .asm_cdc7 + jr c, .failed ld a, $1 ret -.asm_cdc7 +.failed ld a, $2 ret -.asm_cdca +.noglacierbadge ld a, $80 ret -DoWhirlpool: +.DoWhirlpool: ld hl, Script_WhirlpoolFromMenu call QueueScript ld a, $81 ret -FailWhirlpool: +.FailWhirlpool: call FieldMoveFailed ld a, $80 ret -Text_UsedWhirlpool: - text_far Text_UsedWhirlpool_ - db "@" +UseWhirlpoolText: + text_far _UseWhirlpoolText + text_end -TryWhirlpoolMenu: ; cde1 (3:4de1) +TryWhirlpoolMenu: call GetFacingTileCoord ld c, a push de call CheckWhirlpoolTile pop de - jr c, .asm_ce0c + jr c, .failed call GetBlockLocation ld c, [hl] push hl ld hl, WhirlpoolBlockPointers call CheckOverworldTileArrays pop hl - jr nc, .asm_ce0c + jr nc, .failed ld a, l ld [wBuffer3], a ld a, h @@ -1111,22 +1135,23 @@ TryWhirlpoolMenu: ; cde1 (3:4de1) xor a ret -.asm_ce0c +.failed scf ret -Script_WhirlpoolFromMenu: ; 4e0e +Script_WhirlpoolFromMenu: reloadmappart special UpdateTimePals + Script_UsedWhirlpool: - callasm FieldMoveGetPartyNick - writetext Text_UsedWhirlpool + callasm GetPartyNick + writetext UseWhirlpoolText reloadmappart callasm DisappearWhirlpool closetext end -DisappearWhirlpool: ; 4e20 +DisappearWhirlpool: ld hl, wBuffer3 ld a, [hli] ld h, [hl] @@ -1143,46 +1168,46 @@ DisappearWhirlpool: ; 4e20 call GetMovementPermissions ret -TryWhirlpoolOW: +TryWhirlpoolOW:: ld d, WHIRLPOOL - call FieldMovePartyCheck - jr c, .asm_ce5f + call CheckPartyMove + jr c, .failed ld de, ENGINE_GLACIERBADGE - call FieldMoveEngineFlagCheck - jr c, .asm_ce5f + call CheckEngineFlag + jr c, .failed call TryWhirlpoolMenu - jr c, .asm_ce5f + jr c, .failed ld a, BANK(Script_AskWhirlpoolOW) - ld hl, Script_AskWhirlpoolOW ; $4e71 + ld hl, Script_AskWhirlpoolOW call CallScript scf ret -.asm_ce5f +.failed ld a, BANK(Script_MightyWhirlpool) - ld hl, Script_MightyWhirlpool ; $4e69 + ld hl, Script_MightyWhirlpool call CallScript scf ret Script_MightyWhirlpool: - jumptext Text_MightyWhirlpool + jumptext .MayPassWhirlpoolText -Text_MightyWhirlpool: - text_far Text_MightyWhirlpool_ - db "@" +.MayPassWhirlpoolText: + text_far _MayPassWhirlpoolText + text_end -Script_AskWhirlpoolOW: ; ce71 +Script_AskWhirlpoolOW: opentext - writetext Text_AskWhirlpool + writetext AskWhirlpoolText yesorno iftrue Script_UsedWhirlpool closetext end -Text_AskWhirlpool: ; ce7b - text_far Text_AskWhirlpool_ - db "@" +AskWhirlpoolText: + text_far _AskWhirlpoolText + text_end HeadbuttFunction: call TryHeadbuttFromMenu @@ -1190,252 +1215,259 @@ HeadbuttFunction: ld [wFieldMoveSucceeded], a ret -TryHeadbuttFromMenu: ; ce89 (3:4e89) +TryHeadbuttFromMenu: call GetFacingTileCoord call CheckHeadbuttTreeTile - jr nz, .asm_ce9a - ld hl, HeadbuttFromMenuScript ; $4eaa + jr nz, .no_tree + + ld hl, HeadbuttFromMenuScript call QueueScript ld a, $81 ret -.asm_ce9a +.no_tree call FieldMoveFailed ld a, $80 ret -; ceaa -Text_DidAHeadbutt: - text_far Text_DidAHeadbutt_ - db "@" +UseHeadbuttText: + text_far _UseHeadbuttText + text_end -Text_NothingFromHeadbutt: - text_far Text_NothingFromHeadbutt_ - db "@" +HeadbuttNothingText: + text_far _HeadbuttNothingText + text_end HeadbuttFromMenuScript: reloadmappart special UpdateTimePals + HeadbuttScript: - callasm FieldMoveGetPartyNick - writetext Text_DidAHeadbutt + callasm GetPartyNick + writetext UseHeadbuttText + reloadmappart callasm ShakeHeadbuttTree + callasm TreeMonEncounter - iffalse .nope_nothing + iffalse .no_battle closetext randomwildmon startbattle reloadmapafterbattle end -.nope_nothing: - writetext Text_NothingFromHeadbutt +.no_battle + writetext HeadbuttNothingText waitbutton closetext end -TryHeadbuttOW: ; cecc +TryHeadbuttOW:: ld d, HEADBUTT - call FieldMovePartyCheck - jr c, .asm_cedd + call CheckPartyMove + jr c, .no + ld a, BANK(AskHeadbuttScript) - ld hl, AskHeadbuttScript ; $4edf + ld hl, AskHeadbuttScript call CallScript scf ret -.asm_cedd +.no xor a ret AskHeadbuttScript: opentext - writetext Text_AskHeadbutt + writetext AskHeadbuttText yesorno iftrue HeadbuttScript closetext end -Text_AskHeadbutt: ; cee9 - text_far Text_AskHeadbutt_ - db "@" +AskHeadbuttText: + text_far _AskHeadbuttText + text_end +RockSmashFunction: call TryRockSmashFromMenu and $7f ld [wFieldMoveSucceeded], a ret -TryRockSmashFromMenu: ; cef7 (3:4ef7) +TryRockSmashFromMenu: call GetFacingObject - jr c, .asm_cf0a + jr c, .no_rock ld a, d cp $18 - jr nz, .asm_cf0a - ld hl, RockSmashFromMenuScript ; $4f31 + jr nz, .no_rock + + ld hl, RockSmashFromMenuScript call QueueScript ld a, $81 ret -.asm_cf0a +.no_rock call FieldMoveFailed ld a, $80 ret -GetFacingObject: ; cf10 (3:4f10) +GetFacingObject: farcall CheckFacingObject - jr nc, .asm_cf2f + jr nc, .fail + ldh a, [hObjectStructIndexBuffer] call GetObjectStruct - ld hl, $1 + ld hl, OBJECT_MAP_OBJECT_INDEX add hl, bc ld a, [hl] ldh [hLastTalked], a call GetMapObject - ld hl, $4 + ld hl, MAPOBJECT_MOVEMENT add hl, bc ld a, [hl] ld d, a and a ret -.asm_cf2f +.fail scf ret -RockSmashFromMenuScript: ; cf31 +RockSmashFromMenuScript: reloadmappart special UpdateTimePals + RockSmashScript: - callasm FieldMoveGetPartyNick - writetext Text_UsedRockSmash + callasm GetPartyNick + writetext UseRockSmashText closetext special WaitSFX playsound SFX_STRENGTH earthquake 84 - applymovement2 RockSmashMovementData + applymovementlasttalked MovementData_RockSmash disappear -2 + callasm RockMonEncounter - copybytetovar wd117 - iffalse .skip_battle + readmem wTempWildMonSpecies + iffalse .done randomwildmon startbattle reloadmapafterbattle -.skip_battle +.done end -RockSmashMovementData: +MovementData_RockSmash: rock_smash 10 step_end -Text_UsedRockSmash: - text_far Text_UsedRockSmash_ - db "@" -; cf60 +UseRockSmashText: + text_far _UseRockSmashText + text_end + AskRockSmashScript: - callasm TryRockSmashOW - ifequal 1, .fail + callasm HasRockSmash + ifequal 1, .no + opentext - writetext Text_AskRockSmash + writetext AskRockSmashText yesorno iftrue RockSmashScript closetext end -.fail - jumptext Text_MayBeBreakable +.no + jumptext MaySmashText -Text_MayBeBreakable: - text_far Text_MayBeBreakable_ - db "@" +MaySmashText: + text_far _MaySmashText + text_end -Text_AskRockSmash: - text_far Text_AskRockSmash_ - db "@" +AskRockSmashText: + text_far _AskRockSmashText + text_end -TryRockSmashOW: ; cf7f +HasRockSmash: ld d, ROCK_SMASH - call FieldMovePartyCheck - jr nc, .asm_cf8a - ld a, $1 - jr .asm_cf8d - -.asm_cf8a + call CheckPartyMove + jr nc, .yes +.no + ld a, 1 + jr .done +.yes xor a - jr .asm_cf8d - -.asm_cf8d + jr .done +.done ld [wScriptVar], a ret -FishingRodFunction: ; cf91 +FishFunction: ld a, e push af - call FieldMoveBufferReset + call FieldMoveJumptableReset pop af ld [wBuffer2], a -.asm_cf9a - ld hl, .Jumptable ; $4fa8 - call DoFieldMoveAction - jr nc, .asm_cf9a +.loop + ld hl, .FishTable + call FieldMoveJumptable + jr nc, .loop and $7f ld [wFieldMoveSucceeded], a ret -.Jumptable - dw Fish_CheckMap ; 3:4fb2 - dw Fish_NoBite ; 3:5005 - dw Fish_GotSomething ; 3:4ff7 - dw Fish_Failed ; 3:4ff4 - dw Fish_NoFish ; 3:5013 +.FishTable: + dw .TryFish + dw .FishNoBite + dw .FishGotSomething + dw .FailFish + dw .FishNoFish -Fish_CheckMap: +.TryFish: ld a, [wPlayerState] cp PLAYER_SURF - jr z, .asm_cfc7 + jr z, .fail cp PLAYER_SURF_PIKA - jr z, .asm_cfc7 + jr z, .fail call GetFacingTileCoord call GetTileCollision - cp $1 - jr z, .asm_cfca -.asm_cfc7 + cp WATER_TILE + jr z, .facingwater +.fail ld a, $3 ret -.asm_cfca +.facingwater call GetFishingGroup and a - jr nz, .asm_cfd3 + jr nz, .goodtofish ld a, $4 ret -.asm_cfd3 +.goodtofish ld d, a ld a, [wBuffer2] ld e, a - ld a, $24 - ld hl, $697a - rst FarCall + farcall Fish ld a, d and a - jr z, .asm_cff1 - ld [wd117], a + jr z, .nonibble + ld [wTempWildMonSpecies], a ld a, e ld [wCurPartyLevel], a - ld a, $4 + ld a, BATTLETYPE_FISH ld [wBattleType], a ld a, $2 ret -.asm_cff1 +.nonibble ld a, $1 ret -Fish_Failed: +.FailFish: ld a, $80 ret -Fish_GotSomething: +.FishGotSomething: ld a, $1 ld [wBuffer6], a ld hl, Script_GotABite @@ -1443,7 +1475,7 @@ Fish_GotSomething: ld a, $81 ret -Fish_NoBite: +.FishNoBite: ld a, $2 ld [wBuffer6], a ld hl, Script_NotEvenANibble @@ -1451,7 +1483,7 @@ Fish_NoBite: ld a, $81 ret -Fish_NoFish: +.FishNoFish: ld a, $0 ld [wBuffer6], a ld hl, Script_NotEvenANibble2 @@ -1459,32 +1491,34 @@ Fish_NoFish: ld a, $81 ret -Script_NotEvenANibble: ; d021 +Script_NotEvenANibble: scall Script_FishCastRod - writetext Text_NotEvenANibble - jump Script_NotEvenANibble_Continue + writetext RodNothingText + sjump Script_NotEvenANibble_FallThrough Script_NotEvenANibble2: scall Script_FishCastRod - writetext Text_NotEvenANibble -Script_NotEvenANibble_Continue: + writetext RodNothingText + +Script_NotEvenANibble_FallThrough: callasm PutTheRodAway closetext end Script_GotABite: scall Script_FishCastRod - callasm Fish_CheckFacingUp - iffalse .not_facing_up - applymovement 0, Movement_Fishing_BiteFacingUp - jump .continue - -.not_facing_up - applymovement 0, Movement_Fishing_BiteNotFacingUp -.continue + callasm Fishing_CheckFacingUp + iffalse .NotFacingUp + applymovement PLAYER, .Movement_FacingUp + sjump .FightTheHookedPokemon + +.NotFacingUp: + applymovement PLAYER, .Movement_NotFacingUp + +.FightTheHookedPokemon: pause 40 - applymovement 0, Movement_Fishing_RestoreRod - writetext Text_OhABite + applymovement PLAYER, .Movement_RestoreRod + writetext RodBiteText callasm PutTheRodAway closetext randomwildmon @@ -1492,8 +1526,7 @@ Script_GotABite: reloadmapafterbattle end - -Movement_Fishing_BiteNotFacingUp: +.Movement_NotFacingUp: fish_got_bite fish_got_bite fish_got_bite @@ -1501,7 +1534,7 @@ Movement_Fishing_BiteNotFacingUp: show_emote step_end -Movement_Fishing_BiteFacingUp: +.Movement_FacingUp: fish_got_bite fish_got_bite fish_got_bite @@ -1510,40 +1543,41 @@ Movement_Fishing_BiteFacingUp: show_emote step_end -Movement_Fishing_RestoreRod: +.Movement_RestoreRod: hide_emote fish_cast_rod step_end -Fish_CheckFacingUp: ; d06d +Fishing_CheckFacingUp: ld a, [wPlayerDirection] and $c cp OW_UP ld a, $1 - jr z, .asm_d079 + jr z, .up xor a -.asm_d079 + +.up ld [wScriptVar], a ret -Script_FishCastRod: ; d07d +Script_FishCastRod: reloadmappart - loadvar hBGMapMode, 0 + loadmem hBGMapMode, $0 special UpdateTimePals loademote EMOTE_ROD callasm LoadFishingGFX loademote EMOTE_SHOCK - applymovement PLAYER, Movement_CastRod + applymovement PLAYER, MovementData_CastRod pause 40 end -Movement_CastRod: +MovementData_CastRod: fish_cast_rod step_end -PutTheRodAway: ; d096 +PutTheRodAway: hlcoord 1, 14 - lb bc, $3, $12 + lb bc, 3, 18 call ClearBox call WaitBGMap xor a @@ -1551,41 +1585,41 @@ PutTheRodAway: ; d096 ld a, $1 ld [wPlayerAction], a call UpdateSprites - call ReplacePlayerSprite + call ReplaceChrisSprite ret -Text_OhABite: - text_far Text_OhABite_ - db "@" +RodBiteText: + text_far _RodBiteText + text_end -Text_NotEvenANibble: - text_far Text_NotEvenANibble_ - db "@" +RodNothingText: + text_far _RodNothingText + text_end -Text_NothingHereToFish: - text_far Text_NothingHereToFish_ - db "@" +UnusedNothingHereText: ; unused + text_far _UnusedNothingHereText + text_end -BicycleFunction: - call Functiond0c9 +BikeFunction: + call .TryBike and $7f ld [wFieldMoveSucceeded], a ret -Functiond0c9: ; d0c9 (3:50c9) - call CheckBikePermission - jr c, .cant_bike +.TryBike: + call .CheckEnvironment + jr c, .CannotUseBike ld a, [wPlayerState] cp PLAYER_NORMAL - jr z, .get_on_bike + jr z, .GetOnBike cp PLAYER_BIKE - jr z, .get_off_bike - jr .cant_bike + jr z, .GetOffBike + jr .CannotUseBike -.get_on_bike +.GetOnBike: ld hl, Script_GetOnBike ld de, Script_GetOnBike_Register - call ChooseScriptBasedOnWhetherBikeIsRegistered + call .CheckIfRegistered call QueueScript xor a ld [wMusicFade], a @@ -1600,30 +1634,30 @@ Functiond0c9: ; d0c9 (3:50c9) ld a, $1 ret -.get_off_bike +.GetOffBike: ld hl, wBikeFlags - bit 1, [hl] - jr nz, .asm_d118 + bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl] + jr nz, .CantGetOffBike ld hl, Script_GetOffBike ld de, Script_GetOffBike_Register - call ChooseScriptBasedOnWhetherBikeIsRegistered - ld a, $3 - jr .queue_off + call .CheckIfRegistered + ld a, BANK(Script_GetOffBike) + jr .done -.asm_d118 +.CantGetOffBike: ld hl, Script_CantGetOffBike - jr .queue_off + jr .done -.cant_bike +.CannotUseBike: ld a, $0 ret -.queue_off +.done call QueueScript ld a, $1 ret -ChooseScriptBasedOnWhetherBikeIsRegistered: ; d126 (3:5126) +.CheckIfRegistered: ld a, [wUsingItemWithSelect] and a ret z @@ -1631,128 +1665,131 @@ ChooseScriptBasedOnWhetherBikeIsRegistered: ; d126 (3:5126) ld l, e ret -CheckBikePermission: ; d12e (3:512e) - call GetMapPermission +.CheckEnvironment: + call GetMapEnvironment call CheckOutdoorMap - jr z, .asm_d140 + jr z, .ok cp CAVE - jr z, .asm_d140 + jr z, .ok cp GATE - jr z, .asm_d140 - jr .asm_d149 + jr z, .ok + jr .nope -.asm_d140 +.ok call GetPlayerStandingTile - and $f - jr nz, .asm_d149 + and $f ; lo nybble only + jr nz, .nope ; not FLOOR_TILE xor a ret -.asm_d149 +.nope scf ret -Script_GetOnBike: ; d14b +Script_GetOnBike: reloadmappart special UpdateTimePals - writecode VAR_MOVEMENT, PLAYER_BIKE - writetext Text_GotOnTheBike + loadvar VAR_MOVEMENT, PLAYER_BIKE + writetext GotOnBikeText waitbutton closetext - special ReplacePlayerSprite + special ReplaceChrisSprite end Script_GetOnBike_Register: - writecode VAR_MOVEMENT, PLAYER_BIKE + loadvar VAR_MOVEMENT, PLAYER_BIKE closetext - special ReplacePlayerSprite + special ReplaceChrisSprite end +; unused nop ret Script_GetOffBike: reloadmappart special UpdateTimePals - writecode VAR_MOVEMENT, PLAYER_NORMAL - writetext Text_GotOffTheBike + loadvar VAR_MOVEMENT, PLAYER_NORMAL + writetext GotOffBikeText waitbutton + FinishGettingOffBike: closetext - special ReplacePlayerSprite + special ReplaceChrisSprite special PlayMapMusic end Script_GetOffBike_Register: - writecode VAR_MOVEMENT, PLAYER_NORMAL - jump FinishGettingOffBike + loadvar VAR_MOVEMENT, PLAYER_NORMAL + sjump FinishGettingOffBike -Script_CantGetOffBike: ; d17e - writetext Text_CantGetOffBike +Script_CantGetOffBike: + writetext .CantGetOffBikeText waitbutton closetext end -Text_CantGetOffBike: - text_far Text_CantGetOffBike_ - db "@" - -Text_GotOnTheBike: - text_far Text_GotOnTheBike_ - db "@" +.CantGetOffBikeText: + text_far _CantGetOffBikeText + text_end -Text_GotOffTheBike: - text_far Text_GotOffTheBike_ - db "@" +GotOnBikeText: + text_far _GotOnBikeText + text_end +GotOffBikeText: + text_far _GotOffBikeText + text_end -TryCutOW: ; d193 +TryCutOW:: ld d, CUT - call FieldMovePartyCheck - jr c, .asm_d1ac + call CheckPartyMove + jr c, .cant_cut + ld de, ENGINE_HIVEBADGE - call FieldMoveEngineFlagCheck - jr c, .asm_d1ac + call CheckEngineFlag + jr c, .cant_cut + ld a, BANK(AskCutScript) ld hl, AskCutScript call CallScript scf ret -.asm_d1ac +.cant_cut ld a, BANK(CantCutScript) ld hl, CantCutScript call CallScript scf ret -AskCutScript: ; d1b6 +AskCutScript: opentext - writetext Text_AskCut + writetext AskCutText yesorno iffalse .declined - callasm CheckMapForSomethingToCut_ + callasm .CheckMap iftrue Script_Cut -.declined: +.declined closetext end -CheckMapForSomethingToCut_: ; d1c7 +.CheckMap: xor a ld [wScriptVar], a call CheckMapForSomethingToCut ret c - ld a, $1 + ld a, TRUE ld [wScriptVar], a ret -Text_AskCut: - text_far Text_AskCut_ - db "@" +AskCutText: + text_far _AskCutText + text_end -CantCutScript: ; d1da - jumptext Text_MonCanCutThis +CantCutScript: + jumptext CanCutText -Text_MonCanCutThis: - text_far Text_MonCanCutThis_ - db "@" +CanCutText: + text_far _CanCutText + text_end diff --git a/engine/events/pokecenter_pc.asm b/engine/events/pokecenter_pc.asm new file mode 100644 index 00000000..8981bcf4 --- /dev/null +++ b/engine/events/pokecenter_pc.asm @@ -0,0 +1,658 @@ +PokemonCenterPC: + call PC_CheckPartyForPokemon + ret c + call PC_PlayBootSound + ld hl, PokecenterPCTurnOnText + call PC_DisplayText + ld hl, PokecenterPCWhoseText + call PC_DisplayTextWaitMenu + ld hl, .TopMenu + call LoadMenuHeader +.loop + xor a + ldh [hBGMapMode], a + call .ChooseWhichPCListToUse + ld [wWhichIndexSet], a + call DoNthMenu + jr c, .shutdown + ld a, [wMenuSelection] + ld hl, .JumpTable + call MenuJumptable + jr nc, .loop + +.shutdown + call PC_PlayShutdownSound + call ExitMenu + call CloseWindow + ret + +.TopMenu: + db MENU_BACKUP_TILES | MENU_NO_CLICK_SFX ; flags + menu_coords 0, 0, 15, 12 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_WRAP ; flags + db 0 ; items + dw .WhichPC + dw PlaceNthMenuStrings + dw .JumpTable + +PCPC_PLAYERS_PC EQU 0 +PCPC_BILLS_PC EQU 1 +PCPC_OAKS_PC EQU 2 +PCPC_HALL_OF_FAME EQU 3 +PCPC_TURN_OFF EQU 4 + +.JumpTable: +; entries correspond to PCPC_* constants + dw PlayersPC, .String_PlayersPC + dw BillsPC, .String_BillsPC + dw OaksPC, .String_OaksPC + dw HallOfFamePC, .String_HallOfFame + dw TurnOffPC, .String_TurnOff + +.String_PlayersPC: db "<PLAYER>'s PC@" +.String_BillsPC: db "BILL's PC@" +.String_OaksPC: db "PROF.OAK's PC@" +.String_HallOfFame: db "HALL OF FAME@" +.String_TurnOff: db "TURN OFF@" + +.WhichPC: + ; before Pokédex + db 3 + db PCPC_BILLS_PC + db PCPC_PLAYERS_PC + db PCPC_TURN_OFF + db -1 ; end + + ; before Hall Of Fame + db 4 + db PCPC_BILLS_PC + db PCPC_PLAYERS_PC + db PCPC_OAKS_PC + db PCPC_TURN_OFF + db -1 ; end + + ; postgame + db 5 + db PCPC_BILLS_PC + db PCPC_PLAYERS_PC + db PCPC_OAKS_PC + db PCPC_HALL_OF_FAME + db PCPC_TURN_OFF + db -1 ; end + +.ChooseWhichPCListToUse: + call CheckReceivedDex + jr nz, .got_dex + ld a, 0 ; before Pokédex + ret + +.got_dex + ld a, [wHallOfFameCount] + and a + ld a, 1 ; before Hall Of Fame + ret z + ld a, 2 ; postgame + ret + +PC_CheckPartyForPokemon: + ld a, [wPartyCount] + and a + ret nz + ld de, SFX_CHOOSE_PC_OPTION + call PlaySFX + ld hl, .PokecenterPCCantUseText + call PC_DisplayText + scf + ret + +.PokecenterPCCantUseText: + text_far _PokecenterPCCantUseText + text_end + +BillsPC: + call PC_PlayChoosePCSound + ld hl, PokecenterBillsPCText + call PC_DisplayText + farcall _BillsPC + and a + ret + +PlayersPC: + call PC_PlayChoosePCSound + ld hl, PokecenterPlayersPCText + call PC_DisplayText + ld b, $0 + call _PlayersPC + and a + ret + +OaksPC: + call PC_PlayChoosePCSound + ld hl, PokecenterOaksPCText + call PC_DisplayText + farcall ProfOaksPC + and a + ret + +HallOfFamePC: + call PC_PlayChoosePCSound + call FadeToMenu + farcall _HallOfFamePC + call CloseSubmenu + and a + ret + +TurnOffPC: + ld hl, PokecenterPCOaksClosedText + call PrintText + scf + ret + +PC_PlayBootSound: + ld de, SFX_BOOT_PC + jr PC_WaitPlaySFX + +PC_PlayShutdownSound: + ld de, SFX_SHUT_DOWN_PC + call PC_WaitPlaySFX + call WaitSFX + ret + +PC_PlayChoosePCSound: + ld de, SFX_CHOOSE_PC_OPTION + jr PC_WaitPlaySFX + +PC_PlaySwapItemsSound: + ld de, SFX_SWITCH_POKEMON + call PC_WaitPlaySFX + ld de, SFX_SWITCH_POKEMON + +PC_WaitPlaySFX: + push de + call WaitSFX + pop de + call PlaySFX + ret + +_PlayersHousePC: + call PC_PlayBootSound + ld hl, PlayersPCTurnOnText + call PC_DisplayText + ld b, $1 + call _PlayersPC + and a + jr nz, .asm_159d0 + call OverworldTextModeSwitch + call ApplyTilemap + call UpdateSprites + call PC_PlayShutdownSound + ld c, $0 + ret + +.asm_159d0 + call ClearBGPalettes + ld c, $1 + ret + +PlayersPCTurnOnText: + text_far _PlayersPCTurnOnText + text_end + +_PlayersPC: + ld a, b + ld [wWhichIndexSet], a + ld hl, PlayersPCAskWhatDoText + call PC_DisplayTextWaitMenu + call Function159ec + call ExitMenu + ret + +Function159ec: + xor a + ld [wPCItemsCursor], a + ld [wPCItemsScrollPosition], a + ld hl, PlayersPCMenuData + call LoadMenuHeader +.asm_159f9 + call UpdateTimePals + call DoNthMenu + jr c, .asm_15a08 + call MenuJumptable + jr nc, .asm_159f9 + jr .asm_15a09 + +.asm_15a08 + xor a + +.asm_15a09 + call ExitMenu + ret + +PlayersPCMenuData: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 15, 12 + dw .PlayersPCMenuData + db 1 ; default selected option + +.PlayersPCMenuData: + db STATICMENU_CURSOR | STATICMENU_WRAP ; flags + db 0 ; # items? + dw .PlayersPCMenuList1 + dw PlaceNthMenuStrings + dw .PlayersPCMenuPointers + +PLAYERSPC_WITHDRAW_ITEM EQU 0 +PLAYERSPC_DEPOSIT_ITEM EQU 1 +PLAYERSPC_TOSS_ITEM EQU 2 +PLAYERSPC_MAIL_BOX EQU 3 +PLAYERSPC_DECORATION EQU 4 +PLAYERSPC_TURN_OFF EQU 5 +PLAYERSPC_LOG_OFF EQU 6 + +.PlayersPCMenuPointers: +; entries correspond to PLAYERSPC_* constants + dw PlayerWithdrawItemMenu, .WithdrawItem + dw PlayerDepositItemMenu, .DepositItem + dw PlayerTossItemMenu, .TossItem + dw PlayerMailBoxMenu, .MailBox + dw PlayerDecorationMenu, .Decoration + dw PlayerLogOffMenu, .LogOff + dw PlayerLogOffMenu, .TurnOff + +.WithdrawItem: db "WITHDRAW ITEM@" +.DepositItem: db "DEPOSIT ITEM@" +.TossItem: db "TOSS ITEM@" +.MailBox: db "MAIL BOX@" +.Decoration: db "DECORATION@" +.TurnOff: db "TURN OFF@" +.LogOff: db "LOG OFF@" + +.PlayersPCMenuList1: + db 5 + db PLAYERSPC_WITHDRAW_ITEM + db PLAYERSPC_DEPOSIT_ITEM + db PLAYERSPC_TOSS_ITEM + db PLAYERSPC_MAIL_BOX + db PLAYERSPC_TURN_OFF + db -1 ; end + +.PlayersPCMenuList2: + db 6 + db PLAYERSPC_WITHDRAW_ITEM + db PLAYERSPC_DEPOSIT_ITEM + db PLAYERSPC_TOSS_ITEM + db PLAYERSPC_MAIL_BOX + db PLAYERSPC_DECORATION + db PLAYERSPC_LOG_OFF + db -1 ; end + +PC_DisplayTextWaitMenu: + ld a, [wOptions] + push af + set NO_TEXT_SCROLL, a + ld [wOptions], a + call MenuTextbox + pop af + ld [wOptions], a + ret + +PlayersPCAskWhatDoText: + text_far _PlayersPCAskWhatDoText + text_end + +PlayerWithdrawItemMenu: + call LoadStandardMenuHeader + farcall ClearPCItemScreen +.loop + call PCItemsJoypad + jr c, .quit + call .Submenu + jr .loop + +.quit + call CloseSubmenu + xor a + ret + +.Submenu: + ; check if the item has a quantity + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr z, .askquantity + + ; items without quantity are always ×1 + ld a, 1 + ld [wItemQuantityChangeBuffer], a + jr .withdraw + +.askquantity + ld hl, .PlayersPCHowManyWithdrawText + call MenuTextbox + farcall SelectQuantityToToss + call ExitMenu + call ExitMenu + jr c, .done + +.withdraw + ld a, [wItemQuantityChangeBuffer] + ld [wBuffer1], a ; quantity + ld a, [wCurItemQuantity] + ld [wBuffer2], a + ld hl, wNumItems + call ReceiveItem + jr nc, .PackFull + ld a, [wBuffer1] + ld [wItemQuantityChangeBuffer], a + ld a, [wBuffer2] + ld [wCurItemQuantity], a + ld hl, wNumPCItems + call TossItem + predef PartyMonItemName + ld hl, .PlayersPCWithdrewItemsText + call MenuTextbox + xor a + ldh [hBGMapMode], a + call ExitMenu + ret + +.PackFull: + ld hl, .PlayersPCNoRoomWithdrawText + call MenuTextboxBackup + ret + +.done + ret + +.PlayersPCHowManyWithdrawText: + text_far _PlayersPCHowManyWithdrawText + text_end + +.PlayersPCWithdrewItemsText: + text_far _PlayersPCWithdrewItemsText + text_end + +.PlayersPCNoRoomWithdrawText: + text_far _PlayersPCNoRoomWithdrawText + text_end + +PlayerTossItemMenu: + call LoadStandardMenuHeader + farcall ClearPCItemScreen +.loop + call PCItemsJoypad + jr c, .quit + ld de, wNumPCItems + farcall TossItemFromPC + jr .loop + +.quit + call CloseSubmenu + xor a + ret + +PlayerDecorationMenu: + farcall _PlayerDecorationMenu + ld a, c + and a + ret z + scf + ret + +PlayerLogOffMenu: + xor a + scf + ret + +PlayerDepositItemMenu: + call .CheckItemsInBag + jr c, .nope + call DisableSpriteUpdates + call LoadStandardMenuHeader + farcall DepositSellInitPackBuffers +.loop + farcall DepositSellPack + ld a, [wPackUsedItem] + and a + jr z, .close + call .TryDepositItem + farcall CheckRegisteredItem + jr .loop + +.close + call CloseSubmenu + +.nope + xor a + ret + +.CheckItemsInBag: + farcall HasNoItems + ret nc + ld hl, .PlayersPCNoItemsText + call MenuTextboxBackup + scf + ret + +.PlayersPCNoItemsText: + text_far _PlayersPCNoItemsText + text_end + +.TryDepositItem: + ld a, [wSpriteUpdatesEnabled] + push af + ld a, $0 + ld [wSpriteUpdatesEnabled], a + farcall CheckItemMenu + ld a, [wItemAttributeParamBuffer] + ld hl, .dw + rst JumpTable + pop af + ld [wSpriteUpdatesEnabled], a + ret + +.dw +; entries correspond to ITEMMENU_* constants + dw .tossable ; ITEMMENU_NOUSE + dw .no_toss + dw .no_toss + dw .no_toss + dw .tossable ; ITEMMENU_CURRENT + dw .tossable ; ITEMMENU_PARTY + dw .tossable ; ITEMMENU_CLOSE + +.no_toss + ret + +.tossable + ld a, [wBuffer1] + push af + ld a, [wBuffer2] + push af + call .DepositItem + pop af + ld [wBuffer2], a + pop af + ld [wBuffer1], a + ret + +.DepositItem: + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr z, .AskQuantity + ld a, $1 + ld [wItemQuantityChangeBuffer], a + jr .ContinueDeposit + +.AskQuantity: + ld hl, .PlayersPCHowManyDepositText + call MenuTextbox + farcall SelectQuantityToToss + push af + call ExitMenu + call ExitMenu + pop af + jr c, .DeclinedToDeposit + +.ContinueDeposit: + ld a, [wItemQuantityChangeBuffer] + ld [wBuffer1], a + ld a, [wCurItemQuantity] + ld [wBuffer2], a + ld hl, wNumPCItems + call ReceiveItem + jr nc, .NoRoomInPC + ld a, [wBuffer1] + ld [wItemQuantityChangeBuffer], a + ld a, [wBuffer2] + ld [wCurItemQuantity], a + ld hl, wNumItems + call TossItem + predef PartyMonItemName + ld hl, .PlayersPCDepositItemsText + call PrintText + ret + +.NoRoomInPC: + ld hl, .PlayersPCNoRoomDepositText + call PrintText + ret + +.DeclinedToDeposit: + and a + ret + +.PlayersPCHowManyDepositText: + text_far _PlayersPCHowManyDepositText + text_end + +.PlayersPCDepositItemsText: + text_far _PlayersPCDepositItemsText + text_end + +.PlayersPCNoRoomDepositText: + text_far _PlayersPCNoRoomDepositText + text_end + +PlayerMailBoxMenu: + farcall _PlayerMailBoxMenu + xor a + ret + +PCItemsJoypad: + xor a + ld [wSwitchItem], a +.loop + ld a, [wSpriteUpdatesEnabled] + push af + ld a, $0 + ld [wSpriteUpdatesEnabled], a + ld hl, .PCItemsMenuData + call CopyMenuHeader + hlcoord 0, 0 + ld b, 10 + ld c, 18 + call Textbox + ld a, [wPCItemsCursor] + ld [wMenuCursorBuffer], a + ld a, [wPCItemsScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wPCItemsScrollPosition], a + ld a, [wMenuCursorY] + ld [wPCItemsCursor], a + pop af + ld [wSpriteUpdatesEnabled], a + ld a, [wSwitchItem] + and a + jr nz, .moving_stuff_around + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .b_1 + cp A_BUTTON + jr z, .a_1 + cp SELECT + jr z, .select_1 + jr .next + +.moving_stuff_around + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .b_2 + cp A_BUTTON + jr z, .a_select_2 + cp SELECT + jr z, .a_select_2 + jr .next + +.b_2 + xor a + ld [wSwitchItem], a + jr .next + +.a_select_2 + call PC_PlaySwapItemsSound +.select_1 + farcall SwitchItemsInBag +.next + jp .loop + +.a_1 + farcall ScrollingMenu_ClearLeftColumn + call PlaceHollowCursor + and a + ret + +.b_1 + scf + ret + +.PCItemsMenuData: + db MENU_BACKUP_TILES ; flags + menu_coords 4, 1, 18, 10 + dw .MenuData + db 1 ; default option + +.MenuData: + db SCROLLINGMENU_ENABLE_SELECT | SCROLLINGMENU_ENABLE_FUNCTION3 | SCROLLINGMENU_DISPLAY_ARROWS ; flags + db 4, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_QUANTITY ; item format + dbw 0, wNumPCItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +PC_DisplayText: + call MenuTextbox + call ExitMenu + ret + +PokecenterPCTurnOnText: + text_far _PokecenterPCTurnOnText + text_end + +PokecenterPCWhoseText: + text_far _PokecenterPCWhoseText + text_end + +PokecenterBillsPCText: + text_far _PokecenterBillsPCText + text_end + +PokecenterPlayersPCText: + text_far _PokecenterPlayersPCText + text_end + +PokecenterOaksPCText: + text_far _PokecenterOaksPCText + text_end + +PokecenterPCOaksClosedText: + text_far _PokecenterPCOaksClosedText + text_end diff --git a/engine/events/pokepic.asm b/engine/events/pokepic.asm new file mode 100644 index 00000000..523c5df5 --- /dev/null +++ b/engine/events/pokepic.asm @@ -0,0 +1,48 @@ +Pokepic:: + ld hl, PokepicMenuHeader + call CopyMenuHeader + call MenuBox + call UpdateSprites + call ApplyTilemap + ld b, SCGB_POKEPIC + call GetSGBLayout + xor a + ldh [hBGMapMode], a + ld a, [wCurPartySpecies] + ld [wCurSpecies], a + call GetBaseData + ld de, vTiles1 + predef GetMonFrontpic + ld a, [wMenuBorderTopCoord] + inc a + ld b, a + ld a, [wMenuBorderLeftCoord] + inc a + ld c, a + call Coord2Tile + ld a, $80 + ldh [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + call WaitBGMap + ret + +ClosePokepic:: + ld hl, PokepicMenuHeader + call CopyMenuHeader + call ClearMenuBoxInterior + call WaitBGMap + call GetMemSGBLayout + xor a + ldh [hBGMapMode], a + call OverworldTextModeSwitch + call ApplyTilemap + call UpdateSprites + call LoadStandardFont + ret + +PokepicMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 6, 4, 14, 13 + dw NULL + db 1 ; default option diff --git a/engine/events/pokerus/apply_pokerus_tick.asm b/engine/events/pokerus/apply_pokerus_tick.asm new file mode 100644 index 00000000..223fe014 --- /dev/null +++ b/engine/events/pokerus/apply_pokerus_tick.asm @@ -0,0 +1,26 @@ +ApplyPokerusTick: +; decreases all pokemon's pokerus counter by b. if the lower nybble reaches zero, the pokerus is cured. + ld hl, wPartyMon1PokerusStatus ; wPartyMon1 + MON_PKRS + ld a, [wPartyCount] + and a + ret z ; make sure it's not wasting time on an empty party + ld c, a +.loop + ld a, [hl] + and $f ; lower nybble is the number of days remaining + jr z, .next ; if already 0, skip + sub b ; subtract the number of days + jr nc, .ok ; max(result, 0) + xor a +.ok + ld d, a ; back up this value because we need to preserve the strain (upper nybble) + ld a, [hl] + and $f0 + add d + ld [hl], a ; this prevents a cured pokemon from recontracting pokerus +.next + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + dec c + jr nz, .loop + ret diff --git a/engine/events/pokerus/pokerus.asm b/engine/events/pokerus/pokerus.asm new file mode 100644 index 00000000..99a5652c --- /dev/null +++ b/engine/events/pokerus/pokerus.asm @@ -0,0 +1,161 @@ +GivePokerusAndConvertBerries: + call ConvertBerriesToBerryJuice + ld hl, wPartyMon1PokerusStatus + ld a, [wPartyCount] + ld b, a + ld de, PARTYMON_STRUCT_LENGTH +; Check to see if any of your Pokemon already has Pokerus. +; If so, sample its spread through your party. +; This means that you cannot get Pokerus de novo while +; a party member has an active infection. +.loopMons + ld a, [hl] + and $f + jr nz, .TrySpreadPokerus + add hl, de + dec b + jr nz, .loopMons + +; If we haven't been to Goldenrod City at least once, +; prevent the contraction of Pokerus. + ld hl, wStatusFlags2 + bit STATUSFLAGS2_REACHED_GOLDENROD_F, [hl] + ret z + call Random + ldh a, [hRandomAdd] + and a + ret nz + ldh a, [hRandomSub] + cp 3 + ret nc ; 3/65536 chance (00 00, 00 01 or 00 02) + ld a, [wPartyCount] + ld b, a +.randomMonSelectLoop + call Random + and $7 + cp b + jr nc, .randomMonSelectLoop + ld hl, wPartyMon1PokerusStatus + call GetPartyLocation ; get pokerus byte of random mon + ld a, [hl] + and $f0 + ret nz ; if it already has pokerus, do nothing +.randomPokerusLoop ; Simultaneously sample the strain and duration + call Random + and a + jr z, .randomPokerusLoop + ld b, a + and $f0 + jr z, .load_pkrs + ld a, b + and $7 + inc a +.load_pkrs + ld b, a ; this should come before the label + swap b + and $3 + inc a + add b + ld [hl], a + ret + +.TrySpreadPokerus: + call Random + cp 33 percent + 1 + ret nc ; 1/3 chance + + ld a, [wPartyCount] + cp 1 + ret z ; only one mon, nothing to do + + ld c, [hl] + ld a, b + cp 2 + jr c, .checkPreviousMonsLoop ; no more mons after this one, go backwards + + call Random + cp 50 percent + 1 + jr c, .checkPreviousMonsLoop ; 1/2 chance, go backwards +.checkFollowingMonsLoop + add hl, de + ld a, [hl] + and a + jr z, .infectMon + ld c, a + and $3 + ret z ; if mon has cured pokerus, stop searching + dec b ; go on to next mon + ld a, b + cp 1 + jr nz, .checkFollowingMonsLoop ; no more mons left + ret + +.checkPreviousMonsLoop + ld a, [wPartyCount] + cp b + ret z ; no more mons + ld a, l + sub e + ld l, a + ld a, h + sbc d + ld h, a + ld a, [hl] + and a + jr z, .infectMon + ld c, a + and $3 + ret z ; if mon has cured pokerus, stop searching + inc b ; go on to next mon + jr .checkPreviousMonsLoop + +.infectMon + ld a, c + and $f0 + ld b, a + ld a, c + swap a + and $3 + inc a + add b + ld [hl], a + ret + +ConvertBerriesToBerryJuice: +; If we haven't been to Goldenrod City at least once, +; prevent Shuckle from turning held Berry into Berry Juice. + ld hl, wStatusFlags2 + bit STATUSFLAGS2_REACHED_GOLDENROD_F, [hl] + ret z + call Random + cp 1 out_of 16 ; 6.25% chance + ret nc + ld hl, wPartyMons + ld a, [wPartyCount] +.partyMonLoop + push af + push hl + ld a, [hl] + cp SHUCKLE + jr nz, .loopMon + ld bc, MON_ITEM + add hl, bc + ld a, [hl] + cp BERRY + jr z, .convertToJuice + +.loopMon + pop hl + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop af + dec a + jr nz, .partyMonLoop + ret + +.convertToJuice + ld a, BERRY_JUICE + ld [hl], a + pop hl + pop af + ret diff --git a/engine/events/print_photo.asm b/engine/events/print_photo.asm new file mode 100644 index 00000000..056788b9 --- /dev/null +++ b/engine/events/print_photo.asm @@ -0,0 +1,50 @@ +PhotoStudio: + ld hl, .WhichMonPhotoText + call PrintText + farcall SelectMonFromParty + jr c, .cancel + ld a, [wCurPartySpecies] + cp EGG + jr z, .egg + + ld hl, .HoldStillText + call PrintText + call DisableSpriteUpdates + farcall PrintPartymon + call ReturnToMapWithSpeechTextbox + ldh a, [hPrinter] + and a + jr nz, .cancel + ld hl, .PrestoAllDoneText + jr .print_text + +.cancel + ld hl, .NoPhotoText + jr .print_text + +.egg + ld hl, .EggPhotoText + +.print_text + call PrintText + ret + +.WhichMonPhotoText: + text_far _WhichMonPhotoText + text_end + +.HoldStillText: + text_far _HoldStillText + text_end + +.PrestoAllDoneText: + text_far _PrestoAllDoneText + text_end + +.NoPhotoText: + text_far _NoPhotoText + text_end + +.EggPhotoText: + text_far _EggPhotoText + text_end diff --git a/engine/events/print_unown.asm b/engine/events/print_unown.asm new file mode 100644 index 00000000..0d67ae72 --- /dev/null +++ b/engine/events/print_unown.asm @@ -0,0 +1,209 @@ +UNOWNSTAMP_BOLD_A EQU "♂" ; $ef +UNOWNSTAMP_BOLD_B EQU "♀" ; $f5 + +_UnownPrinter: + ld a, [wUnownDex] + and a + ret z + + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + ld a, [wOptions] + push af + set NO_TEXT_SCROLL, a + ld [wOptions], a + call ClearBGPalettes + call ClearTilemap + + ld de, UnownDexATile + ld hl, vTiles0 tile UNOWNSTAMP_BOLD_A + lb bc, BANK(UnownDexATile), 1 + call Request1bpp + + ld de, UnownDexBTile + ld hl, vTiles0 tile UNOWNSTAMP_BOLD_B + 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 [wCurPartySpecies], a + xor a + ld [wTempMonDVs], a + ld [wTempMonDVs + 1], a + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call SetPalettes + +.joy_loop + call JoyTextDelay + + ldh a, [hJoyPressed] + and B_BUTTON + jr nz, .pressed_b + + ldh 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 [wOptions], a + pop af + ldh [hInMenu], a + call ReturnToMapFromSubmenu + ret + +.LeftRight: + ldh a, [hJoyLast] + and D_RIGHT + jr nz, .press_right + ldh 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], NUM_UNOWN + 1 +.wrap_around_left + dec [hl] + jr .return + +.press_right + ld hl, wJumptableIndex + ld a, [hl] + cp NUM_UNOWN + jr c, .wrap_around_right + ld [hl], -1 +.wrap_around_right + inc [hl] + +.return + call .UpdateUnownFrontpic + ret + +.UpdateUnownFrontpic: + ld a, [wJumptableIndex] + cp NUM_UNOWN + jr z, .vacant + inc a + ld [wUnownLetter], a + ld a, UNOWN + ld [wCurPartySpecies], a + xor a + ld [wBoxAlignment], a + ld de, vTiles2 + predef GetMonFrontpic + hlcoord 1, 6 + xor a + ldh [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + ld de, vTiles2 tile $31 + farcall RotateUnownFrontpic + ret + +.vacant + hlcoord 1, 6 + lb bc, 7, 7 + call ClearBox + hlcoord 1, 9 + ld de, UnownDexVacantString + call PlaceString + xor a ; sScratch + call OpenSRAM + ld hl, sScratch + ld bc, $31 tiles + xor a + call ByteFill + ld hl, vTiles2 tile $31 + ld de, sDecompressScratch + ld c, $31 + ldh a, [hROMBank] + ld b, a + call Get2bpp + call CloseSRAM + ld c, 20 + call DelayFrames + ret + +AlphRuinsStampString: + db " ALPH RUINS STAMP@" + +UnownDexDoWhatString: + db "Do what?@" + +UnownDexMenuString: + db UNOWNSTAMP_BOLD_A, "▶PRINT" + next UNOWNSTAMP_BOLD_B, "▶CANCEL" + next "L▶BEFORE" + next "R▶NEXT" + db "@" + +UnownDexVacantString: + db "VACANT@" + +UnownDexATile: +INCBIN "gfx/printer/bold_a.1bpp" +UnownDexBTile: +INCBIN "gfx/printer/bold_b.1bpp" + +PlaceUnownPrinterFrontpic: + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + hlcoord 7, 11 + ld a, $31 + ldh [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + ret diff --git a/engine/events/prof_oaks_pc.asm b/engine/events/prof_oaks_pc.asm new file mode 100644 index 00000000..40230d5b --- /dev/null +++ b/engine/events/prof_oaks_pc.asm @@ -0,0 +1,193 @@ +ProfOaksPC: + ld hl, OakPCText1 + call MenuTextbox + call YesNoBox + jr c, .shutdown + call ProfOaksPCBoot ; player chose "yes"? +.shutdown + ld hl, OakPCText4 + call PrintText + call JoyWaitAorB + call ExitMenu + ret + +ProfOaksPCBoot: + ld hl, OakPCText2 + call PrintText + call Rate + call PlaySFX ; sfx loaded by previous Rate function call + call JoyWaitAorB + call WaitSFX + ret + +ProfOaksPCRating: + call Rate + push de + ld de, MUSIC_NONE + call PlayMusic + pop de + call PlaySFX + call JoyWaitAorB + call WaitSFX + ret + +Rate: +; calculate Seen/Owned + ld hl, wPokedexSeen + ld b, wEndPokedexSeen - wPokedexSeen + call CountSetBits + ld [wceed], a + ld hl, wPokedexCaught + ld b, wEndPokedexCaught - wPokedexCaught + call CountSetBits + ld [wceee], a + +; print appropriate rating + call .UpdateRatingBuffers + ld hl, OakPCText3 + call PrintText + call JoyWaitAorB + ld a, [wceee] + ld hl, OakRatings + call FindOakRating + push de + call PrintText + pop de + ret + +.UpdateRatingBuffers: + ld hl, wStringBuffer3 + ld de, wceed + call .UpdateRatingBuffer + ld hl, wStringBuffer4 + ld de, wceee + call .UpdateRatingBuffer + ret + +.UpdateRatingBuffer: + push hl + ld a, "@" + ld bc, ITEM_NAME_LENGTH + call ByteFill + pop hl + lb bc, PRINTNUM_LEFTALIGN | 1, 3 + call PrintNum + ret + +FindOakRating: +; return sound effect in de +; return text pointer in hl + nop + ld c, a +.loop + ld a, [hli] + cp c + jr nc, .match +rept 4 + inc hl +endr + jr .loop + +.match + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld h, [hl] + ld l, a + ret + +INCLUDE "data/events/pokedex_ratings.asm" + +OakPCText1: + text_far _OakPCText1 + text_end + +OakPCText2: + text_far _OakPCText2 + text_end + +OakPCText3: + text_far _OakPCText3 + text_end + +OakRating01: + text_far _OakRating01 + text_end + +OakRating02: + text_far _OakRating02 + text_end + +OakRating03: + text_far _OakRating03 + text_end + +OakRating04: + text_far _OakRating04 + text_end + +OakRating05: + text_far _OakRating05 + text_end + +OakRating06: + text_far _OakRating06 + text_end + +OakRating07: + text_far _OakRating07 + text_end + +OakRating08: + text_far _OakRating08 + text_end + +OakRating09: + text_far _OakRating09 + text_end + +OakRating10: + text_far _OakRating10 + text_end + +OakRating11: + text_far _OakRating11 + text_end + +OakRating12: + text_far _OakRating12 + text_end + +OakRating13: + text_far _OakRating13 + text_end + +OakRating14: + text_far _OakRating14 + text_end + +OakRating15: + text_far _OakRating15 + text_end + +OakRating16: + text_far _OakRating16 + text_end + +OakRating17: + text_far _OakRating17 + text_end + +OakRating18: + text_far _OakRating18 + text_end + +OakRating19: + text_far _OakRating19 + text_end + +OakPCText4: + text_far _OakPCText4 + text_end diff --git a/engine/events/repel.asm b/engine/events/repel.asm new file mode 100644 index 00000000..e324239c --- /dev/null +++ b/engine/events/repel.asm @@ -0,0 +1,10 @@ +RepelWoreOffScript:: + opentext + writetext .RepelWoreOffText + waitbutton + closetext + end + +.RepelWoreOffText: + text_far _RepelWoreOffText + text_end diff --git a/engine/events/shuckle.asm b/engine/events/shuckle.asm index e83357b2..668a99b0 100755 --- a/engine/events/shuckle.asm +++ b/engine/events/shuckle.asm @@ -2,7 +2,7 @@ MANIA_OT_ID EQU 00518 GiveShuckle: ; Adding to the party. - xor a + xor a ; PARTYMON ld [wMonType], a ; Level 15 Shuckle. @@ -50,7 +50,8 @@ GiveShuckle: call CopyName2 ; Engine flag for this event. - SetFlag ENGINE_GOT_SHUCKIE_TODAY + ld hl, wDailyFlags1 + set DAILYFLAGS1_GOT_SHUCKIE_TODAY_F, [hl] ld a, 1 ld [wScriptVar], a ret @@ -62,6 +63,7 @@ GiveShuckle: SpecialShuckleOT: db "MANIA@" + SpecialShuckleNick: db "SHUCKIE@" diff --git a/engine/events/specials.asm b/engine/events/specials.asm new file mode 100755 index 00000000..91ca4208 --- /dev/null +++ b/engine/events/specials.asm @@ -0,0 +1,463 @@ +Special:: +; Run script special de. + ld hl, SpecialsPointers + add hl, de + add hl, de + add hl, de + ld b, [hl] + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + ld a, b + rst FarCall + ret + +INCLUDE "data/special_pointers.asm" + +DummySpecial_c389: + ret + +GameCornerPrizeMonCheckDex: + ld a, [wScriptVar] + dec a + call CheckCaughtMon + ret nz + ld a, [wScriptVar] + dec a + call SetSeenAndCaughtMon + call FadeToMenu + ld a, [wScriptVar] + ld [wNamedObjectIndexBuffer], a + farcall NewPokedexEntry + call ExitAllMenus + ret + +UnusedSetSeenMon: + ld a, [wScriptVar] + dec a + call SetSeenMon + ret + +FindPartyMonAboveLevel: + ld a, [wScriptVar] + ld b, a + farcall _FindPartyMonAboveLevel + jr z, FoundNone + jr FoundOne + +FindPartyMonAtLeastThatHappy: + ld a, [wScriptVar] + ld b, a + farcall _FindPartyMonAtLeastThatHappy + jr z, FoundNone + jr FoundOne + +FindPartyMonThatSpecies: + ld a, [wScriptVar] + ld b, a + farcall _FindPartyMonThatSpecies + jr z, FoundNone + jr FoundOne + +FindPartyMonThatSpeciesYourTrainerID: + ld a, [wScriptVar] + ld b, a + farcall _FindPartyMonThatSpeciesYourTrainerID + jr z, FoundNone + jr FoundOne + +FoundOne: + ld a, TRUE + ld [wScriptVar], a + ret + +FoundNone: + xor a + ld [wScriptVar], a + ret + +NameRival: + ld b, NAME_RIVAL + ld de, wRivalName + farcall _NamingScreen + ; default to "SILVER" + ld hl, wRivalName + ld de, .default + call InitName + ret + +.default +IF DEF(_GOLD) + db "SILVER@" +ELIF DEF(_SILVER) + db "GOLD@" +ENDC + +NameRater: + farcall _NameRater + ret + +OverworldTownMap: + call FadeToMenu + farcall _TownMap + call ExitAllMenus + ret + +UnownPrinter: + call FadeToMenu + farcall _UnownPrinter + call ExitAllMenus + ret + +DisplayLinkRecord: + call FadeToMenu + farcall _DisplayLinkRecord + call ExitAllMenus + ret + +PlayersHousePC: + xor a + ld [wScriptVar], a + farcall _PlayersHousePC + ld a, c + ld [wScriptVar], a + ret + +CheckMysteryGift: + ld a, BANK(sMysteryGiftItem) + call OpenSRAM + ld a, [sMysteryGiftItem] + and a + jr z, .no + inc a + +.no + ld [wScriptVar], a + call CloseSRAM + ret + +GetMysteryGiftItem: + ld a, BANK(sMysteryGiftItem) + call OpenSRAM + ld a, [sMysteryGiftItem] + ld [wCurItem], a + ld a, 1 + ld [wItemQuantityChangeBuffer], a + ld hl, wNumItems + call ReceiveItem + jr nc, .no_room + xor a + ld [sMysteryGiftItem], a + call CloseSRAM + ld a, [wCurItem] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, .ReceiveItemText + call PrintText + ld a, TRUE + ld [wScriptVar], a + ret + +.no_room + call CloseSRAM + xor a + ld [wScriptVar], a + ret + +.ReceiveItemText: + text_far _ReceiveItemText + text_end + +BugContestJudging: + farcall _BugContestJudging + ld a, b + ld [wScriptVar], a + ret + +MapRadio: + ld a, [wScriptVar] + ld e, a + farcall PlayRadio + ret + +UnownPuzzle: + call FadeToMenu + farcall _UnownPuzzle + ld a, [wSolvedUnownPuzzle] + ld [wScriptVar], a + call ExitAllMenus + ret + +SlotMachine: + call CheckCoinsAndCoinCase + ret c + ld a, BANK(_SlotMachine) + ld hl, _SlotMachine + call StartGameCornerGame + ret + +CardFlip: + call CheckCoinsAndCoinCase + ret c + ld a, BANK(_CardFlip) + ld hl, _CardFlip + call StartGameCornerGame + ret + +DummyNonfunctionalGameCornerGame: + call CheckCoinsAndCoinCase + ret c + ld a, BANK(_DummyGame) + ld hl, _DummyGame + call StartGameCornerGame + ret + +StartGameCornerGame: + call FarQueueScript + call FadeToMenu + ld hl, wQueuedScriptBank + ld a, [hli] + push af + ld a, [hli] + ld h, [hl] + ld l, a + pop af + rst FarCall + call ExitAllMenus + ret + +CheckCoinsAndCoinCase: + ld hl, wCoins + ld a, [hli] + or [hl] + jr z, .no_coins + ld a, COIN_CASE + ld [wCurItem], a + ld hl, wNumItems + call CheckItem + jr nc, .no_coin_case + and a + ret + +.no_coins + ld hl, .NoCoinsText + jr .print + +.no_coin_case + ld hl, .NoCoinCaseText + +.print + call PrintText + scf + ret + +.NoCoinsText: + text_far _NoCoinsText + text_end + +.NoCoinCaseText: + text_far _NoCoinCaseText + text_end + +ClearBGPalettesBufferScreen: + call ClearBGPalettes + call BufferScreen + ret + +ScriptReturnCarry: + jr c, .carry + xor a + ld [wScriptVar], a + ret +.carry + ld a, 1 + ld [wScriptVar], a + ret + +UnusedCheckUnusedTwoDayTimer: + farcall CheckUnusedTwoDayTimer + ld a, [wUnusedTwoDayTimer] + ld [wScriptVar], a + ret + +ActivateFishingSwarm: + ld a, [wScriptVar] + ld [wFishingSwarmFlag], a + jr SetSwarmFlag + +StoreSwarmMapIndices:: + ld a, d + ld [wSwarmMapGroup], a + ld a, e + ld [wSwarmMapNumber], a + ; fallthrough +SetSwarmFlag: + ld hl, wDailyFlags1 + set DAILYFLAGS1_SWARM_F, [hl] + ret + +CheckSwarmFlag:: + ld hl, wDailyFlags1 + bit DAILYFLAGS1_SWARM_F, [hl] + jr z, .clear_swarm + xor a + ld [wScriptVar], a + ret + +.clear_swarm + ld a, 1 + ld [wScriptVar], a + xor a + ld [wFishingSwarmFlag], a + ld [wSwarmMapGroup], a + ld [wSwarmMapNumber], a + ret + +CheckPokerus: +; Check if a monster in your party has Pokerus + farcall _CheckPokerus + jp ScriptReturnCarry + +ResetLuckyNumberShowFlag: + farcall RestartLuckyNumberCountdown + ld hl, wLuckyNumberShowFlag + res LUCKYNUMBERSHOW_GAME_OVER_F, [hl] + farcall LoadOrRegenerateLuckyIDNumber + ret + +CheckLuckyNumberShowFlag: + farcall _CheckLuckyNumberShowFlag + jp ScriptReturnCarry + +CountUnown: + ld hl, wUnownDex + ld b, $0 +.loop + ld a, [hli] + and a + ret z + inc b + ld a, b + cp NUM_UNOWN + jr c, .loop + ret + +SelectApricornForKurt: + farcall Kurt_SelectApricorn + ld a, c + ld [wScriptVar], a + and a + ret z + ld [wCurItem], a + ld a, $1 + ld [wItemQuantityChangeBuffer], a + ld hl, wNumItems + call TossItem + ret + +SnorlaxAwake: +; Check if the Poké Flute channel is playing, and if the player is standing +; next to Snorlax. + +; outputs: +; wScriptVar is 1 if the conditions are met, otherwise 0. + +; check background music + ld a, [wMapMusic] + cp MUSIC_POKE_FLUTE_CHANNEL + jr nz, .nope + + ld a, [wXCoord] + ld b, a + ld a, [wYCoord] + ld c, a + + ld hl, .ProximityCoords +.loop + ld a, [hli] + cp -1 + jr z, .nope + cp b + jr nz, .nextcoord + ld a, [hli] + cp c + jr nz, .loop + + ld a, TRUE + jr .done + +.nextcoord + inc hl + jr .loop + +.nope + xor a +.done + ld [wScriptVar], a + ret + +.ProximityCoords: + ; x, y + db 33, 8 ; left + db 34, 10 ; below + db 35, 10 ; below + db 36, 8 ; right + db 36, 9 ; right + db -1 + +PlayCurMonCry: + ld a, [wCurPartySpecies] + jp PlayMonCry + +GameboyCheck: + ldh a, [hCGB] + and a + jr nz, .cgb + + ldh a, [hSGB] + and a + jr nz, .sgb + +.gb + xor a ; GBCHECK_GB + jr .done +.sgb + ld a, GBCHECK_SGB + jr .done +.cgb + ld a, GBCHECK_CGB +.done + ld [wScriptVar], a + ret + +FadeOutMusic: + ld a, LOW(MUSIC_NONE) + ld [wMusicFadeID], a + ld a, HIGH(MUSIC_NONE) + ld [wMusicFadeID + 1], a + ld a, $2 + ld [wMusicFade], a + ret + +Diploma: + call FadeToMenu + farcall _Diploma + call ExitAllMenus + ret + +PrintDiploma: + call FadeToMenu + farcall _PrintDiploma + call ExitAllMenus + ret + +TrainerHouse: + ld a, BANK(sMysteryGiftTrainerHouseFlag) + call OpenSRAM + ld a, [sMysteryGiftTrainerHouseFlag] + ld [wScriptVar], a + jp CloseSRAM + +; unused + nop diff --git a/engine/events/std_collision.asm b/engine/events/std_collision.asm index bb44687c..8c54c041 100755 --- a/engine/events/std_collision.asm +++ b/engine/events/std_collision.asm @@ -7,12 +7,12 @@ CheckFacingTileForStdScript:: jr nc, .notintable ld a, jumpstd_command - ld [wcf2a], a + ld [wJumpStdScriptBuffer], a inc hl ld a, [hli] - ld [wcf2b], a + ld [wJumpStdScriptBuffer + 1], a ld a, [hli] - ld [wTempTrainer], a + ld [wJumpStdScriptBuffer + 2], a ld a, BANK(Script_JumpStdFromRAM) ld hl, Script_JumpStdFromRAM call CallScript @@ -26,4 +26,4 @@ CheckFacingTileForStdScript:: INCLUDE "data/events/collision_stdscripts.asm" Script_JumpStdFromRAM: - jump wcf2a
\ No newline at end of file + sjump wJumpStdScriptBuffer diff --git a/engine/events/trainer_scripts.asm b/engine/events/trainer_scripts.asm new file mode 100644 index 00000000..1fb0d291 --- /dev/null +++ b/engine/events/trainer_scripts.asm @@ -0,0 +1,31 @@ +TalkToTrainerScript:: + faceplayer + trainerflagaction CHECK_FLAG + iftrue AlreadyBeatenTrainerScript + loadtemptrainer + encountermusic + sjump StartBattleWithMapTrainerScript + +SeenByTrainerScript:: + loadtemptrainer + encountermusic + showemote EMOTE_SHOCK, LAST_TALKED, 30 + callasm TrainerWalkToPlayer + applymovementlasttalked wMovementBuffer + writeobjectxy LAST_TALKED + faceobject PLAYER, LAST_TALKED + sjump StartBattleWithMapTrainerScript + +StartBattleWithMapTrainerScript: + opentext + trainertext TRAINERTEXT_SEEN + waitbutton + closetext + loadtemptrainer + startbattle + reloadmapafterbattle + trainerflagaction SET_FLAG + loadmem wRunningTrainerBattleScript, -1 + +AlreadyBeatenTrainerScript: + scripttalkafter diff --git a/engine/events/treemons.asm b/engine/events/treemons.asm new file mode 100644 index 00000000..c96df83a --- /dev/null +++ b/engine/events/treemons.asm @@ -0,0 +1,273 @@ +TreeMonEncounter: + xor a + ld [wTempWildMonSpecies], a + ld [wCurPartyLevel], a + + ld hl, TreeMonMaps + call GetTreeMonSet + jr nc, .no_battle + + call GetTreeMons + jr nc, .no_battle + + call GetTreeMon + jr nc, .no_battle + + ld a, BATTLETYPE_TREE + ld [wBattleType], a + ld a, 1 + ld [wScriptVar], a + ret + +.no_battle + xor a + ld [wScriptVar], a + ret + +RockMonEncounter: + xor a + ld [wTempWildMonSpecies], a + ld [wCurPartyLevel], a + + ld hl, RockMonMaps + call GetTreeMonSet + jr nc, .no_battle + + call GetTreeMons + jr nc, .no_battle + + ; 40% chance of an encounter + ld a, 10 + call RandomRange + cp 4 + jr nc, .no_battle + + call SelectTreeMon + jr nc, .no_battle + + ret + +.no_battle + xor a + ret + + db $05 ; ???? + +GetTreeMonSet: +; Return carry and treemon set in a +; if the current map is in table hl. + ld a, [wMapNumber] + ld e, a + ld a, [wMapGroup] + ld d, a +.loop + ld a, [hli] + cp -1 + jr z, .not_in_table + + cp d + jr nz, .skip2 + + ld a, [hli] + cp e + jr nz, .skip1 + + jr .in_table + +.skip2 + inc hl +.skip1 + inc hl + jr .loop + +.not_in_table + xor a + ret + +.in_table + ld a, [hl] + scf + ret + +INCLUDE "data/wild/treemon_maps.asm" + +GetTreeMons: +; Return the address of TreeMon table a in hl. +; Return nc if table a doesn't exist. + + cp NUM_TREEMON_SETS + jr nc, .quit + + and a + jr z, .quit + + ld e, a + ld d, 0 + ld hl, TreeMons + add hl, de + add hl, de + + ld a, [hli] + ld h, [hl] + ld l, a + + scf + ret + +.quit + xor a + ret + +INCLUDE "data/wild/treemons.asm" + +GetTreeMon: + push hl + call GetTreeScore + pop hl + and a ; TREEMON_SCORE_BAD + jr z, .bad + cp TREEMON_SCORE_GOOD + jr z, .good + cp TREEMON_SCORE_RARE + jr z, .rare + ret + +.bad + ; 10% chance of an encounter + ld a, 10 + call RandomRange + and a + jr nz, NoTreeMon + jr SelectTreeMon + +.good + ; 50% chance of an encounter + ld a, 10 + call RandomRange + cp 5 + jr nc, NoTreeMon + jr SelectTreeMon + +.rare + ; 80% chance of an encounter + ld a, 10 + call RandomRange + cp 8 + jr nc, NoTreeMon + jr .skip +.skip + ld a, [hli] + cp -1 + jr nz, .skip + call SelectTreeMon + ret + +SelectTreeMon: +; Read a TreeMons table and pick one monster at random. + + ld a, 100 + call RandomRange +.loop + sub [hl] + jr c, .ok + inc hl + inc hl + inc hl + jr .loop + +.ok + ld a, [hli] + cp -1 + jr z, NoTreeMon + + ld a, [hli] + ld [wTempWildMonSpecies], a + ld a, [hl] + ld [wCurPartyLevel], a + scf + ret + +NoTreeMon: + xor a + ld [wTempWildMonSpecies], a + ld [wCurPartyLevel], a + ret + +GetTreeScore: + call .CoordScore + ld [wBuffer1], a + call .OTIDScore + ld [wBuffer2], a + ld c, a + ld a, [wBuffer1] + sub c + jr z, .rare + jr nc, .ok + add 10 +.ok + cp 5 + jr c, .good + +.bad + xor a ; TREEMON_SCORE_BAD + ret + +.good + ld a, TREEMON_SCORE_GOOD + ret + +.rare + ld a, TREEMON_SCORE_RARE + ret + +.CoordScore: + call GetFacingTileCoord + ld hl, 0 + ld c, e + ld b, 0 + ld a, d + + and a + jr z, .next +.loop + add hl, bc + dec a + jr nz, .loop +.next + + add hl, bc + ld c, d + add hl, bc + + ld a, h + ldh [hDividend], a + ld a, l + ldh [hDividend + 1], a + ld a, 5 + ldh [hDivisor], a + ld b, 2 + call Divide + + ldh a, [hQuotient + 2] + ldh [hDividend], a + ldh a, [hQuotient + 3] + ldh [hDividend + 1], a + ld a, 10 + ldh [hDivisor], a + ld b, 2 + call Divide + + ldh a, [hRemainder] + ret + +.OTIDScore: + ld a, [wPlayerID] + ldh [hDividend], a + ld a, [wPlayerID + 1] + ldh [hDividend + 1], a + ld a, 10 + ldh [hDivisor], a + ld b, 2 + call Divide + ldh a, [hRemainder] + ret diff --git a/engine/events/whiteout.asm b/engine/events/whiteout.asm index 01d7b388..635be636 100755 --- a/engine/events/whiteout.asm +++ b/engine/events/whiteout.asm @@ -1,6 +1,6 @@ Script_BattleWhiteout:: callasm BattleBGMap - jump Script_Whiteout + sjump Script_Whiteout Script_OverworldWhiteout:: refreshscreen @@ -25,9 +25,8 @@ Script_Whiteout: jumpstd bugcontestresultswarp .WhitedOutText: - ; is out of useable #MON! whited out! - text_far UnknownText_0x1c0a4e - db "@" + text_far _WhitedOutText + text_end OverworldBGMap: call ClearPalettes @@ -58,19 +57,15 @@ HalveMoney: ret GetWhiteoutSpawn: - ld a, [wd9fb] + ld a, [wLastSpawnMapGroup] ld d, a - ld a, [wd9fc] + ld a, [wLastSpawnMapNumber] ld e, a - - ld a, $05 - ld hl, $5465 - rst $08 - + farcall IsSpawnPoint ld a, c jr c, .yes xor a ; SPAWN_HOME .yes - ld [wceec], a + ld [wDefaultSpawnpoint], a ret diff --git a/engine/facings.asm b/engine/facings.asm deleted file mode 100644 index a5669c2b..00000000 --- a/engine/facings.asm +++ /dev/null @@ -1,265 +0,0 @@ -Facings: ; 404a - dw Facing00 - dw Facing01 - dw Facing02 - dw Facing03 - dw Facing04 - dw Facing05 - dw Facing06 - dw Facing07 - dw Facing08 - dw Facing09 - dw Facing10 - dw Facing11 - dw Facing12 - dw Facing13 - dw Facing14 - dw Facing15 - dw Facing16 - dw Facing17 - dw Facing18 - dw Facing19 - dw Facing20 - dw Facing21 - dw Facing22 - dw Facing23 - dw Facing24 - dw Facing25 - dw Facing26 - dw Facing27 - dw Facing28 - dw Facing29 - dw Facing30 - dw Facing31 -FacingsEnd: dw 0 - -NUM_FACINGS EQU (FacingsEnd - Facings) / 2 - - -; Tables used as a reference to transform OAM data. - -; Format: -; db y, x, attributes, tile index - -; Attributes: -BEHIND_BG EQU 1 << OAM_PRIORITY - -Facing00: -Facing02: -Facing24: -Facing26: ; standing down - db 4 ; # - db 0, 0, 0, $00 - db 0, 8, 0, $01 - db 8, 0, 2, $02 - db 8, 8, 2, $03 -; 409d - -Facing01: ; walking down 1 - db 4 ; # - db 0, 0, 0, $80 - db 0, 8, 0, $81 - db 8, 0, 2, $82 - db 8, 8, 2, $83 -; 40ae - -Facing03: ; walking down 2 - db 4 ; # - db 0, 8, X_FLIP, $80 - db 0, 0, X_FLIP, $81 - db 8, 8, 2 | X_FLIP, $82 - db 8, 0, 2 | X_FLIP, $83 -; 40bf - -Facing04: -Facing06: ; standing up - db 4 ; # - db 0, 0, 0, $04 - db 0, 8, 0, $05 - db 8, 0, 2, $06 - db 8, 8, 2, $07 -; 40d0 - -Facing05: ; walking up 1 - db 4 ; # - db 0, 0, 0, $84 - db 0, 8, 0, $85 - db 8, 0, 2, $86 - db 8, 8, 2, $87 -; 40e1 - -Facing07: ; walking up 2 - db 4 ; # - db 0, 8, X_FLIP, $84 - db 0, 0, X_FLIP, $85 - db 8, 8, 2 | X_FLIP, $86 - db 8, 0, 2 | X_FLIP, $87 -; 40f2 - -Facing08: -Facing10: ; standing left - db 4 ; # - db 0, 0, 0, $08 - db 0, 8, 0, $09 - db 8, 0, 2, $0a - db 8, 8, 2, $0b -; 4103 - -Facing12: -Facing14: ; standing right - db 4 ; # - db 0, 8, X_FLIP, $08 - db 0, 0, X_FLIP, $09 - db 8, 8, 2 | X_FLIP, $0a - db 8, 0, 2 | X_FLIP, $0b -; 4114 - -Facing09: -Facing11: ; walking left - db 4 ; # - db 0, 0, 0, $88 - db 0, 8, 0, $89 - db 8, 0, 2, $8a - db 8, 8, 2, $8b -; 4125 - -Facing13: -Facing15: ; walking right - db 4 ; # - db 0, 8, X_FLIP, $88 - db 0, 0, X_FLIP, $89 - db 8, 8, 2 | X_FLIP, $8a - db 8, 0, 2 | X_FLIP, $8b -; 4136 - -Facing16: ; fishing down - db 5 ; # - db 0, 0, 0, $00 - db 0, 8, 0, $01 - db 8, 0, 2, $02 - db 8, 8, 2, $03 - db 16, 0, 4, $fc -; 414b - -Facing17: ; fishing up - db 5 ; # - db 0, 0, 0, $04 - db 0, 8, 0, $05 - db 8, 0, 2, $06 - db 8, 8, 2, $07 - db -8, 0, 4, $fc -; 4160 - -Facing18: ; fishing left - db 5 ; # - db 0, 0, 0, $08 - db 0, 8, 0, $09 - db 8, 0, 2, $0a - db 8, 8, 2, $0b - db 5, -8, 4 | X_FLIP, $fd -; 4175 - -Facing19: ; fishing right - db 5 ; # - db 0, 8, X_FLIP, $08 - db 0, 0, X_FLIP, $09 - db 8, 8, 2 | X_FLIP, $0a - db 8, 0, 2 | X_FLIP, $0b - db 5, 16, 4, $fd -; 418a - -Facing20: ; emote - db 4 ; # - db 0, 0, 4, $f8 - db 0, 8, 4, $f9 - db 8, 0, 4, $fa - db 8, 8, 4, $fb -; 419b - -Facing21: ; shadow - db 2 ; # - db 0, 0, 4, $fc - db 0, 8, 4 | X_FLIP, $fc -; 41a4 - -Facing23: ; big snorlax or lapras doll - db 16 ; # - db 0, 0, 0, $00 - db 0, 8, 0, $01 - db 8, 0, 0, $02 - db 8, 8, 0, $03 - db 16, 0, 0, $04 - db 16, 8, 0, $05 - db 24, 0, 0, $06 - db 24, 8, 0, $07 - db 0, 24, X_FLIP, $00 - db 0, 16, X_FLIP, $01 - db 8, 24, X_FLIP, $02 - db 8, 16, X_FLIP, $03 - db 16, 24, X_FLIP, $04 - db 16, 16, X_FLIP, $05 - db 24, 24, X_FLIP, $06 - db 24, 16, X_FLIP, $07 -; 41e5 - -Facing25: ; 41e4 - db 4 ; # - db 0, 0, 0, $04 - db 0, 8, 0, $05 - db 8, 0, 0, $06 - db 8, 8, 0, $07 -; 41f6 - -Facing27: ; 41f5 - db 4 ; # - db 0, 8, X_FLIP, $04 - db 0, 0, X_FLIP, $05 - db 8, 8, X_FLIP, $06 - db 8, 0, X_FLIP, $07 -; 4207 - -Facing22: ; big doll other than snorlax or lapras - db 14 ; # - db 0, 0, 0, $00 - db 0, 8, 0, $01 - db 8, 0, 0, $04 - db 8, 8, 0, $05 - db 16, 8, 0, $07 - db 24, 8, 0, $0a - db 0, 24, 0, $03 - db 0, 16, 0, $02 - db 8, 24, X_FLIP, $02 - db 8, 16, 0, $06 - db 16, 24, 0, $09 - db 16, 16, 0, $08 - db 24, 24, X_FLIP, $04 - db 24, 16, 0, $0b -; 4240 - -Facing28: ; boulder dust 1 - db 4 ; # - db 0, 0, 4, $fe - db 0, 8, 4, $fe - db 8, 0, 4, $fe - db 8, 8, 4, $fe -; 4251 - -Facing29: ; boulder dust 2 - db 4 ; # - db 0, 0, 4, $ff - db 0, 8, 4, $ff - db 8, 0, 4, $ff - db 8, 8, 4, $ff -; 4262 - -Facing30: ; 4261 - db 2 ; # - db 8, 0, 0, $00 - db 8, 8, 0 | X_FLIP, $00 -; 426b - -Facing31: ; 426a - db 2 ; # - db 9, -1, 0, $00 - db 9, 9, 0 | X_FLIP, $00 -; 4274 diff --git a/engine/games/slot_machine.asm b/engine/games/slot_machine.asm new file mode 100644 index 00000000..7c017a6a --- /dev/null +++ b/engine/games/slot_machine.asm @@ -0,0 +1,2208 @@ +SLOTS_NO_BIAS EQU -1 +SLOTS_NO_MATCH EQU -1 + +SLOTS_SEVEN EQU $00 +SLOTS_POKEBALL EQU $04 +SLOTS_CHERRY EQU $08 +SLOTS_PIKACHU EQU $0c +SLOTS_SQUIRTLE EQU $10 +SLOTS_STARYU EQU $14 + +REEL_SIZE EQU 15 + +; Constants for slot_reel offsets (see macros/wram.asm) +REEL_ACTION EQUS "(wReel1ReelAction - wReel1)" +REEL_TILEMAP_ADDR EQUS "(wReel1TilemapAddr - wReel1)" +REEL_POSITION EQUS "(wReel1Position - wReel1)" +REEL_SPIN_DISTANCE EQUS "(wReel1SpinDistance - wReel1)" +REEL_SPIN_RATE EQUS "(wReel1SpinRate - wReel1)" +REEL_OAM_ADDR EQUS "(wReel1OAMAddr - wReel1)" +REEL_X_COORD EQUS "(wReel1XCoord - wReel1)" +REEL_MANIP_COUNTER EQUS "(wReel1ManipCounter - wReel1)" +REEL_MANIP_DELAY EQUS "(wReel1ManipDelay - wReel1)" +REEL_FIELD_0B EQUS "(wReel1Field0b - wReel1)" +REEL_STOP_DELAY EQUS "(wReel1StopDelay - wReel1)" + +; SlotsJumptable constants + const_def + const SLOTS_INIT + const SLOTS_BET_AND_START + const SLOTS_WAIT_START + const SLOTS_WAIT_REEL1 + const SLOTS_WAIT_STOP_REEL1 + const SLOTS_WAIT_REEL2 + const SLOTS_WAIT_STOP_REEL2 + const SLOTS_WAIT_REEL3 + const SLOTS_WAIT_STOP_REEL3 + const SLOTS_NEXT_09 + const SLOTS_NEXT_0A + const SLOTS_NEXT_0B + const SLOTS_FLASH_IF_WIN + const SLOTS_FLASH_SCREEN + const SLOTS_GIVE_EARNED_COINS + const SLOTS_PAYOUT_TEXT_AND_ANIM + const SLOTS_PAYOUT_ANIM + const SLOTS_RESTART_OF_QUIT + const SLOTS_QUIT +SLOTS_END_LOOP_F EQU 7 + +; ReelActionJumptable constants + const_def + const REEL_ACTION_DO_NOTHING + const REEL_ACTION_STOP_REEL_IGNORE_JOYPAD + const REEL_ACTION_QUADRUPLE_RATE + const REEL_ACTION_DOUBLE_RATE + const REEL_ACTION_NORMAL_RATE + const REEL_ACTION_HALF_RATE + const REEL_ACTION_QUARTER_RATE + const REEL_ACTION_STOP_REEL1 + const REEL_ACTION_STOP_REEL2 + const REEL_ACTION_STOP_REEL3 + const REEL_ACTION_SET_UP_REEL2_SKIP_TO_7 + const REEL_ACTION_WAIT_REEL2_SKIP_TO_7 + const REEL_ACTION_FAST_SPIN_REEL2_UNTIL_LINED_UP_7S + const REEL_ACTION_UNUSED + const REEL_ACTION_CHECK_DROP_REEL + const REEL_ACTION_WAIT_DROP_REEL + const REEL_ACTION_START_SLOW_ADVANCE_REEL3 + const REEL_ACTION_WAIT_SLOW_ADVANCE_REEL3 + const REEL_ACTION_INIT_GOLEM + const REEL_ACTION_WAIT_GOLEM + const REEL_ACTION_END_GOLEM + const REEL_ACTION_INIT_CHANSEY + const REEL_ACTION_WAIT_CHANSEY + const REEL_ACTION_WAIT_EGG + const REEL_ACTION_DROP_REEL + +_SlotMachine: + ld hl, wOptions + set NO_TEXT_SCROLL, [hl] + call .InitGFX + call DelayFrame +.loop + call SlotsLoop + jr nc, .loop + call WaitSFX + ld de, SFX_QUIT_SLOTS + call PlaySFX + call WaitSFX + call ClearBGPalettes + ld hl, wOptions + res NO_TEXT_SCROLL, [hl] + ld hl, rLCDC + res rLCDC_SPRITE_SIZE, [hl] ; 8x8 + ret + +.InitGFX: + call ClearBGPalettes + call ClearTilemap + call ClearSprites + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + call DisableLCD + hlbgcoord 0, 0 + ld bc, vBGMap1 - vBGMap0 + ld a, " " + call ByteFill + ld b, SCGB_SLOT_MACHINE + call GetSGBLayout + callfar ClearSpriteAnims + ld hl, wSlots + ld bc, wSlotsDataEnd - wSlots + xor a + call ByteFill + + ld hl, Slots2LZ + ld de, vTiles0 tile $00 + call Decompress + + ld hl, Slots3LZ + ld de, vTiles0 tile $40 + call Decompress + + ld hl, Slots1LZ + ld de, vTiles2 tile $00 + call Decompress + + ld hl, Slots2LZ + ld de, vTiles2 tile $25 + call Decompress + + ld hl, SlotsTilemap + decoord 0, 0 + ld bc, SCREEN_WIDTH * 12 + call CopyBytes + + ld hl, rLCDC + set rLCDC_SPRITE_SIZE, [hl] ; 8x16 + call EnableLCD + ld hl, wSlots + ld bc, wSlotsEnd - wSlots + xor a + call ByteFill + call Slots_InitReelTiles + call Slots_GetPals + ld a, $7 + ld hl, wSpriteAnimDict + ld [hli], a + ld [hl], $40 + xor a ; SLOTS_INIT + ld [wJumptableIndex], a + ld a, SLOTS_NO_BIAS + ld [wSlotBias], a + ld de, MUSIC_GAME_CORNER + call PlayMusic + xor a + ld [wKeepSevenBiasChance], a ; 87.5% chance + call Random + and %00101010 + ret nz + ld a, 1 + ld [wKeepSevenBiasChance], a ; 12.5% chance + ret + +Slots_GetPals: + ld a, %11100100 + call DmgToCgbBGPals + lb de, %11100100, %11100100 + ldh a, [hCGB] + and a + jr nz, .cgb + lb de, %11000000, %11100100 +.cgb + call DmgToCgbObjPals + ret + +SlotsLoop: + ld a, [wJumptableIndex] + bit SLOTS_END_LOOP_F, a + jr nz, .stop + call SlotsJumptable + call Slots_SpinReels + xor a + ld [wCurSpriteOAMAddr], a + callfar DoNextFrameForFirst16Sprites + call .PrintCoinsAndPayout + call .Stubbed_Function92d3c + call DelayFrame + and a + ret + +.stop + scf + ret + +.Stubbed_Function92d3c: +; dummied out + ret + ld a, [wReel1ReelAction] + and a + ret nz + ld a, [wReel2ReelAction] + and a + ret nz + ld a, [wFirstTwoReelsMatchingSevens] + and a + jr nz, .matching_sevens + ld a, %11100100 + call DmgToCgbBGPals + ret + +.matching_sevens + ld a, [wTextDelayFrames] + and $7 + ret nz + ldh a, [rBGP] + xor %00001100 + call DmgToCgbBGPals + ret + +.PrintCoinsAndPayout: + hlcoord 5, 1 + ld de, wCoins + lb bc, PRINTNUM_LEADINGZEROS | 2, 4 + call PrintNum + hlcoord 11, 1 + ld de, wPayout + lb bc, PRINTNUM_LEADINGZEROS | 2, 4 + call PrintNum + ret + +Unreferenced_Function92d7a: +; debug function? + ld a, [wSlotBias] + add 0 + daa + ld e, a + and $f + add "0" + hlcoord 1, 0 + ld [hl], a + ld a, e + swap a + and $f + add "0" + hlcoord 0, 0 + ld [hl], a + ret + +Unreferenced_Function92d95: +; animate OAM tiles? + ld hl, wSlotsCE66 + ld a, [hl] + inc [hl] + and $7 + ret nz + ld hl, wVirtualOAMSprite16TileID + ld c, NUM_SPRITE_OAM_STRUCTS - 16 +.loop + ld a, [hl] + xor %00100000 + ld [hli], a ; tile id +rept SPRITEOAMSTRUCT_LENGTH - 1 + inc hl +endr + dec c + jr nz, .loop + ret + +SlotsJumptable: + jumptable .Jumptable, wJumptableIndex + +.Jumptable: + dw SlotsAction_Init ; 00 + dw SlotsAction_BetAndStart ; 01 + dw SlotsAction_WaitStart ; 02 + dw SlotsAction_WaitReel1 ; 03 + dw SlotsAction_WaitStopReel1 ; 04 + dw SlotsAction_WaitReel2 ; 05 + dw SlotsAction_WaitStopReel2 ; 06 + dw SlotsAction_WaitReel3 ; 07 + dw SlotsAction_WaitStopReel3 ; 08 + dw SlotsAction_Next ; 09 + dw SlotsAction_Next ; 0a + dw SlotsAction_Next ; 0b + dw SlotsAction_FlashIfWin ; 0c + dw SlotsAction_FlashScreen ; 0d + dw SlotsAction_GiveEarnedCoins ; 0e + dw SlotsAction_PayoutTextAndAnim ; 0f + dw SlotsAction_PayoutAnim ; 10 + dw SlotsAction_RestartOrQuit ; 11 + dw SlotsAction_Quit ; 12 + +SlotsAction_Next: + ld hl, wJumptableIndex + inc [hl] + ret + +SlotsAction_Init: + call SlotsAction_Next + xor a + ld [wFirstTwoReelsMatching], a + ld [wFirstTwoReelsMatchingSevens], a + ld a, SLOTS_NO_MATCH + ld [wSlotMatched], a + ret + +SlotsAction_BetAndStart: + call Slots_AskBet + jr nc, .proceed + ld a, SLOTS_QUIT + ld [wJumptableIndex], a + ret + +.proceed + call SlotsAction_Next + call Slots_IlluminateBetLights + call Slots_InitBias + ld a, 32 + ld [wSlotsDelay], a + ld a, REEL_ACTION_NORMAL_RATE + ld [wReel1ReelAction], a + ld [wReel2ReelAction], a + ld [wReel3ReelAction], a + ld a, 4 + ld [wReel1ManipCounter], a + ld [wReel2ManipCounter], a + ld [wReel3ManipCounter], a + call WaitSFX + ld a, SFX_SLOT_MACHINE_START + call Slots_PlaySFX + ret + +SlotsAction_WaitStart: + ld hl, wSlotsDelay + ld a, [hl] + and a + jr z, .proceed + dec [hl] + ret + +.proceed + call SlotsAction_Next + xor a + ldh [hJoypadSum], a + ret + +SlotsAction_WaitReel1: + ld hl, hJoypadSum + ld a, [hl] + and A_BUTTON + ret z + call SlotsAction_Next + call Slots_StopReel1 + ld [wReel1ReelAction], a +SlotsAction_WaitStopReel1: + ld a, [wReel1ReelAction] + cp REEL_ACTION_DO_NOTHING + ret nz + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + ld bc, wReel1 + ld de, wReel1Stopped + call Slots_LoadReelState + call SlotsAction_Next + xor a + ldh [hJoypadSum], a +SlotsAction_WaitReel2: + ld hl, hJoypadSum + ld a, [hl] + and A_BUTTON + ret z + call SlotsAction_Next + call Slots_StopReel2 + ld [wReel2ReelAction], a +SlotsAction_WaitStopReel2: + ld a, [wReel2ReelAction] + cp REEL_ACTION_DO_NOTHING + ret nz + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + ld bc, wReel2 + ld de, wReel2Stopped + call Slots_LoadReelState + call SlotsAction_Next + xor a + ldh [hJoypadSum], a +SlotsAction_WaitReel3: + ld hl, hJoypadSum + ld a, [hl] + and A_BUTTON + ret z + call SlotsAction_Next + call Slots_StopReel3 + ld [wReel3ReelAction], a +SlotsAction_WaitStopReel3: + ld a, [wReel3ReelAction] + cp REEL_ACTION_DO_NOTHING + ret nz + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + ld bc, wReel3 + ld de, wReel3Stopped + call Slots_LoadReelState + call SlotsAction_Next + xor a + ldh [hJoypadSum], a + ret + +SlotsAction_FlashIfWin: + ld a, [wSlotMatched] + cp SLOTS_NO_MATCH + jr nz, .GotIt + call SlotsAction_Next + call SlotsAction_Next + ret + +.GotIt: + call SlotsAction_Next + ld a, 16 + ld [wSlotsDelay], a +SlotsAction_FlashScreen: + ld hl, wSlotsDelay + ld a, [hl] + and a + jr z, .done + dec [hl] + srl a + ret z + + ldh a, [rOBP0] + xor $ff + ld e, a + ld d, a + call DmgToCgbObjPals + ret + +.done + call Slots_GetPals + call SlotsAction_Next + ret + +SlotsAction_GiveEarnedCoins: + xor a + ld [wFirstTwoReelsMatching], a + ld [wFirstTwoReelsMatchingSevens], a + ld a, %11100100 + call DmgToCgbBGPals + call Slots_GetPayout + xor a + ld [wSlotsDelay], a + call SlotsAction_Next + ret + +SlotsAction_PayoutTextAndAnim: + call Slots_PayoutText + call SlotsAction_Next +SlotsAction_PayoutAnim: + ld hl, wSlotsDelay + ld a, [hl] + inc [hl] + and $1 + ret z + ld hl, wPayout + ld a, [hli] + ld d, a + or [hl] + jr z, .done + ld e, [hl] + dec de + ld [hl], e + dec hl + ld [hl], d + ld hl, wCoins + ld d, [hl] + inc hl + ld e, [hl] + call Slots_CheckCoinCaseFull + jr c, .okay + inc de +.okay + ld [hl], e + dec hl + ld [hl], d + ld a, [wSlotsDelay] + and $7 + ret z ; ret nz would be more appropriate + ld de, SFX_GET_COIN_FROM_SLOTS + call PlaySFX + ret + +.done + call SlotsAction_Next + ret + +SlotsAction_RestartOrQuit: + call Slots_DeilluminateBetLights + call WaitPressAorB_BlinkCursor + call Slots_AskPlayAgain + jr c, .exit_slots + ld a, SLOTS_INIT + ld [wJumptableIndex], a + ret + +.exit_slots + ld a, SLOTS_QUIT + ld [wJumptableIndex], a + ret + +SlotsAction_Quit: + ld hl, wJumptableIndex + set SLOTS_END_LOOP_F, [hl] + ret + +Slots_LoadReelState: + push de + call Slots_GetCurrentReelState + pop de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ret + +Slots_CheckCoinCaseFull: + ld a, d + cp HIGH(MAX_COINS) + jr c, .not_full + ld a, e + cp LOW(MAX_COINS) + jr c, .not_full + scf + ret + +.not_full + and a + ret + +Slots_GetCurrentReelState: + ld hl, REEL_POSITION + add hl, bc + ld a, [hl] + and a + jr nz, .okay + ld a, $f +.okay + dec a + and $f + ld e, a + ld d, $0 + ld hl, REEL_TILEMAP_ADDR + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + add hl, de + ret + +Slots_StopReel1: +; Always set the REEL_ACTION_STOP_REEL1 action. + ld a, REEL_ACTION_STOP_REEL1 + ret + +Slots_StopReel2: +; As long as, the following three meet, there's a 31.25% chance +; to set action REEL_ACTION_SET_UP_REEL2_SKIP_TO_7: +; - Bet is >= 2 coins +; - There's a 7 symbol visible in reel #1 +; - Current spin isn't biased or is biased towards SEVEN +; In any other case, REEL_ACTION_STOP_REEL2 is set. + + ld a, [wSlotBet] + cp $2 + jr c, .dont_jump + ld a, [wSlotBias] + and a + jr z, .skip + cp SLOTS_NO_BIAS + jr nz, .dont_jump +.skip + call .CheckReel1ForASeven + jr nz, .dont_jump + call Random + cp 31 percent + 1 + jr nc, .dont_jump + ld a, REEL_ACTION_SET_UP_REEL2_SKIP_TO_7 + ret + +.dont_jump + ld a, REEL_ACTION_STOP_REEL2 + ret + +.CheckReel1ForASeven: + ld a, [wReel1Stopped] + and a + ret z + ld a, [wReel1Stopped + 1] + and a + ret z + ld a, [wReel1Stopped + 2] + and a + ret + +Slots_StopReel3: +; If no matching SEVEN symbols in reels #1 and #2: +; - REEL_ACTION_STOP_REEL3, 100% + +; If matching SEVEN symbols and NO bias to SEVEN: +; - REEL_ACTION_STOP_REEL3, 37.5% +; - REEL_ACTION_START_SLOW_ADVANCE_REEL3, 31.3% +; - REEL_ACTION_INIT_GOLEM, 31.3% +; - REEL_ACTION_INIT_CHANSEY, 0% + +; If matching SEVEN symbols and bias to SEVEN: +; - REEL_ACTION_STOP_REEL3, 29.7% +; - REEL_ACTION_START_SLOW_ADVANCE_REEL3, 23.4% +; - REEL_ACTION_INIT_GOLEM, 23.4% +; - REEL_ACTION_INIT_CHANSEY, 23.4% + + ld a, [wFirstTwoReelsMatching] + and a + jr z, .stop + ld a, [wFirstTwoReelsMatchingSevens] + and a + jr z, .stop + ld a, [wSlotBias] + and a + jr nz, .biased + call Random + cp 71 percent - 1 + jr nc, .stop + cp 47 percent + 1 + jr nc, .slow_advance + cp 24 percent - 1 + jr nc, .golem + ld a, REEL_ACTION_INIT_CHANSEY + ret + +.biased + call Random + cp 63 percent + jr nc, .stop + cp 31 percent + 1 + jr nc, .slow_advance +.golem + ld a, REEL_ACTION_INIT_GOLEM + ret + +.slow_advance + ld a, REEL_ACTION_START_SLOW_ADVANCE_REEL3 + ret + +.stop + ld a, REEL_ACTION_STOP_REEL3 + ret + +Slots_InitReelTiles: + ld bc, wReel1 + ld hl, REEL_OAM_ADDR + add hl, bc + ld de, wVirtualOAMSprite16 + ld [hl], e + inc hl + ld [hl], d + ld hl, REEL_TILEMAP_ADDR + add hl, bc + ld de, Reel1Tilemap + ld [hl], e + inc hl + ld [hl], d + ld hl, REEL_X_COORD + add hl, bc + ld [hl], 6 * 8 + call .OAM + + ld bc, wReel2 + ld hl, REEL_OAM_ADDR + add hl, bc + ld de, wVirtualOAMSprite24 + ld [hl], e + inc hl + ld [hl], d + ld hl, REEL_TILEMAP_ADDR + add hl, bc + ld de, Reel2Tilemap + ld [hl], e + inc hl + ld [hl], d + ld hl, REEL_X_COORD + add hl, bc + ld [hl], 10 * 8 + call .OAM + + ld bc, wReel3 + ld hl, REEL_OAM_ADDR + add hl, bc + ld de, wVirtualOAMSprite32 + ld [hl], e + inc hl + ld [hl], d + ld hl, REEL_TILEMAP_ADDR + add hl, bc + ld de, Reel3Tilemap + ld [hl], e + inc hl + ld [hl], d + ld hl, REEL_X_COORD + add hl, bc + ld [hl], 14 * 8 + call .OAM + ret + +.OAM: + ld hl, REEL_ACTION + add hl, bc + ld [hl], REEL_ACTION_DO_NOTHING + ld hl, REEL_POSITION + add hl, bc + ld [hl], REEL_SIZE - 1 + ld hl, REEL_SPIN_DISTANCE + add hl, bc + ld [hl], REEL_ACTION_DO_NOTHING + call Slots_UpdateReelPositionAndOAM + ret + +Slots_SpinReels: + ld bc, wReel1 + call .SpinReel + ld bc, wReel2 + call .SpinReel + ld bc, wReel3 + call .SpinReel + ret + +.SpinReel: + ld hl, REEL_SPIN_DISTANCE + add hl, bc + ld a, [hl] + and $f + jr nz, .skip + call ReelActionJumptable +.skip + ld hl, REEL_SPIN_RATE + add hl, bc + ld a, [hl] + and a + ret z + ld d, a + ld hl, REEL_SPIN_DISTANCE + add hl, bc + add [hl] + ld [hl], a + and $f + jr z, Slots_UpdateReelPositionAndOAM + ld hl, REEL_OAM_ADDR + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld e, $8 +.loop + ld a, [hl] + add d + ld [hli], a + inc hl + inc hl + inc hl + dec e + jr nz, .loop + ret + +Slots_UpdateReelPositionAndOAM: + ld hl, REEL_X_COORD + add hl, bc + ld a, [hl] + ld [wCurReelXCoord], a + ld a, 10 * 8 + ld [wCurReelYCoord], a + ld hl, REEL_POSITION + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, REEL_TILEMAP_ADDR + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + call .LoadOAM + ld hl, REEL_POSITION + add hl, bc + ld a, [hl] + inc a + and $f + cp REEL_SIZE + jr nz, .load + xor a +.load + ld [hl], a + ret + +.LoadOAM: + ld hl, REEL_OAM_ADDR + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a +.loop + ld a, [wCurReelYCoord] + ld [hli], a ; y + ld a, [wCurReelXCoord] + ld [hli], a ; x + ld a, [de] + ld [hli], a ; tile id + srl a + srl a + set OAM_PRIORITY, a + ld [hli], a ; attributes + + ld a, [wCurReelYCoord] + ld [hli], a ; y + ld a, [wCurReelXCoord] + add 1 * TILE_WIDTH + ld [hli], a ; x + ld a, [de] + inc a + inc a + ld [hli], a ; tile id + srl a + srl a + set OAM_PRIORITY, a + ld [hli], a ; attributes + inc de + ld a, [wCurReelYCoord] + sub 2 * TILE_WIDTH + ld [wCurReelYCoord], a + cp 2 * TILE_WIDTH + jr nz, .loop + ret + +Unreferenced_Function93127: + push hl + srl a + srl a + add LOW(.Unknown_93137) + ld l, a + ld a, 0 + adc HIGH(.Unknown_93137) + ld h, a + ld a, [hl] + pop hl + ret + +.Unknown_93137: + db 0, 1, 2, 3, 4, 5 + +ReelActionJumptable: + ld hl, REEL_ACTION + 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 + +.Jumptable: + dw ReelAction_DoNothing ; 00 + dw ReelAction_StopReelIgnoreJoypad ; 01 + dw ReelAction_QuadrupleRate ; 02 + dw ReelAction_DoubleRate ; 03 + dw ReelAction_NormalRate ; 04 + dw ReelAction_HalfRate ; 05 + dw ReelAction_QuarterRate ; 06 + dw ReelAction_StopReel1 ; 07 + dw ReelAction_StopReel2 ; 08 + dw ReelAction_StopReel3 ; 09 + dw ReelAction_SetUpReel2SkipTo7 ; 0a + dw ReelAction_WaitReel2SkipTo7 ; 0b + dw ReelAction_FastSpinReel2UntilLinedUp7s ; 0c + dw ReelAction_Unused ; 0d + dw ReelAction_CheckDropReel ; 0e + dw ReelAction_WaitDropReel ; 0f + dw ReelAction_StartSlowAdvanceReel3 ; 10 + dw ReelAction_WaitSlowAdvanceReel3 ; 11 + dw ReelAction_InitGolem ; 12 + dw ReelAction_WaitGolem ; 13 + dw ReelAction_EndGolem ; 14 + dw ReelAction_InitChansey ; 15 + dw ReelAction_WaitChansey ; 16 + dw ReelAction_WaitEgg ; 17 + dw ReelAction_DropReel ; 18 + +ReelAction_DoNothing: + ret + +ReelAction_QuadrupleRate: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 16 + ret + +ReelAction_DoubleRate: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 8 + ret + +ReelAction_NormalRate: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 4 + ret + +ReelAction_HalfRate: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 2 + ret + +ReelAction_QuarterRate: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 1 + ret + +Slots_StopReel: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 + ld hl, REEL_ACTION + add hl, bc + ld [hl], REEL_ACTION_STOP_REEL_IGNORE_JOYPAD + ld hl, REEL_STOP_DELAY + add hl, bc + ld [hl], 3 +ReelAction_StopReelIgnoreJoypad: + ld hl, REEL_STOP_DELAY + add hl, bc + ld a, [hl] + and a + jr z, .EndReel + dec [hl] + ret + +.EndReel: + ld hl, REEL_ACTION + add hl, bc + ld a, REEL_ACTION_DO_NOTHING + ld [hl], a + ret + +ReelAction_StopReel1: +; If no bias: don't manipulate reel. +; If bias: manipulate reel up to wReel1ManipCounter (i.e. 4) slots, +; stoping early if the biased symbol shows up anywhere in reel #1, +; even if the current bet won't allow lining it up. + + ld a, [wSlotBias] + cp SLOTS_NO_BIAS + jr z, .NoBias + ld hl, REEL_MANIP_COUNTER + add hl, bc + ld a, [hl] + and a + jr z, .NoBias + dec [hl] + call .CheckForBias + ret nz +.NoBias: + call Slots_StopReel + ret + +.CheckForBias: + call Slots_GetCurrentReelState + ld a, [wSlotBias] + ld e, a + ld a, [hli] + cp e + ret z + ld a, [hli] + cp e + ret z + ld a, [hl] + cp e + ret + +ReelAction_StopReel2: +; If no bias: don't manipulate reel. +; If bias: manipulate reel up to wReel2ManipCounter (i.e. 4) slots, +; stoping early if the biased symbol is lined up in the first two +; reels, according to the lines that the current bet allows. + + call Slots_CheckMatchedFirstTwoReels + jr nc, .nope + ld a, [wSlotBuildingMatch] + ld hl, wSlotBias + cp [hl] + jr z, .NoBias +.nope + ld a, [wSlotBias] + cp SLOTS_NO_BIAS + jr z, .NoBias + ld hl, REEL_MANIP_COUNTER + add hl, bc + ld a, [hl] + and a + jr z, .NoBias + dec [hl] + ret + +.NoBias: + call Slots_StopReel + ret + +ReelAction_StopReel3: +; Manipulate the reel up to wReel3ManipCounter (i.e. 4) slots, +; stopping early if the bias symbol is lined up for a win. +; If not biased to any symbols, stop as soon as nothing is lined up. + + call Slots_CheckMatchedAllThreeReels + jr nc, .NoMatch + ld hl, wSlotBias + cp [hl] + jr z, .NoBias + ld hl, REEL_MANIP_COUNTER + add hl, bc + ld a, [hl] + and a + ret z + dec [hl] + ret + +.NoMatch: + ld a, [wSlotBias] + cp SLOTS_NO_BIAS + jr z, .NoBias + ld hl, REEL_MANIP_COUNTER + add hl, bc + ld a, [hl] + and a + jr z, .NoBias + dec [hl] + ret + +.NoBias: + call Slots_StopReel + ret + +ReelAction_SetUpReel2SkipTo7: +; Unique reel 2 action (see Slots_StopReel2) +; Ensures that 7 symbols become lined up in the first two reels, +; but more often than not, this is only a way to get our hopes up, as +; it makes exciting reel #3 modes with no success hope more common. + + call Slots_CheckMatchedFirstTwoReels + jr nc, .no_match + ld a, [wFirstTwoReelsMatchingSevens] + and a + jr z, .no_match + call Slots_StopReel + ret + +.no_match + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_WAIT_REEL2_SKIP_TO_7 + ld hl, REEL_MANIP_DELAY + add hl, bc + ld [hl], 32 + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 + ret + +ReelAction_WaitReel2SkipTo7: + ld hl, REEL_MANIP_DELAY + add hl, bc + ld a, [hl] + and a + jr z, .asm_9326b + dec [hl] + ret + +.asm_9326b + ld a, SFX_THROW_BALL + call Slots_PlaySFX + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_FAST_SPIN_REEL2_UNTIL_LINED_UP_7S + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 8 + ret + +ReelAction_FastSpinReel2UntilLinedUp7s: + call Slots_CheckMatchedFirstTwoReels + ret nc + ld a, [wFirstTwoReelsMatchingSevens] + and a + ret z + call Slots_StopReel + ret + +ReelAction_InitGolem: +; Ensures SEVENs are lined up if there's bias to SEVEN. +; Ensures nothing is lined up if there's no bias symbols. +; No other bias symbols are compatible with this mode. + +; This is achieved by throwing Golem until the desired result +; is produced. The amount of Golem thrown can be anywhere from +; 1 to 14 for SEVEN bias, and 4-8 for no bias. + + call Slots_CheckMatchedAllThreeReels + ret c + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + call Slots_WaitSFX + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_WAIT_GOLEM + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 + call Slots_GetNumberOfGolems + push bc + push af + depixel 12, 13 + ld a, SPRITE_ANIM_INDEX_SLOTS_GOLEM + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + pop af + ld [hl], a + pop bc + xor a + ld [wSlotsDelay], a +ReelAction_WaitGolem: + ld a, [wSlotsDelay] + cp 2 + jr z, .two + cp 1 + jr z, .one + ret + +.two + call Slots_CheckMatchedAllThreeReels + call Slots_StopReel + ret + +.one + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_END_GOLEM + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 8 + ret + +ReelAction_EndGolem: + xor a + ld [wSlotsDelay], a + ld hl, REEL_ACTION + add hl, bc + dec [hl] ; REEL_ACTION_WAIT_GOLEM + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 + ret + +ReelAction_InitChansey: +; Ensures the lining up of SEVEN symbols, but this mode is only possible +; when there is bias to SEVEN symbols (and even then, it's still rare). +; Chansey releases and egg and reel #3 is made to advance 17 slots very +; quickly as many times as necessary for the match to SEVENs to show up. + + call Slots_CheckMatchedAllThreeReels + ret c + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + call Slots_WaitSFX + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_WAIT_CHANSEY + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 + push bc + depixel 12, 0 + ld a, SPRITE_ANIM_INDEX_SLOTS_CHANSEY + call InitSpriteAnimStruct + pop bc + xor a + ld [wSlotsDelay], a + ret + +ReelAction_WaitChansey: + ld a, [wSlotsDelay] + and a + ret z + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_WAIT_EGG + ld a, 2 + ld [wSlotsDelay], a +ReelAction_WaitEgg: + ld a, [wSlotsDelay] + cp $4 + ret c + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_DROP_REEL + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 16 + ld hl, REEL_MANIP_DELAY + add hl, bc + ld [hl], 17 +ReelAction_DropReel: + ld hl, REEL_MANIP_DELAY + add hl, bc + ld a, [hl] + and a + jr z, .check_match + dec [hl] + ret + +.check_match + call Slots_CheckMatchedAllThreeReels + jr nc, .EggAgain + and a + jr nz, .EggAgain + ld a, 5 + ld [wSlotsDelay], a + call Slots_StopReel + ret + +.EggAgain: + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 + ld hl, REEL_ACTION + add hl, bc + dec [hl] + dec [hl] ; REEL_ACTION_WAIT_CHANSEY + ld a, 1 + ld [wSlotsDelay], a + ret + +ReelAction_Unused: + call Slots_CheckMatchedAllThreeReels + ret c + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + call Slots_WaitSFX + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_CHECK_DROP_REEL + call Slots_GetNumberOfGolems + ld hl, REEL_MANIP_DELAY + add hl, bc + ld [hl], a +ReelAction_CheckDropReel: + ld hl, REEL_MANIP_DELAY + add hl, bc + ld a, [hl] + and a + jr nz, .spin + call Slots_CheckMatchedAllThreeReels + call Slots_StopReel + ret + +.spin + dec [hl] + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_WAIT_DROP_REEL + ld hl, REEL_FIELD_0B + add hl, bc + ld [hl], 32 + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 0 +ReelAction_WaitDropReel: + ld hl, REEL_FIELD_0B + add hl, bc + ld a, [hl] + and a + jr z, .DropReel + dec [hl] + ret + +.DropReel: + ld hl, REEL_ACTION + add hl, bc + dec [hl] + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 8 + ret + +ReelAction_StartSlowAdvanceReel3: +; Ensures SEVENs are lined up if there's bias to SEVEN. +; Ensures nothing is lined up if there's no bias symbols. +; No other bias symbols are compatible with this mode. + +; This is achieved by slowly advancing the reel a full round, +; plus any necessary slot until the desired result is produced. + + call Slots_CheckMatchedAllThreeReels + ret c + ld a, SFX_STOP_SLOT + call Slots_PlaySFX + call Slots_WaitSFX + ld hl, REEL_SPIN_RATE + add hl, bc + ld [hl], 1 + ld hl, REEL_ACTION + add hl, bc + inc [hl] ; REEL_ACTION_WAIT_SLOW_ADVANCE_REEL3 + ld hl, REEL_MANIP_DELAY + add hl, bc + ld [hl], 16 +ReelAction_WaitSlowAdvanceReel3: + ld hl, REEL_MANIP_DELAY + add hl, bc + ld a, [hl] + and a + jr z, .check1 + dec [hl] +.play_sfx + ld a, SFX_GOT_SAFARI_BALLS + call Slots_PlaySFX + ret + +.check1 + ld a, [wSlotBias] + and a + jr nz, .check2 + call Slots_CheckMatchedAllThreeReels + jr nc, .play_sfx + and a + jr nz, .play_sfx + call Slots_StopReel + call WaitSFX + ret + +.check2 + call Slots_CheckMatchedAllThreeReels + jr c, .play_sfx + call Slots_StopReel + call WaitSFX + ret + +Slots_CheckMatchedFirstTwoReels: + xor a + ld [wFirstTwoReelsMatching], a + ld [wFirstTwoReelsMatchingSevens], a + call Slots_GetCurrentReelState + call Slots_CopyReelState + ld a, [wSlotBet] + and 3 + ld e, a + ld d, 0 + ld hl, .Jumptable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .return + push de + jp hl + +.return + ld a, [wFirstTwoReelsMatching] + and a + ret z + scf + ret + +.Jumptable: + dw .zero + dw .one + dw .two + dw .three + +.three + call .CheckUpwardsDiag + call .CheckDownwardsDiag + +.two + call .CheckBottomRow + call .CheckTopRow + +.one + call .CheckMiddleRow + +.zero + ret + +.CheckBottomRow: + ld hl, wCurReelStopped + ld a, [wReel1Stopped] + cp [hl] + call z, .StoreResult + ret + +.CheckUpwardsDiag: + ld hl, wCurReelStopped + 1 + ld a, [wReel1Stopped] + cp [hl] + call z, .StoreResult + ret + +.CheckMiddleRow: + ld hl, wCurReelStopped + 1 + ld a, [wReel1Stopped + 1] + cp [hl] + call z, .StoreResult + ret + +.CheckDownwardsDiag: + ld hl, wCurReelStopped + 1 + ld a, [wReel1Stopped + 2] + cp [hl] + call z, .StoreResult + ret + +.CheckTopRow: + ld hl, wCurReelStopped + 2 + ld a, [wReel1Stopped + 2] + cp [hl] + call z, .StoreResult + ret + +.StoreResult: + ld [wSlotBuildingMatch], a + and a + jr nz, .matching_sevens + ld a, 1 + ld [wFirstTwoReelsMatchingSevens], a + +.matching_sevens + ld a, 1 + ld [wFirstTwoReelsMatching], a + ret + +Slots_CheckMatchedAllThreeReels: + ld a, SLOTS_NO_MATCH + ld [wSlotMatched], a + call Slots_GetCurrentReelState + call Slots_CopyReelState + ld a, [wSlotBet] + and 3 + ld e, a + ld d, 0 + ld hl, .Jumptable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .return + push de + jp hl + +.return + ld a, [wSlotMatched] + cp SLOTS_NO_MATCH + jr nz, .matched_nontrivial + and a + ret + +.matched_nontrivial + scf + ret + +.Jumptable: + dw .zero + dw .one + dw .two + dw .three + +.three + call .CheckUpwardsDiag + call .CheckDownwardsDiag + +.two + call .CheckBottomRow + call .CheckTopRow + +.one + call .CheckMiddleRow + +.zero + ret + +.CheckBottomRow: + ld hl, wCurReelStopped + ld a, [wReel1Stopped] + cp [hl] + ret nz + ld hl, wReel2Stopped + cp [hl] + call z, .StoreResult + ret + +.CheckUpwardsDiag: + ld hl, wCurReelStopped + 2 + ld a, [wReel1Stopped] + cp [hl] + ret nz + ld hl, wReel2Stopped + 1 + cp [hl] + call z, .StoreResult + ret + +.CheckMiddleRow: + ld hl, wCurReelStopped + 1 + ld a, [wReel1Stopped + 1] + cp [hl] + ret nz + ld hl, wReel2Stopped + 1 + cp [hl] + call z, .StoreResult + ret + +.CheckDownwardsDiag: + ld hl, wCurReelStopped + ld a, [wReel1Stopped + 2] + cp [hl] + ret nz + ld hl, wReel2Stopped + 1 + cp [hl] + call z, .StoreResult + ret + +.CheckTopRow: + ld hl, wCurReelStopped + 2 + ld a, [wReel1Stopped + 2] + cp [hl] + ret nz + ld hl, wReel2Stopped + 2 + cp [hl] + call z, .StoreResult + ret + +.StoreResult: + ld [wSlotMatched], a + ret + +Slots_CopyReelState: + ld de, wCurReelStopped + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ret + +Slots_GetNumberOfGolems: + ld hl, REEL_POSITION + add hl, bc + ld a, [hl] + push af + push hl + call .Check7Bias + pop hl + pop af + ld [hl], a + ld a, e + ret + +.Check7Bias: + ld a, [wSlotBias] + and a + jr nz, .not_biased_to_seven + ld e, $0 +.loop1 + ld hl, REEL_POSITION + add hl, bc + inc [hl] + inc e + push de + call Slots_CheckMatchedAllThreeReels + pop de + jr nc, .loop1 + and a + jr nz, .loop1 + ret + +.not_biased_to_seven + call Random + and $7 + cp $8 / 2 ; 50% + jr c, .not_biased_to_seven + ld e, a +.loop2 + ld a, e + inc e + ld hl, REEL_POSITION + add hl, bc + add [hl] + ld [hl], a + push de + call Slots_CheckMatchedAllThreeReels + pop de + jr c, .loop2 + ret + +Slots_InitBias: + ld a, [wSlotBias] + and a + ret z + ld hl, .Normal + ld a, [wScriptVar] + and a + jr z, .okay + ld hl, .Lucky +.okay + call Random + ld c, a +.loop + ld a, [hli] + cp c + jr nc, .done + inc hl + jr .loop + +.done + ld a, [hl] + ld [wSlotBias], a + ret + +.Normal: + db 1 percent - 1, SLOTS_SEVEN + db 1 percent + 1, SLOTS_POKEBALL + db 4 percent, SLOTS_STARYU + db 8 percent, SLOTS_SQUIRTLE + db 16 percent, SLOTS_PIKACHU + db 19 percent, SLOTS_CHERRY + db 100 percent, SLOTS_NO_BIAS + +.Lucky: + db 1 percent, SLOTS_SEVEN + db 1 percent + 1, SLOTS_POKEBALL + db 3 percent + 1, SLOTS_STARYU + db 6 percent + 1, SLOTS_SQUIRTLE + db 12 percent, SLOTS_PIKACHU + db 31 percent + 1, SLOTS_CHERRY + db 100 percent, SLOTS_NO_BIAS + +Slots_IlluminateBetLights: + ld b, $14 ; turned on + ld a, [wSlotBet] + dec a + jr z, Slots_Lights1OnOff + dec a + jr z, Slots_Lights2OnOff + jr Slots_Lights3OnOff + +Slots_DeilluminateBetLights: + ld b, $23 ; turned off +Slots_Lights3OnOff: + hlcoord 3, 2 + call Slots_TurnLightsOnOrOff + hlcoord 3, 10 + call Slots_TurnLightsOnOrOff +Slots_Lights2OnOff: + hlcoord 3, 4 + call Slots_TurnLightsOnOrOff + hlcoord 3, 8 + call Slots_TurnLightsOnOrOff +Slots_Lights1OnOff: + hlcoord 3, 6 + +Slots_TurnLightsOnOrOff: + ld a, b + ld [hl], a + ld de, SCREEN_WIDTH / 2 + 3 + add hl, de + ld [hl], a + ld de, SCREEN_WIDTH / 2 - 3 + add hl, de + inc a + ld [hl], a + ld de, SCREEN_WIDTH / 2 + 3 + add hl, de + ld [hl], a + ret + +Slots_AskBet: +.loop + ld hl, .SlotsBetHowManyCoinsText + call PrintText + ld hl, .MenuHeader + call LoadMenuHeader + call VerticalMenu + call CloseWindow + ret c + ld a, [wMenuCursorY] + ld b, a + ld a, 4 + sub b + ld [wSlotBet], a + ld hl, wCoins + ld c, a + ld a, [hli] + and a + jr nz, .Start + ld a, [hl] + cp c + jr nc, .Start + ld hl, .SlotsNotEnoughCoinsText + call PrintText + jr .loop + +.Start: + ld hl, wCoins + 1 + ld a, [hl] + sub c + ld [hld], a + jr nc, .ok + dec [hl] +.ok + call WaitSFX + ld de, SFX_PAY_DAY + call PlaySFX + ld hl, .SlotsStartText + call PrintText + and a + ret + +.SlotsBetHowManyCoinsText: + text_far _SlotsBetHowManyCoinsText + text_end + +.SlotsStartText: + text_far _SlotsStartText + text_end + +.SlotsNotEnoughCoinsText: + text_far _SlotsNotEnoughCoinsText + text_end + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 14, 10, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR ; flags + db 3 ; items + db " 3@" + db " 2@" + db " 1@" + +Slots_AskPlayAgain: + ld hl, wCoins + ld a, [hli] + or [hl] + jr nz, .you_have_coins + ld hl, .SlotsRanOutOfCoinsText + call PrintText + ld c, 60 + call DelayFrames + jr .exit_slots + +.you_have_coins + ld hl, .SlotsPlayAgainText + call PrintText + call LoadMenuTextbox + lb bc, 14, 12 + call PlaceYesNoBox + ld a, [wMenuCursorY] + dec a + call CloseWindow + and a + jr nz, .exit_slots + and a + ret + +.exit_slots + scf + ret + +.SlotsRanOutOfCoinsText: + text_far _SlotsRanOutOfCoinsText + text_end + +.SlotsPlayAgainText: + text_far _SlotsPlayAgainText + text_end + +Slots_GetPayout: + ld a, [wSlotMatched] + cp SLOTS_NO_MATCH + jr z, .no_win + srl a + ld e, a + ld d, 0 + ld hl, .PayoutTable + add hl, de + ld a, [hli] + ld [wPayout + 1], a + ld a, [hl] + ld [wPayout], a + ret + +.PayoutTable: + dw 300 + dw 50 + dw 6 + dw 8 + dw 10 + dw 15 + +.no_win + ld hl, wPayout + xor a + ld [hli], a + ld [hl], a + ret + +Slots_PayoutText: + ld a, [wSlotMatched] + cp SLOTS_NO_MATCH + jr nz, .MatchedSomething + ld hl, .SlotsDarnText + call PrintText + ret + +.MatchedSomething: + srl a + ld e, a + ld d, 0 + ld hl, .PayoutStrings + add hl, de + add hl, de + add hl, de + ld de, wStringBuffer2 + ld bc, 4 + call CopyBytes + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .return + push de + jp hl + +.return + ld hl, .Text_PrintPayout + call PrintText + ret + +.PayoutStrings: + dbw "300@", .LinedUpSevens + dbw "50@@", .LinedUpPokeballs + dbw "6@@@", .LinedUpMonOrCherry + dbw "8@@@", .LinedUpMonOrCherry + dbw "10@@", .LinedUpMonOrCherry + dbw "15@@", .LinedUpMonOrCherry + +.Text_PrintPayout: + text_asm + ld a, [wSlotMatched] + add $25 + ldcoord_a 2, 13 + inc a + ldcoord_a 2, 14 + inc a + ldcoord_a 3, 13 + inc a + ldcoord_a 3, 14 + hlcoord 18, 17 + ld [hl], "▼" + ld hl, .SlotsLinedUpText +rept 4 + inc bc +endr + ret + +.SlotsLinedUpText: + text_far _SlotsLinedUpText + text_end + +.SlotsDarnText: + text_far _SlotsDarnText + text_end + +.LinedUpSevens: + ld a, SFX_2ND_PLACE + call Slots_PlaySFX + call WaitSFX + +; Oddly, the rarest mode (wKeepSevenBiasChance = 1) is the one with +; the worse odds to favor seven symbol streaks (12.5% vs 25%). +; it's possible that either the wKeepSevenBiasChance initialization +; or this code was intended to lead to flipped percentages. + ld a, [wKeepSevenBiasChance] + and a + jr nz, .lower_seven_streak_odds + call Random + and %0010100 + ret z ; 25% chance to stick with seven symbol bias + ld a, SLOTS_NO_BIAS + ld [wSlotBias], a + ret + +.lower_seven_streak_odds + call Random + and %0011100 + ret z ; 12.5% chance to stick with seven symbol bias + ld a, SLOTS_NO_BIAS + ld [wSlotBias], a + ret + +.LinedUpPokeballs: + ld a, SFX_3RD_PLACE + call Slots_PlaySFX + call WaitSFX + ret + +.LinedUpMonOrCherry: + ld a, SFX_PRESENT + call Slots_PlaySFX + call WaitSFX + ret + +Slots_AnimateGolem: + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + 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 + +.Jumptable: + dw .init + dw .fall + dw .roll + +.init + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + ld a, [hl] + and a + jr nz, .retain + ld a, 2 + ld [wSlotsDelay], a + ld hl, SPRITEANIMSTRUCT_INDEX + add hl, bc + ld [hl], $0 + ret + +.retain + dec [hl] + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + inc [hl] + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], $30 + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], $0 + +.fall + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + cp $20 + jr c, .play_sound + dec [hl] + ld e, a + ld d, 14 * 8 + farcall BattleAnim_Sine_e + ld a, e + ld hl, SPRITEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +.play_sound + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + inc [hl] + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld [hl], $2 + ld a, 1 + ld [wSlotsDelay], a + ld a, SFX_PLACE_PUZZLE_PIECE_DOWN + call Slots_PlaySFX + ret + +.roll + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + cp 9 * 8 + jr nc, .restart + and $3 + ret nz + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ldh [hSCY], a + ret + +.restart + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + xor a + ld [hl], a + ldh [hSCY], a + ret + +Slots_AnimateChansey: + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + 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 + +.Jumptable: + dw .walk + dw .one + dw .two + +.walk + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + inc [hl] + cp 13 * 8 + jr z, .limit + and $f + ret nz + ld de, SFX_JUMP_OVER_LEDGE + call PlaySFX + ret + +.limit + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + inc [hl] + ld a, 1 + ld [wSlotsDelay], a + +.one + ld a, [wSlotsDelay] + cp $2 + jr z, .retain + cp $5 + ret nz + ld hl, SPRITEANIMSTRUCT_INDEX + add hl, bc + ld [hl], $0 + ret + +.retain + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + inc [hl] + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], $8 +.two + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + and a + jr z, .spawn_egg + dec [hl] + ret + +.spawn_egg + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + dec [hl] + push bc + depixel 12, 13, 0, 4 + ld a, SPRITE_ANIM_INDEX_SLOTS_EGG + call InitSpriteAnimStruct + pop bc + ret + +Slots_WaitSFX: + push bc + ld c, 16 + call DelayFrames + pop bc + ret + +Slots_PlaySFX: + push de + ld e, a + ld d, 0 + call PlaySFX + pop de + ret + +; The first three positions are repeated to +; avoid needing to check indices when copying. +Reel1Tilemap: + db SLOTS_SEVEN ; 0 + db SLOTS_CHERRY ; 1 + db SLOTS_STARYU ; 2 + db SLOTS_PIKACHU ; 3 + db SLOTS_SQUIRTLE ; 4 + db SLOTS_SEVEN ; 5 + db SLOTS_CHERRY ; 6 + db SLOTS_STARYU ; 7 + db SLOTS_PIKACHU ; 8 + db SLOTS_SQUIRTLE ; 9 + db SLOTS_POKEBALL ; 10 + db SLOTS_CHERRY ; 11 + db SLOTS_STARYU ; 12 + db SLOTS_PIKACHU ; 13 + db SLOTS_SQUIRTLE ; 14 + db SLOTS_SEVEN ; 0 + db SLOTS_CHERRY ; 1 + db SLOTS_STARYU ; 2 + +Reel2Tilemap: + db SLOTS_SEVEN ; 0 + db SLOTS_PIKACHU ; 1 + db SLOTS_CHERRY ; 2 + db SLOTS_SQUIRTLE ; 3 + db SLOTS_STARYU ; 4 + db SLOTS_POKEBALL ; 5 + db SLOTS_PIKACHU ; 6 + db SLOTS_CHERRY ; 7 + db SLOTS_SQUIRTLE ; 8 + db SLOTS_STARYU ; 9 + db SLOTS_POKEBALL ; 10 + db SLOTS_PIKACHU ; 11 + db SLOTS_CHERRY ; 12 + db SLOTS_SQUIRTLE ; 13 + db SLOTS_STARYU ; 14 + db SLOTS_SEVEN ; 0 + db SLOTS_PIKACHU ; 1 + db SLOTS_CHERRY ; 2 + +Reel3Tilemap: + db SLOTS_SEVEN ; 0 + db SLOTS_PIKACHU ; 1 + db SLOTS_CHERRY ; 2 + db SLOTS_SQUIRTLE ; 3 + db SLOTS_STARYU ; 4 + db SLOTS_PIKACHU ; 5 + db SLOTS_CHERRY ; 6 + db SLOTS_SQUIRTLE ; 7 + db SLOTS_STARYU ; 8 + db SLOTS_PIKACHU ; 9 + db SLOTS_POKEBALL ; 10 + db SLOTS_CHERRY ; 11 + db SLOTS_SQUIRTLE ; 12 + db SLOTS_STARYU ; 13 + db SLOTS_PIKACHU ; 14 + db SLOTS_SEVEN ; 0 + db SLOTS_PIKACHU ; 1 + db SLOTS_CHERRY ; 2 + +SlotsTilemap: +INCBIN "gfx/slots/slots.tilemap" + +Slots1LZ: +INCBIN "gfx/slots/slots_1.2bpp.lz" + +Slots2LZ: +INCBIN "gfx/slots/slots_2.2bpp.lz" + +Slots3LZ: +INCBIN "gfx/slots/slots_3.2bpp.lz" diff --git a/engine/gfx/cgb_layouts.asm b/engine/gfx/cgb_layouts.asm new file mode 100755 index 00000000..a9a2038a --- /dev/null +++ b/engine/gfx/cgb_layouts.asm @@ -0,0 +1,865 @@ +; Replaces the functionality of sgb.asm to work with CGB hardware. + +CheckCGB: + ldh a, [hCGB] + and a + ret + +LoadSGBLayoutCGB: + ld a, b + cp SCGB_RAM + jr nz, .not_ram + ld a, [wSGBPredef] +.not_ram + cp SCGB_PARTY_MENU_HP_PALS + jp z, CGB_ApplyPartyMenuHPPals + call ResetBGPals + ld l, a + ld h, 0 + add hl, hl + ld de, .dw + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .ReturnFromJumpTable + push de + jp hl + +.ReturnFromJumpTable: + ret + +.dw + dw _CGB_BattleGrayscale + dw _CGB_BattleColors + dw _CGB_PokegearPals + dw _CGB_StatsScreenHPPals + dw _CGB_Pokedex + dw _CGB_SlotMachine + dw _CGB_BetaTitleScreen + dw _CGB_GSIntro + dw _CGB_Diploma + dw _CGB_MapPals + dw _CGB_PartyMenu + dw _CGB_Evolution + dw _CGB_GSTitleScreen + dw _CGB0d + dw _CGB_MoveList + dw _CGB_BetaPikachuMinigame + dw _CGB_PokedexSearchOption + dw _CGB_BetaPoker + dw _CGB_Pokepic + dw _CGB_MagnetTrain + dw _CGB_PackPals + dw _CGB_TrainerCard + dw _CGB_PokedexUnownMode + dw _CGB_BillsPC + dw _CGB_UnownPuzzle + dw _CGB_GamefreakLogo + dw _CGB_PlayerOrMonFrontpicPals + dw _CGB_TradeTube + dw _CGB_TrainerOrMonFrontpicPals + dw _CGB_MysteryGift + dw _CGB1e + dw _CGB_Pokedex_5_5 + +_CGB_BattleGrayscale: + ld hl, PalPacket_BattleGrayscale + 1 + ld de, wBGPals1 + ld c, 4 + call CopyPalettes + ld hl, PalPacket_BattleGrayscale + 1 + ld de, wBGPals1 palette PAL_BATTLE_BG_EXP + ld c, 4 + call CopyPalettes + ld hl, PalPacket_BattleGrayscale + 1 + ld de, wOBPals1 + ld c, 2 + call CopyPalettes + jr _CGB_FinishBattleScreenLayout + +_CGB_BattleColors: + ld de, wBGPals1 + call GetBattlemonBackpicPalettePointer + push hl + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_PLAYER + call GetEnemyFrontpicPalettePointer + push hl + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_ENEMY + ld a, [wEnemyHPPal] + ld l, a + ld h, $0 + add hl, hl + add hl, hl + ld bc, HPBarPals + add hl, bc + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_ENEMY_HP + ld a, [wPlayerHPPal] + ld l, a + ld h, $0 + add hl, hl + add hl, hl + ld bc, HPBarPals + add hl, bc + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_PLAYER_HP + ld hl, ExpBarPalette + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_BG_EXP + ld de, wOBPals1 + pop hl + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_OB_ENEMY + pop hl + call LoadPalette_White_Col1_Col2_Black ; PAL_BATTLE_OB_PLAYER + ld a, SCGB_BATTLE_COLORS + ld [wSGBPredef], a + call ApplyPals +_CGB_FinishBattleScreenLayout: + ld hl, TilesetBGPalette + 7 * 8 + ld de, wBGPals1 palette 7 + ld bc, $8 + call CopyBytes + hlcoord 0, 0, wAttrmap + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, PAL_BATTLE_BG_ENEMY_HP + call ByteFill + hlcoord 0, 4, wAttrmap + lb bc, 8, 10 + ld a, PAL_BATTLE_BG_PLAYER + call FillBoxCGB + hlcoord 10, 0, wAttrmap + lb bc, 7, 10 + ld a, PAL_BATTLE_BG_ENEMY + call FillBoxCGB + hlcoord 0, 0, wAttrmap + lb bc, 4, 10 + ld a, PAL_BATTLE_BG_ENEMY_HP + call FillBoxCGB + hlcoord 10, 7, wAttrmap + lb bc, 5, 10 + ld a, PAL_BATTLE_BG_PLAYER_HP + call FillBoxCGB + hlcoord 10, 11, wAttrmap + lb bc, 1, 9 + ld a, PAL_BATTLE_BG_EXP + call FillBoxCGB + hlcoord 0, 12, wAttrmap + ld bc, 6 * SCREEN_WIDTH + ld a, PAL_BATTLE_BG_TEXT + call ByteFill + ld hl, BattleObjectPals + ld de, wOBPals1 palette PAL_BATTLE_OB_GRAY + ld bc, 6 palettes + call CopyBytes + call ApplyAttrmap + ret + +_CGB_PokegearPals: + ld hl, PokegearPals + ld de, wBGPals1 + ld bc, 6 palettes + call CopyBytes + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_StatsScreenHPPals: + ld de, wBGPals1 + ld a, [wCurHPPal] + ld l, a + ld h, $0 + add hl, hl + add hl, hl + ld bc, HPBarPals + add hl, bc + call LoadPalette_White_Col1_Col2_Black ; hp palette + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + call LoadPalette_White_Col1_Col2_Black ; mon palette + ld hl, ExpBarPalette + call LoadPalette_White_Col1_Col2_Black ; exp palette + ld hl, StatsScreenPagePals + ld de, wBGPals1 palette 3 + ld bc, 3 palettes ; pink, green, and blue page palettes + call CopyBytes + call WipeAttrmap + + hlcoord 0, 0, wAttrmap + lb bc, 8, SCREEN_WIDTH + ld a, $1 ; mon palette + call FillBoxCGB + + hlcoord 10, 16, wAttrmap + ld bc, 10 + ld a, $2 ; exp palette + call ByteFill + + hlcoord 13, 5, wAttrmap + lb bc, 2, 2 + ld a, $3 ; pink page palette + call FillBoxCGB + + hlcoord 15, 5, wAttrmap + lb bc, 2, 2 + ld a, $4 ; green page palette + call FillBoxCGB + + hlcoord 17, 5, wAttrmap + lb bc, 2, 2 + ld a, $5 ; blue page palette + call FillBoxCGB + + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +StatsScreenPagePals: +INCLUDE "gfx/stats/pages.pal" + +StatsScreenPals: +INCLUDE "gfx/stats/stats.pal" + +_CGB_Pokedex: + call _CGB_Pokedex_Init + hlcoord 1, 1, wAttrmap + lb bc, 7, 7 + ld a, $1 + call FillBoxCGB + jp _CGB_Pokedex_Resume + +_CGB_Pokedex_5_5: + call _CGB_Pokedex_Init + hlcoord 1, 1, wAttrmap + lb bc, 5, 5 + ld a, $1 + call FillBoxCGB + jp _CGB_Pokedex_Resume + +_CGB_Pokedex_Init: + ld de, wBGPals1 + ld a, PREDEFPAL_POKEDEX + call GetPredefPal + call LoadHLPaletteIntoDE ; dex interface palette + ld a, [wCurPartySpecies] + cp $ff + jr nz, .is_pokemon + ld hl, PokedexQuestionMarkPalette + call LoadHLPaletteIntoDE ; green question mark palette + jr .got_palette + +.is_pokemon + call GetMonPalettePointer + call LoadPalette_White_Col1_Col2_Black ; mon palette +.got_palette + call WipeAttrmap + ret + +_CGB_Pokedex_Resume: + call InitPartyMenuOBPals + ld hl, PokedexCursorPalette + ld de, wOBPals1 palette 7 ; green cursor palette + ld bc, 1 palettes + call CopyBytes + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +PokedexCursorPalette: +INCLUDE "gfx/pokedex/cursor.pal" + +PokedexQuestionMarkPalette: +INCLUDE "gfx/pokedex/question_mark.pal" + +_CGB_BillsPC: + ld de, wBGPals1 + ld a, PREDEFPAL_POKEDEX + call GetPredefPal + call LoadHLPaletteIntoDE + ld a, [wCurPartySpecies] + cp $ff + jr nz, .GetMonPalette + ld hl, .BillsPCOrangePalette + call LoadHLPaletteIntoDE + jr .Resume + +.GetMonPalette: + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + call LoadPalette_White_Col1_Col2_Black +.Resume: + call WipeAttrmap + hlcoord 1, 4, wAttrmap + lb bc, 7, 7 + ld a, $1 + call FillBoxCGB + call InitPartyMenuOBPals + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +.Function9009: + ld hl, .BillsPCOrangePalette + call LoadHLPaletteIntoDE + jr .asm_95b1 + +.unused + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + call LoadPalette_White_Col1_Col2_Black +.asm_95b1 + call WipeAttrmap + hlcoord 1, 1, wAttrmap + lb bc, 7, 7 + ld a, $1 + call FillBoxCGB + call InitPartyMenuOBPals + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +.BillsPCOrangePalette: +INCLUDE "gfx/pc/orange.pal" + +_CGB_PokedexUnownMode: + ld de, wBGPals1 + ld a, PREDEFPAL_POKEDEX + call GetPredefPal + call LoadHLPaletteIntoDE + ld a, [wCurPartySpecies] + call GetMonPalettePointer + call LoadPalette_White_Col1_Col2_Black + call WipeAttrmap + hlcoord 7, 5, wAttrmap + lb bc, 7, 7 + ld a, $1 + call FillBoxCGB + call InitPartyMenuOBPals + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_SlotMachine: + ld hl, SlotMachinePals + ld de, wBGPals1 + ld bc, 16 palettes + call CopyBytes + call WipeAttrmap + hlcoord 0, 2, wAttrmap + lb bc, 10, 3 + ld a, $2 + call FillBoxCGB + hlcoord 17, 2, wAttrmap + lb bc, 10, 3 + ld a, $2 + call FillBoxCGB + hlcoord 0, 4, wAttrmap + lb bc, 6, 3 + ld a, $3 + call FillBoxCGB + hlcoord 17, 4, wAttrmap + lb bc, 6, 3 + ld a, $3 + call FillBoxCGB + hlcoord 0, 6, wAttrmap + lb bc, 2, 3 + ld a, $4 + call FillBoxCGB + hlcoord 17, 6, wAttrmap + lb bc, 2, 3 + ld a, $4 + call FillBoxCGB + hlcoord 4, 2, wAttrmap + lb bc, 2, 12 + ld a, $1 + call FillBoxCGB + hlcoord 3, 2, wAttrmap + lb bc, 10, 1 + ld a, $1 + call FillBoxCGB + hlcoord 16, 2, wAttrmap + lb bc, 10, 1 + ld a, $1 + call FillBoxCGB + hlcoord 0, 12, wAttrmap + ld bc, $78 + ld a, $7 + call ByteFill + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_BetaTitleScreen: + ld hl, PalPacket_BetaTitleScreen + 1 + call CopyFourPalettes + call WipeAttrmap + ld de, wOBPals1 + ld a, PREDEFPAL_PACK + call GetPredefPal + call LoadHLPaletteIntoDE + hlcoord 0, 6, wAttrmap + lb bc, 12, SCREEN_WIDTH + ld a, $1 + call FillBoxCGB + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_GSIntro: + ld b, 0 + ld hl, .Jumptable + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.Jumptable: + dw .ShellderLaprasScene + dw .JigglypuffPikachuScene + dw .StartersCharizardScene + +.ShellderLaprasScene: + ld hl, .ShellderLaprasBGPalette + ld de, wBGPals1 + call LoadHLPaletteIntoDE + ld hl, .ShellderLaprasOBPals + ld de, wOBPals1 + ld bc, 2 palettes + call CopyBytes + call WipeAttrmap + ret + +.ShellderLaprasBGPalette: + RGB 19, 31, 19 + RGB 18, 23, 31 + RGB 11, 21, 28 + RGB 04, 16, 24 + +.ShellderLaprasOBPals: + RGB 29, 29, 29 + RGB 20, 19, 20 + RGB 19, 06, 04 + RGB 03, 04, 06 + + RGB 31, 31, 31 + RGB 31, 31, 31 + RGB 31, 00, 00 + RGB 03, 04, 06 + +.JigglypuffPikachuScene: + ld de, wBGPals1 + ld a, PREDEFPAL_GS_INTRO_JIGGLYPUFF_PIKACHU_BG + call GetPredefPal + call LoadHLPaletteIntoDE + + ld de, wOBPals1 + ld a, PREDEFPAL_GS_INTRO_JIGGLYPUFF_PIKACHU_OB + call GetPredefPal + call LoadHLPaletteIntoDE + call WipeAttrmap + ret + +.StartersCharizardScene: + ld hl, PalPacket_Pack + 1 + call CopyFourPalettes + ld de, wOBPals1 + ld a, PREDEFPAL_GS_INTRO_STARTERS_TRANSITION + call GetPredefPal + call LoadHLPaletteIntoDE + call WipeAttrmap + ret + +_CGB_BetaPoker: + ld hl, BetaPokerPals + ld de, wBGPals1 + ld bc, 5 palettes + call CopyBytes + call ApplyPals + call WipeAttrmap + call ApplyAttrmap + ret + +_CGB_Diploma: + ld hl, DiplomaPalettes + ld de, wBGPals1 + ld bc, 16 palettes + call CopyBytes + + ld hl, PalPacket_Diploma + 1 + call CopyFourPalettes + call WipeAttrmap + call ApplyAttrmap + ret + +_CGB_MapPals: + call LoadMapPals + ld a, SCGB_MAPPALS + ld [wSGBPredef], a + ret + +_CGB_PartyMenu: + ld hl, PalPacket_PartyMenu + 1 + call CopyFourPalettes + call InitPartyMenuOBPals + call ApplyAttrmap + ret + +_CGB_Evolution: + ld de, wBGPals1 + ld a, c + and a + jr z, .pokemon + ld a, PREDEFPAL_BLACKOUT + call GetPredefPal + call LoadHLPaletteIntoDE + jr .got_palette + +.pokemon + ld hl, wPartyMon1DVs + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [wCurPartyMon] + call AddNTimes + ld c, l + ld b, h + ld a, [wPlayerHPPal] + call GetPlayerOrMonPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld hl, BattleObjectPals + ld de, wOBPals1 palette PAL_BATTLE_OB_GRAY + ld bc, 6 palettes + call CopyBytes + +.got_palette + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_GSTitleScreen: + ld hl, GSTitleBGPals + ld de, wBGPals1 + ld bc, 5 palettes + call CopyBytes + ld hl, GSTitleOBPals + ld de, wOBPals1 + ld bc, 2 palettes + call CopyBytes + ld a, SCGB_DIPLOMA + ld [wSGBPredef], a + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB0d: + ld hl, PalPacket_Diploma + 1 + call CopyFourPalettes + call WipeAttrmap + call ApplyAttrmap + ret + +_CGB_UnownPuzzle: + ld hl, PalPacket_UnownPuzzle + 1 + call CopyFourPalettes + ld de, wOBPals1 + ld a, PREDEFPAL_UNOWN_PUZZLE + call GetPredefPal + call LoadHLPaletteIntoDE + ld hl, wOBPals1 + ld a, LOW(palred 31 + palgreen 0 + palblue 0) + ld [hli], a + ld a, HIGH(palred 31 + palgreen 0 + palblue 0) + ld [hl], a + call WipeAttrmap + call ApplyAttrmap + ret + +_CGB_TrainerCard: + ld de, wBGPals1 + xor a ; CHRIS + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, FALKNER + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, BUGSY + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, WHITNEY + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, MORTY + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, CHUCK + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, JASMINE + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, PRYCE + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, PREDEFPAL_CGB_BADGE + call GetPredefPal + call LoadHLPaletteIntoDE + + ; card border + hlcoord 0, 0, wAttrmap + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, $1 ; FALKNER + call ByteFill + hlcoord 14, 1, wAttrmap + lb bc, 7, 5 + xor a ; CHRIS + call FillBoxCGB + ; top-right corner still uses the border's palette + hlcoord 18, 1, wAttrmap + ld [hl], $1 + hlcoord 2, 11, wAttrmap + lb bc, 2, 4 + ld a, $1 ; falkner + call FillBoxCGB + hlcoord 6, 11, wAttrmap + lb bc, 2, 4 + ld a, $2 ; bugsy + call FillBoxCGB + hlcoord 10, 11, wAttrmap + lb bc, 2, 4 + ld a, $3 ; whitney + call FillBoxCGB + hlcoord 14, 11, wAttrmap + lb bc, 2, 4 + ld a, $4 ; morty + call FillBoxCGB + hlcoord 2, 14, wAttrmap + lb bc, 2, 4 + ld a, $5 ; chuck + call FillBoxCGB + hlcoord 6, 14, wAttrmap + lb bc, 2, 4 + ld a, $6 ; jasmine + call FillBoxCGB + hlcoord 10, 14, wAttrmap + lb bc, 2, 4 + ld a, $7 ; pryce + call FillBoxCGB + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_MoveList: + ld de, wBGPals1 + ld a, PREDEFPAL_GOLDENROD + call GetPredefPal + call LoadHLPaletteIntoDE + ld a, [wPlayerHPPal] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld bc, HPBarPals + add hl, bc + call LoadPalette_White_Col1_Col2_Black + call WipeAttrmap + hlcoord 11, 1, wAttrmap + lb bc, 2, 9 + ld a, $1 + call FillBoxCGB + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_BetaPikachuMinigame: + ld hl, PalPacket_BetaPikachuMinigame + 1 + call CopyFourPalettes + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_PokedexSearchOption: + ld de, wBGPals1 + ld a, PREDEFPAL_POKEDEX + call GetPredefPal + call LoadHLPaletteIntoDE + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_PackPals: + ld de, wBGPals1 + ld hl, .PackPals + ld bc, 8 palettes ; 6 palettes? + call CopyBytes + call WipeAttrmap + hlcoord 0, 0, wAttrmap + lb bc, 1, 10 + ld a, $1 + call FillBoxCGB + hlcoord 10, 0, wAttrmap + lb bc, 1, 10 + ld a, $2 + call FillBoxCGB + hlcoord 7, 2, wAttrmap + lb bc, 9, 1 + ld a, $3 + call FillBoxCGB + hlcoord 0, 7, wAttrmap + lb bc, 3, 5 + ld a, $4 + call FillBoxCGB + hlcoord 0, 3, wAttrmap + lb bc, 3, 5 + ld a, $5 + call FillBoxCGB + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +.PackPals: +INCLUDE "gfx/pack/pack.pal" + +_CGB_Pokepic: + call _CGB_MapPals + call SwapTextboxPalettes + ld de, SCREEN_WIDTH + hlcoord 0, 0, wAttrmap + ld a, [wMenuBorderTopCoord] +.loop + and a + jr z, .found_top + dec a + add hl, de + jr .loop + +.found_top + ld a, [wMenuBorderLeftCoord] + ld e, a + ld d, $0 + add hl, de + ld a, [wMenuBorderTopCoord] + ld b, a + ld a, [wMenuBorderBottomCoord] + inc a + sub b + ld b, a + ld a, [wMenuBorderLeftCoord] + ld c, a + ld a, [wMenuBorderRightCoord] + sub c + inc a + ld c, a + ld a, $0 + call FillBoxCGB + call ApplyAttrmap + ret + +_CGB_MagnetTrain: + ld hl, PalPacket_MagnetTrain + 1 + call CopyFourPalettes + call WipeAttrmap + hlcoord 0, 4, wAttrmap + lb bc, 10, SCREEN_WIDTH + ld a, $2 + call FillBoxCGB + hlcoord 0, 6, wAttrmap + lb bc, 6, SCREEN_WIDTH + ld a, $1 + call FillBoxCGB + call ApplyAttrmap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +_CGB_GamefreakLogo: + ld de, wBGPals1 + ld a, PREDEFPAL_GAMEFREAK_LOGO_BG + call GetPredefPal + call LoadHLPaletteIntoDE + ld de, wOBPals1 + ld a, PREDEFPAL_GAMEFREAK_LOGO_OB + call GetPredefPal + call LoadHLPaletteIntoDE + ld de, wOBPals1 palette 1 + ld a, PREDEFPAL_GAMEFREAK_LOGO_OB + call GetPredefPal + call LoadHLPaletteIntoDE + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ret + +_CGB_PlayerOrMonFrontpicPals: + ld de, wBGPals1 + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + call LoadPalette_White_Col1_Col2_Black + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ret + +_CGB1e: + ld de, wBGPals1 + ld a, [wCurPartySpecies] + call GetMonPalettePointer + call LoadPalette_White_Col1_Col2_Black + call WipeAttrmap + call ApplyAttrmap + ret + +_CGB_TradeTube: + ld hl, PalPacket_TradeTube + 1 + call CopyFourPalettes + ld hl, PartyMenuOBPals + ld de, wOBPals1 + ld bc, 1 palettes + call CopyBytes + ld de, wOBPals1 palette 7 + ld a, PREDEFPAL_TRADE_TUBE + call GetPredefPal + call LoadHLPaletteIntoDE + call WipeAttrmap + ret + +_CGB_TrainerOrMonFrontpicPals: + ld de, wBGPals1 + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetFrontpicPalettePointer + call LoadPalette_White_Col1_Col2_Black + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ret diff --git a/engine/gfx/color.asm b/engine/gfx/color.asm new file mode 100755 index 00000000..a39ab794 --- /dev/null +++ b/engine/gfx/color.asm @@ -0,0 +1,1260 @@ +INCLUDE "engine/gfx/sgb_layouts.asm" + +SHINY_ATK_BIT EQU 5 +SHINY_DEF_VAL EQU 10 +SHINY_SPD_VAL EQU 10 +SHINY_SPC_VAL EQU 10 + +CheckShininess: +; Check if a mon is shiny by DVs at bc. +; Return carry if shiny. + + ld l, c + ld h, b + +; Attack + ld a, [hl] + and 1 << SHINY_ATK_BIT + jr z, .NotShiny + +; Defense + ld a, [hli] + and $f + cp SHINY_DEF_VAL + jr nz, .NotShiny + +; Speed + ld a, [hl] + and $f0 + cp SHINY_SPD_VAL << 4 + jr nz, .NotShiny + +; Special + ld a, [hl] + and $f + cp SHINY_SPC_VAL + jr nz, .NotShiny + +.Shiny: + scf + ret + +.NotShiny: + and a + ret + +Unused_CheckShininess: +; Return carry if the DVs at hl are all 10 or higher. + +; Attack + ld a, [hl] + cp 10 << 4 + jr c, .NotShiny + +; Defense + ld a, [hli] + and $f + cp 10 + jr c, .NotShiny + +; Speed + ld a, [hl] + cp 10 << 4 + jr c, .NotShiny + +; Special + ld a, [hl] + and $f + cp 10 + jr c, .NotShiny + +.Shiny: + scf + ret + +.NotShiny: + and a + ret + +Function908e: + push de + push bc + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + pop bc + pop de + ld a, c + ld [wSGBPals + 3], a + ld a, b + ld [wSGBPals + 4], a + ld a, e + ld [wSGBPals + 5], a + ld a, d + ld [wSGBPals + 6], a + ld hl, wSGBPals + call PushSGBPals + ld hl, BlkPacket_9ee5 + call PushSGBPals + ret + +InitPartyMenuPalettes: + call CheckCGB + jr nz, .cgb + ld hl, BlkPacket_9fa5 + ld de, wSGBPals + 1 + ld bc, 6 palettes + jp CopyBytes + +.cgb + ld hl, PalPacket_PartyMenu + 1 + call CopyFourPalettes + call InitPartyMenuOBPals + call WipeAttrmap + ret + +; SGB layout for SCGB_PARTY_MENU_HP_PALS +SGB_ApplyPartyMenuHPPals: + ld hl, wHPPals + ld a, [wSGBPals] + ld e, a + ld d, $0 + add hl, de + ld e, l + ld d, h + ld a, [de] + and a + ld e, $5 + jr z, .okay + dec a + ld e, $a + jr z, .okay + ld e, $f +.okay + push de + ld hl, wSGBPals + 10 + ld bc, $6 + ld a, [wSGBPals] + call AddNTimes + pop de + ld [hl], e + ret + +Unreferenced_Function9102: + call CheckCGB + ret z +; CGB only + ld hl, .BGPal + ld de, wBGPals1 + ld bc, 1 palettes + call CopyBytes + + ld hl, .OBPal + ld de, wOBPals1 + ld bc, 1 palettes + call CopyBytes + + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +.BGPal: + RGB 31, 31, 31 + RGB 18, 23, 31 + RGB 15, 20, 31 + RGB 00, 00, 00 + +.OBPal: + RGB 31, 31, 31 + RGB 31, 31, 12 + RGB 08, 16, 28 + RGB 00, 00, 00 + +Unreferenced_Function9136: + call CheckCGB + ret nz + ldh a, [hSGB] + and a + ret z + ld hl, BlkPacket_9ee5 + jp PushSGBPals + +Unreferenced_Function9144: + call CheckCGB + jr nz, .cgb + ldh a, [hSGB] + and a + ret z + ld hl, PalPacket_BetaIntroVenusaur + jp PushSGBPals + +.cgb + ld de, wOBPals1 + ld a, PREDEFPAL_BETA_INTRO_VENUSAUR + call GetPredefPal + jp LoadHLPaletteIntoDE + +Unreferenced_Function915e: + call CheckCGB + jr nz, .cgb + ldh a, [hSGB] + and a + ret z + ld hl, PalPacket_Pack + jp PushSGBPals + +.cgb + ld de, wOBPals1 + ld a, PREDEFPAL_PACK + call GetPredefPal + jp LoadHLPaletteIntoDE + +Unreferenced_Function9178: + call CheckCGB + jr nz, .cgb + ldh a, [hSGB] + and a + ret z + ld a, c + push af + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + pop af + call GetMonPalettePointer + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + ld hl, wSGBPals + jp PushSGBPals + +.cgb + ld de, wOBPals1 + ld a, c + call GetMonPalettePointer + call LoadPalette_White_Col1_Col2_Black + ret + +Unreferenced_Function91b4: + ldh a, [hCGB] + and a + jr nz, .cgb + ld hl, wc602 + jp PushSGBPals + +.cgb + ld a, [wc606] ; col + ld c, a + ld a, [wc607] ; row + hlcoord 0, 0, wAttrmap + ld de, SCREEN_WIDTH +.loop + and a + jr z, .done + add hl, de + dec a + jr .loop + +.done + ld b, $0 + add hl, bc + lb bc, 6, 4 + ld a, [wc605] ; value + and $3 + call FillBoxCGB + call CopyTilemapAtOnce + ret + +ApplyMonOrTrainerPals: + call CheckCGB + ret z + ld a, e + and a + jr z, .get_trainer + ld a, [wCurPartySpecies] + call GetMonPalettePointer + jr .load_palettes + +.get_trainer + ld a, [wTrainerClass] + call GetTrainerPalettePointer + +.load_palettes + ld de, wBGPals1 + call LoadPalette_White_Col1_Col2_Black + call WipeAttrmap + call ApplyAttrmap + call ApplyPals + ret + +ApplyHPBarPals: + ld a, [wWhichHPBar] + and a + jr z, .Enemy + cp $1 + jr z, .Player + cp $2 + jr z, .PartyMenu + ret + +.Enemy: + ld de, wBGPals2 palette PAL_BATTLE_BG_ENEMY_HP color 1 + jr .okay + +.Player: + ld de, wBGPals2 palette PAL_BATTLE_BG_PLAYER_HP color 1 + +.okay + ld l, c + ld h, $0 + add hl, hl + add hl, hl + ld bc, HPBarPals + add hl, bc + ld bc, 4 + call CopyBytes + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +.PartyMenu: + ld e, c + inc e + hlcoord 11, 1, wAttrmap + ld bc, 2 * SCREEN_WIDTH + ld a, [wCurPartyMon] +.loop + and a + jr z, .done + add hl, bc + dec a + jr .loop + +.done + lb bc, 2, 8 + ld a, e + call FillBoxCGB + ret + +LoadStatsScreenPals: + call CheckCGB + ret z + ld hl, StatsScreenPals + ld b, 0 + dec c + add hl, bc + add hl, bc + ld a, [hli] + ld [wBGPals1 palette 0], a + ld [wBGPals1 palette 2], a + ld a, [hl] + ld [wBGPals1 palette 0 + 1], a + ld [wBGPals1 palette 2 + 1], a + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret + +LoadMailPalettes: + ld l, e + ld h, 0 + add hl, hl + add hl, hl + add hl, hl + ld de, .MailPals + add hl, de + call CheckCGB + jr nz, .cgb + push hl + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + pop hl + inc hl + inc hl + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hli] + ld [wSGBPals + 6], a + ld hl, wSGBPals + call PushSGBPals + ld hl, BlkPacket_9ee5 + call PushSGBPals + ret + +.cgb + ld de, wBGPals1 + ld bc, 1 palettes + call CopyBytes + call ApplyPals + call WipeAttrmap + call ApplyAttrmap + ret + +.MailPals: +INCLUDE "gfx/mail/mail.pal" + +INCLUDE "engine/gfx/cgb_layouts.asm" + +_CGB_MysteryGift: + ld hl, .Palette + ld de, wBGPals1 + ld bc, 1 palettes + call CopyBytes + call ApplyPals + call WipeAttrmap + call ApplyAttrmap + ret + +.Palette: + RGB 31, 31, 31 + RGB 09, 31, 31 + RGB 10, 12, 31 + RGB 00, 03, 19 + +CopyFourPalettes: + ld de, wBGPals1 + ld c, 4 + +CopyPalettes: +.loop + push bc + ld a, [hli] + push hl + call GetPredefPal + call LoadHLPaletteIntoDE + pop hl + inc hl + pop bc + dec c + jr nz, .loop + ret + +GetPredefPal: + ld l, a + ld h, $0 + add hl, hl + add hl, hl + add hl, hl + ld bc, PredefPals + add hl, bc + ret + +LoadHLPaletteIntoDE: + ld c, 1 palettes +.loop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop + ret + +LoadPalette_White_Col1_Col2_Black: + ld a, LOW(PALRGB_WHITE) + ld [de], a + inc de + ld a, HIGH(PALRGB_WHITE) + ld [de], a + inc de + + ld c, 2 * PAL_COLOR_SIZE +.loop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop + + xor a + ld [de], a + inc de + ld [de], a + inc de + ret + +FillBoxCGB: +.row + push bc + push hl +.col + ld [hli], a + dec c + jr nz, .col + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + ret + +ResetBGPals: + push af + push bc + push de + push hl + ld hl, wBGPals1 + ld c, 1 palettes +.loop + ld a, $ff + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + xor a + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + dec c + jr nz, .loop + pop hl + pop de + pop bc + pop af + ret + +WipeAttrmap: + hlcoord 0, 0, wAttrmap + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + xor a + call ByteFill + ret + +ApplyPals: + ld hl, wBGPals1 + ld de, wBGPals2 + ld bc, 16 palettes + call CopyBytes + ret + +ApplyAttrmap: + ldh a, [rLCDC] + bit rLCDC_ENABLE, a + jr z, .UpdateVBank1 + ldh a, [hBGMapMode] + push af + ld a, $2 + ldh [hBGMapMode], a + call DelayFrame + call DelayFrame + call DelayFrame + call DelayFrame + pop af + ldh [hBGMapMode], a + ret + +.UpdateVBank1: + hlcoord 0, 0, wAttrmap + debgcoord 0, 0 + ld b, SCREEN_HEIGHT + ld a, $1 + ldh [rVBK], a +.row + ld c, SCREEN_WIDTH +.col + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .col + ld a, BG_MAP_WIDTH - SCREEN_WIDTH + add e + jr nc, .okay + inc d +.okay + ld e, a + dec b + jr nz, .row + ld a, $0 + ldh [rVBK], a + ret + +; CGB layout for SCGB_PARTY_MENU_HP_PALS +CGB_ApplyPartyMenuHPPals: + ld hl, wHPPals + ld a, [wSGBPals] + ld e, a + ld d, $0 + add hl, de + ld e, l + ld d, h + ld a, [de] + inc a + ld e, a + hlcoord 11, 2, wAttrmap + ld bc, 2 * SCREEN_WIDTH + ld a, [wSGBPals] +.loop + and a + jr z, .done + add hl, bc + dec a + jr .loop +.done + lb bc, 2, 8 + ld a, e + call FillBoxCGB + ret + +InitPartyMenuOBPals: + ld hl, PartyMenuOBPals + ld de, wOBPals1 + ld bc, 2 palettes + call CopyBytes + ret + +GetBattlemonBackpicPalettePointer: + push de + farcall GetPartyMonDVs + ld c, l + ld b, h + ld a, [wTempBattleMonSpecies] + call GetPlayerOrMonPalettePointer + pop de + ret + +GetEnemyFrontpicPalettePointer: + push de + farcall GetEnemyMonDVs + ld c, l + ld b, h + ld a, [wTempEnemyMonSpecies] + call GetFrontpicPalettePointer + pop de + ret + +GetPlayerOrMonPalettePointer: + and a + jp nz, GetMonNormalOrShinyPalettePointer + ld hl, PlayerPalette + ret + +GetFrontpicPalettePointer: + and a + jp nz, GetMonNormalOrShinyPalettePointer + ld a, [wTrainerClass] + +GetTrainerPalettePointer: + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld bc, TrainerPalettes + add hl, bc + ret + +GetMonPalettePointer: + call _GetMonPalettePointer + ret + +Unreferenced_Function9be8: + ret + call CheckCGB + ret z + ld hl, BattleObjectPals + ld a, $90 + ldh [rOBPI], a + ld c, 6 palettes +.loop + ld a, [hli] + ldh [rOBPD], a + dec c + jr nz, .loop + ld hl, BattleObjectPals + ld de, wOBPals1 palette 2 + ld bc, 2 palettes + call CopyBytes + ret + +BattleObjectPals: +INCLUDE "gfx/battle_anims/battle_anims.pal" + +Unreferenced_Function9c39: + call CheckCGB + ret z + ld a, $90 + ldh [rOBPI], a + ld a, PREDEFPAL_TRADE_TUBE + call GetPredefPal + call .PushPalette + ld a, PREDEFPAL_RB_GREENMON + call GetPredefPal + call .PushPalette + ret + +.PushPalette: + ld c, 1 palettes +.loop + ld a, [hli] + ldh [rOBPD], a + dec c + jr nz, .loop + ret + +_GetMonPalettePointer: + ld l, a + ld h, $0 + add hl, hl + add hl, hl + add hl, hl + ld bc, PokemonPalettes + add hl, bc + ret + +GetMonNormalOrShinyPalettePointer: + push bc + call _GetMonPalettePointer + pop bc + push hl + call CheckShininess + pop hl + ret nc +rept 4 + inc hl +endr + ret + +PushSGBPals: + ld a, [wd8ba] + push af + set 7, a + ld [wd8ba], a + call _PushSGBPals + pop af + ld [wd8ba], a + ret + +_PushSGBPals: + ld a, [hl] + and $7 + ret z + ld b, a +.loop + push bc + xor a + ldh [rJOYP], a + ld a, $30 + ldh [rJOYP], a + ld b, $10 +.loop2 + ld e, $8 + ld a, [hli] + ld d, a +.loop3 + bit 0, d + ld a, $10 + jr nz, .okay + ld a, $20 +.okay + ldh [rJOYP], a + ld a, $30 + ldh [rJOYP], a + rr d + dec e + jr nz, .loop3 + dec b + jr nz, .loop2 + ld a, $20 + ldh [rJOYP], a + ld a, $30 + ldh [rJOYP], a + call SGBDelayCycles + pop bc + dec b + jr nz, .loop + ret + +InitSGBBorder: + call CheckCGB + ret nz +; SGB/DMG only + di + ld a, [wd8ba] + push af + set 7, a + ld [wd8ba], a + xor a + ldh [rJOYP], a + ldh [hSGB], a + call PushSGBBorderPalsAndWait + jr nc, .skip + ld a, $1 + ldh [hSGB], a + call _InitSGBBorderPals + call SGBBorder_PushBGPals + call SGBDelayCycles + call SGB_ClearVRAM + call PushSGBBorder + call SGBDelayCycles + call SGB_ClearVRAM + ld hl, MaskEnCancelPacket + call _PushSGBPals + +.skip + pop af + ld [wd8ba], a + ei + ret + +InitCGBPals:: + call CheckCGB + ret z +; CGB only + ld a, BANK(vTiles3) + ldh [rVBK], a + ld hl, vTiles3 + ld bc, $200 tiles + xor a + call ByteFill + ld a, BANK(vTiles0) + ldh [rVBK], a + ld a, 1 << rBGPI_AUTO_INCREMENT + ldh [rBGPI], a + ld c, 4 * 8 +.bgpals_loop + ld a, LOW(PALRGB_WHITE) + ldh [rBGPD], a + ld a, HIGH(PALRGB_WHITE) + ldh [rBGPD], a + dec c + jr nz, .bgpals_loop + ld a, 1 << rOBPI_AUTO_INCREMENT + ldh [rOBPI], a + ld c, 4 * 8 +.obpals_loop + ld a, LOW(PALRGB_WHITE) + ldh [rOBPD], a + ld a, HIGH(PALRGB_WHITE) + ldh [rOBPD], a + dec c + jr nz, .obpals_loop + ld hl, wBGPals1 + call .LoadWhitePals + ld hl, wBGPals2 +.LoadWhitePals: + ld c, 4 * 16 +.loop + ld a, LOW(PALRGB_WHITE) + ld [hli], a + ld a, HIGH(PALRGB_WHITE) + ld [hli], a + dec c + jr nz, .loop + ret + +_InitSGBBorderPals: + ld hl, .PacketPointerTable + ld c, 9 +.loop + push bc + ld a, [hli] + push hl + ld h, [hl] + ld l, a + call _PushSGBPals + pop hl + inc hl + pop bc + dec c + jr nz, .loop + ret + +.PacketPointerTable: + dw MaskEnFreezePacket + dw DataSndPacket1 + dw DataSndPacket2 + dw DataSndPacket3 + dw DataSndPacket4 + dw DataSndPacket5 + dw DataSndPacket6 + dw DataSndPacket7 + dw DataSndPacket8 + +Unreferenced_Function9d70: + di + xor a + ldh [rJOYP], a + ld hl, MaskEnFreezePacket + call _PushSGBPals + call PushSGBBorder + call SGBDelayCycles + call SGB_ClearVRAM + ld hl, MaskEnCancelPacket + call _PushSGBPals + ei + ret + +PushSGBBorder: + call .LoadSGBBorderPointers + push de + call SGBBorder_YetMorePalPushing + pop hl + call SGBBorder_MorePalPushing + ret + +.LoadSGBBorderPointers: + ld hl, SGBBorder + ld de, SGBBorderMap + ret + +SGB_ClearVRAM: + ld hl, VRAM_Begin + ld bc, VRAM_End - VRAM_Begin + xor a + call ByteFill + ret + +PushSGBBorderPalsAndWait: + ld hl, MltReq2Packet + call _PushSGBPals + call SGBDelayCycles + ldh a, [rJOYP] + and $3 + cp $3 + jr nz, .carry + ld a, $20 + ldh [rJOYP], a + ldh a, [rJOYP] + ldh a, [rJOYP] + call SGBDelayCycles + call SGBDelayCycles + ld a, $30 + ldh [rJOYP], a + call SGBDelayCycles + call SGBDelayCycles + ld a, $10 + ldh [rJOYP], a +rept 6 + ldh a, [rJOYP] +endr + call SGBDelayCycles + call SGBDelayCycles + ld a, $30 + ldh [rJOYP], a + ldh a, [rJOYP] + ldh a, [rJOYP] + ldh a, [rJOYP] + call SGBDelayCycles + call SGBDelayCycles + ldh a, [rJOYP] + and $3 + cp $3 + jr nz, .carry + call .FinalPush + and a + ret + +.carry + call .FinalPush + scf + ret + +.FinalPush: + ld hl, MltReq1Packet + call _PushSGBPals + jp SGBDelayCycles + +SGBBorder_PushBGPals: + call DisableLCD + ld a, %11100100 + ldh [rBGP], a + ld hl, PredefPals + ld de, vTiles1 + ld bc, $100 tiles + call CopyData + call DrawDefaultTiles + ld a, LCDC_DEFAULT + ldh [rLCDC], a + ld hl, PalTrnPacket + call _PushSGBPals + xor a + ldh [rBGP], a + ret + +SGBBorder_MorePalPushing: + call DisableLCD + ld a, $e4 + ldh [rBGP], a + ld de, vTiles1 + ld bc, (6 + SCREEN_WIDTH + 6) * 5 * 2 + call CopyData + ld b, SCREEN_HEIGHT +.loop + push bc + ld bc, 6 * 2 + call CopyData + ld bc, SCREEN_WIDTH * 2 + call ClearBytes + ld bc, 6 * 2 + call CopyData + pop bc + dec b + jr nz, .loop + ld bc, (6 + SCREEN_WIDTH + 6) * 5 * 2 + call CopyData + ld bc, $100 + call ClearBytes + ld bc, 16 palettes + call CopyData + call DrawDefaultTiles + ld a, LCDC_DEFAULT + ldh [rLCDC], a + ld hl, PctTrnPacket + call _PushSGBPals + xor a + ldh [rBGP], a + ret + +SGBBorder_YetMorePalPushing: + call DisableLCD + ld a, %11100100 + ldh [rBGP], a + ld de, vTiles1 + ld b, $80 +.loop + push bc + ld bc, 1 tiles + call CopyData + ld bc, 1 tiles + call ClearBytes + pop bc + dec b + jr nz, .loop + call DrawDefaultTiles + ld a, LCDC_DEFAULT + ldh [rLCDC], a + ld hl, ChrTrnPacket + call _PushSGBPals + xor a + ldh [rBGP], a + ret + +CopyData: +; copy bc bytes of data from hl to de +.loop + ld a, [hli] + ld [de], a + inc de + dec bc + ld a, c + or b + jr nz, .loop + ret + +ClearBytes: +; clear bc bytes of data starting from de +.loop + xor a + ld [de], a + inc de + dec bc + ld a, c + or b + jr nz, .loop + ret + +DrawDefaultTiles: +; Draw 240 tiles (2/3 of the screen) from tiles in VRAM + hlbgcoord 0, 0 ; BG Map 0 + ld de, BG_MAP_WIDTH - SCREEN_WIDTH + ld a, $80 ; starting tile + ld c, 12 + 1 +.line + ld b, 20 +.tile + ld [hli], a + inc a + dec b + jr nz, .tile +; next line + add hl, de + dec c + jr nz, .line + ret + +SGBDelayCycles: + ld de, 7000 +.wait + nop + nop + nop + dec de + ld a, d + or e + jr nz, .wait + ret + +INCLUDE "gfx/sgb/blk_packets.asm" +INCLUDE "gfx/sgb/pal_packets.asm" +INCLUDE "data/sgb_ctrl_packets.asm" + +PredefPals: +INCLUDE "gfx/sgb/predef.pal" + +IF DEF(_GOLD) +SGBBorderMap: +INCBIN "gfx/sgb/gold_border.sgb.tilemap" +SGBBorderPalettes: +INCLUDE "gfx/sgb/gold_border.pal" +SGBBorder: +INCBIN "gfx/sgb/gold_border.2bpp" + +ELIF DEF(_SILVER) +SGBBorderMap: +INCBIN "gfx/sgb/silver_border.sgb.tilemap" +SGBBorderPalettes: +INCLUDE "gfx/sgb/silver_border.pal" +SGBBorder: +INCBIN "gfx/sgb/silver_border.2bpp" +ENDC + +HPBarPals: +INCLUDE "gfx/battle/hp_bar.pal" + +ExpBarPalette: +INCLUDE "gfx/battle/exp_bar.pal" + +INCLUDE "data/pokemon/palettes.asm" + +INCLUDE "data/trainers/palettes.asm" + +LoadMapPals: + ; Which palette group is based on whether we're outside or inside + ld a, [wEnvironment] + and 7 + ld e, a + ld d, 0 + ld hl, EnvironmentColorsPointers + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ; Futher refine by time of day + ld a, [wTimeOfDayPal] + maskbits NUM_DAYTIMES + add a + add a + add a + ld e, a + ld d, 0 + add hl, de + ld e, l + ld d, h + ld hl, wBGPals1 + ld b, 8 +.outer_loop + ld a, [de] ; lookup index for TilesetBGPalette + push de + push hl + ld l, a + ld h, 0 + add hl, hl + add hl, hl + add hl, hl + ld de, TilesetBGPalette + add hl, de + ld e, l + ld d, h + pop hl + ld c, 1 palettes +.inner_loop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .inner_loop + pop de + inc de + dec b + jr nz, .outer_loop + ld a, [wTimeOfDayPal] + maskbits NUM_DAYTIMES + ld bc, 8 palettes + ld hl, MapObjectPals + call AddNTimes + ld de, wOBPals1 + ld bc, 8 palettes + call CopyBytes + + ld a, [wEnvironment] + cp TOWN + jr z, .outside + cp ROUTE + ret nz +.outside + ld a, [wMapGroup] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + add hl, hl + ld de, RoofPals + add hl, de + ld a, [wTimeOfDayPal] + maskbits NUM_DAYTIMES + cp NITE_F + jr c, .morn_day +rept 4 + inc hl +endr +.morn_day + ld de, wBGPals1 palette PAL_BG_ROOF color 1 + ld bc, 4 + call CopyBytes + ret + +INCLUDE "data/maps/environment_colors.asm" + +TilesetBGPalette: +INCLUDE "gfx/tilesets/bg_tiles.pal" + +MapObjectPals:: +INCLUDE "gfx/overworld/npc_sprites.pal" + +RoofPals: +INCLUDE "gfx/tilesets/roofs.pal" + +DiplomaPalettes: +INCLUDE "gfx/diploma/diploma.pal" + +PartyMenuOBPals: +INCLUDE "gfx/stats/party_menu_ob.pal" + +GSTitleBGPals: +IF DEF(_GOLD) +INCLUDE "gfx/title/title_bg_gold.pal" +ELIF DEF(_SILVER) +INCLUDE "gfx/title/title_bg_silver.pal" +ENDC + +GSTitleOBPals: +INCLUDE "gfx/title/title_fg.pal" + +PokegearPals: +INCLUDE "gfx/pokegear/pokegear.pal" + +BetaPokerPals: +INCLUDE "gfx/beta_poker/beta_poker.pal" + +SlotMachinePals: +IF DEF(_GOLD) +INCLUDE "gfx/slots/slots_gold.pal" +ELIF DEF(_SILVER) +INCLUDE "gfx/slots/slots_silver.pal" +ENDC diff --git a/engine/gfx/load_pics.asm b/engine/gfx/load_pics.asm new file mode 100644 index 00000000..c9ee98b7 --- /dev/null +++ b/engine/gfx/load_pics.asm @@ -0,0 +1,428 @@ +GetUnownLetter: +; Return Unown letter in wUnownLetter based on DVs at hl + +; Take the middle 2 bits of each DV and place them in order: +; atk def spd spc +; .ww..xx. .yy..zz. + + ; atk + ld a, [hl] + and %01100000 + sla a + ld b, a + ; def + ld a, [hli] + and %00000110 + swap a + srl a + or b + ld b, a + + ; spd + ld a, [hl] + and %01100000 + swap a + sla a + or b + ld b, a + ; spc + ld a, [hl] + and %00000110 + srl a + or b + +; Divide by 10 to get 0-25 + ldh [hDividend + 3], a + xor a + ldh [hDividend], a + ldh [hDividend + 1], a + ldh [hDividend + 2], a + ld a, $ff / NUM_UNOWN + 1 + ldh [hDivisor], a + ld b, 4 + call Divide + +; Increment to get 1-26 + ldh a, [hQuotient + 3] + inc a + ld [wUnownLetter], a + ret + +GetMonFrontpic: + call GetFrontpic + jp Load2bppToSRAM + +UnusedFrontpicPredef: + call GetFrontpic + push hl + farcall StubbedGetFrontpic + pop hl + jp Load2bppToSRAM + +GetFrontpic: + ld a, [wCurPartySpecies] + ld [wCurSpecies], a + and a + ret z + cp NUM_POKEMON + 1 + ret z + cp EGG + 1 + ret nc + +.is_a_pokemon + push de + call GetBaseData + ld a, [wBasePicSize] + and $f + ld b, a + push bc + ld a, BANK(sDecompressBuffer) + call OpenSRAM + ld hl, PokemonPicPointers ; UnownPicPointers + ld a, [wCurPartySpecies] + ld d, BANK(PokemonPicPointers) + cp UNOWN + jr z, .unown + cp EGG + jr nz, .not_egg + ld hl, EggPic + ld a, BANK(EggPic) + jr .ok + +.unown + ld a, [wUnownLetter] + ld d, BANK(UnownPicPointers) + +.not_egg + dec a + ld bc, 6 + call AddNTimes + ld a, d + call GetFarByte + call FixPicBank + push af + inc hl + ld a, d + call GetFarHalfword + pop af + +.ok + ld de, sDecompressBuffer + call FarDecompress + pop bc + ld hl, sDecompressScratch + ld de, sDecompressBuffer + call PadFrontpic + pop hl + ret + +Load2bppToSRAM: + ld de, sDecompressScratch + ld c, 7 * 7 + ldh a, [hROMBank] + ld b, a + call Get2bpp + jp CloseSRAM + +GetMonBackpic: + ld a, [wCurPartySpecies] + and a + ret z + cp NUM_POKEMON + 1 + ret z + cp EGG + 1 + ret nc + +.is_a_pokemon + push de + ld a, BANK(sDecompressBuffer) + call OpenSRAM + + ; These are assumed to be at the same address in their respective banks. + ld hl, PokemonPicPointers ; UnownPicPointers + ld a, [wCurPartySpecies] + ld d, BANK(PokemonPicPointers) + cp UNOWN + jr nz, .ok + ld a, [wUnownLetter] + ld d, BANK(UnownPicPointers) +.ok + dec a + ld bc, 6 + call AddNTimes + ld bc, 3 + add hl, bc + ld a, d + call GetFarByte + call FixPicBank + push af + inc hl + ld a, d + call GetFarByte + push af + inc hl + ld a, d + call GetFarByte + ld h, a + pop af + ld l, a + ld de, sDecompressBuffer + pop af + call FarDecompress + ld hl, sDecompressBuffer + ld c, 6 * 6 + call FixBackpicAlignment + pop hl + ld de, sDecompressBuffer + ldh a, [hROMBank] + ld b, a + call Get2bpp + call CloseSRAM + ret + +FixPicBank: +; Precondition: a = defined bank for pic +; Postcondition: a = repaired bank for pic +; +; Pic bank values that will get repaired (and what they'll be repaired to): +; $13 -> $1f +; $14 -> $20 +; $1f -> $2e +; +; Otherwise, the repaired bank will match the defined bank. + push hl + push bc + ld b, a + ld hl, .FixPicBankTable +.loop + ld a, [hli] + cp -1 + jr z, .done + inc hl + cp b + jr nz, .loop + dec hl + ld b, [hl] + +.done + ld a, b + pop bc + pop hl + ret + +.FixPicBankTable: + db $13, $1f + db $14, $20 + db $1f, $2e + db -1 + +Function1587f: + ld a, c + push de + ld hl, PokemonPicPointers + dec a + ld bc, 6 + call AddNTimes + ld a, BANK(PokemonPicPointers) + call GetFarByte + call FixPicBank + push af + inc hl + ld a, BANK(PokemonPicPointers) + call GetFarHalfword + pop af + pop de + call FarDecompress + ret + +GetTrainerPic: + ld a, [wTrainerClass] + and a + ret z + cp NUM_TRAINER_CLASSES + ret nc + ld a, 0 + call WaitBGMap + xor a + ldh [hBGMapMode], a + ld a, BANK(sDecompressBuffer) + call OpenSRAM + push de + ld hl, TrainerPicPointers + ld a, [wTrainerClass] + dec a + ld bc, 3 + call AddNTimes + ld a, BANK(TrainerPicPointers) + call GetFarByte + call FixPicBank + push af + inc hl + ld a, BANK(TrainerPicPointers) + call GetFarByte + push af + inc hl + ld a, BANK(TrainerPicPointers) + call GetFarByte + ld h, a + pop af + ld l, a + ld de, sDecompressBuffer + pop af + call FarDecompress + pop hl + ld de, sDecompressBuffer + ld c, 7 * 7 + ldh a, [hROMBank] + ld b, a + call Get2bpp + call CloseSRAM + call WaitBGMap + ld a, 1 + ldh [hBGMapMode], a + ret + +DecompressGet2bpp: + push de + push bc + ld a, BANK(sDecompressBuffer) + call OpenSRAM + ld a, b + ld de, sDecompressBuffer + call FarDecompress + pop bc + ld de, sDecompressBuffer + pop hl + ldh a, [hROMBank] + ld b, a + call Get2bpp + call CloseSRAM + ret + +FixBackpicAlignment: + push de + push bc + ld a, [wBoxAlignment] + and a + jr z, .keep_dims + ld a, c + cp 7 * 7 + ld de, 7 * 7 tiles + jr z, .got_dims + cp 6 * 6 + ld de, 6 * 6 tiles + jr z, .got_dims + ld de, 5 * 5 tiles + +.got_dims + ld a, [hl] + ld b, 0 + ld c, 8 +.loop + rra + rl b + dec c + jr nz, .loop + ld a, b + ld [hli], a + dec de + ld a, e + or d + jr nz, .got_dims + +.keep_dims + pop bc + pop de + ret + +PadFrontpic: +; pads frontpic to fill 7x7 box + ld a, b + cp 6 + jr z, .six + cp 5 + jr z, .five + +.seven_loop + ld c, 7 << 4 + call LoadOrientedFrontpic + dec b + jr nz, .seven_loop + ret + +.six + ld c, 7 << 4 + xor a + call .Fill +.six_loop + ld c, (7 - 6) << 4 + xor a + call .Fill + ld c, 6 << 4 + call LoadOrientedFrontpic + dec b + jr nz, .six_loop + ret + +.five + ld c, 7 << 4 + xor a + call .Fill +.five_loop + ld c, (7 - 5) << 4 + xor a + call .Fill + ld c, 5 << 4 + call LoadOrientedFrontpic + dec b + jr nz, .five_loop + ld c, 7 << 4 + xor a + call .Fill + ret + +.Fill: +rept 4 + srl c +endr +.loop +rept 16 + ld [hli], a +endr + dec c + jr nz, .loop + ret + +LoadOrientedFrontpic: + ld a, [wBoxAlignment] + and a + jr nz, .x_flip +rept 4 + srl c +endr +.left_loop +rept 16 + ld a, [de] + inc de + ld [hli], a +endr + dec c + jr nz, .left_loop + ret + +.x_flip + push bc +.right_loop + ld a, [de] + inc de + ld b, a + xor a +rept 8 + rr b + rla +endr + ld [hli], a + dec c + jr nz, .right_loop + pop bc + ret diff --git a/engine/gfx/load_push_oam.asm b/engine/gfx/load_push_oam.asm new file mode 100644 index 00000000..2e43c1ff --- /dev/null +++ b/engine/gfx/load_push_oam.asm @@ -0,0 +1,21 @@ +WriteOAMDMACodeToHRAM:: + ld c, LOW(hTransferVirtualOAM) + ld b, .PushOAMEnd - .PushOAM + ld hl, .PushOAM +.loop + ld a, [hli] + ldh [c], a + inc c + dec b + jr nz, .loop + ret + +.PushOAM: + ld a, HIGH(wVirtualOAM) + ldh [rDMA], a + ld a, NUM_SPRITE_OAM_STRUCTS +.pushoam_loop + dec a + jr nz, .pushoam_loop + ret +.PushOAMEnd diff --git a/engine/gfx/sgb_layouts.asm b/engine/gfx/sgb_layouts.asm new file mode 100755 index 00000000..db4e929f --- /dev/null +++ b/engine/gfx/sgb_layouts.asm @@ -0,0 +1,577 @@ +LoadSGBLayout: + call CheckCGB + jp nz, LoadSGBLayoutCGB + + ld a, b + cp SCGB_RAM + jr nz, .not_ram + ld a, [wSGBPredef] +.not_ram + cp SCGB_PARTY_MENU_HP_PALS + jp z, SGB_ApplyPartyMenuHPPals + ld l, a + ld h, 0 + add hl, hl + ld de, .Jumptable + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, _LoadSGBLayout_ReturnFromJumpTable + push de + jp hl + +.Jumptable: + dw .SGB_BattleGrayscale + dw .SGB_BattleColors + dw .SGB_PokegearPals + dw .SGB_StatsScreenHPPals + dw .SGB_Pokedex + dw .SGB_SlotMachine + dw .SGB_BetaTitleScreen + dw .SGB_GSIntro + dw .SGB_Diploma + dw .SGB_MapPals + dw .SGB_PartyMenu + dw .SGB_Evolution + dw .SGB_GSTitleScreen + dw .SGB0d + dw .SGB_MoveList + dw .SGB_BetaPikachuMinigame + dw .SGB_PokedexSearchOption + dw .SGB_BetaPoker + dw .SGB_Pokepic + dw .SGB_MagnetTrain + dw .SGB_PackPals + dw .SGB_TrainerCard + dw .SGB_PokedexUnownMode + dw .SGB_BillsPC + dw .SGB_UnownPuzzle + dw .SGB_GamefreakLogo + dw .SGB_PlayerOrMonFrontpicPals + dw .SGB_TradeTube + dw .SGB_TrainerOrMonFrontpicPals + dw .SGB_MysteryGift + dw .SGB1e + dw .SGB_Pokedex_5_5 + +.SGB_BattleGrayscale: + ld hl, PalPacket_BattleGrayscale + ld de, BlkPacket_Battle + ret + +.SGB_BattleColors: + ld hl, BlkPacket_Battle + call PushSGBPals + + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + + ld a, [wPlayerHPPal] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, HPBarPals + add hl, de + + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + + ld a, [wEnemyHPPal] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + + ld de, HPBarPals + add hl, de + ld a, [hli] + ld [wSGBPals + 9], a + ld a, [hli] + ld [wSGBPals + 10], a + ld a, [hli] + ld [wSGBPals + 11], a + ld a, [hl] + ld [wSGBPals + 12], a + + ld hl, PalPacket_a165 + ld de, wSGBPals + PALPACKET_LENGTH + ld bc, PALPACKET_LENGTH + call CopyBytes + + call GetBattlemonBackpicPalettePointer + + ld a, [hli] + ld [wSGBPals + 19], a + ld a, [hli] + ld [wSGBPals + 20], a + ld a, [hli] + ld [wSGBPals + 21], a + ld a, [hl] + ld [wSGBPals + 22], a + call GetEnemyFrontpicPalettePointer + ld a, [hli] + ld [wSGBPals + 25], a + ld a, [hli] + ld [wSGBPals + 26], a + ld a, [hli] + ld [wSGBPals + 27], a + ld a, [hl] + ld [wSGBPals + 28], a + + ld hl, wSGBPals + ld de, wSGBPals + PALPACKET_LENGTH + ld a, SCGB_BATTLE_COLORS + ld [wSGBPredef], a + ret + +.SGB_MoveList: + ld hl, PalPacket_a045 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + + ld hl, wSGBPals + 1 + ld [hl], $10 + inc hl + inc hl + + ld a, [wPlayerHPPal] + add PREDEFPAL_HP_GREEN + ld [hl], a + ld hl, wSGBPals + ld de, BlkPacket_MoveList + ret + +.SGB_PokegearPals: + ld hl, PalPacket_Pokegear + ld de, BlkPacket_9ee5 + ret + +.SGB_StatsScreenHPPals: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld a, [wCurHPPal] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, HPBarPals + add hl, de + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + ld a, [hli] + ld [wSGBPals + 9], a + ld a, [hli] + ld [wSGBPals + 10], a + ld a, [hli] + ld [wSGBPals + 11], a + ld a, [hl] + ld [wSGBPals + 12], a + ld hl, wSGBPals + ld de, BlkPacket_StatsScreen + ret + +.SGB_PartyMenu: + ld hl, PalPacket_PartyMenu + ld de, wSGBPals + 1 + ret + +.SGB_Pokedex: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld hl, wSGBPals + 3 + ld [hl], LOW(palred 31 + palgreen 20 + palblue 10) + inc hl + ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10) + inc hl + ld [hl], LOW(palred 26 + palgreen 10 + palblue 6) + inc hl + ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6) + ld a, [wCurPartySpecies] + call GetMonPalettePointer + ld a, [hli] + ld [wSGBPals + 9], a + ld a, [hli] + ld [wSGBPals + 10], a + ld a, [hli] + ld [wSGBPals + 11], a + ld a, [hl] + ld [wSGBPals + 12], a + ld hl, wSGBPals + ld de, BlkPacket_Pokedex_PC + ret + +.SGB_Pokedex_5_5: + call .SGB_Pokedex + ld de, BlkPacket_9f65 + ret + +.SGB_BillsPC: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld hl, wSGBPals + 3 + ld [hl], LOW(palred 31 + palgreen 20 + palblue 10) + inc hl + ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10) + inc hl + ld [hl], LOW(palred 26 + palgreen 10 + palblue 6) + inc hl + ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6) + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + ld a, [hli] + ld [wSGBPals + 9], a + ld a, [hli] + ld [wSGBPals + 10], a + ld a, [hli] + ld [wSGBPals + 11], a + ld a, [hl] + ld [wSGBPals + 12], a + ld hl, wSGBPals + ld de, BlkPacket_9f55 + ret + +.SGB_PokedexUnownMode: + call .SGB_Pokedex + ld de, BlkPacket_PokedexUnownMode + ret + +.SGB_PokedexSearchOption: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld hl, wSGBPals + 3 + ld [hl], LOW(palred 31 + palgreen 20 + palblue 10) + inc hl + ld [hl], HIGH(palred 31 + palgreen 20 + palblue 10) + inc hl + ld [hl], LOW(palred 26 + palgreen 10 + palblue 6) + inc hl + ld [hl], HIGH(palred 26 + palgreen 10 + palblue 6) + ld hl, wSGBPals + ld de, BlkPacket_9ee5 + ret + +.SGB_PackPals: + ld hl, PalPacket_Pack + ld de, BlkPacket_9ee5 + ret + +.SGB_SlotMachine: + ld hl, PalPacket_SlotMachine + ld de, BlkPacket_SlotMachine + ret + +.SGB_BetaTitleScreen: + ld hl, PalPacket_BetaTitleScreen + ld de, BlkPacket_BetaTitleScreen + ret + +.SGB_Diploma: +.SGB_MysteryGift: + ld hl, PalPacket_Diploma + ld de, BlkPacket_9ee5 + ret + +.SGB_GSIntro: + ld b, 0 + ld hl, .BlkPacketTable_GSIntro +rept 4 + add hl, bc +endr + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + ret + +.BlkPacketTable_GSIntro: + dw BlkPacket_9ee5, PalPacket_GSIntroShellderLapras + dw BlkPacket_GSIntroJigglypuffPikachu, PalPacket_GSIntroJigglypuffPikachu + dw BlkPacket_9ee5, PalPacket_GSIntroStartersTransition + +.SGB_GSTitleScreen: + ld hl, PalPacket_GSTitleScreen + ld de, BlkPacket_GSTitleScreen + ld a, SCGB_DIPLOMA + ld [wSGBPredef], a + ret + +.SGB_MagnetTrain: + ld hl, PalPacket_MagnetTrain + ld de, BlkPacket_MagnetTrain + ret + +.SGB_BetaPikachuMinigame: + ld hl, PalPacket_BetaPikachuMinigame + ld de, BlkPacket_9ee5 + ret + +.SGB_BetaPoker: + ld hl, BlkPacket_9ee5 + ld de, wc602 + ld bc, PALPACKET_LENGTH + call CopyBytes + ld hl, PalPacket_BetaPoker + ld de, BlkPacket_9ee5 + ret + +.SGB_MapPals: + ld hl, PalPacket_a045 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + call .GetMapPalsIndex + ld hl, wSGBPals + 1 + ld [hld], a + ld de, BlkPacket_9ee5 + ld a, SCGB_MAPPALS + ld [wSGBPredef], a + ret + +.SGB_Evolution: + push bc + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + pop bc + ld a, c + and a + jr z, .partymon + ; Egg + ld hl, wSGBPals + 3 + ld [hl], LOW(palred 7 + palgreen 7 + palblue 7) + inc hl + ld [hl], HIGH(palred 7 + palgreen 7 + palblue 7) + inc hl + ld [hl], LOW(palred 2 + palgreen 3 + palblue 3) + inc hl + ld [hl], HIGH(palred 2 + palgreen 3 + palblue 3) + jr .done + +.partymon + ld hl, wPartyMon1DVs + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [wCurPartyMon] + call AddNTimes + ld c, l + ld b, h + ld a, [wPlayerHPPal] + call GetPlayerOrMonPalettePointer + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + +.done + ld hl, wSGBPals + ld de, BlkPacket_9ee5 + ret + +.SGB0d: +.SGB_TrainerCard: + ld hl, PalPacket_Diploma + ld de, BlkPacket_9ee5 + ret + +.SGB_UnownPuzzle: + ld hl, PalPacket_UnownPuzzle + ld de, BlkPacket_9ee5 + ret + +.SGB_Pokepic: + ld hl, PalPacket_a045 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld hl, BlkPacket_9ee5 + ld de, wSGBPals + PALPACKET_LENGTH + ld bc, PALPACKET_LENGTH + call CopyBytes + call .GetMapPalsIndex + ld hl, wSGBPals + 1 + ld [hl], a + ld hl, wSGBPals + 3 + ld [hl], $2e + ld hl, wSGBPals + $13 + ld a, 5 + ld [hli], a + ld a, [wMenuBorderLeftCoord] + ld [hli], a + ld a, [wMenuBorderTopCoord] + ld [hli], a + ld a, [wMenuBorderRightCoord] + ld [hli], a + ld a, [wMenuBorderBottomCoord] + ld [hl], a + ld hl, wSGBPals + ld de, wSGBPals + PALPACKET_LENGTH + ret + +.SGB1e: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld a, [wCurPartySpecies] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + add hl, hl + ld de, PokemonPalettes + add hl, de + ld a, [wce65] + and 3 + sla a + sla a + ld c, a + ld b, 0 + add hl, bc + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + ld hl, wSGBPals + ld de, BlkPacket_9ee5 + ret + +.SGB_GamefreakLogo: + ld hl, PalPacket_GamefreakLogo + ld de, BlkPacket_9ee5 + ret + +.SGB_PlayerOrMonFrontpicPals: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetPlayerOrMonPalettePointer + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + ld hl, wSGBPals + ld de, BlkPacket_9ee5 + ret + +.SGB_TradeTube: + ld hl, PalPacket_TradeTube + ld de, BlkPacket_9ee5 + ret + +.SGB_TrainerOrMonFrontpicPals: + ld hl, PalPacket_a155 + ld de, wSGBPals + ld bc, PALPACKET_LENGTH + call CopyBytes + ld a, [wCurPartySpecies] + ld bc, wTempMonDVs + call GetFrontpicPalettePointer + ld a, [hli] + ld [wSGBPals + 3], a + ld a, [hli] + ld [wSGBPals + 4], a + ld a, [hli] + ld [wSGBPals + 5], a + ld a, [hl] + ld [wSGBPals + 6], a + ld hl, wSGBPals + ld de, BlkPacket_9ee5 + ret + +.GetMapPalsIndex: + ld a, [wTimeOfDayPal] + cp NITE_F + jr c, .morn_day + ld a, PREDEFPAL_NITE + ret + +.morn_day + ld a, [wEnvironment] + cp ROUTE + jr z, .route + cp CAVE + jr z, .cave + cp DUNGEON + jr z, .cave + cp ENVIRONMENT_5 + jr z, .env5 + cp GATE + jr z, .gate + ld a, [wMapGroup] + ld e, a + ld d, 0 + ld hl, MapGroupRoofSGBPalInds + add hl, de + ld a, [hl] + ret + +.route + ld a, PREDEFPAL_ROUTES + ret + +.cave + ld a, PREDEFPAL_DUNGEONS + ret + +.env5 + ld a, PREDEFPAL_VERMILION + ret + +.gate + ld a, PREDEFPAL_PEWTER + ret + +INCLUDE "data/maps/sgb_roof_pal_inds.asm" + +_LoadSGBLayout_ReturnFromJumpTable: + push de + call PushSGBPals + pop hl + jp PushSGBPals diff --git a/engine/sprite_anims.asm b/engine/gfx/sprite_anims.asm index 2877539d..2877539d 100755 --- a/engine/sprite_anims.asm +++ b/engine/gfx/sprite_anims.asm diff --git a/engine/sprites.asm b/engine/gfx/sprites.asm index b9267d66..b9267d66 100755 --- a/engine/sprites.asm +++ b/engine/gfx/sprites.asm diff --git a/engine/items.asm b/engine/items.asm deleted file mode 100755 index deafa60c..00000000 --- a/engine/items.asm +++ /dev/null @@ -1,551 +0,0 @@ -_ReceiveItem:: ; d1e2 (3:51e2) - call CheckBagOrPC - jp nz, PutItemInPocketOrPC - push hl - call CheckItemPocket - pop de - ld a, [wItemAttributeParamBuffer] - dec a - ld hl, .Jumptable - rst JumpTable - ret - -.Jumptable - dw ReceiveNormalItem - dw ReceiveKeyItem - dw ReceiveBall - dw ReceiveTMHM - -ReceiveNormalItem: - ld h, d - ld l, e - jp PutItemInPocketOrPC - -ReceiveKeyItem: - ld h, d - ld l, e - jp PutItemInKeyItemPocket - -ReceiveBall: - ld hl, wNumBalls - jp PutItemInPocketOrPC - -ReceiveTMHM: - ld h, d - ld l, e - ld a, [wd002] - ld c, a - call GetTMHMNumber - jp PutItemInTMPocket - -_TossItem:: ; d21a (3:521a) - call CheckBagOrPC - jr nz, remove_item_from_bag_or_pc - push hl - call CheckItemPocket - pop de - ld a, [wItemAttributeParamBuffer] - dec a - ld hl, .Jumptable ; $522d - rst JumpTable - ret - -.Jumptable - dw RemoveNormalItem - dw RemoveKeyItem - dw RemoveBall - dw RemoveTMHM - -RemoveBall: - ld hl, wNumBalls - jp RemoveItemAndQuantity - -RemoveTMHM: - ld h, d - ld l, e - ld a, [wd002] - ld c, a - call GetTMHMNumber - jp RemoveTMorHM - -RemoveKeyItem: - ld h, d - ld l, e - jp RemoveItemWithoutQuantity - -RemoveNormalItem: - ld h, d - ld l, e -remove_item_from_bag_or_pc - jp RemoveItemAndQuantity - -_CheckItem:: ; d251 (3:5251) - call CheckBagOrPC - jr nz, check_item_in_bag_or_pc - push hl - call CheckItemPocket - pop de - ld a, [wItemAttributeParamBuffer] - dec a - ld hl, .Jumptable - rst JumpTable - ret - -.Jumptable - dw CheckNormalItem - dw CheckKeyItem - dw CheckBall - dw CheckTMHM - -CheckBall: - ld hl, wNumBalls - jp CheckItemWithQuantity - -CheckTMHM: - ld h, d - ld l, e - ld a, [wd002] - ld c, a - call GetTMHMNumber - jp CheckTMorHM - -CheckKeyItem: - ld h, d - ld l, e - jp CheckItemWithoutQuantity - -CheckNormalItem: - ld h, d - ld l, e -check_item_in_bag_or_pc - jp CheckItemWithQuantity - -CheckBagOrPC: ; d288 (3:5288) - ld a, l - cp wNumItems % $100 - ret nz - ld a, h - cp wNumItems / $100 - ret - -GetPocketCapacity: ; d290 (3:5290) - ld c, MAX_ITEMS - ld a, e - cp wNumItems % $100 - jr nz, .asm_d29b - ld a, d - cp wNumItems / $100 - ret z -.asm_d29b - ld c, MAX_PC_ITEMS - ld a, e - cp wPCItems % $100 - jr nz, .asm_d2a6 - ld a, d - cp wPCItems / $100 - ret z -.asm_d2a6 - ld c, MAX_BALLS - ret - -PutItemInPocketOrPC: ; d2a9 (3:52a9) - ld d, h - ld e, l - inc hl - ld a, [wd002] - ld c, a - ld b, $0 -.asm_d2b2 - ld a, [hli] - cp $ff - jr z, .asm_d2ca - cp c - jr nz, .asm_d2c7 - ld a, $63 - sub [hl] - add b - ld b, a - ld a, [wItemQuantityChangeBuffer] - cp b - jr z, .asm_d2d3 - jr c, .asm_d2d3 -.asm_d2c7 - inc hl - jr .asm_d2b2 - -.asm_d2ca - call GetPocketCapacity - ld a, [de] - cp c - jr c, .asm_d2d3 - and a - ret - -.asm_d2d3 - ld h, d - ld l, e - ld a, [wd002] - ld c, a - ld a, [wItemQuantityChangeBuffer] - ld [wItemQuantityBuffer], a -.asm_d2df - inc hl - ld a, [hli] - cp $ff - jr z, .asm_d2fc - cp c - jr nz, .asm_d2df - ld a, [wItemQuantityBuffer] - add [hl] - cp $64 - jr nc, .asm_d2f3 - ld [hl], a - jr .asm_d30a - -.asm_d2f3 - ld [hl], $63 - sub $63 - ld [wItemQuantityBuffer], a - jr .asm_d2df - -.asm_d2fc - dec hl - ld a, [wd002] - ld [hli], a - ld a, [wItemQuantityBuffer] - ld [hli], a - ld [hl], $ff - ld h, d - ld l, e - inc [hl] -.asm_d30a - scf - ret - -RemoveItemAndQuantity: ; d30c (3:530c) - ld d, h - ld e, l - ld a, [hli] - ld c, a - ld a, [wd003] - cp c - jr nc, .asm_d325 - ld c, a - ld b, $0 - add hl, bc - add hl, bc - ld a, [wd002] - cp [hl] - inc hl - jr z, .asm_d334 - ld h, d - ld l, e - inc hl -.asm_d325 - ld a, [wd002] - ld b, a -.asm_d329 - ld a, [hli] - cp b - jr z, .asm_d334 - cp $ff - jr z, .asm_d354 - inc hl - jr .asm_d329 - -.asm_d334 - ld a, [wItemQuantityChangeBuffer] - ld b, a - ld a, [hl] - sub b - jr c, .asm_d354 - ld [hl], a - ld [wItemQuantityBuffer], a - and a - jr nz, .asm_d352 - dec hl - ld b, h - ld c, l - inc hl - inc hl -.asm_d348 - ld a, [hli] - ld [bc], a - inc bc - cp $ff - jr nz, .asm_d348 - ld h, d - ld l, e - dec [hl] -.asm_d352 - scf - ret - -.asm_d354 - and a - ret - -CheckItemWithQuantity: ; d356 (3:5356) - ld a, [wd002] - ld c, a -.asm_d35a - inc hl - ld a, [hli] - cp $ff - jr z, .asm_d365 - cp c - jr nz, .asm_d35a - scf - ret - -.asm_d365 - and a - ret - -PutItemInKeyItemPocket: ; d367 (3:5367) - ld hl, wItemsEnd - ld a, [hli] - cp $19 - jr nc, .asm_d37f - ld c, a - ld b, $0 - add hl, bc - ld a, [wd002] - ld [hli], a - ld [hl], $ff - ld hl, wNumKeyItems - inc [hl] - scf - ret - -.asm_d37f - and a - ret - -RemoveItemWithoutQuantity: ; d381 (3:5381) - ld a, [wd003] - ld e, a - ld d, $0 - ld hl, wItemsEnd - ld a, [hl] - cp e - jr nc, .asm_d394 - call FindAndTossKeyItem - ret nc - jr .asm_d397 - -.asm_d394 - dec [hl] - inc hl - add hl, de -.asm_d397 - ld d, h - ld e, l - inc hl -.asm_d39a - ld a, [hli] - ld [de], a - inc de - cp $ff - jr nz, .asm_d39a - scf - ret - -FindAndTossKeyItem: ; d3a3 (3:53a3) - ld hl, wItemsEnd - ld a, [wd002] - ld c, a -.asm_d3aa - inc hl - ld a, [hl] - cp c - jr z, .asm_d3b5 - cp $ff - jr nz, .asm_d3aa - xor a - ret - -.asm_d3b5 - ld a, [wNumKeyItems] - dec a - ld [wNumKeyItems], a - scf - ret - -CheckItemWithoutQuantity: ; d3be (3:53be) - ld a, [wd002] - ld c, a - ld hl, wKeyItems -.asm_d3c5 - ld a, [hli] - cp c - jr z, .asm_d3cf - cp $ff - jr nz, .asm_d3c5 - and a - ret - -.asm_d3cf - scf - ret - -PutItemInTMPocket: ; d3d1 (3:53d1) - dec c - ld b, $0 - ld hl, wTMsHMs - add hl, bc - ld a, [wItemQuantityChangeBuffer] - add [hl] - cp $64 - jr nc, .asm_d3e3 - ld [hl], a - scf - ret - -.asm_d3e3 - and a - ret - -RemoveTMorHM: ; d3e5 (3:53e5) - dec c - ld b, $0 - ld hl, wTMsHMs - add hl, bc - ld a, [wItemQuantityChangeBuffer] - ld b, a - ld a, [hl] - sub b - jr c, .asm_d406 - ld [hl], a - ld [wItemQuantityBuffer], a - jr nz, .asm_d404 - ld a, [wcfd2] - and a - jr z, .asm_d404 - dec a - ld [wcfd2], a -.asm_d404 - scf - ret - -.asm_d406 - and a - ret - -CheckTMorHM: ; d408 (3:5408) - dec c - ld b, $0 - ld hl, wTMsHMs - add hl, bc - ld a, [hl] - and a - ret z - scf - ret - -GetTMHMNumber:: ; d414 (3:5414) - ld a, c - cp ITEM_C3 - jr c, .asm_d41f - cp ITEM_DC - jr c, .asm_d41e - dec a -.asm_d41e - dec a -.asm_d41f - sub $bf - inc a - ld c, a - ret - -GetNumberedTM: - ld a, c - cp ITEM_C3 - (TM01 - 1) - jr c, .asm_d42f - cp ITEM_DC - (TM01 - 1) - 1 - jr c, .asm_d42e - inc a -.asm_d42e - inc a -.asm_d42f - add TM01 - dec a - ld c, a - ret - -_CheckTossableItem:: ; d434 (3:5434) - ld a, $4 - call GetItemAttr - bit 7, a - jr nz, ItemAttr_ReturnCarry - and a - ret - -CheckSelectableItem: - ld a, $4 - call GetItemAttr - bit 6, a - jr nz, ItemAttr_ReturnCarry - and a - ret - -CheckItemPocket: ; d44a (3:544a) - ld a, $5 - call GetItemAttr - and $f - ld [wItemAttributeParamBuffer], a - ret - -CheckItemContext: - ld a, $6 - call GetItemAttr - and $f - ld [wItemAttributeParamBuffer], a - ret - -CheckItemMenu: - ld a, $6 - call GetItemAttr - swap a - and $f - ld [wItemAttributeParamBuffer], a - ret - -GetItemAttr: ; d46d (3:546d) - push hl - push bc - ld hl, ItemAttributes - ld c, a - ld b, $0 - add hl, bc - xor a - ld [wItemAttributeParamBuffer], a - ld a, [wd002] - dec a - ld c, a - ld a, $7 - call AddNTimes - ld a, BANK(ItemAttributes) - call GetFarByte - pop bc - pop hl - ret - -ItemAttr_ReturnCarry - ld a, $1 - ld [wItemAttributeParamBuffer], a - scf - ret - -GetItemPrice: - push hl - push bc - ld a, $0 - call GetItemAttr - ld e, a - ld a, $1 - call GetItemAttr - ld d, a - pop bc - pop hl - ret diff --git a/engine/items/buy_sell_toss.asm b/engine/items/buy_sell_toss.asm new file mode 100644 index 00000000..45c3dfcf --- /dev/null +++ b/engine/items/buy_sell_toss.asm @@ -0,0 +1,218 @@ +SelectQuantityToToss: + ld hl, TossItem_MenuHeader + call LoadMenuHeader + call Toss_Sell_Loop + ret + +SelectQuantityToBuy: + farcall GetItemPrice + ld a, d + ld [wBuffer1], a + ld a, e + ld [wBuffer2], a + ld hl, BuyItem_MenuHeader + call LoadMenuHeader + call Toss_Sell_Loop + ret + +SelectQuantityToSell: + farcall GetItemPrice + ld a, d + ld [wBuffer1], a + ld a, e + ld [wBuffer2], a + ld hl, SellItem_MenuHeader + call LoadMenuHeader + call Toss_Sell_Loop + ret + +Toss_Sell_Loop: + ld a, 1 + ld [wItemQuantityChangeBuffer], a +.loop + call BuySellToss_UpdateQuantityDisplay ; update display + call BuySellToss_InterpretJoypad ; joy action + jr nc, .loop + cp -1 + jr nz, .nope ; pressed B + scf + ret + +.nope + and a + ret + +BuySellToss_InterpretJoypad: + call JoyTextDelay_ForcehJoyDown ; get joypad + bit B_BUTTON_F, c + jr nz, .b + bit A_BUTTON_F, c + jr nz, .a + bit D_DOWN_F, c + jr nz, .down + bit D_UP_F, c + jr nz, .up + bit D_LEFT_F, c + jr nz, .left + bit D_RIGHT_F, c + jr nz, .right + and a + ret + +.b + ld a, -1 + scf + ret + +.a + ld a, 0 + scf + ret + +.down + ld hl, wItemQuantityChangeBuffer + dec [hl] + jr nz, .finish_down + ld a, [wItemQuantityBuffer] + ld [hl], a + +.finish_down + and a + ret + +.up + ld hl, wItemQuantityChangeBuffer + inc [hl] + ld a, [wItemQuantityBuffer] + cp [hl] + jr nc, .finish_up + ld [hl], 1 + +.finish_up + and a + ret + +.left + ld a, [wItemQuantityChangeBuffer] + sub 10 + jr c, .load_1 + jr z, .load_1 + jr .finish_left + +.load_1 + ld a, 1 + +.finish_left + ld [wItemQuantityChangeBuffer], a + and a + ret + +.right + ld a, [wItemQuantityChangeBuffer] + add 10 + ld b, a + ld a, [wItemQuantityBuffer] + cp b + jr nc, .finish_right + ld b, a + +.finish_right + ld a, b + ld [wItemQuantityChangeBuffer], a + and a + ret + +BuySellToss_UpdateQuantityDisplay: + call MenuBox + call MenuBoxCoord2Tile + ld de, SCREEN_WIDTH + 1 + add hl, de + ld [hl], "×" + inc hl + ld de, wItemQuantityChangeBuffer + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ld a, [wMenuDataPointer] + ld e, a + ld a, [wMenuDataPointer + 1] + ld d, a + push de + ret + +ret_24ff3: + ret + +DisplayPurchasePrice: + call BuySell_MultiplyPrice + call BuySell_DisplaySubtotal + ret + +DisplaySellingPrice: + call BuySell_MultiplyPrice + call Sell_HalvePrice + call BuySell_DisplaySubtotal + ret + +BuySell_MultiplyPrice: + xor a + ldh [hMultiplicand + 0], a + ld a, [wBuffer1] + ldh [hMultiplicand + 1], a + ld a, [wBuffer2] + ldh [hMultiplicand + 2], a + ld a, [wItemQuantityChangeBuffer] + ldh [hMultiplier], a + push hl + call Multiply + pop hl + ret + +Sell_HalvePrice: + push hl + ld hl, hProduct + 1 + ld a, [hl] + srl a + ld [hli], a + ld a, [hl] + rra + ld [hli], a + ld a, [hl] + rra + ld [hl], a + pop hl + ret + +BuySell_DisplaySubtotal: + push hl + ld hl, hMoneyTemp + ldh a, [hProduct + 1] + ld [hli], a + ldh a, [hProduct + 2] + ld [hli], a + ldh a, [hProduct + 3] + ld [hl], a + pop hl + inc hl + ld de, hMoneyTemp + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + call WaitBGMap + ret + +TossItem_MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 15, 9, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw ret_24ff3 + db 0 ; default option + +BuyItem_MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 15, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw DisplayPurchasePrice + db -1 ; default option + +SellItem_MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 15, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw DisplaySellingPrice + db 0 ; default option diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm new file mode 100755 index 00000000..35a7cd6c --- /dev/null +++ b/engine/items/item_effects.asm @@ -0,0 +1,2891 @@ +_DoItemEffect:: + ld a, [wCurItem] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call CopyName1 + ld a, 1 + ld [wItemEffectSucceeded], a + ld a, [wCurItem] + dec a + ld hl, ItemEffects + rst JumpTable + ret + +ItemEffects: +; entries correspond to item ids + dw PokeBallEffect ; MASTER_BALL + dw PokeBallEffect ; ULTRA_BALL + dw NoEffect ; BRIGHTPOWDER + dw PokeBallEffect ; GREAT_BALL + dw PokeBallEffect ; POKE_BALL + dw TownMapEffect ; TOWN_MAP + dw BicycleEffect ; BICYCLE + dw EvoStoneEffect ; MOON_STONE + dw StatusHealingEffect ; ANTIDOTE + dw StatusHealingEffect ; BURN_HEAL + dw StatusHealingEffect ; ICE_HEAL + dw StatusHealingEffect ; AWAKENING + dw StatusHealingEffect ; PARLYZ_HEAL + dw FullRestoreEffect ; FULL_RESTORE + dw RestoreHPEffect ; MAX_POTION + dw RestoreHPEffect ; HYPER_POTION + dw RestoreHPEffect ; SUPER_POTION + dw RestoreHPEffect ; POTION + dw EscapeRopeEffect ; ESCAPE_ROPE + dw RepelEffect ; REPEL + dw RestorePPEffect ; MAX_ELIXER + dw EvoStoneEffect ; FIRE_STONE + dw EvoStoneEffect ; THUNDERSTONE + dw EvoStoneEffect ; WATER_STONE + dw NoEffect ; ITEM_19 + dw VitaminEffect ; HP_UP + dw VitaminEffect ; PROTEIN + dw VitaminEffect ; IRON + dw VitaminEffect ; CARBOS + dw NoEffect ; LUCKY_PUNCH + dw VitaminEffect ; CALCIUM + dw RareCandyEffect ; RARE_CANDY + dw XAccuracyEffect ; X_ACCURACY + dw EvoStoneEffect ; LEAF_STONE + dw NoEffect ; METAL_POWDER + dw NoEffect ; NUGGET + dw PokeDollEffect ; POKE_DOLL + dw StatusHealingEffect ; FULL_HEAL + dw ReviveEffect ; REVIVE + dw ReviveEffect ; MAX_REVIVE + dw GuardSpecEffect ; GUARD_SPEC + dw SuperRepelEffect ; SUPER_REPEL + dw MaxRepelEffect ; MAX_REPEL + dw DireHitEffect ; DIRE_HIT + dw NoEffect ; ITEM_2D + dw RestoreHPEffect ; FRESH_WATER + dw RestoreHPEffect ; SODA_POP + dw RestoreHPEffect ; LEMONADE + dw XItemEffect ; X_ATTACK + dw NoEffect ; ITEM_32 + dw XItemEffect ; X_DEFEND + dw XItemEffect ; X_SPEED + dw XItemEffect ; X_SPECIAL + dw CoinCaseEffect ; COIN_CASE + dw ItemfinderEffect ; ITEMFINDER + dw PokeFluteEffect ; POKE_FLUTE + dw NoEffect ; EXP_SHARE + dw OldRodEffect ; OLD_ROD + dw GoodRodEffect ; GOOD_ROD + dw NoEffect ; SILVER_LEAF + dw SuperRodEffect ; SUPER_ROD + dw RestorePPEffect ; PP_UP + dw RestorePPEffect ; ETHER + dw RestorePPEffect ; MAX_ETHER + dw RestorePPEffect ; ELIXER + dw NoEffect ; RED_SCALE + dw NoEffect ; SECRETPOTION + dw NoEffect ; S_S_TICKET + dw NoEffect ; MYSTERY_EGG + dw NoEffect ; ITEM_46 + dw NoEffect ; SILVER_WING + dw RestoreHPEffect ; MOOMOO_MILK + dw NoEffect ; QUICK_CLAW + dw StatusHealingEffect ; PSNCUREBERRY + dw NoEffect ; GOLD_LEAF + dw NoEffect ; SOFT_SAND + dw NoEffect ; SHARP_BEAK + dw StatusHealingEffect ; PRZCUREBERRY + dw StatusHealingEffect ; BURNT_BERRY + dw StatusHealingEffect ; ICE_BERRY + dw NoEffect ; POISON_BARB + dw NoEffect ; KINGS_ROCK + dw BitterBerryEffect ; BITTER_BERRY + dw StatusHealingEffect ; MINT_BERRY + dw NoEffect ; RED_APRICORN + dw NoEffect ; TINYMUSHROOM + dw NoEffect ; BIG_MUSHROOM + dw NoEffect ; SILVERPOWDER + dw NoEffect ; BLU_APRICORN + dw NoEffect ; ITEM_5A + dw NoEffect ; AMULET_COIN + dw NoEffect ; YLW_APRICORN + dw NoEffect ; GRN_APRICORN + dw NoEffect ; CLEANSE_TAG + dw NoEffect ; MYSTIC_WATER + dw NoEffect ; TWISTEDSPOON + dw NoEffect ; WHT_APRICORN + dw NoEffect ; BLACKBELT_I + dw NoEffect ; BLK_APRICORN + dw NoEffect ; ITEM_64 + dw NoEffect ; PNK_APRICORN + dw NoEffect ; BLACKGLASSES + dw NoEffect ; SLOWPOKETAIL + dw NoEffect ; PINK_BOW + dw NoEffect ; STICK + dw NoEffect ; SMOKE_BALL + dw NoEffect ; NEVERMELTICE + dw NoEffect ; MAGNET + dw StatusHealingEffect ; MIRACLEBERRY + dw NoEffect ; PEARL + dw NoEffect ; BIG_PEARL + dw NoEffect ; EVERSTONE + dw NoEffect ; SPELL_TAG + dw RestoreHPEffect ; RAGECANDYBAR + dw NoEffect ; ITEM_73 + dw NoEffect ; ITEM_74 + dw NoEffect ; MIRACLE_SEED + dw NoEffect ; THICK_CLUB + dw NoEffect ; FOCUS_BAND + dw NoEffect ; ITEM_78 + dw EnergypowderEffect ; ENERGYPOWDER + dw EnergyRootEffect ; ENERGY_ROOT + dw HealPowderEffect ; HEAL_POWDER + dw RevivalHerbEffect ; REVIVAL_HERB + dw NoEffect ; HARD_STONE + dw NoEffect ; LUCKY_EGG + dw CardKeyEffect ; CARD_KEY + dw NoEffect ; MACHINE_PART + dw NoEffect ; ITEM_81 + dw NoEffect ; LOST_ITEM + dw NoEffect ; STARDUST + dw NoEffect ; STAR_PIECE + dw BasementKeyEffect ; BASEMENT_KEY + dw NoEffect ; PASS + dw NoEffect ; ITEM_87 + dw NoEffect ; ITEM_88 + dw NoEffect ; ITEM_89 + dw NoEffect ; CHARCOAL + dw RestoreHPEffect ; BERRY_JUICE + dw NoEffect ; SCOPE_LENS + dw NoEffect ; ITEM_8D + dw NoEffect ; ITEM_8E + dw NoEffect ; METAL_COAT + dw NoEffect ; DRAGON_FANG + dw NoEffect ; ITEM_91 + dw NoEffect ; LEFTOVERS + dw NoEffect ; ITEM_93 + dw NoEffect ; ITEM_94 + dw NoEffect ; ITEM_95 + dw RestorePPEffect ; MYSTERYBERRY + dw NoEffect ; DRAGON_SCALE + dw NoEffect ; BERSERK_GENE + dw NoEffect ; ITEM_99 + dw NoEffect ; ITEM_9A + dw NoEffect ; ITEM_9B + dw SacredAshEffect ; SACRED_ASH + dw PokeBallEffect ; HEAVY_BALL + dw NoEffect ; FLOWER_MAIL + dw PokeBallEffect ; LEVEL_BALL + dw PokeBallEffect ; LURE_BALL + dw PokeBallEffect ; FAST_BALL + dw NoEffect ; ITEM_A2 + dw NoEffect ; LIGHT_BALL + dw PokeBallEffect ; FRIEND_BALL + dw PokeBallEffect ; MOON_BALL + dw PokeBallEffect ; LOVE_BALL + dw NormalBoxEffect ; NORMAL_BOX + dw GorgeousBoxEffect ; GORGEOUS_BOX + dw EvoStoneEffect ; SUN_STONE + dw NoEffect ; POLKADOT_BOW + dw NoEffect ; ITEM_AB + dw NoEffect ; UP_GRADE + dw RestoreHPEffect ; BERRY + dw RestoreHPEffect ; GOLD_BERRY + dw SquirtbottleEffect ; SQUIRTBOTTLE + dw NoEffect ; ITEM_B0 + dw PokeBallEffect ; PARK_BALL + dw NoEffect ; RAINBOW_WING + dw NoEffect ; ITEM_B3 + +PokeBallEffect: + ld a, [wBattleMode] + dec a + jp nz, UseBallInTrainerBattle + + ld a, [wPartyCount] + cp PARTY_LENGTH + jr nz, .room_in_party + + ld a, BANK(sBoxCount) + call OpenSRAM + ld a, [sBoxCount] + cp MONS_PER_BOX + call CloseSRAM + jp z, Ball_BoxIsFullMessage + +.room_in_party + xor a + ld [wWildMon], a + ld a, [wCurItem] + cp PARK_BALL + call nz, ReturnToBattle_UseBall + + ld hl, wOptions + res NO_TEXT_SCROLL, [hl] + ld hl, ItemUsedText + call PrintText + + ld a, [wEnemyMonCatchRate] + ld b, a + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jp z, .catch_without_fail + ld a, [wCurItem] + cp MASTER_BALL + jp z, .catch_without_fail + ld a, [wCurItem] + ld c, a + ld hl, BallMultiplierFunctionTable + +.get_multiplier_loop + ld a, [hli] + cp $ff + jr z, .skip_or_return_from_ball_fn + cp c + jr z, .call_ball_function + inc hl + inc hl + jr .get_multiplier_loop + +.call_ball_function + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .skip_or_return_from_ball_fn + push de + jp hl + +.skip_or_return_from_ball_fn + ld a, [wCurItem] + cp LEVEL_BALL + ld a, b + jp z, .skip_hp_calc + + ld a, b + ldh [hMultiplicand + 2], a + + ld hl, wEnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + inc hl + ld d, [hl] + inc hl + ld e, [hl] + sla c + rl b + + ld h, d + ld l, e + add hl, de + add hl, de + ld d, h + ld e, l + ld a, d + and a + jr z, .okay_1 + + srl d + rr e + srl d + rr e + srl b + rr c + srl b + rr c + + ld a, c + and a + jr nz, .okay_1 + ld c, $1 +.okay_1 + ld b, e + + push bc + ld a, b + sub c + ldh [hMultiplier], a + xor a + ldh [hDividend + 0], a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + call Multiply + pop bc + + ld a, b + ldh [hDivisor], a + ld b, 4 + call Divide + + ldh a, [hQuotient + 3] + and a + jr nz, .statuscheck + ld a, 1 +.statuscheck +; This routine is buggy. It was intended that SLP and FRZ provide a higher +; catch rate than BRN/PSN/PAR, which in turn provide a higher catch rate than +; no status effect at all. But instead, it makes BRN/PSN/PAR provide no +; benefit. +; Uncomment the line below to fix this. + ld b, a + ld a, [wEnemyMonStatus] + and 1 << FRZ | SLP + ld c, 10 + jr nz, .addstatus + ; ld a, [wEnemyMonStatus] + and a + ld c, 5 + jr nz, .addstatus + ld c, 0 +.addstatus + ld a, b + add c + jr nc, .max_1 + ld a, $ff +.max_1 + + ; BUG: farcall overwrites a, and GetItemHeldEffect takes b anyway. + ; This is probably the reason the HELD_CATCH_CHANCE effect is never used. + ; Uncomment the line below to fix. + ld d, a + push de + ld a, [wBattleMonItem] + ; ld b, a + farcall GetItemHeldEffect + ld a, b + cp HELD_CATCH_CHANCE + pop de + ld a, d + jr nz, .max_2 + add c + jr nc, .max_2 + ld a, $ff +.max_2 + +.skip_hp_calc + ld b, a + ld [wBuffer1], a + call Random + + cp b + ld a, 0 + jr z, .catch_without_fail + jr nc, .fail_to_catch + +.catch_without_fail + ld a, [wEnemyMonSpecies] + +.fail_to_catch + ld [wWildMon], a + ld c, 20 + call DelayFrames + + ld a, [wCurItem] + cp POKE_BALL + 1 ; Assumes Master/Ultra/Great come before + jr c, .not_kurt_ball + ld a, POKE_BALL +.not_kurt_ball + ld [wBattleAnimParam], a + + ld de, ANIM_THROW_POKE_BALL + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 1], a + xor a + ldh [hBattleTurn], a + ld [wBuffer2], a + ld [wNumHits], a + predef PlayBattleAnim + + ld a, [wWildMon] + and a + jr nz, .caught + ld a, [wBuffer2] + cp $1 + ld hl, BallBrokeFreeText + jp z, .shake_and_break_free + cp $2 + ld hl, BallAppearedCaughtText + jp z, .shake_and_break_free + cp $3 + ld hl, BallAlmostHadItText + jp z, .shake_and_break_free + cp $4 + ld hl, BallSoCloseText + jp z, .shake_and_break_free +.caught + + ld hl, wEnemyMonStatus + ld a, [hli] + push af + inc hl + ld a, [hli] + push af + ld a, [hl] + push af + push hl + ld hl, wEnemyMonItem + ld a, [hl] + push af + push hl + ld hl, wEnemySubStatus5 + ld a, [hl] + push af + set SUBSTATUS_TRANSFORMED, [hl] + +; This code is buggy. Any wild Pokémon that has Transformed will be +; caught as a Ditto, even if it was something else like Mew. +; To fix, do not set [wTempEnemyMonSpecies] to DITTO. + bit SUBSTATUS_TRANSFORMED, a + jr nz, .ditto + jr .not_ditto + +.ditto + ld a, DITTO + ld [wTempEnemyMonSpecies], a + jr .load_data + +.not_ditto + set SUBSTATUS_TRANSFORMED, [hl] + ld hl, wEnemyBackupDVs + ld a, [wEnemyMonDVs] + ld [hli], a + ld a, [wEnemyMonDVs + 1] + ld [hl], a + +.load_data + ld a, [wTempEnemyMonSpecies] + ld [wCurPartySpecies], a + ld a, [wEnemyMonLevel] + ld [wCurPartyLevel], a + farcall LoadEnemyMon + + pop af + ld [wEnemySubStatus5], a + + pop hl + pop af + ld [hl], a + pop hl + pop af + ld [hld], a + pop af + ld [hld], a + dec hl + pop af + ld [hl], a + + ld hl, wEnemySubStatus5 + bit SUBSTATUS_TRANSFORMED, [hl] + jr nz, .Transformed + ld hl, wWildMonMoves + ld de, wEnemyMonMoves + ld bc, NUM_MOVES + call CopyBytes + + ld hl, wWildMonPP + ld de, wEnemyMonPP + ld bc, NUM_MOVES + call CopyBytes + +.Transformed: + ld a, [wEnemyMonSpecies] + ld [wWildMon], a + ld [wCurPartySpecies], a + ld [wTempSpecies], a + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jp z, .FinishTutorial + + ld hl, Text_GotchaMonWasCaught + call PrintText + + call ClearSprites + + ld a, [wTempSpecies] + dec a + call CheckCaughtMon + + ld a, c + push af + ld a, [wTempSpecies] + dec a + call SetSeenAndCaughtMon + pop af + and a + jr nz, .skip_pokedex + + call CheckReceivedDex + jr z, .skip_pokedex + + ld hl, NewDexDataText + call PrintText + + call ClearSprites + + ld a, [wEnemyMonSpecies] + ld [wTempSpecies], a + predef NewPokedexEntry + +.skip_pokedex + ld a, [wBattleType] + cp BATTLETYPE_CONTEST + jp z, .catch_bug_contest_mon + ld a, [wPartyCount] + cp PARTY_LENGTH + jr z, .SendToPC + + xor a ; PARTYMON + ld [wMonType], a + call ClearSprites + + predef TryAddMonToParty + + ld a, [wCurItem] + cp FRIEND_BALL + jr nz, .SkipPartyMonFriendBall + + ld a, [wPartyCount] + dec a + ld hl, wPartyMon1Happiness + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + + ld a, FRIEND_BALL_HAPPINESS + ld [hl], a + +.SkipPartyMonFriendBall: + ld hl, AskGiveNicknameText + call PrintText + + ld a, [wCurPartySpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + + call YesNoBox + jp c, .return_from_capture + + ld a, [wPartyCount] + dec a + ld [wCurPartyMon], a + ld hl, wPartyMonNicknames + ld bc, MON_NAME_LENGTH + call AddNTimes + + ld d, h + ld e, l + push de + xor a ; PARTYMON + ld [wMonType], a + ld b, NAME_MON + farcall NamingScreen + + call RotateThreePalettesRight + + call LoadStandardFont + + pop hl + ld de, wStringBuffer1 + call InitName + + jp .return_from_capture + +.SendToPC: + call ClearSprites + + predef SendMonIntoBox + + ld a, BANK(sBoxCount) + call OpenSRAM + + ld a, [sBoxCount] + cp MONS_PER_BOX + jr nz, .BoxNotFullYet + ld hl, wBattleResult + set BATTLERESULT_BOX_FULL, [hl] +.BoxNotFullYet: + ld a, [wCurItem] + cp FRIEND_BALL + jr nz, .SkipBoxMonFriendBall + ; The captured mon is now first in the box + ld a, FRIEND_BALL_HAPPINESS + ld [sBoxMon1Happiness], a +.SkipBoxMonFriendBall: + call CloseSRAM + + ld hl, AskGiveNicknameText + call PrintText + + ld a, [wCurPartySpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + + call YesNoBox + jr c, .SkipBoxMonNickname + + xor a + ld [wCurPartyMon], a + ld a, BOXMON + ld [wMonType], a + ld de, wMonOrItemNameBuffer + ld b, NAME_MON + farcall NamingScreen + + ld a, BANK(sBoxMonNicknames) + call OpenSRAM + + ld hl, wMonOrItemNameBuffer + ld de, sBoxMonNicknames + ld bc, MON_NAME_LENGTH + call CopyBytes + + ld hl, sBoxMonNicknames + ld de, wStringBuffer1 + call InitName + + call CloseSRAM + +.SkipBoxMonNickname: + ld a, BANK(sBoxMonNicknames) + call OpenSRAM + + ld hl, sBoxMonNicknames + ld de, wMonOrItemNameBuffer + ld bc, MON_NAME_LENGTH + call CopyBytes + + call CloseSRAM + + ld hl, BallSentToPCText + call PrintText + + call RotateThreePalettesRight + call LoadStandardFont + jr .return_from_capture + +.catch_bug_contest_mon + farcall BugContest_SetCaughtContestMon + jr .return_from_capture + +.FinishTutorial: + ld hl, Text_GotchaMonWasCaught + +.shake_and_break_free + call PrintText + call ClearSprites + +.return_from_capture + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + ret z + cp BATTLETYPE_DEBUG + ret z + cp BATTLETYPE_CONTEST + jr z, .used_park_ball + + ld a, [wWildMon] + and a + jr z, .toss + + call ClearBGPalettes + call ClearTilemap + +.toss + ld hl, wNumItems + inc a + ld [wItemQuantityChangeBuffer], a + jp TossItem + +.used_park_ball + ld hl, wParkBallsRemaining + dec [hl] + ret + +BallMultiplierFunctionTable: +; table of routines that increase or decrease the catch rate based on +; which ball is used in a certain situation. + dbw ULTRA_BALL, UltraBallMultiplier + dbw GREAT_BALL, GreatBallMultiplier + dbw SAFARI_BALL, SafariBallMultiplier ; Safari Ball, leftover from RBY + dbw HEAVY_BALL, HeavyBallMultiplier + dbw LEVEL_BALL, LevelBallMultiplier + dbw LURE_BALL, LureBallMultiplier + dbw FAST_BALL, FastBallMultiplier + dbw MOON_BALL, MoonBallMultiplier + dbw LOVE_BALL, LoveBallMultiplier + dbw PARK_BALL, ParkBallMultiplier + db -1 ; end + +UltraBallMultiplier: +; multiply catch rate by 2 + sla b + ret nc + ld b, $ff + ret + +SafariBallMultiplier: +GreatBallMultiplier: +ParkBallMultiplier: +; multiply catch rate by 1.5 + ld a, b + srl a + add b + ld b, a + ret nc + ld b, $ff + ret + +HeavyBallMultiplier: +; subtract 20 from catch rate if weight < 102.4 kg +; else add 0 to catch rate if weight < 204.8 kg +; else add 20 to catch rate if weight < 307.2 kg +; else add 30 to catch rate if weight < 409.6 kg +; else add 40 to catch rate (never happens) + ld a, [wEnemyMonSpecies] + dec a + ld hl, PokedexDataPointerTable + ld e, a + ld d, 0 + add hl, de + add hl, de + rlca + rlca + and %11 + add BANK("Pokedex Entries 001-064") + ld d, a + ld a, BANK(PokedexDataPointerTable) + call GetFarHalfword + +.SkipText: + ld a, d + call GetFarByte + inc hl + cp "@" + jr nz, .SkipText + + ld a, d + push bc + inc hl + inc hl + call GetFarHalfword + + srl h + rr l + ld b, h + ld c, l + +rept 4 + srl b + rr c +endr + call .subbc + + srl b + rr c + call .subbc + + ld a, h + pop bc + jr .compare + +.subbc + ; subtract bc from hl + push bc + ld a, b + cpl + ld b, a + ld a, c + cpl + ld c, a + inc bc + add hl, bc + pop bc + ret + +.compare + ld c, a + cp HIGH(1024) ; 102.4 kg + jr c, .lightmon + + ld hl, .WeightsTable +.lookup + ld a, c + cp [hl] + jr c, .heavymon + inc hl + inc hl + jr .lookup + +.heavymon + inc hl + ld a, b + add [hl] + ld b, a + ret nc + ld b, $ff + ret + +.lightmon + ld a, b + sub 20 + ld b, a + ret nc + ld b, $1 + ret + +.WeightsTable: +; weight factor, boost + db HIGH(2048), 0 + db HIGH(3072), 20 + db HIGH(4096), 30 + db HIGH(65280), 40 + +LureBallMultiplier: +; multiply catch rate by 3 if this is a fishing rod battle + ld a, [wBattleType] + cp BATTLETYPE_FISH + ret nz + + ld a, b + add a + jr c, .max + + add b + jr nc, .done +.max + ld a, $ff +.done + ld b, a + ret + +MoonBallMultiplier: +; This function is buggy. +; Intent: multiply catch rate by 4 if mon evolves with moon stone +; Reality: no boost + push bc + ld a, [wTempEnemyMonSpecies] + dec a + ld c, a + ld b, 0 + ld hl, EvosAttacksPointers + add hl, bc + add hl, bc + ld a, BANK(EvosAttacksPointers) + call GetFarHalfword + pop bc + + push bc + ld a, BANK("Evolutions and Attacks") + call GetFarByte + cp EVOLVE_ITEM + pop bc + ret nz + + inc hl + inc hl + inc hl + +; Moon Stone's constant from Pokémon Red is used. +; No Pokémon evolve with Burn Heal, +; so Moon Balls always have a catch rate of 1×. + push bc + ld a, BANK("Evolutions and Attacks") + call GetFarByte + cp MOON_STONE_RED ; BURN_HEAL + pop bc + ret nz + + sla b + jr c, .max + sla b + jr nc, .done +.max + ld b, $ff +.done + ret + +LoveBallMultiplier: +; This function is buggy. +; Intent: multiply catch rate by 8 if mons are of same species, different sex +; Reality: multiply catch rate by 8 if mons are of same species, same sex + + ; does species match? + ld a, [wTempEnemyMonSpecies] + ld c, a + ld a, [wTempBattleMonSpecies] + cp c + ret nz + + ; check player mon species + push bc + ld a, [wTempBattleMonSpecies] + ld [wCurPartySpecies], a + xor a ; PARTYMON + ld [wMonType], a + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + farcall GetGender + jr c, .done1 ; no effect on genderless + + ld d, 0 ; male + jr nz, .playermale + inc d ; female +.playermale + + ; check wild mon species + push de + ld a, [wTempEnemyMonSpecies] + ld [wCurPartySpecies], a + ld a, WILDMON + ld [wMonType], a + farcall GetGender + jr c, .done2 ; no effect on genderless + + ld d, 0 ; male + jr nz, .wildmale + inc d ; female +.wildmale + + ld a, d + pop de + cp d + pop bc + ret nz ; for the intended effect, this should be "ret z" + + sla b + jr c, .max + sla b + jr c, .max + sla b + ret nc +.max + ld b, $ff + ret + +.done2 + pop de + +.done1 + pop bc + ret + +FastBallMultiplier: +; This function is buggy. +; Intent: multiply catch rate by 4 if enemy mon is in one of the three +; FleeMons tables. +; Reality: multiply catch rate by 4 if enemy mon is one of the first three in +; the first FleeMons table. + ld a, [wTempEnemyMonSpecies] + ld c, a + ld hl, FleeMons + ld d, 3 + +.loop + ld a, BANK(FleeMons) + call GetFarByte + + inc hl + cp -1 + jr z, .next + cp c + jr nz, .next ; for the intended effect, this should be "jr nz, .loop" + sla b + jr c, .max + + sla b + ret nc + +.max + ld b, $ff + ret + +.next + dec d + jr nz, .loop + ret + +LevelBallMultiplier: +; multiply catch rate by 8 if player mon level / 4 > enemy mon level +; multiply catch rate by 4 if player mon level / 2 > enemy mon level +; multiply catch rate by 2 if player mon level > enemy mon level + ld a, [wBattleMonLevel] + ld c, a + ld a, [wEnemyMonLevel] + cp c + ret nc ; if player is lower level, we're done here + sla b + jr c, .max + + srl c + cp c + ret nc ; if player/2 is lower level, we're done here + sla b + jr c, .max + + srl c + cp c + ret nc ; if player/4 is lower level, we're done here + sla b + ret nc + +.max + ld b, $ff + ret + +; These two texts were carried over from gen 1. +; They are not used in gen 2, and are dummied out. + +BallDodgedText: + text_far _BallDodgedText + text_end + +BallMissedText: + text_far _BallMissedText + text_end + +BallBrokeFreeText: + text_far _BallBrokeFreeText + text_end + +BallAppearedCaughtText: + text_far _BallAppearedCaughtText + text_end + +BallAlmostHadItText: + text_far _BallAlmostHadItText + text_end + +BallSoCloseText: + text_far _BallSoCloseText + text_end + +Text_GotchaMonWasCaught: + ; Gotcha! @ was caught!@ @ + text_far Text_BallCaught + text_asm + call WaitSFX + push bc + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + ld de, MUSIC_CAPTURE + call PlayMusic + pop bc + ld hl, WaitButtonText + ret + +WaitButtonText: + text_far _WaitButtonText + text_end + +BallSentToPCText: + text_far _BallSentToPCText + text_end + +NewDexDataText: + text_far _NewDexDataText + text_end + +AskGiveNicknameText: + text_far _AskGiveNicknameText + text_end + +ReturnToBattle_UseBall: + farcall _ReturnToBattle_UseBall + ret + +TownMapEffect: + farcall PokegearMap + ret + +BicycleEffect: + farcall BikeFunction + ret + +EvoStoneEffect: + ld b, PARTYMENUACTION_EVO_STONE + call UseItem_SelectMon + + jp c, .DecidedNotToUse + + ld a, MON_ITEM + call GetPartyParamLocation + + ld a, [hl] + cp EVERSTONE + jr z, .NoEffect + + ld a, $1 + ld [wForceEvolution], a + farcall EvolvePokemon + + ld a, [wMonTriedToEvolve] + and a + jr z, .NoEffect + + jp UseDisposableItem + +.NoEffect: + call WontHaveAnyEffectMessage + +.DecidedNotToUse: + xor a + ld [wItemEffectSucceeded], a + ret + +VitaminEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + + jp c, RareCandy_StatBooster_ExitMenu + + call RareCandy_StatBooster_GetParameters + + call GetStatExpRelativePointer + + ld a, MON_STAT_EXP + call GetPartyParamLocation + + add hl, bc + ld a, [hl] + cp 100 + jr nc, NoEffectMessage + + add 10 + ld [hl], a + call UpdateStatsAfterItem + + call GetStatExpRelativePointer + + ld hl, StatStrings + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wStringBuffer2 + ld bc, ITEM_NAME_LENGTH + call CopyBytes + + call Play_SFX_FULL_HEAL + + ld hl, ItemStatRoseText + call PrintText + + ld c, HAPPINESS_USEDITEM + farcall ChangeHappiness + + jp UseDisposableItem + +NoEffectMessage: + ld hl, ItemWontHaveEffectText + call PrintText + jp ClearPalettes + +UpdateStatsAfterItem: + ld a, MON_MAXHP + call GetPartyParamLocation + ld d, h + ld e, l + ld a, MON_STAT_EXP - 1 + call GetPartyParamLocation + ld b, TRUE + predef_jump CalcMonStats + +RareCandy_StatBooster_ExitMenu: + xor a + ld [wItemEffectSucceeded], a + jp ClearPalettes + +ItemStatRoseText: + text_far _ItemStatRoseText + text_end + +StatStrings: + dw .health + dw .attack + dw .defense + dw .speed + dw .special + +.health db "HEALTH@" +.attack db "ATTACK@" +.defense db "DEFENSE@" +.speed db "SPEED@" +.special db "SPECIAL@" + +GetStatExpRelativePointer: + ld a, [wCurItem] + ld hl, Table_eeeb +.next + cp [hl] + inc hl + jr z, .got_it + inc hl + jr .next + +.got_it + ld a, [hl] + ld c, a + ld b, 0 + ret + +Table_eeeb: + db HP_UP, MON_HP_EXP - MON_STAT_EXP + db PROTEIN, MON_ATK_EXP - MON_STAT_EXP + db IRON, MON_DEF_EXP - MON_STAT_EXP + db CARBOS, MON_SPD_EXP - MON_STAT_EXP + db CALCIUM, MON_SPC_EXP - MON_STAT_EXP + +RareCandy_StatBooster_GetParameters: + ld a, [wCurPartySpecies] + ld [wCurSpecies], a + ld [wTempSpecies], a + ld a, MON_LEVEL + call GetPartyParamLocation + ld a, [hl] + ld [wCurPartyLevel], a + call GetBaseData + ld a, [wCurPartyMon] + ld hl, wPartyMonNicknames + call GetNick + ret + +RareCandyEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + + jp c, RareCandy_StatBooster_ExitMenu + + call RareCandy_StatBooster_GetParameters + + ld a, MON_LEVEL + call GetPartyParamLocation + + ld a, [hl] + cp MAX_LEVEL + jp nc, NoEffectMessage + + inc a + ld [hl], a + ld [wCurPartyLevel], a + push de + ld d, a + farcall CalcExpAtLevel + + pop de + ld a, MON_EXP + call GetPartyParamLocation + + ldh a, [hMultiplicand + 0] + ld [hli], a + ldh a, [hMultiplicand + 1] + ld [hli], a + ldh a, [hMultiplicand + 2] + ld [hl], a + + ld a, MON_MAXHP + call GetPartyParamLocation + ld a, [hli] + ld b, a + ld c, [hl] + push bc + call UpdateStatsAfterItem + + ld a, MON_MAXHP + 1 + call GetPartyParamLocation + + pop bc + ld a, [hld] + sub c + ld c, a + ld a, [hl] + sbc b + ld b, a + dec hl + ld a, [hl] + add c + ld [hld], a + ld a, [hl] + adc b + ld [hl], a + ld c, 1 + farcall ChangeHappiness + + ld a, PARTYMENUTEXT_LEVEL_UP + call ItemActionText + + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + + hlcoord 9, 0 + ld b, 10 + ld c, 9 + call Textbox + + hlcoord 11, 1 + ld bc, 4 + predef PrintTempMonStats + + call WaitPressAorB_BlinkCursor + + xor a ; PARTYMON + ld [wMonType], a + ld a, [wCurPartySpecies] + ld [wTempSpecies], a + predef LearnLevelMoves + + xor a + ld [wForceEvolution], a + farcall EvolvePokemon + + jp UseDisposableItem + +HealPowderEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + + jp c, StatusHealer_ExitMenu + + call UseStatusHealer + + cp $0 + jr nz, .asm_efc9 + ld c, HAPPINESS_BITTERPOWDER + farcall ChangeHappiness + + call LooksBitterMessage + + ld a, $0 + +.asm_efc9 + jp StatusHealer_Jumptable + +StatusHealingEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + jp c, StatusHealer_ExitMenu + +FullyHealStatus: + call UseStatusHealer + jp StatusHealer_Jumptable + +UseStatusHealer: + call IsMonFainted + ld a, $1 + ret z + call GetItemHealingAction + ld a, MON_STATUS + call GetPartyParamLocation + ld a, [hl] + and c + jr nz, .good + call IsItemUsedOnConfusedMon + ld a, $1 + ret nc + ld b, PARTYMENUTEXT_HEAL_CONFUSION +.good + xor a + ld [hl], a + ld a, b + ld [wPartyMenuActionText], a + call HealStatus + call Play_SFX_FULL_HEAL + call ItemActionTextWaitButton + call UseDisposableItem + ld a, $0 + ret + +IsItemUsedOnConfusedMon: + call IsItemUsedOnBattleMon + jr nc, .nope + ld a, [wPlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + jr z, .nope + ld a, c + cp $ff + jr nz, .nope + scf + ret + +.nope + and a + ret + +BattlemonRestoreHealth: + call IsItemUsedOnBattleMon + ret nc + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + ld [wBattleMonHP], a + ld a, [hld] + ld [wBattleMonHP + 1], a + ret + +HealStatus: + call IsItemUsedOnBattleMon + ret nc + xor a + ld [wBattleMonStatus], a + ld hl, wPlayerSubStatus5 + res SUBSTATUS_TOXIC, [hl] + ld hl, wPlayerSubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + call GetItemHealingAction + ld a, c + cp %11111111 + jr nz, .not_full_heal + ld hl, wPlayerSubStatus3 + res SUBSTATUS_CONFUSED, [hl] +.not_full_heal + push bc + farcall CalcPlayerStats + pop bc + ret + +GetItemHealingAction: + push hl + ld a, [wCurItem] + ld hl, StatusHealingActions + ld bc, 3 +.next + cp [hl] + jr z, .found_it + add hl, bc + jr .next + +.found_it + inc hl + ld b, [hl] + inc hl + ld a, [hl] + ld c, a + cp %11111111 + pop hl + ret + +INCLUDE "data/items/heal_status.asm" + +StatusHealer_Jumptable: + ld hl, .dw + rst JumpTable + ret + +.dw + dw StatusHealer_ClearPalettes + dw StatusHealer_NoEffect + dw StatusHealer_ExitMenu + +RevivalHerbEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + jp c, StatusHealer_ExitMenu + + call RevivePokemon + cp 0 + jr nz, .asm_f0c5 + + ld c, HAPPINESS_REVIVALHERB + farcall ChangeHappiness + call LooksBitterMessage + ld a, 0 + +.asm_f0c5 + jp StatusHealer_Jumptable + +ReviveEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + jp c, StatusHealer_ExitMenu + + call RevivePokemon + jp StatusHealer_Jumptable + +RevivePokemon: + call IsMonFainted + ld a, 1 + ret nz + ld a, [wBattleMode] + and a + jr z, .skip_to_revive + + ld a, [wCurPartyMon] + ld c, a + ld d, 0 + ld hl, wBattleParticipantsIncludingFainted + ld b, CHECK_FLAG + predef SmallFarFlagAction + ld a, c + and a + jr z, .skip_to_revive + + ld a, [wCurPartyMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, SET_FLAG + predef SmallFarFlagAction + +.skip_to_revive + xor a + ld [wLowHealthAlarm], a + ld a, [wCurItem] + cp REVIVE + jr z, .revive_half_hp + + call ReviveFullHP + jr .finish_revive + +.revive_half_hp + call ReviveHalfHP + +.finish_revive + call HealHP_SFX_GFX + ld a, PARTYMENUTEXT_REVIVE + ld [wPartyMenuActionText], a + call ItemActionTextWaitButton + call UseDisposableItem + ld a, 0 + ret + +FullRestoreEffect: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + jp c, StatusHealer_ExitMenu + + call IsMonFainted + jp z, StatusHealer_NoEffect + + call IsMonAtFullHealth + jr c, .NotAtFullHealth + + jp FullyHealStatus + +.NotAtFullHealth: + call .FullRestore + jp StatusHealer_Jumptable + +.FullRestore: + xor a + ld [wLowHealthAlarm], a + call ReviveFullHP + ld a, MON_STATUS + call GetPartyParamLocation + xor a + ld [hli], a + ld [hl], a + call HealStatus + call BattlemonRestoreHealth + call HealHP_SFX_GFX + ld a, PARTYMENUTEXT_HEAL_HP + ld [wPartyMenuActionText], a + call ItemActionTextWaitButton + call UseDisposableItem + ld a, 0 + ret + +BitterBerryEffect: + ld hl, wPlayerSubStatus3 + bit SUBSTATUS_CONFUSED, [hl] + ld a, 1 + jr z, .done + + res SUBSTATUS_CONFUSED, [hl] + xor a + ldh [hBattleTurn], a + call UseItemText + + ld hl, ConfusedNoMoreText + call StdBattleTextbox + + ld a, 0 + +.done + jp StatusHealer_Jumptable + +RestoreHPEffect: + call ItemRestoreHP + jp StatusHealer_Jumptable + +EnergypowderEffect: + ld c, HAPPINESS_BITTERPOWDER + jr EnergypowderEnergyRootCommon + +EnergyRootEffect: + ld c, HAPPINESS_ENERGYROOT + +EnergypowderEnergyRootCommon: + push bc + call ItemRestoreHP + pop bc + cp 0 + jr nz, .skip_happiness + + farcall ChangeHappiness + call LooksBitterMessage + ld a, 0 + +.skip_happiness + jp StatusHealer_Jumptable + +ItemRestoreHP: + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + ld a, 2 + ret c + + call IsMonFainted + ld a, 1 + ret z + + call IsMonAtFullHealth + ld a, 1 + ret nc + + xor a + ld [wLowHealthAlarm], a + call GetHealingItemAmount + call RestoreHealth + call BattlemonRestoreHealth + call HealHP_SFX_GFX + ld a, PARTYMENUTEXT_HEAL_HP + ld [wPartyMenuActionText], a + call ItemActionTextWaitButton + call UseDisposableItem + ld a, 0 + ret + +HealHP_SFX_GFX: + push de + ld de, SFX_POTION + call WaitPlaySFX + pop de + ld a, [wCurPartyMon] + hlcoord 11, 0 + ld bc, SCREEN_WIDTH * 2 + call AddNTimes + ld a, $2 + ld [wWhichHPBar], a + predef_jump AnimateHPBar + +UseItem_SelectMon: + call .SelectMon + ret c + + ld a, [wCurPartySpecies] + cp EGG + jr nz, .not_egg + + call CantUseOnEggMessage + scf + ret + +.not_egg + and a + ret + +.SelectMon: + ld a, b + ld [wPartyMenuActionText], a + push hl + push de + push bc + call ClearBGPalettes + call ChooseMonToUseItemOn + pop bc + pop de + pop hl + ret + +ChooseMonToUseItemOn: + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + farcall PartyMenuSelect + ret + +ItemActionText: + ld [wPartyMenuActionText], a + ld a, [wCurPartySpecies] + push af + ld a, [wCurPartyMon] + push af + push hl + push de + push bc + farcall WritePartyMenuTilemap + farcall PrintPartyMenuActionText + call WaitBGMap + call SetPalettes + call DelayFrame + pop bc + pop de + pop hl + pop af + ld [wCurPartyMon], a + pop af + ld [wCurPartySpecies], a + ret + +ItemActionTextWaitButton: + xor a + ldh [hBGMapMode], a + hlcoord 0, 0 + ld bc, wTilemapEnd - wTilemap + ld a, " " + call ByteFill + ld a, [wPartyMenuActionText] + call ItemActionText + ld a, $1 + ldh [hBGMapMode], a + ld c, 50 + call DelayFrames + jp WaitPressAorB_BlinkCursor + +StatusHealer_NoEffect: + call WontHaveAnyEffectMessage + jr StatusHealer_ClearPalettes + +StatusHealer_ExitMenu: + xor a + ld [wItemEffectSucceeded], a +StatusHealer_ClearPalettes: + call ClearPalettes + ret + +IsItemUsedOnBattleMon: + ld a, [wBattleMode] + and a + ret z + ld a, [wCurPartyMon] + push hl + ld hl, wCurBattleMon + cp [hl] + pop hl + jr nz, .nope + scf + ret + +.nope + xor a + ret + +ReviveHalfHP: + call LoadHPFromBuffer1 + srl d + rr e + jr ContinueRevive + +ReviveFullHP: + call LoadHPFromBuffer1 +ContinueRevive: + ld a, MON_HP + call GetPartyParamLocation + ld [hl], d + inc hl + ld [hl], e + jp LoadCurHPIntoBuffer5 + +RestoreHealth: + ld a, MON_HP + 1 + call GetPartyParamLocation + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hl], a + jr c, .full_hp + call LoadCurHPIntoBuffer5 + ld a, MON_HP + 1 + call GetPartyParamLocation + ld d, h + ld e, l + ld a, MON_MAXHP + 1 + call GetPartyParamLocation + ld a, [de] + sub [hl] + dec de + dec hl + ld a, [de] + sbc [hl] + jr c, .finish +.full_hp + call ReviveFullHP +.finish + ret + +RemoveHP: + ld a, MON_HP + 1 + call GetPartyParamLocation + ld a, [hl] + sub e + ld [hld], a + ld a, [hl] + sbc d + ld [hl], a + jr nc, .okay + xor a + ld [hld], a + ld [hl], a +.okay + call LoadCurHPIntoBuffer5 + ret + +IsMonFainted: + push de + call LoadMaxHPToBuffer1 + call LoadCurHPToBuffer3 + call LoadHPFromBuffer3 + ld a, d + or e + pop de + ret + +IsMonAtFullHealth: + call LoadHPFromBuffer3 + ld h, d + ld l, e + call LoadHPFromBuffer1 + ld a, l + sub e + ld a, h + sbc d + ret + +LoadCurHPIntoBuffer5: + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + ld [wBuffer6], a + ld a, [hl] + ld [wBuffer5], a + ret + +LoadHPIntoBuffer5: + ld a, d + ld [wBuffer6], a + ld a, e + ld [wBuffer5], a + ret + +LoadHPFromBuffer5: + ld a, [wBuffer6] + ld d, a + ld a, [wBuffer5] + ld e, a + ret + +LoadCurHPToBuffer3: + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + ld [wBuffer4], a + ld a, [hl] + ld [wBuffer3], a + ret + +LoadHPFromBuffer3: + ld a, [wBuffer4] + ld d, a + ld a, [wBuffer3] + ld e, a + ret + +LoadMaxHPToBuffer1: + push hl + ld a, MON_MAXHP + call GetPartyParamLocation + ld a, [hli] + ld [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + pop hl + ret + +LoadHPFromBuffer1: + ld a, [wBuffer2] + ld d, a + ld a, [wBuffer1] + ld e, a + ret + +GetOneFifthMaxHP: + push bc + ld a, MON_MAXHP + call GetPartyParamLocation + ld a, [hli] + ldh [hDividend + 0], a + ld a, [hl] + ldh [hDividend + 1], a + ld a, 5 + ldh [hDivisor], a + ld b, 2 + call Divide + ldh a, [hQuotient + 2] + ld d, a + ldh a, [hQuotient + 3] + ld e, a + pop bc + ret + +GetHealingItemAmount: + push hl + ld a, [wCurItem] + ld hl, HealingHPAmounts + ld d, a +.next + ld a, [hli] + cp -1 + jr z, .NotFound + cp d + jr z, .done + inc hl + inc hl + jr .next + +.NotFound: + scf +.done + ld e, [hl] + inc hl + ld d, [hl] + pop hl + ret + +INCLUDE "data/items/heal_hp.asm" + +Softboiled_MilkDrinkFunction: +; Softboiled/Milk Drink in the field + ld a, [wPartyMenuCursor] + dec a + ld b, a + call .SelectMilkDrinkRecipient ; select pokemon + jr c, .skip + ld a, b + ld [wCurPartyMon], a + call IsMonFainted + call GetOneFifthMaxHP + call RemoveHP + push bc + call HealHP_SFX_GFX + pop bc + call GetOneFifthMaxHP + ld a, c + ld [wCurPartyMon], a + call IsMonFainted + call RestoreHealth + call HealHP_SFX_GFX + ld a, PARTYMENUTEXT_HEAL_HP + call ItemActionText + call JoyWaitAorB +.skip + ld a, b + inc a + ld [wPartyMenuCursor], a + ret + +.SelectMilkDrinkRecipient: +.loop + push bc + ld a, PARTYMENUACTION_HEALING_ITEM + ld [wPartyMenuActionText], a + call ChooseMonToUseItemOn + pop bc + jr c, .set_carry + ld a, [wPartyMenuCursor] + dec a + ld c, a + ld a, b + cp c + jr z, .cant_use ; chose the same mon as user + ld a, c + ld [wCurPartyMon], a + call IsMonFainted + jr z, .cant_use + call IsMonAtFullHealth + jr nc, .cant_use + xor a + ret + +.set_carry + scf + ret + +.cant_use + push bc + ld hl, .ItemCantUseOnMonText + call MenuTextboxBackup + pop bc + jr .loop + +.ItemCantUseOnMonText: + text_far _ItemCantUseOnMonText + text_end + +EscapeRopeEffect: + xor a + ld [wItemEffectSucceeded], a + farcall EscapeRopeFunction + + ld a, [wItemEffectSucceeded] + cp 1 + call z, UseDisposableItem + ret + +SuperRepelEffect: + ld b, 200 + jr UseRepel + +MaxRepelEffect: + ld b, 250 + jr UseRepel + +RepelEffect: + ld b, 100 + +UseRepel: + ld a, [wRepelEffect] + and a + ld hl, RepelUsedEarlierIsStillInEffectText + jp nz, PrintText + + ld a, b + ld [wRepelEffect], a + jp UseItemText + +RepelUsedEarlierIsStillInEffectText: + text_far _RepelUsedEarlierIsStillInEffectText + text_end + +XAccuracyEffect: + ld hl, wPlayerSubStatus4 + bit SUBSTATUS_X_ACCURACY, [hl] + jp nz, WontHaveAnyEffect_NotUsedMessage + set SUBSTATUS_X_ACCURACY, [hl] + jp UseItemText + +PokeDollEffect: + ld a, [wBattleMode] + dec a + jr nz, .asm_f4f6 + inc a + ld [wForcedSwitch], a + ; set battle draw + inc a + ld [wBattleResult], a + jp UseItemText + +.asm_f4f6 + xor a + ld [wItemEffectSucceeded], a + ret + +GuardSpecEffect: + ld hl, wPlayerSubStatus4 + bit SUBSTATUS_MIST, [hl] + jp nz, WontHaveAnyEffect_NotUsedMessage + set SUBSTATUS_MIST, [hl] + jp UseItemText + +DireHitEffect: + ld hl, wPlayerSubStatus4 + bit SUBSTATUS_FOCUS_ENERGY, [hl] + jp nz, WontHaveAnyEffect_NotUsedMessage + set SUBSTATUS_FOCUS_ENERGY, [hl] + jp UseItemText + +XItemEffect: + call UseItemText + + ld a, [wCurItem] + ld hl, XItemStats + +.loop + cp [hl] + jr z, .got_it + inc hl + inc hl + jr .loop + +.got_it + inc hl + ld b, [hl] + xor a + ldh [hBattleTurn], a + ld [wAttackMissed], a + ld [wEffectFailed], a + farcall RaiseStat + call WaitSFX + + farcall BattleCommand_StatUpMessage + farcall BattleCommand_StatUpFailText + + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + ld c, HAPPINESS_USEDXITEM + farcall ChangeHappiness + ret + +INCLUDE "data/items/x_stats.asm" + +PokeFluteEffect: + ld a, [wBattleMode] + and a + jr nz, .dummy +.dummy + + xor a + ld [wceed], a + + ld b, $ff ^ SLP + + ld hl, wPartyMon1Status + call .CureSleep + + ld a, [wBattleMode] + cp WILD_BATTLE + jr z, .skip_otrainer + ld hl, wOTPartyMon1Status + call .CureSleep +.skip_otrainer + + ld hl, wBattleMonStatus + ld a, [hl] + and b + ld [hl], a + ld hl, wEnemyMonStatus + ld a, [hl] + and b + ld [hl], a + + ld a, [wceed] + and a + ld hl, .PlayedFluteText + jp z, PrintText + ld hl, .PlayedTheFlute + call PrintText + + ld a, [wLowHealthAlarm] + and 1 << DANGER_ON_F + jr nz, .dummy2 +.dummy2 + ld hl, .FluteWakeUpText + jp PrintText + +.CureSleep: + ld de, PARTYMON_STRUCT_LENGTH + ld c, PARTY_LENGTH + +.loop + ld a, [hl] + push af + and SLP + jr z, .not_asleep + ld a, 1 + ld [wceed], a +.not_asleep + pop af + and b + ld [hl], a + add hl, de + dec c + jr nz, .loop + ret + +.PlayedFluteText: + text_far _PlayedFluteText + text_end + +.FluteWakeUpText: + text_far _FluteWakeUpText + text_end + +.PlayedTheFlute: + ; played the # FLUTE.@ @ + text_far Text_PlayedPokeFlute + text_asm + ld a, [wBattleMode] + and a + jr nz, .battle + + push de + ld de, SFX_POKEFLUTE + call WaitPlaySFX + call WaitSFX + pop de + +.battle + ld hl, .terminator + ret + +.terminator + db "@" + +CoinCaseEffect: + ld hl, .CoinCaseCountText + jp MenuTextboxWaitButton + +.CoinCaseCountText: + text_far _CoinCaseCountText + text_end + +OldRodEffect: + ld e, $0 + jr UseRod + +GoodRodEffect: + ld e, $1 + jr UseRod + +SuperRodEffect: + ld e, $2 + jr UseRod + +UseRod: + farcall FishFunction + ret + +ItemfinderEffect: + farcall ItemFinder + ret + +RestorePPEffect: + ld a, [wCurItem] + ld [wceed], a + +.loop + ; Party Screen opens to choose on which mon to use the Item + ld b, PARTYMENUACTION_HEALING_ITEM + call UseItem_SelectMon + jp c, PPRestoreItem_Cancel + +.loop2 + ld a, [wceed] + cp MAX_ELIXER + jp z, Elixer_RestorePPofAllMoves + cp ELIXER + jp z, Elixer_RestorePPofAllMoves + + ld hl, RaiseThePPOfWhichMoveText + ld a, [wceed] + cp PP_UP + jr z, .ppup + ld hl, RestoreThePPOfWhichMoveText + +.ppup + call PrintText + + ld a, [wCurMoveNum] + push af + xor a + ld [wCurMoveNum], a + ld a, $2 + ld [wMoveSelectionMenuType], a + farcall MoveSelectionScreen + pop bc + + ld a, b + ld [wCurMoveNum], a + jr nz, .loop + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + call GetMthMoveOfNthPartymon + + push hl + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetMoveName + call CopyName1 + pop hl + + ld a, [wceed] + cp PP_UP + jp nz, Not_PP_Up + + ld a, [hl] + cp SKETCH + jr z, .CantUsePPUpOnSketch + + ld bc, MON_PP - MON_MOVES + add hl, bc + ld a, [hl] + cp PP_UP_MASK + jr c, .do_ppup + +.CantUsePPUpOnSketch: +.pp_is_maxed_out + ld hl, PPIsMaxedOutText + call PrintText + jr .loop2 + +.do_ppup + ld a, [hl] + add PP_UP_ONE + ld [hl], a + ld a, TRUE + ld [wUsePPUp], a + call ApplyPPUp + call Play_SFX_FULL_HEAL + + ld hl, PPsIncreasedText + call PrintText + +FinishPPRestore: + call ClearPalettes + jp UseDisposableItem + +BattleRestorePP: + ld a, [wBattleMode] + and a + jr z, .not_in_battle + ld a, [wCurPartyMon] + ld b, a + ld a, [wCurBattleMon] + cp b + jr nz, .not_in_battle + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .not_in_battle + call .UpdateBattleMonPP + +.not_in_battle + call Play_SFX_FULL_HEAL + ld hl, PPRestoredText + call PrintText + jr FinishPPRestore + +.UpdateBattleMonPP: + ld a, [wCurPartyMon] + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld de, wBattleMonMoves + ld b, NUM_MOVES +.loop + ld a, [de] + and a + jr z, .done + cp [hl] + jr nz, .next + push hl + push de + push bc +rept NUM_MOVES + 2 ; wBattleMonPP - wBattleMonMoves + inc de +endr + ld bc, MON_PP - MON_MOVES + add hl, bc + ld a, [hl] + ld [de], a + pop bc + pop de + pop hl + +.next + inc hl + inc de + dec b + jr nz, .loop + +.done + ret + +Not_PP_Up: + call RestorePP + jr nz, BattleRestorePP + jp PPRestoreItem_NoEffect + +Elixer_RestorePPofAllMoves: + xor a + ld hl, wMenuCursorY + ld [hli], a + ld [hl], a + ld b, NUM_MOVES +.moveLoop + push bc + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + call GetMthMoveOfNthPartymon + ld a, [hl] + and a + jr z, .next + + call RestorePP + jr z, .next + ld hl, wMenuCursorX + inc [hl] + +.next + ld hl, wMenuCursorY + inc [hl] + pop bc + dec b + jr nz, .moveLoop + ld a, [wMenuCursorX] + and a + jp nz, BattleRestorePP + +PPRestoreItem_NoEffect: + call WontHaveAnyEffectMessage + +PPRestoreItem_Cancel: + call ClearPalettes + xor a + ld [wItemEffectSucceeded], a + ret + +RestorePP: + xor a ; PARTYMON + ld [wMonType], a + call GetMaxPPOfMove + ld hl, wPartyMon1PP + ld bc, PARTYMON_STRUCT_LENGTH + call GetMthMoveOfNthPartymon + ld a, [wTempPP] + ld b, a + ld a, [hl] + and PP_MASK + cp b + jr nc, .dont_restore + + ld a, [wceed] + cp MAX_ELIXER + jr z, .restore_all + cp MAX_ETHER + jr z, .restore_all + + ld c, 5 + cp MYSTERYBERRY + jr z, .restore_some + + ld c, 10 + +.restore_some + ld a, [hl] + and PP_MASK + add c + cp b + jr nc, .restore_all + ld b, a + +.restore_all + ld a, [hl] + and PP_UP_MASK + or b + ld [hl], a + ret + +.dont_restore + xor a + ret + +RaiseThePPOfWhichMoveText: + text_far _RaiseThePPOfWhichMoveText + text_end + +RestoreThePPOfWhichMoveText: + text_far _RestoreThePPOfWhichMoveText + text_end + +PPIsMaxedOutText: + text_far _PPIsMaxedOutText + text_end + +PPsIncreasedText: + text_far _PPsIncreasedText + text_end + +PPRestoredText: + text_far _PPRestoredText + text_end + +SquirtbottleEffect: + farcall _Squirtbottle + ret + +CardKeyEffect: + farcall _CardKey + ret + +BasementKeyEffect: + farcall _BasementKey + ret + +SacredAshEffect: + farcall _SacredAsh + ld a, [wItemEffectSucceeded] + cp $1 + ret nz + call UseDisposableItem + ret + +NormalBoxEffect: + ld c, DECOFLAG_SILVER_TROPHY_DOLL + jr OpenBox + +GorgeousBoxEffect: + ld c, DECOFLAG_GOLD_TROPHY_DOLL +OpenBox: + farcall SetSpecificDecorationFlag + + ld hl, .SentTrophyHomeText + call PrintText + + jp UseDisposableItem + +.SentTrophyHomeText: + text_far _SentTrophyHomeText + text_end + +NoEffect: + jp IsntTheTimeMessage + +Play_SFX_FULL_HEAL: + push de + ld de, SFX_FULL_HEAL + call WaitPlaySFX + pop de + ret + +UseItemText: + ld hl, ItemUsedText + call PrintText + call Play_SFX_FULL_HEAL + call WaitPressAorB_BlinkCursor +UseDisposableItem: + ld hl, wNumItems + ld a, 1 + ld [wItemQuantityChangeBuffer], a + jp TossItem + +UseBallInTrainerBattle: + call ReturnToBattle_UseBall + ld de, ANIM_THROW_POKE_BALL + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 1], a + xor a + ld [wBattleAnimParam], a + ldh [hBattleTurn], a + ld [wNumHits], a + predef PlayBattleAnim + ld hl, BallBlockedText + call PrintText + ld hl, BallDontBeAThiefText + call PrintText + jr UseDisposableItem + +WontHaveAnyEffect_NotUsedMessage: + ld hl, ItemWontHaveEffectText + call PrintText + + ; Item wasn't used. + ld a, $2 + ld [wItemEffectSucceeded], a + ret + +LooksBitterMessage: + ld hl, ItemLooksBitterText + jp PrintText + +Ball_BoxIsFullMessage: + ld hl, BallBoxFullText + call PrintText + + ; Item wasn't used. + ld a, $2 + ld [wItemEffectSucceeded], a + ret + +CantUseOnEggMessage: + ld hl, ItemCantUseOnEggText + jr CantUseItemMessage + +IsntTheTimeMessage: + ld hl, ItemOakWarningText + jr CantUseItemMessage + +WontHaveAnyEffectMessage: + ld hl, ItemWontHaveEffectText + jr CantUseItemMessage + +BelongsToSomeoneElseMessage: + ld hl, ItemBelongsToSomeoneElseText + jr CantUseItemMessage + +CyclingIsntAllowedMessage: + ld hl, NoCyclingText + jr CantUseItemMessage + +CantGetOnYourBikeMessage: + ld hl, ItemCantGetOnText + +CantUseItemMessage: +; Item couldn't be used. + xor a + ld [wItemEffectSucceeded], a + jp PrintText + +ItemLooksBitterText: + text_far _ItemLooksBitterText + text_end + +ItemCantUseOnEggText: + text_far _ItemCantUseOnEggText + text_end + +ItemOakWarningText: + text_far _ItemOakWarningText + text_end + +ItemBelongsToSomeoneElseText: + text_far _ItemBelongsToSomeoneElseText + text_end + +ItemWontHaveEffectText: + text_far _ItemWontHaveEffectText + text_end + +BallBlockedText: + text_far _BallBlockedText + text_end + +BallDontBeAThiefText: + text_far _BallDontBeAThiefText + text_end + +NoCyclingText: + text_far _NoCyclingText + text_end + +ItemCantGetOnText: + text_far _ItemCantGetOnText + text_end + +BallBoxFullText: + text_far _BallBoxFullText + text_end + +ItemUsedText: + text_far _ItemUsedText + text_end + +ItemGotOnText: + text_far _ItemGotOnText + text_end + +ItemGotOffText: + text_far _ItemGotOffText + text_end + +ApplyPPUp: + ld a, MON_MOVES + call GetPartyParamLocation + push hl + ld de, wBuffer1 + predef FillPP + pop hl + ld bc, MON_PP - MON_MOVES + add hl, bc + ld de, wBuffer1 + ld b, 0 +.loop + inc b + ld a, b + cp NUM_MOVES + 1 + ret z + ld a, [wUsePPUp] + dec a ; FALSE? + jr nz, .use + ld a, [wMenuCursorY] + inc a + cp b + jr nz, .skip + +.use + ld a, [hl] + and PP_UP_MASK + ld a, [de] ; wasted cycle + call nz, ComputeMaxPP + +.skip + inc hl + inc de + jr .loop + +ComputeMaxPP: + push bc + ; Divide the base PP by 5. + ld a, [de] + ldh [hDividend + 3], a + xor a + ldh [hDividend], a + ldh [hDividend + 1], a + ldh [hDividend + 2], a + ld a, 5 + ldh [hDivisor], a + ld b, 4 + call Divide + ; Get the number of PP, which are bits 6 and 7 of the PP value stored in RAM. + ld a, [hl] + ld b, a + swap a + and $f + srl a + srl a + ld c, a + ; If this value is 0, we are done + and a + jr z, .NoPPUp + +.loop + ; Normally, a move with 40 PP would have 64 PP with three PP Ups. + ; Since this would overflow into bit 6, we prevent that from happening + ; by decreasing the extra amount of PP each PP Up provides, resulting + ; in a maximum of 61. + ldh a, [hQuotient + 3] + cp $8 + jr c, .okay + ld a, $7 + +.okay + add b + ld b, a + ld a, [wTempPP] + dec a + jr z, .NoPPUp + dec c + jr nz, .loop + +.NoPPUp: + ld [hl], b + pop bc + ret + +RestoreAllPP: + ld a, MON_PP + call GetPartyParamLocation + push hl + ld a, MON_MOVES + call GetPartyParamLocation + pop de + xor a ; PARTYMON + ld [wMenuCursorY], a + ld [wMonType], a + ld c, NUM_MOVES +.loop + ld a, [hli] + and a + ret z + push hl + push de + push bc + call GetMaxPPOfMove + pop bc + pop de + ld a, [de] + and PP_UP_MASK + ld b, a + ld a, [wTempPP] + add b + ld [de], a + inc de + ld hl, wMenuCursorY + inc [hl] + pop hl + dec c + jr nz, .loop + ret + +GetMaxPPOfMove: + ld a, [wStringBuffer1 + 0] + push af + ld a, [wStringBuffer1 + 1] + push af + + ld a, [wMonType] + and a + + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + jr z, .got_partymon ; PARTYMON + + ld hl, wOTPartyMon1Moves + dec a + jr z, .got_partymon ; OTPARTYMON + + ld hl, wTempMonMoves + dec a + jr z, .got_nonpartymon ; BOXMON + + ld hl, wTempMonMoves ; Wasted cycles + dec a + jr z, .got_nonpartymon ; TEMPMON + + ld hl, wBattleMonMoves ; WILDMON + +.got_nonpartymon ; BOXMON, TEMPMON, WILDMON + call GetMthMoveOfCurrentMon + jr .gotdatmove + +.got_partymon ; PARTYMON, OTPARTYMON + call GetMthMoveOfNthPartymon + +.gotdatmove + ld a, [hl] + dec a + + push hl + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + ld b, a + ld de, wStringBuffer1 + ld [de], a + pop hl + + push bc + ld bc, MON_PP - MON_MOVES + ld a, [wMonType] + cp WILDMON + jr nz, .notwild + ld bc, wEnemyMonPP - wEnemyMonMoves +.notwild + add hl, bc + ld a, [hl] + and PP_UP_MASK + pop bc + + or b + ld hl, wStringBuffer1 + 1 + ld [hl], a + xor a + ld [wTempPP], a + ld a, b ; this gets lost anyway + call ComputeMaxPP + ld a, [hl] + and PP_MASK + ld [wTempPP], a + + pop af + ld [wStringBuffer1 + 1], a + pop af + ld [wStringBuffer1 + 0], a + ret + +GetMthMoveOfNthPartymon: + ld a, [wCurPartyMon] + call AddNTimes + +GetMthMoveOfCurrentMon: + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ret diff --git a/engine/items/items.asm b/engine/items/items.asm new file mode 100755 index 00000000..ef0f10dd --- /dev/null +++ b/engine/items/items.asm @@ -0,0 +1,581 @@ +_ReceiveItem:: + call DoesHLEqualNumItems + jp nz, PutItemInPocket + push hl + call CheckItemPocket + pop de + ld a, [wItemAttributeParamBuffer] + dec a + ld hl, .Pockets + rst JumpTable + ret + +.Pockets: +; entries correspond to item types + dw .Item + dw .KeyItem + dw .Ball + dw .TMHM + +.Item: + ld h, d + ld l, e + jp PutItemInPocket + +.KeyItem: + ld h, d + ld l, e + jp ReceiveKeyItem + +.Ball: + ld hl, wNumBalls + jp PutItemInPocket + +.TMHM: + ld h, d + ld l, e + ld a, [wCurItem] + ld c, a + call GetTMHMNumber + jp ReceiveTMHM + +_TossItem:: + call DoesHLEqualNumItems + jr nz, .remove + push hl + call CheckItemPocket + pop de + ld a, [wItemAttributeParamBuffer] + dec a + ld hl, .Pockets + rst JumpTable + ret + +.Pockets: +; entries correspond to item types + dw .Item + dw .KeyItem + dw .Ball + dw .TMHM + +.Ball: + ld hl, wNumBalls + jp RemoveItemFromPocket + +.TMHM: + ld h, d + ld l, e + ld a, [wCurItem] + ld c, a + call GetTMHMNumber + jp TossTMHM + +.KeyItem: + ld h, d + ld l, e + jp TossKeyItem + +.Item: + ld h, d + ld l, e + +.remove + jp RemoveItemFromPocket + +_CheckItem:: + call DoesHLEqualNumItems + jr nz, .nope + push hl + call CheckItemPocket + pop de + ld a, [wItemAttributeParamBuffer] + dec a + ld hl, .Pockets + rst JumpTable + ret + +.Pockets: +; entries correspond to item types + dw .Item + dw .KeyItem + dw .Ball + dw .TMHM + +.Ball: + ld hl, wNumBalls + jp CheckTheItem + +.TMHM: + ld h, d + ld l, e + ld a, [wCurItem] + ld c, a + call GetTMHMNumber + jp CheckTMHM + +.KeyItem: + ld h, d + ld l, e + jp CheckKeyItems + +.Item: + ld h, d + ld l, e + +.nope + jp CheckTheItem + +DoesHLEqualNumItems: + ld a, l + cp LOW(wNumItems) + ret nz + ld a, h + cp HIGH(wNumItems) + ret + +GetPocketCapacity: + ld c, MAX_ITEMS + ld a, e + cp LOW(wNumItems) + jr nz, .not_bag + ld a, d + cp HIGH(wNumItems) + ret z + +.not_bag + ld c, MAX_PC_ITEMS + ld a, e + cp LOW(wNumPCItems) + jr nz, .not_pc + ld a, d + cp HIGH(wNumPCItems) + ret z + +.not_pc + ld c, MAX_BALLS + ret + +PutItemInPocket: + ld d, h + ld e, l + inc hl + ld a, [wCurItem] + ld c, a + ld b, 0 +.loop + ld a, [hli] + cp -1 + jr z, .terminator + cp c + jr nz, .next + ld a, 99 + sub [hl] + add b + ld b, a + ld a, [wItemQuantityChangeBuffer] + cp b + jr z, .ok + jr c, .ok + +.next + inc hl + jr .loop + +.terminator + call GetPocketCapacity + ld a, [de] + cp c + jr c, .ok + and a + ret + +.ok + ld h, d + ld l, e + ld a, [wCurItem] + ld c, a + ld a, [wItemQuantityChangeBuffer] + ld [wItemQuantityBuffer], a +.loop2 + inc hl + ld a, [hli] + cp -1 + jr z, .terminator2 + cp c + jr nz, .loop2 + ld a, [wItemQuantityBuffer] + add [hl] + cp 100 + jr nc, .newstack + ld [hl], a + jr .done + +.newstack + ld [hl], 99 + sub 99 + ld [wItemQuantityBuffer], a + jr .loop2 + +.terminator2 + dec hl + ld a, [wCurItem] + ld [hli], a + ld a, [wItemQuantityBuffer] + ld [hli], a + ld [hl], -1 + ld h, d + ld l, e + inc [hl] + +.done + scf + ret + +RemoveItemFromPocket: + ld d, h + ld e, l + ld a, [hli] + ld c, a + ld a, [wCurItemQuantity] + cp c + jr nc, .ok ; memory + ld c, a + ld b, $0 + add hl, bc + add hl, bc + ld a, [wCurItem] + cp [hl] + inc hl + jr z, .skip + ld h, d + ld l, e + inc hl + +.ok + ld a, [wCurItem] + ld b, a +.loop + ld a, [hli] + cp b + jr z, .skip + cp -1 + jr z, .nope + inc hl + jr .loop + +.skip + ld a, [wItemQuantityChangeBuffer] + ld b, a + ld a, [hl] + sub b + jr c, .nope + ld [hl], a + ld [wItemQuantityBuffer], a + and a + jr nz, .yup + dec hl + ld b, h + ld c, l + inc hl + inc hl +.loop2 + ld a, [hli] + ld [bc], a + inc bc + cp -1 + jr nz, .loop2 + ld h, d + ld l, e + dec [hl] + +.yup + scf + ret + +.nope + and a + ret + +CheckTheItem: + ld a, [wCurItem] + ld c, a +.loop + inc hl + ld a, [hli] + cp -1 + jr z, .done + cp c + jr nz, .loop + scf + ret + +.done + and a + ret + +ReceiveKeyItem: + ld hl, wNumKeyItems + ld a, [hli] + cp MAX_KEY_ITEMS + jr nc, .nope + ld c, a + ld b, 0 + add hl, bc + ld a, [wCurItem] + ld [hli], a + ld [hl], -1 + ld hl, wNumKeyItems + inc [hl] + scf + ret + +.nope + and a + ret + +TossKeyItem: + ld a, [wCurItemQuantity] + ld e, a + ld d, 0 + ld hl, wNumKeyItems + ld a, [hl] + cp e + jr nc, .ok + call .Toss + ret nc + jr .ok2 + +.ok + dec [hl] + inc hl + add hl, de + +.ok2 + ld d, h + ld e, l + inc hl +.loop + ld a, [hli] + ld [de], a + inc de + cp -1 + jr nz, .loop + scf + ret + +.Toss: + ld hl, wNumKeyItems + ld a, [wCurItem] + ld c, a +.loop3 + inc hl + ld a, [hl] + cp c + jr z, .ok3 + cp -1 + jr nz, .loop3 + xor a + ret + +.ok3 + ld a, [wNumKeyItems] + dec a + ld [wNumKeyItems], a + scf + ret + +CheckKeyItems: + ld a, [wCurItem] + ld c, a + ld hl, wKeyItems +.loop + ld a, [hli] + cp c + jr z, .done + cp -1 + jr nz, .loop + and a + ret + +.done + scf + ret + +ReceiveTMHM: + dec c + ld b, 0 + ld hl, wTMsHMs + add hl, bc + ld a, [wItemQuantityChangeBuffer] + add [hl] + cp 100 + jr nc, .toomany + ld [hl], a + scf + ret + +.toomany + and a + ret + +TossTMHM: + dec c + ld b, 0 + ld hl, wTMsHMs + add hl, bc + ld a, [wItemQuantityChangeBuffer] + ld b, a + ld a, [hl] + sub b + jr c, .nope + ld [hl], a + ld [wItemQuantityBuffer], a + jr nz, .yup + ld a, [wTMHMPocketScrollPosition] + and a + jr z, .yup + dec a + ld [wTMHMPocketScrollPosition], a + +.yup + scf + ret + +.nope + and a + ret + +CheckTMHM: + dec c + ld b, $0 + ld hl, wTMsHMs + add hl, bc + ld a, [hl] + and a + ret z + scf + ret + +GetTMHMNumber:: +; Return the number of a TM/HM by item id c. + ld a, c +; Skip any dummy items. + cp ITEM_C3 ; TM04-05 + jr c, .done + cp ITEM_DC ; TM28-29 + jr c, .skip + dec a +.skip + dec a +.done + sub TM01 + inc a + ld c, a + ret + +GetNumberedTMHM: +; Return the item id of a TM/HM by number c. + ld a, c +; Skip any gaps. + cp ITEM_C3 - (TM01 - 1) + jr c, .done + cp ITEM_DC - (TM01 - 1) - 1 + jr c, .skip_one +.skip_two + inc a +.skip_one + inc a +.done + add TM01 + dec a + ld c, a + ret + +_CheckTossableItem:: +; Return 1 in wItemAttributeParamBuffer and carry if wCurItem can't be removed from the bag. + ld a, ITEMATTR_PERMISSIONS + call GetItemAttr + bit CANT_TOSS_F, a + jr nz, ItemAttr_ReturnCarry + and a + ret + +CheckSelectableItem: +; Return 1 in wItemAttributeParamBuffer and carry if wCurItem can't be selected. + ld a, ITEMATTR_PERMISSIONS + call GetItemAttr + bit CANT_SELECT_F, a + jr nz, ItemAttr_ReturnCarry + and a + ret + +CheckItemPocket:: +; Return the pocket for wCurItem in wItemAttributeParamBuffer. + ld a, ITEMATTR_POCKET + call GetItemAttr + and $f + ld [wItemAttributeParamBuffer], a + ret + +CheckItemContext: +; Return the context for wCurItem in wItemAttributeParamBuffer. + ld a, ITEMATTR_HELP + call GetItemAttr + and $f + ld [wItemAttributeParamBuffer], a + ret + +CheckItemMenu: +; Return the menu for wCurItem in wItemAttributeParamBuffer. + ld a, ITEMATTR_HELP + call GetItemAttr + swap a + and $f + ld [wItemAttributeParamBuffer], a + ret + +GetItemAttr: +; Get attribute a of wCurItem. + + push hl + push bc + + ld hl, ItemAttributes + ld c, a + ld b, 0 + add hl, bc + + xor a + ld [wItemAttributeParamBuffer], a + + ld a, [wCurItem] + dec a + ld c, a + ld a, ITEMATTR_STRUCT_LENGTH + call AddNTimes + ld a, BANK(ItemAttributes) + call GetFarByte + + pop bc + pop hl + ret + +ItemAttr_ReturnCarry: + ld a, 1 + ld [wItemAttributeParamBuffer], a + scf + ret + +GetItemPrice: +; Return the price of wCurItem in de. + push hl + push bc + ld a, ITEMATTR_PRICE + call GetItemAttr + ld e, a + ld a, ITEMATTR_PRICE_HI + call GetItemAttr + ld d, a + pop bc + pop hl + ret diff --git a/engine/items/mart.asm b/engine/items/mart.asm new file mode 100644 index 00000000..3978ef33 --- /dev/null +++ b/engine/items/mart.asm @@ -0,0 +1,811 @@ + const_def + const MARTTEXT_HOW_MANY + const MARTTEXT_COSTS_THIS_MUCH + const MARTTEXT_NOT_ENOUGH_MONEY + const MARTTEXT_BAG_FULL + const MARTTEXT_HERE_YOU_GO + const MARTTEXT_SOLD_OUT + +GetMart: + ld a, e + cp (Marts.End - Marts) / 2 + jr c, .IsAMart + ld b, BANK(DefaultMart) + ld de, DefaultMart + ret + +.IsAMart: + ld hl, Marts + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld b, BANK(Marts) + ret + +OpenMartDialog:: + call GetMart + ld a, c + ld [wMartType], a + call LoadMartPointer + ld a, [wMartType] + ld hl, .dialogs + rst JumpTable + ret + +.dialogs + dw MartDialog + dw HerbShop + dw BargainShop + dw Pharmacist + +MartDialog: + ld a, MARTTYPE_STANDARD + ld [wMartType], a + xor a ; STANDARDMART_HOWMAYIHELPYOU + ld [wMartJumptableIndex], a + call StandardMart + ret + +HerbShop: + call FarReadMart + call LoadStandardMenuHeader + ld hl, HerbShopLadyIntroText + call MartTextbox + call BuyMenu + ld hl, HerbalLadyComeAgainText + call MartTextbox + ret + +BargainShop: + ld b, BANK(BargainShopData) + ld de, BargainShopData + call LoadMartPointer + call ReadMart + call LoadStandardMenuHeader + ld hl, BargainShopIntroText + call MartTextbox + call BuyMenu + ld hl, wBargainShopFlags + ld a, [hli] + or [hl] + jr z, .skip_set + ld hl, wDailyFlags1 + set DAILYFLAGS1_GOLDENROD_UNDERGROUND_BARGAIN_F, [hl] + +.skip_set + ld hl, BargainShopComeAgainText + call MartTextbox + ret + +Pharmacist: + call FarReadMart + call LoadStandardMenuHeader + ld hl, PharmacyIntroText + call MartTextbox + call BuyMenu + ld hl, PharmacyComeAgainText + call MartTextbox + ret + +LoadMartPointer: + ld a, b + ld [wMartPointerBank], a + ld a, e + ld [wMartPointer], a + ld a, d + ld [wMartPointer + 1], a + ld hl, wCurMart + xor a + ld bc, wCurMartEnd - wCurMart + call ByteFill + xor a ; STANDARDMART_HOWMAYIHELPYOU + ld [wMartJumptableIndex], a + ld [wBargainShopFlags], a + ld [wFacingDirection], a + ret + +; StandardMart.MartFunctions indexes + const_def + const STANDARDMART_HOWMAYIHELPYOU ; 0 + const STANDARDMART_TOPMENU ; 1 + const STANDARDMART_BUY ; 2 + const STANDARDMART_SELL ; 3 + const STANDARDMART_QUIT ; 4 + const STANDARDMART_ANYTHINGELSE ; 5 + +STANDARDMART_EXIT EQU -1 + +StandardMart: +.loop + ld a, [wMartJumptableIndex] + ld hl, .MartFunctions + rst JumpTable + ld [wMartJumptableIndex], a + cp STANDARDMART_EXIT + jr nz, .loop + ret + +.MartFunctions: +; entries correspond to STANDARDMART_* constants + dw .HowMayIHelpYou + dw .TopMenu + dw .Buy + dw .Sell + dw .Quit + dw .AnythingElse + +.HowMayIHelpYou: + call LoadStandardMenuHeader + ld hl, MartWelcomeText + call PrintText + ld a, STANDARDMART_TOPMENU + ret + +.TopMenu: + ld hl, MenuHeader_BuySell + call CopyMenuHeader + call VerticalMenu + jr c, .quit + ld a, [wMenuCursorY] + cp $1 + jr z, .buy + cp $2 + jr z, .sell +.quit + ld a, STANDARDMART_QUIT + ret +.buy + ld a, STANDARDMART_BUY + ret +.sell + ld a, STANDARDMART_SELL + ret + +.Buy: + call ExitMenu + call FarReadMart + call BuyMenu + and a + ld a, STANDARDMART_ANYTHINGELSE + ret + +.Sell: + call ExitMenu + call SellMenu + ld a, STANDARDMART_ANYTHINGELSE + ret + +.Quit: + call ExitMenu + ld hl, MartComeAgainText + call MartTextbox + ld a, STANDARDMART_EXIT + ret + +.AnythingElse: + call LoadStandardMenuHeader + ld hl, MartAskMoreText + call PrintText + ld a, STANDARDMART_TOPMENU + ret + +FarReadMart: + ld hl, wMartPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wCurMart +.CopyMart: + ld a, [wMartPointerBank] + call GetFarByte + ld [de], a + inc hl + inc de + cp -1 + jr nz, .CopyMart + ld hl, wMartItem1BCD + ld de, wCurMart + 1 +.ReadMartItem: + ld a, [de] + inc de + cp -1 + jr z, .done + push de + call GetMartItemPrice + pop de + jr .ReadMartItem + +.done + ret + +GetMartItemPrice: +; Return the price of item a in BCD at hl and in tiles at wStringBuffer1. + push hl + ld [wCurItem], a + farcall GetItemPrice + pop hl + +GetMartPrice: +; Return price de in BCD at hl and in tiles at wStringBuffer1. + push hl + ld a, d + ld [wStringBuffer2], a + ld a, e + ld [wStringBuffer2 + 1], a + ld hl, wStringBuffer1 + ld de, wStringBuffer2 + lb bc, PRINTNUM_LEADINGZEROS | 2, 6 ; 6 digits + call PrintNum + pop hl + + ld de, wStringBuffer1 + ld c, 6 / 2 ; 6 digits +.loop + call .CharToNybble + swap a + ld b, a + call .CharToNybble + or b + ld [hli], a + dec c + jr nz, .loop + ret + +.CharToNybble: + ld a, [de] + inc de + cp " " + jr nz, .not_space + ld a, "0" + +.not_space + sub "0" + ret + +ReadMart: +; Load the mart pointer. Mart data is local (no need for bank). + ld hl, wMartPointer + ld a, [hli] + ld h, [hl] + ld l, a + push hl +; set hl to the first item + inc hl + ld bc, wMartItem1BCD + ld de, wCurMart + 1 +.loop +; copy the item to wCurMart + (ItemIndex) + ld a, [hli] + ld [de], a + inc de +; -1 is the terminator + cp -1 + jr z, .done + + push de +; copy the price to de + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a +; convert the price to 3-byte BCD at [bc] + push hl + ld h, b + ld l, c + call GetMartPrice + ld b, h + ld c, l + pop hl + + pop de + jr .loop + +.done + pop hl + ld a, [hl] + ld [wCurMart], a + ret + +INCLUDE "data/items/bargain_shop.asm" + +BuyMenu: + call FadeToMenu + farcall BlankScreen + xor a + ld [wMenuScrollPositionBackup], a + ld a, 1 + ld [wMenuCursorBufferBackup], a +.loop + call BuyMenuLoop ; menu loop + jr nc, .loop + call CloseSubmenu + ret + +LoadBuyMenuText: +; load text from a nested table +; which table is in wMartType +; which entry is in register a + push af + call GetMartDialogGroup ; gets a pointer from GetMartDialogGroup.MartTextFunctionPointers + ld a, [hli] + ld h, [hl] + ld l, a + pop af + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + ret + +MartAskPurchaseQuantity: + call GetMartDialogGroup ; gets a pointer from GetMartDialogGroup.MartTextFunctionPointers + inc hl + inc hl + ld a, [hl] + and a + jp z, StandardMartAskPurchaseQuantity + jp BargainShopAskPurchaseQuantity + +GetMartDialogGroup: + ld a, [wMartType] + ld e, a + ld d, 0 + ld hl, .MartTextFunctionPointers + add hl, de + add hl, de + add hl, de + ret + +.MartTextFunctionPointers: + dwb .StandardMartPointers, 0 + dwb .HerbShopPointers, 0 + dwb .BargainShopPointers, 1 + dwb .PharmacyPointers, 0 + +.StandardMartPointers: + dw MartHowManyText + dw MartFinalPriceText + dw MartNoMoneyText + dw MartPackFullText + dw MartThanksText + dw BuyMenuLoop + +.HerbShopPointers: + dw HerbalLadyHowManyText + dw HerbalLadyFinalPriceText + dw HerbalLadyNoMoneyText + dw HerbalLadyPackFullText + dw HerbalLadyThanksText + dw BuyMenuLoop + +.BargainShopPointers: + dw BuyMenuLoop + dw BargainShopFinalPriceText + dw BargainShopNoFundsText + dw BargainShopPackFullText + dw BargainShopThanksText + dw BargainShopSoldOutText + +.PharmacyPointers: + dw PharmacyHowManyText + dw PharmacyFinalPriceText + dw PharmacyNoMoneyText + dw PharmacyPackFullText + dw PharmacyThanksText + dw BuyMenuLoop + +BuyMenuLoop: + farcall PlaceMoneyTopRight + call UpdateSprites + ld hl, MenuHeader_Buy + call CopyMenuHeader + ld a, [wMenuCursorBufferBackup] + ld [wMenuCursorBuffer], a + ld a, [wMenuScrollPositionBackup] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wMenuScrollPositionBackup], a + ld a, [wMenuCursorY] + ld [wMenuCursorBufferBackup], a + call SpeechTextbox + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .set_carry + cp A_BUTTON + jr z, .useless_pointer + +.useless_pointer + call MartAskPurchaseQuantity + jr c, .cancel + call MartConfirmPurchase + jr c, .cancel + ld de, wMoney + ld bc, hMoneyTemp + ld a, 3 ; useless load + call CompareMoney + jr c, .insufficient_funds + ld hl, wNumItems + call ReceiveItem + jr nc, .insufficient_bag_space + ld a, [wMartItemID] + ld e, a + ld d, 0 + ld b, SET_FLAG + ld hl, wBargainShopFlags + call FlagAction + call PlayTransactionSound + ld de, wMoney + ld bc, hMoneyTemp + call TakeMoney + ld a, MARTTEXT_HERE_YOU_GO + call LoadBuyMenuText + call JoyWaitAorB + +.cancel + call SpeechTextbox + and a + ret + +.set_carry + scf + ret + +.insufficient_bag_space + ld a, MARTTEXT_BAG_FULL + call LoadBuyMenuText + call JoyWaitAorB + and a + ret + +.insufficient_funds + ld a, MARTTEXT_NOT_ENOUGH_MONEY + call LoadBuyMenuText + call JoyWaitAorB + and a + ret + +StandardMartAskPurchaseQuantity: + ld a, 99 + ld [wItemQuantityBuffer], a + ld a, MARTTEXT_HOW_MANY + call LoadBuyMenuText + farcall SelectQuantityToBuy + call ExitMenu + ret + +MartConfirmPurchase: + predef PartyMonItemName + ld a, MARTTEXT_COSTS_THIS_MUCH + call LoadBuyMenuText + call YesNoBox + ret + +BargainShopAskPurchaseQuantity: + ld a, 1 + ld [wItemQuantityChangeBuffer], a + ld a, [wMartItemID] + ld e, a + ld d, 0 + ld b, CHECK_FLAG + ld hl, wBargainShopFlags + call FlagAction + ld a, c + and a + jr nz, .SoldOut + ld a, [wMartItemID] + ld e, a + ld d, 0 + ld hl, wMartPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + add hl, de + add hl, de + add hl, de + inc hl + ld a, [hli] + ldh [hMoneyTemp + 2], a + ld a, [hl] + ldh [hMoneyTemp + 1], a + xor a + ldh [hMoneyTemp], a + and a + ret + +.SoldOut: + ld a, MARTTEXT_SOLD_OUT + call LoadBuyMenuText + call JoyWaitAorB + scf + ret + +MartHowManyText: + text_far _MartHowManyText + text_end + +MartFinalPriceText: + text_far _MartFinalPriceText + text_end + +MenuHeader_Buy: + db MENU_BACKUP_TILES ; flags + menu_coords 1, 3, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData + db SCROLLINGMENU_DISPLAY_ARROWS | SCROLLINGMENU_ENABLE_FUNCTION3 ; flags + db 4, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_NORMAL ; item format + dbw 0, wCurMart + dba PlaceMenuItemName + dba .PrintBCDPrices + dba UpdateItemDescription + +.PrintBCDPrices: + ld a, [wScrollingMenuCursorPosition] + ld c, a + ld b, 0 + ld hl, wMartItem1BCD + add hl, bc + add hl, bc + add hl, bc + push de + ld d, h + ld e, l + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + ld c, PRINTNUM_LEADINGZEROS | PRINTNUM_MONEY | 3 + call PrintBCDNumber + ret + +HerbShopLadyIntroText: + text_far _HerbShopLadyIntroText + text_end + +HerbalLadyHowManyText: + text_far _HerbalLadyHowManyText + text_end + +HerbalLadyFinalPriceText: + text_far _HerbalLadyFinalPriceText + text_end + +HerbalLadyThanksText: + text_far _HerbalLadyThanksText + text_end + +HerbalLadyPackFullText: + text_far _HerbalLadyPackFullText + text_end + +HerbalLadyNoMoneyText: + text_far _HerbalLadyNoMoneyText + text_end + +HerbalLadyComeAgainText: + text_far _HerbalLadyComeAgainText + text_end + +BargainShopIntroText: + text_far _BargainShopIntroText + text_end + +BargainShopFinalPriceText: + text_far _BargainShopFinalPriceText + text_end + +BargainShopThanksText: + text_far _BargainShopThanksText + text_end + +BargainShopPackFullText: + text_far _BargainShopPackFullText + text_end + +BargainShopSoldOutText: + text_far _BargainShopSoldOutText + text_end + +BargainShopNoFundsText: + text_far _BargainShopNoFundsText + text_end + +BargainShopComeAgainText: + text_far _BargainShopComeAgainText + text_end + +PharmacyIntroText: + text_far _PharmacyIntroText + text_end + +PharmacyHowManyText: + text_far _PharmacyHowManyText + text_end + +PharmacyFinalPriceText: + text_far _PharmacyFinalPriceText + text_end + +PharmacyThanksText: + text_far _PharmacyThanksText + text_end + +PharmacyPackFullText: + text_far _PharmacyPackFullText + text_end + +PharmacyNoMoneyText: + text_far _PharmacyNoMoneyText + text_end + +PharmacyComeAgainText: + text_far _PharmacyComeAgainText + text_end + +SellMenu: + call DisableSpriteUpdates + farcall DepositSellInitPackBuffers +.loop + farcall DepositSellPack + ld a, [wPackUsedItem] + and a + jp z, .quit + call .TryToSellItem + jr .loop + +.quit + call ReturnToMapWithSpeechTextbox + and a + ret + +.Unreferenced_NothingToSell: + ld hl, .NothingToSellText + call MenuTextboxBackup + and a + ret + +.NothingToSellText: + text_far _NothingToSellText + text_end + +.TryToSellItem: + farcall CheckItemMenu + ld a, [wItemAttributeParamBuffer] + ld hl, .dw + rst JumpTable + ret + +.dw + dw .try_sell + dw .cant_buy + dw .cant_buy + dw .cant_buy + dw .try_sell + dw .try_sell + dw .try_sell + +.cant_buy + ret + +.try_sell + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr z, .okay_to_sell + ld hl, MartCantBuyText + call PrintText + and a + ret + +.okay_to_sell + ld hl, MartSellHowManyText + call PrintText + farcall PlaceMoneyAtTopLeftOfTextbox + farcall SelectQuantityToSell + call ExitMenu + jr c, .declined + hlcoord 1, 14 + lb bc, 3, 18 + call ClearBox + ld hl, MartSellPriceText + call PrintTextboxText + call YesNoBox + jr c, .declined + ld de, wMoney + ld bc, hMoneyTemp + call GiveMoney + ld a, [wMartItemID] + ld hl, wNumItems + call TossItem + predef PartyMonItemName + hlcoord 1, 14 + lb bc, 3, 18 + call ClearBox + ld hl, MartBoughtText + call PrintTextboxText + call PlayTransactionSound + farcall PlaceMoneyBottomLeft + call JoyWaitAorB + +.declined + call ExitMenu + and a + ret + +MartSellHowManyText: + text_far _MartSellHowManyText + text_end + +MartSellPriceText: + text_far _MartSellPriceText + text_end + +.UnusedString161d2: + db "!ダミー!@" + +MartWelcomeText: + text_far _MartWelcomeText + text_end + +MenuHeader_BuySell: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 11, 8 + dw .MenuData + db 1 ; default option + +.MenuData + db STATICMENU_CURSOR ; strings + db 3 ; items + db "BUY@" + db "SELL@" + db "QUIT@" + +MartThanksText: + text_far _MartThanksText + text_end + +MartNoMoneyText: + text_far _MartNoMoneyText + text_end + +MartPackFullText: + text_far _MartPackFullText + text_end + +MartCantBuyText: + text_far _MartCantBuyText + text_end + +MartComeAgainText: + text_far _MartComeAgainText + text_end + +MartAskMoreText: + text_far _MartAskMoreText + text_end + +MartBoughtText: + text_far _MartBoughtText + text_end + +PlayTransactionSound: + call WaitSFX + ld de, SFX_TRANSACTION + call PlaySFX + ret + +MartTextbox: + call MenuTextbox + call JoyWaitAorB + call ExitMenu + ret diff --git a/engine/items/pack.asm b/engine/items/pack.asm new file mode 100755 index 00000000..e7caceca --- /dev/null +++ b/engine/items/pack.asm @@ -0,0 +1,1584 @@ +; Pack.Jumptable and BattlePack.Jumptable indexes + const_def + const PACKSTATE_INITGFX ; 0 + const PACKSTATE_INITITEMSPOCKET ; 1 + const PACKSTATE_ITEMSPOCKETMENU ; 2 + const PACKSTATE_INITBALLSPOCKET ; 3 + const PACKSTATE_BALLSPOCKETMENU ; 4 + const PACKSTATE_INITKEYITEMSPOCKET ; 5 + const PACKSTATE_KEYITEMSPOCKETMENU ; 6 + const PACKSTATE_INITTMHMPOCKET ; 7 + const PACKSTATE_TMHMPOCKETMENU ; 8 + const PACKSTATE_QUITNOSCRIPT ; 9 + const PACKSTATE_QUITRUNSCRIPT ; 10 + +Pack: + ld hl, wOptions + set NO_TEXT_SCROLL, [hl] + call InitPackBuffers +.loop + call JoyTextDelay + ld a, [wJumptableIndex] + bit 7, a + jr nz, .done + call .RunJumptable + call DelayFrame + jr .loop + +.done + ld a, [wCurPocket] + ld [wLastPocket], a + ld hl, wOptions + res NO_TEXT_SCROLL, [hl] + ret + +.RunJumptable: + ld a, [wJumptableIndex] + ld hl, .Jumptable + call Pack_GetJumptablePointer + jp hl + +.Jumptable: +; entries correspond to PACKSTATE_* constants + dw .InitGFX ; 0 + dw .InitItemsPocket ; 1 + dw .ItemsPocketMenu ; 2 + dw .InitBallsPocket ; 3 + dw .BallsPocketMenu ; 4 + dw .InitKeyItemsPocket ; 5 + dw .KeyItemsPocketMenu ; 6 + dw .InitTMHMPocket ; 7 + dw .TMHMPocketMenu ; 8 + dw Pack_QuitNoScript ; 9 + dw Pack_QuitRunScript ; 10 + +.InitGFX: + xor a + ldh [hBGMapMode], a + call Pack_InitGFX + ld a, [wPackJumptableIndex] + ld [wJumptableIndex], a + call Pack_InitColors + ret + +.InitItemsPocket: + xor a ; ITEM_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.ItemsPocketMenu: + ld hl, ItemsPocketMenuHeader + call CopyMenuHeader + ld a, [wItemsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wItemsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wItemsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wItemsPocketCursor], a + ld b, PACKSTATE_INITTMHMPOCKET ; left + ld c, PACKSTATE_INITBALLSPOCKET ; right + call Pack_InterpretJoypad + ret c + call .ItemBallsKey_LoadSubmenu + ret + +.InitKeyItemsPocket: + ld a, KEY_ITEM_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.KeyItemsPocketMenu: + ld hl, KeyItemsPocketMenuHeader + call CopyMenuHeader + ld a, [wKeyItemsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wKeyItemsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wKeyItemsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wKeyItemsPocketCursor], a + ld b, PACKSTATE_INITBALLSPOCKET ; left + ld c, PACKSTATE_INITTMHMPOCKET ; right + call Pack_InterpretJoypad + ret c + call .ItemBallsKey_LoadSubmenu + ret + +.InitTMHMPocket: + ld a, TM_HM_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + xor a + ldh [hBGMapMode], a + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.TMHMPocketMenu: + farcall TMHMPocket + ld b, PACKSTATE_INITKEYITEMSPOCKET ; left + ld c, PACKSTATE_INITITEMSPOCKET ; right + call Pack_InterpretJoypad + ret c + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .use_quit + ld hl, .MenuHeader2 + ld de, .Jumptable2 + jr .load_jump + +.use_quit + ld hl, .MenuHeader1 + ld de, .Jumptable1 +.load_jump + push de + call LoadMenuHeader + call VerticalMenu + call ExitMenu + pop hl + ret c + ld a, [wMenuCursorY] + dec a + call Pack_GetJumptablePointer + jp hl + +.MenuHeader1: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 7, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData_1 + db 1 ; default option + +.MenuData_1: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 2 ; items + db "USE@" + db "QUIT@" + +.Jumptable1: + dw .UseItem + dw QuitItemSubmenu + +.MenuHeader2: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 5, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData_2 + db 1 ; default option + +.MenuData_2: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 3 ; items + db "USE@" + db "GIVE@" + db "QUIT@" + +.Jumptable2: + dw .UseItem + dw GiveItem + dw QuitItemSubmenu + +.UseItem: + farcall AskTeachTMHM + ret c + farcall ChooseMonToLearnTMHM + jr c, .declined + ld hl, wOptions + ld a, [hl] + push af + res NO_TEXT_SCROLL, [hl] + farcall TeachTMHM + pop af + ld [wOptions], a +.declined + xor a + ldh [hBGMapMode], a + call Pack_InitGFX + call WaitBGMap_DrawPackGFX + call Pack_InitColors + ret + +.InitBallsPocket: + ld a, BALL_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.BallsPocketMenu: + ld hl, BallsPocketMenuHeader + call CopyMenuHeader + ld a, [wBallsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wBallsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wBallsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wBallsPocketCursor], a + ld b, PACKSTATE_INITITEMSPOCKET ; left + ld c, PACKSTATE_INITKEYITEMSPOCKET ; right + call Pack_InterpretJoypad + ret c + call .ItemBallsKey_LoadSubmenu + ret + +.ItemBallsKey_LoadSubmenu: + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .tossable + farcall CheckSelectableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .selectable + farcall CheckItemMenu + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .usable + jr .unusable + +.selectable + farcall CheckItemMenu + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .selectable_usable + jr .selectable_unusable + +.tossable + farcall CheckSelectableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .tossable_selectable + jr .tossable_unselectable + +.usable + ld hl, MenuHeader_UsableKeyItem + ld de, Jumptable_UseGiveTossRegisterQuit + jr .build_menu + +.selectable_usable + ld hl, MenuHeader_UsableItem + ld de, Jumptable_UseGiveTossQuit + jr .build_menu + +.tossable_selectable + ld hl, MenuHeader_UnusableItem + ld de, Jumptable_UseQuit + jr .build_menu + +.tossable_unselectable + ld hl, MenuHeader_UnusableKeyItem + ld de, Jumptable_UseRegisterQuit + jr .build_menu + +.unusable + ld hl, MenuHeader_HoldableKeyItem + ld de, Jumptable_GiveTossRegisterQuit + jr .build_menu + +.selectable_unusable + ld hl, MenuHeader_HoldableItem + ld de, Jumptable_GiveTossQuit +.build_menu + push de + call LoadMenuHeader + call VerticalMenu + call ExitMenu + pop hl + ret c + ld a, [wMenuCursorY] + dec a + call Pack_GetJumptablePointer + jp hl + +MenuHeader_UsableKeyItem: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 2, SCREEN_WIDTH - 14, TEXTBOX_Y + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 5 ; items + db "USE@" + db "GIVE@" + db "TOSS@" + db "SEL@" + db "QUIT@" + +Jumptable_UseGiveTossRegisterQuit: + dw UseItem + dw GiveItem + dw TossMenu + dw RegisterItem + dw QuitItemSubmenu + +MenuHeader_UsableItem: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 3, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 4 ; items + db "USE@" + db "GIVE@" + db "TOSS@" + db "QUIT@" + +Jumptable_UseGiveTossQuit: + dw UseItem + dw GiveItem + dw TossMenu + dw QuitItemSubmenu + +MenuHeader_UnusableItem: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 7, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 2 ; items + db "USE@" + db "QUIT@" + +Jumptable_UseQuit: + dw UseItem + dw QuitItemSubmenu + +MenuHeader_UnusableKeyItem: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 5, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 3 ; items + db "USE@" + db "SEL@" + db "QUIT@" + +Jumptable_UseRegisterQuit: + dw UseItem + dw RegisterItem + dw QuitItemSubmenu + +MenuHeader_HoldableKeyItem: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 3, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 4 ; items + db "GIVE@" + db "TOSS@" + db "SEL@" + db "QUIT@" + +Jumptable_GiveTossRegisterQuit: + dw GiveItem + dw TossMenu + dw RegisterItem + dw QuitItemSubmenu + +MenuHeader_HoldableItem: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 5, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 3 ; items + db "GIVE@" + db "TOSS@" + db "QUIT@" + +Jumptable_GiveTossQuit: + dw GiveItem + dw TossMenu + dw QuitItemSubmenu + +UseItem: + farcall CheckItemMenu + ld a, [wItemAttributeParamBuffer] + ld hl, .dw + rst JumpTable + ret + +.dw +; entries correspond to ITEMMENU_* constants + dw .Oak ; ITEMMENU_NOUSE + dw .Oak + dw .Oak + dw .Oak + dw .Current ; ITEMMENU_CURRENT + dw .Party ; ITEMMENU_PARTY + dw .Field ; ITEMMENU_CLOSE + +.Oak: + ld hl, OakThisIsntTheTimeText + call Pack_PrintTextNoScroll + ret + +.Current: + call DoItemEffect + ret + +.Party: + ld a, [wPartyCount] + and a + jr z, .NoPokemon + call DoItemEffect + xor a + ldh [hBGMapMode], a + call Pack_InitGFX + call WaitBGMap_DrawPackGFX + call Pack_InitColors + ret + +.NoPokemon: + ld hl, YouDontHaveAMonText + call Pack_PrintTextNoScroll + ret + +.Field: + call DoItemEffect + ld a, [wItemEffectSucceeded] + and a + jr z, .Oak + ld a, PACKSTATE_QUITRUNSCRIPT + ld [wJumptableIndex], a + ret + +TossMenu: + ld hl, AskThrowAwayText + call Pack_PrintTextNoScroll + farcall SelectQuantityToToss + push af + call ExitMenu + pop af + jr c, .finish + call Pack_GetItemName + ld hl, AskQuantityThrowAwayText + call MenuTextbox + call YesNoBox + push af + call ExitMenu + pop af + jr c, .finish + ld hl, wNumItems + ld a, [wCurItemQuantity] + call TossItem + call Pack_GetItemName + ld hl, ThrewAwayText + call Pack_PrintTextNoScroll +.finish + ret + +Unreferenced_ResetPocketCursorPositions: + ld a, [wCurPocket] + and a ; ITEM_POCKET + jr z, .items + dec a ; BALL_POCKET + jr z, .balls + dec a ; KEY_ITEM_POCKET + jr z, .key + ret + +.balls + xor a + ld [wBallsPocketCursor], a + ld [wBallsPocketScrollPosition], a + ret + +.items + xor a + ld [wItemsPocketCursor], a + ld [wItemsPocketScrollPosition], a + ret + +.key + xor a + ld [wKeyItemsPocketCursor], a + ld [wKeyItemsPocketScrollPosition], a + ret + +RegisterItem: + farcall CheckSelectableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .cant_register + ld a, [wCurPocket] + rrca + rrca + and REGISTERED_POCKET + ld b, a + ld a, [wCurItemQuantity] + inc a + and REGISTERED_NUMBER + or b + ld [wWhichRegisteredItem], a + ld a, [wCurItem] + ld [wRegisteredItem], a + call Pack_GetItemName + ld de, SFX_FULL_HEAL + call WaitPlaySFX + ld hl, RegisteredItemText + call Pack_PrintTextNoScroll + ret + +.cant_register + ld hl, CantRegisterText + call Pack_PrintTextNoScroll + ret + +GiveItem: + ld a, [wPartyCount] + and a + jp z, .NoPokemon + ld a, [wOptions] + push af + res NO_TEXT_SCROLL, a + ld [wOptions], a + ld a, PARTYMENUACTION_GIVE_ITEM + ld [wPartyMenuActionText], a + call ClearBGPalettes + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX +.loop + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + farcall PartyMenuSelect + jr c, .finish + ld a, [wCurPartySpecies] + cp EGG + jr nz, .give + ld hl, .AnEggCantHoldAnItemText + call PrintText + jr .loop + +.give + ld a, [wJumptableIndex] + push af + ld a, [wPackJumptableIndex] + push af + call GetCurNick + ld hl, wStringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, MON_NAME_LENGTH + call CopyBytes + call TryGiveItemToPartymon + pop af + ld [wPackJumptableIndex], a + pop af + ld [wJumptableIndex], a +.finish + pop af + ld [wOptions], a + xor a + ldh [hBGMapMode], a + call Pack_InitGFX + call WaitBGMap_DrawPackGFX + call Pack_InitColors + ret + +.NoPokemon: + ld hl, YouDontHaveAMonText + call Pack_PrintTextNoScroll + ret +.AnEggCantHoldAnItemText: + text_far _AnEggCantHoldAnItemText + text_end + +QuitItemSubmenu: + ret + +BattlePack: + ld hl, wOptions + set NO_TEXT_SCROLL, [hl] + call InitPackBuffers +.loop + call JoyTextDelay + ld a, [wJumptableIndex] + bit 7, a + jr nz, .end + call .RunJumptable + call DelayFrame + jr .loop + +.end + ld a, [wCurPocket] + ld [wLastPocket], a + ld hl, wOptions + res NO_TEXT_SCROLL, [hl] + ret + +.RunJumptable: + ld a, [wJumptableIndex] + ld hl, .Jumptable + call Pack_GetJumptablePointer + jp hl + +.Jumptable: +; entries correspond to PACKSTATE_* constants + dw .InitGFX ; 0 + dw .InitItemsPocket ; 1 + dw .ItemsPocketMenu ; 2 + dw .InitBallsPocket ; 3 + dw .BallsPocketMenu ; 4 + dw .InitKeyItemsPocket ; 5 + dw .KeyItemsPocketMenu ; 6 + dw .InitTMHMPocket ; 7 + dw .TMHMPocketMenu ; 8 + dw Pack_QuitNoScript ; 9 + dw Pack_QuitRunScript ; 10 + +.InitGFX: + xor a + ldh [hBGMapMode], a + call Pack_InitGFX + ld a, [wPackJumptableIndex] + ld [wJumptableIndex], a + call Pack_InitColors + ret + +.InitItemsPocket: + xor a ; ITEM_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.ItemsPocketMenu: + ld hl, ItemsPocketMenuHeader + call CopyMenuHeader + ld a, [wItemsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wItemsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wItemsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wItemsPocketCursor], a + ld b, PACKSTATE_INITTMHMPOCKET ; left + ld c, PACKSTATE_INITBALLSPOCKET ; right + call Pack_InterpretJoypad + ret c + call ItemSubmenu + ret + +.InitKeyItemsPocket: + ld a, KEY_ITEM_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.KeyItemsPocketMenu: + ld hl, KeyItemsPocketMenuHeader + call CopyMenuHeader + ld a, [wKeyItemsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wKeyItemsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wKeyItemsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wKeyItemsPocketCursor], a + ld b, PACKSTATE_INITBALLSPOCKET ; left + ld c, PACKSTATE_INITTMHMPOCKET ; right + call Pack_InterpretJoypad + ret c + call ItemSubmenu + ret + +.InitTMHMPocket: + ld a, TM_HM_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + xor a + ldh [hBGMapMode], a + call WaitBGMap_DrawPackGFX + ld hl, PackEmptyText + call Pack_PrintTextNoScroll + call Pack_JumptableNext + ret + +.TMHMPocketMenu: + farcall TMHMPocket + ld b, PACKSTATE_INITKEYITEMSPOCKET ; left + ld c, PACKSTATE_INITITEMSPOCKET ; right + call Pack_InterpretJoypad + ret c + xor a + call TMHMSubmenu + ret + +.InitBallsPocket: + ld a, BALL_POCKET + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + call Pack_JumptableNext + ret + +.BallsPocketMenu: + ld hl, BallsPocketMenuHeader + call CopyMenuHeader + ld a, [wBallsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wBallsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wBallsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wBallsPocketCursor], a + ld b, PACKSTATE_INITITEMSPOCKET ; left + ld c, PACKSTATE_INITKEYITEMSPOCKET ; right + call Pack_InterpretJoypad + ret c + call ItemSubmenu + ret + +ItemSubmenu: + farcall CheckItemContext + ld a, [wItemAttributeParamBuffer] +TMHMSubmenu: + and a + jr z, .NoUse + ld hl, .UsableMenuHeader + ld de, .UsableJumptable + jr .proceed + +.NoUse: + ld hl, .UnusableMenuHeader + ld de, .UnusableJumptable +.proceed + push de + call LoadMenuHeader + call VerticalMenu + call ExitMenu + pop hl + ret c + ld a, [wMenuCursorY] + dec a + call Pack_GetJumptablePointer + jp hl + +.UsableMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 7, TEXTBOX_HEIGHT, TEXTBOX_Y - 1 + dw .UsableMenuData + db 1 ; default option + +.UsableMenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 2 ; items + db "USE@" + db "QUIT@" + +.UsableJumptable: + dw .Use + dw .Quit + +.UnusableMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 9, SCREEN_WIDTH - 14, TEXTBOX_Y - 1 + dw .UnusableMenuData + db 1 ; default option + +.UnusableMenuData: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 1 ; items + db "QUIT@" + +.UnusableJumptable: + dw .Quit + +.Use: + farcall CheckItemContext + ld a, [wItemAttributeParamBuffer] + ld hl, .ItemFunctionJumptable + rst JumpTable + ret + +.ItemFunctionJumptable: +; entries correspond to ITEMMENU_* constants + dw .Oak ; ITEMMENU_NOUSE + dw .Oak + dw .Oak + dw .Oak + dw .Unused ; ITEMMENU_CURRENT + dw .BattleField ; ITEMMENU_PARTY + dw .BattleOnly ; ITEMMENU_CLOSE + +.Oak: + ld hl, OakThisIsntTheTimeText + call Pack_PrintTextNoScroll + ret + +.Unused: + call DoItemEffect + ld a, [wItemEffectSucceeded] + and a + jr nz, .ReturnToBattle + ret + +.BattleField: + call DoItemEffect + ld a, [wItemEffectSucceeded] + and a + jr nz, .quit_run_script + xor a + ldh [hBGMapMode], a + call Pack_InitGFX + call WaitBGMap_DrawPackGFX + call Pack_InitColors + ret + +.ReturnToBattle: + call ClearBGPalettes + jr .quit_run_script + +.BattleOnly: + call DoItemEffect + ld a, [wItemEffectSucceeded] + and a + jr z, .Oak + cp $2 + jr z, .didnt_use_item +.quit_run_script + ld a, PACKSTATE_QUITRUNSCRIPT + ld [wJumptableIndex], a + ret + +.didnt_use_item + xor a + ld [wItemEffectSucceeded], a + ret +.Quit: + ret + +InitPackBuffers: + xor a + ld [wJumptableIndex], a + ; pocket id -> jumptable index + ld a, [wLastPocket] + maskbits NUM_POCKETS + ld [wCurPocket], a + inc a + add a + dec a + ld [wPackJumptableIndex], a + xor a ; FALSE + ld [wPackUsedItem], a + xor a + ld [wSwitchItem], a + ret + +DepositSellInitPackBuffers: + xor a + ldh [hBGMapMode], a + ld [wJumptableIndex], a ; PACKSTATE_INITGFX + ld [wPackJumptableIndex], a ; PACKSTATE_INITGFX + ld [wCurPocket], a ; ITEM_POCKET + ld [wPackUsedItem], a + ld [wSwitchItem], a + call Pack_InitGFX + call Pack_InitColors + ret + +DepositSellPack: +.loop + call .RunJumptable + call DepositSellTutorial_InterpretJoypad + jr c, .loop + ret + +.RunJumptable: + ld a, [wJumptableIndex] + ld hl, .Jumptable + call Pack_GetJumptablePointer + jp hl + +.Jumptable: +; entries correspond to *_POCKET constants + dw .ItemsPocket + dw .BallsPocket + dw .KeyItemsPocket + dw .TMHMPocket + +.ItemsPocket: + xor a ; ITEM_POCKET + call InitPocket + ld hl, PC_Mart_ItemsPocketMenuHeader + call CopyMenuHeader + ld a, [wItemsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wItemsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wItemsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wItemsPocketCursor], a + ret + +.KeyItemsPocket: + ld a, KEY_ITEM_POCKET + call InitPocket + ld hl, PC_Mart_KeyItemsPocketMenuHeader + call CopyMenuHeader + ld a, [wKeyItemsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wKeyItemsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wKeyItemsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wKeyItemsPocketCursor], a + ret + +.TMHMPocket: + ld a, TM_HM_POCKET + call InitPocket + call WaitBGMap_DrawPackGFX + farcall TMHMPocket + ld a, [wCurItem] + ld [wCurItem], a + ret + +.BallsPocket: + ld a, BALL_POCKET + call InitPocket + ld hl, PC_Mart_BallsPocketMenuHeader + call CopyMenuHeader + ld a, [wBallsPocketCursor] + ld [wMenuCursorBuffer], a + ld a, [wBallsPocketScrollPosition] + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuScrollPosition] + ld [wBallsPocketScrollPosition], a + ld a, [wMenuCursorY] + ld [wBallsPocketCursor], a + ret + +InitPocket: + ld [wCurPocket], a + call ClearPocketList + call DrawPocketName + call WaitBGMap_DrawPackGFX + ret + +DepositSellTutorial_InterpretJoypad: + ld hl, wMenuJoypad + ld a, [hl] + and A_BUTTON + jr nz, .a_button + ld a, [hl] + and B_BUTTON + jr nz, .b_button + ld a, [hl] + and D_LEFT + jr nz, .d_left + ld a, [hl] + and D_RIGHT + jr nz, .d_right + scf + ret + +.a_button + ld a, TRUE + ld [wPackUsedItem], a + and a + ret + +.b_button + xor a ; FALSE + ld [wPackUsedItem], a + and a + ret + +.d_left + ld a, [wJumptableIndex] + dec a + maskbits NUM_POCKETS + ld [wJumptableIndex], a + push de + ld de, SFX_SWITCH_POCKETS + call PlaySFX + pop de + scf + ret + +.d_right + ld a, [wJumptableIndex] + inc a + maskbits NUM_POCKETS + ld [wJumptableIndex], a + push de + ld de, SFX_SWITCH_POCKETS + call PlaySFX + pop de + scf + ret + +TutorialPack: + call DepositSellInitPackBuffers + ld a, [wInputType] + or a + jr z, .loop + farcall _DudeAutoInput_RightA +.loop + call .RunJumptable + call DepositSellTutorial_InterpretJoypad + jr c, .loop + xor a ; FALSE + ld [wPackUsedItem], a + ret + +.RunJumptable: + ld a, [wJumptableIndex] + ld hl, .dw + call Pack_GetJumptablePointer + jp hl + +.dw +; entries correspond to *_POCKET constants + dw .Items + dw .Balls + dw .KeyItems + dw .TMHM + +.Items: + xor a ; ITEM_POCKET + ld hl, .ItemsMenuHeader + jr .DisplayPocket + +.ItemsMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .ItemsMenuData + db 1 ; default option + +.ItemsMenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags + db 5, 8 ; rows, columns + db 2 ; horizontal spacing + dbw 0, wDudeNumItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +.KeyItems: + ld a, KEY_ITEM_POCKET + ld hl, .KeyItemsMenuHeader + jr .DisplayPocket + +.KeyItemsMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .KeyItemsMenuData + db 1 ; default option + +.KeyItemsMenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags + db 5, 8 ; rows, columns + db 1 ; horizontal spacing + dbw 0, wDudeNumKeyItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +.TMHM: + ld a, TM_HM_POCKET + call InitPocket + call WaitBGMap_DrawPackGFX + farcall TMHMPocket + ld a, [wCurItem] + ld [wCurItem], a + ret + +.Balls: + ld a, BALL_POCKET + ld hl, .BallsMenuHeader + jr .DisplayPocket + +.BallsMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .BallsMenuData + db 1 ; default option + +.BallsMenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags + db 5, 8 ; rows, columns + db 2 ; horizontal spacing + dbw 0, wDudeNumBalls + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +.DisplayPocket: + push hl + call InitPocket + pop hl + call CopyMenuHeader + call ScrollingMenu + ret + +Pack_JumptableNext: + ld hl, wJumptableIndex + inc [hl] + ret + +Pack_GetJumptablePointer: + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ret + +Pack_QuitNoScript: + ld hl, wJumptableIndex + set 7, [hl] + xor a ; FALSE + ld [wPackUsedItem], a + ret + +Pack_QuitRunScript: + ld hl, wJumptableIndex + set 7, [hl] + ld a, TRUE + ld [wPackUsedItem], a + ret + +Pack_PrintTextNoScroll: + ld a, [wOptions] + push af + set NO_TEXT_SCROLL, a + ld [wOptions], a + call PrintText + pop af + ld [wOptions], a + ret + +WaitBGMap_DrawPackGFX: + call WaitBGMap +DrawPackGFX: + ld a, [wCurPocket] + maskbits NUM_POCKETS + ld e, a + ld d, 0 + ld hl, PackGFXPointers + add hl, de + add hl, de + ld a, [hli] + ld e, a + ld d, [hl] + ld hl, vTiles2 tile $50 + lb bc, BANK(PackGFX), 15 + call Request2bpp + ret + +PackGFXPointers: + dw PackGFX + (15 tiles) * 1 ; ITEM_POCKET + dw PackGFX + (15 tiles) * 3 ; BALL_POCKET + dw PackGFX + (15 tiles) * 0 ; KEY_ITEM_POCKET + dw PackGFX + (15 tiles) * 2 ; TM_HM_POCKET + +Pack_InterpretJoypad: + ld hl, wMenuJoypad + ld a, [wSwitchItem] + and a + jr nz, .switching_item + ld a, [hl] + and A_BUTTON + jr nz, .a_button + ld a, [hl] + and B_BUTTON + jr nz, .b_button + ld a, [hl] + and D_LEFT + jr nz, .d_left + ld a, [hl] + and D_RIGHT + jr nz, .d_right + ld a, [hl] + and SELECT + jr nz, .select + scf + ret + +.a_button + and a + ret + +.b_button + ld a, PACKSTATE_QUITNOSCRIPT + ld [wJumptableIndex], a + scf + ret + +.d_left + ld a, b + ld [wJumptableIndex], a + ld [wPackJumptableIndex], a + push de + ld de, SFX_SWITCH_POCKETS + call PlaySFX + pop de + scf + ret + +.d_right + ld a, c + ld [wJumptableIndex], a + ld [wPackJumptableIndex], a + push de + ld de, SFX_SWITCH_POCKETS + call PlaySFX + pop de + scf + ret + +.select + farcall SwitchItemsInBag + ld hl, AskItemMoveText + call Pack_PrintTextNoScroll + scf + ret + +.switching_item + ld a, [hl] + and A_BUTTON | SELECT + jr nz, .place_insert + ld a, [hl] + and B_BUTTON + jr nz, .end_switch + scf + ret + +.place_insert + farcall SwitchItemsInBag + ld de, SFX_SWITCH_POKEMON + call WaitPlaySFX + ld de, SFX_SWITCH_POKEMON + call WaitPlaySFX +.end_switch + xor a + ld [wSwitchItem], a + scf + ret + +Pack_InitGFX: + call ClearBGPalettes + call ClearTilemap + call ClearSprites + call DisableLCD + ld hl, PackMenuGFX + ld de, vTiles2 + ld bc, $60 tiles + ld a, BANK(PackMenuGFX) + call FarCopyBytes +; Background + hlcoord 0, 1 + ld bc, 11 * SCREEN_WIDTH + ld a, $24 + call ByteFill +; This is where the items themselves will be listed. + hlcoord 5, 1 + lb bc, 11, 15 + call ClearBox +; ◀▶ POCKET ▼▲ ITEMS + hlcoord 0, 0 + ld a, $28 + ld c, SCREEN_WIDTH +.loop + ld [hli], a + inc a + dec c + jr nz, .loop + call DrawPocketName + call PlacePackGFX +; Place the textbox for displaying the item description + hlcoord 0, SCREEN_HEIGHT - 4 - 2 + lb bc, 4, SCREEN_WIDTH - 2 + call Textbox + call EnableLCD + call DrawPackGFX + ret + +PlacePackGFX: + hlcoord 0, 3 + ld a, $50 + ld de, SCREEN_WIDTH - 5 + ld b, 3 +.row + ld c, 5 +.column + ld [hli], a + inc a + dec c + jr nz, .column + add hl, de + dec b + jr nz, .row + ret + +DrawPocketName: + ld a, [wCurPocket] + ; * 15 + ld d, a + swap a + sub d + ld d, 0 + ld e, a + ld hl, .tilemap + add hl, de + ld d, h + ld e, l + hlcoord 0, 7 + ld c, 3 +.row + ld b, 5 +.col + ld a, [de] + inc de + ld [hli], a + dec b + jr nz, .col + ld a, c + ld c, SCREEN_WIDTH - 5 + add hl, bc + ld c, a + dec c + jr nz, .row + ret + +.tilemap +; ITEM_POCKET + db $00, $04, $04, $04, $01 ; top border + db $06, $07, $08, $09, $0a ; Items + db $02, $05, $05, $05, $03 ; bottom border +; BALL_POCKET + db $00, $04, $04, $04, $01 ; top border + db $15, $16, $17, $18, $19 ; Balls + db $02, $05, $05, $05, $03 ; bottom border +; KEY_ITEM_POCKET + db $00, $04, $04, $04, $01 ; top border + db $0b, $0c, $0d, $0e, $0f ; Key Items + db $02, $05, $05, $05, $03 ; bottom border +; TM_HM_POCKET + db $00, $04, $04, $04, $01 ; top border + db $10, $11, $12, $13, $14 ; TM/HM + db $02, $05, $05, $05, $03 ; bottom border + +Pack_GetItemName: + ld a, [wCurItem] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call CopyName1 + ret + +Unreferenced_Pack_ClearTilemap: + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + ret + +ClearPocketList: + hlcoord 5, 2 + lb bc, 10, SCREEN_WIDTH - 5 + call ClearBox + ret + +Pack_InitColors: + call WaitBGMap + ld b, SCGB_PACKPALS + call GetSGBLayout + call SetPalettes + call DelayFrame + ret + +ItemsPocketMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags + db 5, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_QUANTITY ; item format + dbw 0, wNumItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +PC_Mart_ItemsPocketMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags + db 5, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_QUANTITY ; item format + dbw 0, wNumItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +KeyItemsPocketMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags + db 5, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_NORMAL ; item format + dbw 0, wNumKeyItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +PC_Mart_KeyItemsPocketMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags + db 5, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_NORMAL ; item format + dbw 0, wNumKeyItems + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +BallsPocketMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags + db 5, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_QUANTITY ; item format + dbw 0, wNumBalls + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +PC_Mart_BallsPocketMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags + db 5, 8 ; rows, columns + db SCROLLINGMENU_ITEMS_QUANTITY ; item format + dbw 0, wNumBalls + dba PlaceMenuItemName + dba PlaceMenuItemQuantity + dba UpdateItemDescription + +PackNoItemText: + text_far _PackNoItemText + text_end + +AskThrowAwayText: + text_far _AskThrowAwayText + text_end + +AskQuantityThrowAwayText: + text_far _AskQuantityThrowAwayText + text_end + +ThrewAwayText: + text_far _ThrewAwayText + text_end + +OakThisIsntTheTimeText: + text_far _OakThisIsntTheTimeText + text_end + +YouDontHaveAMonText: + text_far _YouDontHaveAMonText + text_end + +RegisteredItemText: + text_far _RegisteredItemText + text_end + +CantRegisterText: + text_far _CantRegisterText + text_end + +AskItemMoveText: + text_far _AskItemMoveText + text_end + +PackEmptyText: + text_far _PackEmptyText + text_end + +YouCantUseItInABattleText: + text_far _YouCantUseItInABattleText + text_end + +PackMenuGFX: +INCBIN "gfx/pack/pack_menu.2bpp" +PackGFX: +INCBIN "gfx/pack/pack.2bpp" diff --git a/engine/items/print_item_description.asm b/engine/items/print_item_description.asm new file mode 100644 index 00000000..89a949ad --- /dev/null +++ b/engine/items/print_item_description.asm @@ -0,0 +1,32 @@ +PrintItemDescription: +; Print the description for item [wCurSpecies] at de. + + ld a, [wCurSpecies] + cp TM01 + jr c, .not_a_tm + + ld [wCurItem], a + push de + call GetTMHMItemMove + pop hl + ld a, [wTempTMHM] + ld [wCurSpecies], a + call PrintMoveDesc + ret + +.not_a_tm + push de + ld hl, ItemDescriptions + ld a, [wCurSpecies] + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, BANK(ItemDescriptions) + call GetFarHalfword + ld d, h + ld e, l + pop hl + ld a, BANK(ItemDescriptions) + jp FarString diff --git a/engine/items/switch_items.asm b/engine/items/switch_items.asm new file mode 100644 index 00000000..cb1554d7 --- /dev/null +++ b/engine/items/switch_items.asm @@ -0,0 +1,272 @@ +SwitchItemsInBag: + ld a, [wSwitchItem] + and a + jr z, .init + ld b, a + ld a, [wScrollingMenuCursorPosition] + inc a + cp b + jr z, .trivial + ld a, [wScrollingMenuCursorPosition] + call ItemSwitch_GetNthItem + ld a, [hl] + cp -1 + ret z + ld a, [wSwitchItem] + dec a + ld [wSwitchItem], a + call Function248cf + jp c, Function248f9 + ld a, [wScrollingMenuCursorPosition] + ld c, a + ld a, [wSwitchItem] + cp c + jr c, .asm_248a2 + jr .asm_24872 + +.init + ld a, [wScrollingMenuCursorPosition] + inc a + ld [wSwitchItem], a + ret + +.trivial + xor a + ld [wSwitchItem], a + ret + +.asm_24872 + ld a, [wSwitchItem] + call Function24968 + ld a, [wScrollingMenuCursorPosition] + ld d, a + ld a, [wSwitchItem] + ld e, a + call Function24994 + push bc + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + dec hl + push hl + call ItemSwitch_ConvertItemFormatToDW + add hl, bc + ld d, h + ld e, l + pop hl + pop bc + call Function249d3 + ld a, [wScrollingMenuCursorPosition] + call Function24975 + xor a + ld [wSwitchItem], a + ret + +.asm_248a2 + ld a, [wSwitchItem] + call Function24968 + ld a, [wScrollingMenuCursorPosition] + ld d, a + ld a, [wSwitchItem] + ld e, a + call Function24994 + push bc + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + ld d, h + ld e, l + call ItemSwitch_ConvertItemFormatToDW + add hl, bc + pop bc + call CopyBytes + ld a, [wScrollingMenuCursorPosition] + call Function24975 + xor a + ld [wSwitchItem], a + ret + +Function248cf: + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + ld d, h + ld e, l + ld a, [wScrollingMenuCursorPosition] + call ItemSwitch_GetNthItem + ld a, [de] + cp [hl] + jr nz, .asm_248f5 + ld a, [wScrollingMenuCursorPosition] + call Function249bf + cp 99 + jr z, .asm_248f5 + ld a, [wSwitchItem] + call Function249bf + cp 99 + jr nz, .asm_248f7 +.asm_248f5 + and a + ret + +.asm_248f7 + scf + ret + +Function248f9: + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + inc hl + push hl + ld a, [wScrollingMenuCursorPosition] + call ItemSwitch_GetNthItem + inc hl + ld a, [hl] + pop hl + add [hl] + cp 100 + jr c, .asm_24929 + sub 99 + push af + ld a, [wScrollingMenuCursorPosition] + call ItemSwitch_GetNthItem + inc hl + ld [hl], 99 + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + inc hl + pop af + ld [hl], a + xor a + ld [wSwitchItem], a + ret + +.asm_24929 + push af + ld a, [wScrollingMenuCursorPosition] + call ItemSwitch_GetNthItem + inc hl + pop af + ld [hl], a + ld hl, wMenuData_ItemsPointerAddr + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wSwitchItem] + cp [hl] + jr nz, .asm_2494d + dec [hl] + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + ld [hl], $ff + xor a + ld [wSwitchItem], a + ret + +.asm_2494d + dec [hl] + call ItemSwitch_ConvertItemFormatToDW + push bc + ld a, [wSwitchItem] + call ItemSwitch_GetNthItem + pop bc + push hl + add hl, bc + pop de +.asm_2495c + ld a, [hli] + ld [de], a + inc de + cp $ff + jr nz, .asm_2495c + xor a + ld [wSwitchItem], a + ret + +Function24968: + call ItemSwitch_GetNthItem + ld de, wceed + call ItemSwitch_ConvertItemFormatToDW + call CopyBytes + ret + +Function24975: + call ItemSwitch_GetNthItem + ld d, h + ld e, l + ld hl, wceed + call ItemSwitch_ConvertItemFormatToDW + call CopyBytes + ret + +ItemSwitch_GetNthItem: + push af + call ItemSwitch_ConvertItemFormatToDW + ld hl, wMenuData_ItemsPointerAddr + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + pop af + call AddNTimes + ret + +Function24994: + push hl + call ItemSwitch_ConvertItemFormatToDW + ld a, d + sub e + jr nc, .dont_negate + dec a + cpl +.dont_negate + ld hl, 0 + call AddNTimes + ld b, h + ld c, l + pop hl + ret + +ItemSwitch_ConvertItemFormatToDW: + push hl + ld a, [wMenuData_ScrollingMenuItemFormat] + ld c, a + ld b, 0 + ld hl, .format_dws + add hl, bc + add hl, bc + ld c, [hl] + inc hl + ld b, [hl] + pop hl + ret + +.format_dws + dw 0 + dw 1 + dw 2 + +Function249bf: + push af + call ItemSwitch_ConvertItemFormatToDW + ld a, c + cp 2 + jr nz, .not_2 + pop af + call ItemSwitch_GetNthItem + inc hl + ld a, [hl] + ret + +.not_2 + pop af + ld a, $1 + ret + +Function249d3: +.loop + ld a, [hld] + ld [de], a + dec de + dec bc + ld a, b + or c + jr nz, .loop + ret diff --git a/engine/items/tmhm.asm b/engine/items/tmhm.asm new file mode 100644 index 00000000..f5261123 --- /dev/null +++ b/engine/items/tmhm.asm @@ -0,0 +1,552 @@ +TMHMPocket: + ld a, $1 + ldh [hInMenu], a + call TMHM_PocketLoop + ld a, $0 + ldh [hInMenu], a + ret nc + call PlaceHollowCursor + call WaitBGMap + ld a, [wCurItem] + dec a + ld [wCurItemQuantity], a + ld hl, wTMsHMs + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wItemQuantityBuffer], a + call .ConvertItemToTMHMNumber + scf + ret + +.ConvertItemToTMHMNumber: + ld a, [wCurItem] + ld c, a + callfar GetNumberedTMHM + ld a, c + ld [wCurItem], a + ret + +ConvertCurItemIntoCurTMHM: + ld a, [wCurItem] + ld c, a + callfar GetTMHMNumber + ld a, c + ld [wTempTMHM], a + ret + +GetTMHMItemMove: + call ConvertCurItemIntoCurTMHM + predef GetTMHMMove + ret + +AskTeachTMHM: + ld hl, wOptions + ld a, [hl] + push af + res NO_TEXT_SCROLL, [hl] + ld a, [wCurItem] + cp TM01 + jr c, .NotTMHM + call GetTMHMItemMove + ld a, [wTempTMHM] + ld [wPutativeTMHMMove], a + call GetMoveName + call CopyName1 + ld hl, BootedTMText ; Booted up a TM + ld a, [wCurItem] + cp HM01 + jr c, .TM + ld hl, BootedHMText ; Booted up an HM +.TM: + call PrintText + ld hl, ContainedMoveText + call PrintText + call YesNoBox +.NotTMHM: + pop bc + ld a, b + ld [wOptions], a + ret + +ChooseMonToLearnTMHM: + ld hl, wStringBuffer2 + ld de, wTMHMMoveNameBackup + ld bc, 12 + call CopyBytes + call ClearBGPalettes +ChooseMonToLearnTMHM_NoRefresh: + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + ld a, PARTYMENUACTION_TEACH_TMHM + ld [wPartyMenuActionText], a +.loopback + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + farcall PartyMenuSelect + push af + ld a, [wCurPartySpecies] + cp EGG + pop bc ; now contains the former contents of af + jr z, .egg + push bc + ld hl, wTMHMMoveNameBackup + ld de, wStringBuffer2 + ld bc, 12 + call CopyBytes + pop af ; now contains the original contents of af + ret + +.egg + push hl + push de + push bc + push af + ld de, SFX_WRONG + call PlaySFX + call WaitSFX + pop af + pop bc + pop de + pop hl + jr .loopback + +TeachTMHM: + predef CanLearnTMHMMove + + push bc + ld a, [wCurPartyMon] + ld hl, wPartyMonNicknames + call GetNick + pop bc + + ld a, c + and a + jr nz, .compatible + push de + ld de, SFX_WRONG + call PlaySFX + pop de + ld hl, TMHMNotCompatibleText + call PrintText + jr .nope + +.compatible + callfar KnowsMove + jr c, .nope + + predef LearnMove + ld a, b + and a + jr z, .nope + + ld a, [wCurItem] + call IsHM + ret c + + ld c, HAPPINESS_LEARNMOVE + callfar ChangeHappiness + call ConsumeTM + jr .learned_move + +.nope + and a + ret + +.unused + ld a, 2 + ld [wItemEffectSucceeded], a +.learned_move + scf + ret + +BootedTMText: + text_far _BootedTMText + text_end + +BootedHMText: + text_far _BootedHMText + text_end + +ContainedMoveText: + text_far _ContainedMoveText + text_end + +TMHMNotCompatibleText: + text_far _TMHMNotCompatibleText + text_end + +TMHM_PocketLoop: + xor a + ldh [hBGMapMode], a + call TMHM_DisplayPocketItems + ld a, 2 + ld [w2DMenuCursorInitY], a + ld a, 7 + ld [w2DMenuCursorInitX], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, 5 + sub d + inc a + cp 6 + jr nz, .okay + dec a +.okay + ld [w2DMenuNumRows], a + ld a, $c + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + ld a, $20 + ld [w2DMenuCursorOffsets], a + ld a, A_BUTTON | B_BUTTON | D_UP | D_DOWN | D_LEFT | D_RIGHT + ld [wMenuJoypadFilter], a + ld a, [wTMHMPocketCursor] + inc a + ld [wMenuCursorY], a + ld a, $1 + ld [wMenuCursorX], a + jr TMHM_ShowTMMoveDescription + +TMHM_JoypadLoop: + call TMHM_DisplayPocketItems + call StaticMenuJoypad + ld b, a + ld a, [wMenuCursorY] + dec a + ld [wTMHMPocketCursor], a + xor a + ldh [hBGMapMode], a + ld a, [w2DMenuFlags2] + bit 7, a + jp nz, TMHM_ScrollPocket + ld a, b + ld [wMenuJoypad], a + bit A_BUTTON_F, a + jp nz, TMHM_ChooseTMorHM + bit B_BUTTON_F, a + jp nz, TMHM_ExitPack + bit D_RIGHT_F, a + jp nz, TMHM_ExitPocket + bit D_LEFT_F, a + jp nz, TMHM_ExitPocket +TMHM_ShowTMMoveDescription: + call TMHM_CheckHoveringOverCancel + jp nc, TMHM_ExitPocket + hlcoord 0, 12 + ld b, 4 + ld c, SCREEN_WIDTH - 2 + call Textbox + ld a, [wCurItem] + cp NUM_TMS + NUM_HMS + 1 + jr nc, TMHM_JoypadLoop + ld [wTempTMHM], a + predef GetTMHMMove + ld a, [wTempTMHM] + ld [wCurSpecies], a + hlcoord 1, 14 + call PrintMoveDesc + jp TMHM_JoypadLoop + +TMHM_ChooseTMorHM: + call TMHM_PlaySFX_ReadText2 + call CountTMsHMs ; This stores the count to wTempTMHM. + ld a, [wMenuCursorY] + dec a + ld b, a + ld a, [wTMHMPocketScrollPosition] + add b + ld b, a + ld a, [wTempTMHM] + cp b + jr z, _TMHM_ExitPack ; our cursor was hovering over CANCEL +TMHM_CheckHoveringOverCancel: + call TMHM_GetCurrentPocketPosition + ld a, [wMenuCursorY] + ld b, a +.loop + inc c + ld a, c + cp NUM_TMS + NUM_HMS + 1 + jr nc, .okay + ld a, [hli] + and a + jr z, .loop + dec b + jr nz, .loop + ld a, c +.okay + ld [wCurItem], a + cp -1 + ret + +TMHM_ExitPack: + call TMHM_PlaySFX_ReadText2 +_TMHM_ExitPack: + ld a, $2 + ld [wMenuJoypad], a + and a + ret + +TMHM_ExitPocket: + and a + ret + +TMHM_ScrollPocket: + ld a, b + bit 7, a + jr nz, .skip + ld hl, wTMHMPocketScrollPosition + ld a, [hl] + and a + jp z, TMHM_JoypadLoop + dec [hl] + call TMHM_DisplayPocketItems + jp TMHM_ShowTMMoveDescription + +.skip + call TMHM_GetCurrentPocketPosition + ld b, 5 +.loop + inc c + ld a, c + cp NUM_TMS + NUM_HMS + 1 + jp nc, TMHM_JoypadLoop + ld a, [hli] + and a + jr z, .loop + dec b + jr nz, .loop + ld hl, wTMHMPocketScrollPosition + inc [hl] + call TMHM_DisplayPocketItems + jp TMHM_ShowTMMoveDescription + +TMHM_DisplayPocketItems: + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jp z, Tutorial_TMHMPocket + + hlcoord 5, 2 + lb bc, 10, 15 + ld a, " " + call ClearBox + call TMHM_GetCurrentPocketPosition + ld d, $5 +.loop2 + inc c + ld a, c + cp NUM_TMS + NUM_HMS + 1 + jr nc, .NotTMHM + ld a, [hli] + and a + jr z, .loop2 + ld b, a + ld a, c + ld [wTempTMHM], a + push hl + push de + push bc + call TMHMPocket_GetCurrentLineCoord + push hl + ld a, [wTempTMHM] + cp NUM_TMS + 1 + jr nc, .HM + ld de, wTempTMHM + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + jr .okay + +.HM: + push af + sub NUM_TMS + ld [wTempTMHM], a + ld [hl], "H" + inc hl + ld de, wTempTMHM + lb bc, PRINTNUM_LEFTALIGN | 1, 2 + call PrintNum + pop af + ld [wTempTMHM], a +.okay + predef GetTMHMMove + ld a, [wNamedObjectIndexBuffer] + ld [wPutativeTMHMMove], a + call GetMoveName + pop hl + ld bc, 3 + add hl, bc + push hl + call PlaceString + pop hl + pop bc + ld a, c + push bc + cp NUM_TMS + 1 + jr nc, .hm2 + ld bc, SCREEN_WIDTH + 9 + add hl, bc + ld [hl], "×" + inc hl + ld a, "0" ; why are we doing this? + pop bc + push bc + ld a, b + ld [wTempTMHM], a + ld de, wTempTMHM + lb bc, 1, 2 + call PrintNum +.hm2 + pop bc + pop de + pop hl + dec d + jr nz, .loop2 + jr .done + +.NotTMHM: + call TMHMPocket_GetCurrentLineCoord + inc hl + inc hl + inc hl + push de + ld de, TMHM_String_Cancel + call PlaceString + pop de +.done + ret + +TMHMPocket_GetCurrentLineCoord: + hlcoord 5, 0 + ld bc, 2 * SCREEN_WIDTH + ld a, 6 + sub d + ld e, a + ; AddNTimes +.loop + add hl, bc + dec e + jr nz, .loop + ret + +Unreferenced_Function2c89a: + pop hl + ld bc, 3 + add hl, bc + predef GetTMHMMove + ld a, [wTempTMHM] + ld [wPutativeTMHMMove], a + call GetMoveName + push hl + call PlaceString + pop hl + ret + +TMHM_String_Cancel: + db "CANCEL@" + +TMHM_GetCurrentPocketPosition: + ld hl, wTMsHMs + ld a, [wTMHMPocketScrollPosition] + ld b, a + inc b + ld c, 0 +.loop + inc c + ld a, [hli] + and a + jr z, .loop + dec b + jr nz, .loop + dec hl + dec c + ret + +Tutorial_TMHMPocket: + hlcoord 9, 3 + push de + ld de, TMHM_String_Cancel + call PlaceString + pop de + ret + +TMHM_PlaySFX_ReadText2: + push de + ld de, SFX_READ_TEXT_2 + call PlaySFX + pop de + ret + +Unreferenced_Function2c8e4: + call ConvertCurItemIntoCurTMHM + call .CheckHaveRoomForTMHM + ld hl, .NoRoomTMHMText + jr nc, .print + ld hl, .ReceivedTMHMText +.print + jp PrintText + +.NoRoomTMHMText: + text_far _NoRoomTMHMText + text_end + +.ReceivedTMHMText: + text_far _ReceivedTMHMText + text_end + +.CheckHaveRoomForTMHM: + ld a, [wTempTMHM] + dec a + ld hl, wTMsHMs + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + inc a + cp NUM_TMS * 2 + ret nc + ld [hl], a + ret + +ConsumeTM: + call ConvertCurItemIntoCurTMHM + ld a, [wTempTMHM] + dec a + ld hl, wTMsHMs + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + and a + ret z + dec a + ld [hl], a + ret nz + ld a, [wTMHMPocketScrollPosition] + and a + ret z + dec a + ld [wTMHMPocketScrollPosition], a + ret + +CountTMsHMs: + ld b, 0 + ld c, NUM_TMS + NUM_HMS + ld hl, wTMsHMs +.loop + ld a, [hli] + and a + jr z, .skip + inc b +.skip + dec c + jr nz, .loop + ld a, b + ld [wTempTMHM], a + ret diff --git a/engine/items/tmhm2.asm b/engine/items/tmhm2.asm new file mode 100755 index 00000000..eb3eb58e --- /dev/null +++ b/engine/items/tmhm2.asm @@ -0,0 +1,46 @@ +CanLearnTMHMMove: + ld a, [wCurPartySpecies] + ld [wCurSpecies], a + call GetBaseData + ld hl, wBaseTMHM + push hl + + ld a, [wPutativeTMHMMove] + ld b, a + ld c, 0 + ld hl, TMHMMoves +.loop + ld a, [hli] + and a + jr z, .end + cp b + jr z, .asm_11a45 + inc c + jr .loop + +.asm_11a45 + pop hl + ld b, CHECK_FLAG + push de + ld d, 0 + predef SmallFarFlagAction + pop de + ret + +.end + pop hl + ld c, 0 + ret + +GetTMHMMove: + ld a, [wTempTMHM] + dec a + ld hl, TMHMMoves + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wTempTMHM], a + ret + +INCLUDE "data/moves/tmhm_moves.asm" diff --git a/engine/items/update_item_description.asm b/engine/items/update_item_description.asm new file mode 100644 index 00000000..da56732a --- /dev/null +++ b/engine/items/update_item_description.asm @@ -0,0 +1,13 @@ +UpdateItemDescription: + ld a, [wMenuSelection] + ld [wCurSpecies], a + hlcoord 0, 12 + ld b, 4 + ld c, SCREEN_WIDTH - 2 + call Textbox + ld a, [wMenuSelection] + cp -1 + ret z + decoord 1, 14 + farcall PrintItemDescription + ret diff --git a/engine/learn.asm b/engine/learn.asm deleted file mode 100644 index f61b0c6c..00000000 --- a/engine/learn.asm +++ /dev/null @@ -1,220 +0,0 @@ -LearnMove: - call LoadTilemapToTempTilemap - ld a, [wCurPartyMon] - ld hl, wPartyMon1Nickname - call GetNick - ld hl, wStringBuffer1 - ld de, wMonOrItemNameBuffer - ld bc, $b - call CopyBytes -.loop - ld hl, wPartyMon1Moves - ld bc, $30 - ld a, [wCurPartyMon] - call AddNTimes - ld d, h - ld e, l - ld b, $4 -.asm_660f - ld a, [hl] - and a - jr z, .asm_6643 - inc hl - dec b - jr nz, .asm_660f - push de - call .AlreadyHaveFourMoves - pop de - jp c, .ConfirmStopLearning - push hl - push de - ld [wd151], a - ld b, a - ld a, [wBattleMode] - and a - jr z, .asm_6638 - ld a, [wcbd3] - cp b - jr nz, .asm_6638 - xor a - ld [wcbd3], a - ld [wcb53], a -.asm_6638 - call GetMoveName - ld hl, Text_1_2_and_Poof - call PrintText - pop de - pop hl -.asm_6643 - ld a, [wd14d] - ld [hl], a - ld bc, $15 - add hl, bc - push hl - push de - dec a - ld hl, Moves + MOVE_PP ; $5b03 - ld bc, $7 - call AddNTimes - ld a, BANK(Moves) - call GetFarByte - pop de - pop hl - ld [hl], a - ld a, [wBattleMode] - and a - jp z, .LearnedMove - ld a, [wCurPartyMon] - ld b, a - ld a, [wCurBattleMon] - cp b - jp nz, .LearnedMove - ld a, [wPlayerSubStatus5] - bit 3, a - jp nz, .LearnedMove - ld h, d - ld l, e - ld de, wBattleMonMoves - ld bc, $4 - call CopyBytes - ld bc, $11 - add hl, bc - ld de, wBattleMonPP - ld bc, $4 - call CopyBytes - jp .LearnedMove - -.ConfirmStopLearning: ; 6694 (1:6694) - ld hl, Text_StopLearning - call PrintText - call YesNoBox - jp c, .loop - ld hl, Text_DidNotLearn - call PrintText - ld b, $0 - ret - -.LearnedMove: ; 66a9 (1:66a9) - ld hl, Text_LearnedMove - call PrintText - ld b, $1 - ret - -.AlreadyHaveFourMoves: ; 66b2 (1:66b2) - push hl - ld hl, Text_TryingToLearn - call PrintText - call YesNoBox - pop hl - ret c - ld bc, -4 - add hl, bc - push hl - ld de, wd149 - ld bc, $4 - call CopyBytes - pop hl -.asm_66cd - push hl - ld hl, Text_ForgetWhich - call PrintText - hlcoord 5, 2 - ld b, $8 - ld c, $d - call Textbox - hlcoord 7, 4 - ld a, $28 - ld [wBuffer1], a - predef ListMoves - ld a, $4 - ld [wMenuDataEnd], a - ld a, $6 - ld [wced9], a - ld a, [wcfe3] - inc a - ld [wceda], a - ld a, $1 - ld [wcedb], a - ld [wMenuCursorY], a - ld [wcee1], a - ld a, $3 - ld [wMenuJoypadFilter], a - ld a, $20 - ld [w2DMenuFlags1], a - xor a - ld [wcedd], a - ld a, $20 - ld [wcede], a - call StaticMenuJoypad - push af - call SafeLoadTempTilemapToTilemap - pop af - pop hl - bit 1, a - jr nz, .asm_6748 - push hl - ld a, [wMenuCursorY] - dec a - ld c, a - ld b, $0 - add hl, bc - ld a, [hl] - push af - push bc - call IsHMMove - pop bc - pop de - ld a, d - jr c, .asm_673f - pop hl - add hl, bc - and a - ret - -.asm_673f - ld hl, Text_CantForgetHM - call PrintText - pop hl - jr .asm_66cd - -.asm_6748 - scf - ret - -Text_LearnedMove: - text_far Text_LearnedMove_ - db "@" - -Text_ForgetWhich: - text_far Text_ForgetWhich_ - db "@" - -Text_StopLearning: - text_far Text_StopLearning_ - db "@" - -Text_DidNotLearn: - text_far Text_DidNotLearn_ - db "@" - -Text_TryingToLearn: - text_far Text_TryingToLearn_ - db "@" - -Text_1_2_and_Poof: - text_far Text_1_2_and_Poof_ - text_asm - push de - ld de, SFX_SWITCH_POKEMON - call PlaySFX - pop de - ld hl, .PoofForgot - ret - -.PoofForgot: - text_far Text_PoofForgot_ - db "@" - -Text_CantForgetHM: - text_far Text_CantForgetHM_ - db "@" diff --git a/engine/learn_tm.asm b/engine/learn_tm.asm deleted file mode 100755 index 530ecf41..00000000 --- a/engine/learn_tm.asm +++ /dev/null @@ -1,107 +0,0 @@ -CanLearnTMHMMove: ; 11a25 (4:5a25) - ld a, [wCurPartySpecies] - ld [wCurSpecies], a - call GetBaseData - ld hl, wd138 - push hl - ld a, [wd14d] - ld b, a - ld c, $0 - ld hl, TMMovesList -.asm_11a3b - ld a, [hli] - and a - jr z, .asm_11a52 - cp b - jr z, .asm_11a45 - inc c - jr .asm_11a3b - -.asm_11a45 - pop hl - ld b, CHECK_FLAG - push de - ld d, $0 - predef SmallFarFlagAction - pop de - ret - -.asm_11a52 - pop hl - ld c, $0 - ret - -GetTMHMMove: ; 11a56 (4:5a56) - ld a, [wd151] - dec a - ld hl, TMMovesList - ld b, $0 - ld c, a - add hl, bc - ld a, [hl] - ld [wd151], a - ret - -TMMovesList: - db DYNAMICPUNCH - db HEADBUTT - db CURSE - db ROLLOUT - db ROAR - db TOXIC - db ZAP_CANNON - db ROCK_SMASH - db PSYCH_UP - db HIDDEN_POWER - db SUNNY_DAY - db SWEET_SCENT - db SNORE - db BLIZZARD - db HYPER_BEAM - db ICY_WIND - db PROTECT - db RAIN_DANCE - db GIGA_DRAIN - db ENDURE - db FRUSTRATION - db SOLARBEAM - db IRON_TAIL - db DRAGONBREATH - db THUNDER - db EARTHQUAKE - db RETURN - db DIG - db PSYCHIC_M - db SHADOW_BALL - db MUD_SLAP - db DOUBLE_TEAM - db ICE_PUNCH - db SWAGGER - db SLEEP_TALK - db SLUDGE_BOMB - db SANDSTORM - db FIRE_BLAST - db SWIFT - db DEFENSE_CURL - db THUNDERPUNCH - db DREAM_EATER - db DETECT - db REST - db ATTRACT - db THIEF - db STEEL_WING - db FIRE_PUNCH - db FURY_CUTTER - db NIGHTMARE - db CUT - db FLY - db SURF - db STRENGTH - db FLASH - db WHIRLPOOL - db WATERFALL - - db 0 - db 0 - db 0 - db 0 diff --git a/engine/link/link.asm b/engine/link/link.asm new file mode 100644 index 00000000..5f88a087 --- /dev/null +++ b/engine/link/link.asm @@ -0,0 +1,2345 @@ +LinkCommunications: + ld c, 80 + call DelayFrames + call ClearTilemap + call ClearSprites + call UpdateSprites + call WaitBGMap + call SetTradeRoomBGPals + xor a + ldh [hSCX], a + ldh [hSCY], a + ld c, 80 + call DelayFrames + call ClearTilemap + call UpdateSprites + call LoadStandardFont + call LoadFontsBattleExtra + call LoadTradeScreenBorder + call SetTradeRoomBGPals + call WaitBGMap + hlcoord 3, 8 + ld b, 2 + ld c, 12 + call LinkTextboxAtHL + hlcoord 4, 10 + ld de, String_PleaseWait + call PlaceString + ld hl, wce5d + xor a ; LOW($5000) + ld [hli], a + ld [hl], HIGH($5000) + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + jp nz, Gen2ToGen2LinkComms + +Gen2ToGen1LinkComms: + call ClearLinkData + call Link_PrepPartyData_Gen1 + call FixDataForLinkTransfer + xor a + ld [wPlayerLinkAction], a + call WaitLinkTransfer + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr nz, .player_1 + + ld c, 3 + call DelayFrames + xor a + ldh [hSerialSend], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + + call DelayFrame + xor a + ldh [hSerialSend], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + +.player_1 + ld de, MUSIC_NONE + call PlayMusic + ld c, 3 + call DelayFrames + xor a + ldh [rIF], a + ld a, 1 << SERIAL + ldh [rIE], a + ld hl, wd0dc + ld de, wEnemyMonSpecies + ld bc, $11 + call Serial_ExchangeBytes + ld a, SERIAL_NO_DATA_BYTE + ld [de], a + ld hl, wLinkData + ld de, wOTPlayerName + ld bc, $1a8 + call Serial_ExchangeBytes + ld a, SERIAL_NO_DATA_BYTE + ld [de], a + ld hl, wc508 + ld de, wTrademons + ld bc, wTrademons - wc508 + call Serial_ExchangeBytes + xor a + ldh [rIF], a + ld a, (1 << JOYPAD) | (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK) + ldh [rIE], a + call Link_CopyRandomNumbers + ld hl, wOTPlayerName + call Link_FindFirstNonControlCharacter_SkipZero + push hl + ld bc, NAME_LENGTH + add hl, bc + ld a, [hl] + pop hl + and a + jp z, Function28a04 + cp $7 + jp nc, Function28a04 + ld de, wLinkData + ld bc, $1a2 + call Link_CopyOTData + ld de, wPlayerTrademonSpecies + ld hl, wTimeCapsulePartyMon1Species + ld c, 2 +.loop + ld a, [de] + inc de + and a + jr z, .loop + cp SERIAL_PREAMBLE_BYTE + jr z, .loop + cp SERIAL_NO_DATA_BYTE + jr z, .loop + cp SERIAL_PATCH_LIST_PART_TERMINATOR + jr z, .next + push hl + push bc + ld b, 0 + dec a + ld c, a + add hl, bc + ld a, SERIAL_NO_DATA_BYTE + ld [hl], a + pop bc + pop hl + jr .loop + +.next + ld hl, wc80f + dec c + jr nz, .loop + ld hl, wLinkPlayerName + ld de, wOTPlayerName + ld bc, NAME_LENGTH + call CopyBytes + ld de, wOTPartyCount + ld a, [hli] + ld [de], a + inc de +.party_loop + ld a, [hli] + cp -1 + jr z, .done_party + ld [wTempSpecies], a + push hl + push de + callfar ConvertMon_1to2 + pop de + pop hl + ld a, [wTempSpecies] + ld [de], a + inc de + jr .party_loop + +.done_party + ld [de], a + ld hl, wTimeCapsulePartyMon1Species + call Function285db + ld a, LOW(wOTPartyMonOT) + ld [wUnusedCFFE], a + ld a, HIGH(wOTPartyMonOT) + ld [wUnusedCFFE + 1], a + ld de, MUSIC_NONE + call PlayMusic + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + ld c, 66 + call z, DelayFrames + ld de, MUSIC_ROUTE_30 + call PlayMusic + jp InitTradeMenuDisplay + +Gen2ToGen2LinkComms: + call ClearLinkData + call Link_PrepPartyData_Gen2 + call FixDataForLinkTransfer + call Function29bf4 + ld a, [wScriptVar] + and a + jp z, LinkTimeout + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr nz, .Player1 + + ld c, 3 + call DelayFrames + xor a + ldh [hSerialSend], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + + call DelayFrame + xor a + ldh [hSerialSend], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + +.Player1: + ld de, MUSIC_NONE + call PlayMusic + ld c, 3 + call DelayFrames + xor a + ldh [rIF], a + ld a, 1 << SERIAL + ldh [rIE], a + ld hl, wd0dc + ld de, wEnemyMonSpecies + ld bc, $11 + call Serial_ExchangeBytes + ld a, SERIAL_NO_DATA_BYTE + ld [de], a + ld hl, wLinkData + ld de, wOTPlayerName + ld bc, $1c2 + call Serial_ExchangeBytes + ld a, SERIAL_NO_DATA_BYTE + ld [de], a + ld hl, wc508 + ld de, wTrademons + ld bc, wTrademons - wc508 + call Serial_ExchangeBytes + ld a, [wLinkMode] + cp LINK_TRADECENTER + jr nz, .not_trading + ld hl, wc8f4 + ld de, wca84 + ld bc, $186 + call ExchangeBytes + +.not_trading + xor a + ldh [rIF], a + ld a, (1 << JOYPAD) | (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK) + ldh [rIE], a + ld de, MUSIC_NONE + call PlayMusic + call Link_CopyRandomNumbers + ld hl, wOTPlayerName + call Link_FindFirstNonControlCharacter_SkipZero + ld de, wLinkData + ld bc, $1b9 + call Link_CopyOTData + ld de, wPlayerTrademonSpecies + ld hl, wLinkPlayerPartyMon1Species + ld c, 2 +.loop1 + ld a, [de] + inc de + and a + jr z, .loop1 + cp SERIAL_PREAMBLE_BYTE + jr z, .loop1 + cp SERIAL_NO_DATA_BYTE + jr z, .loop1 + cp SERIAL_PATCH_LIST_PART_TERMINATOR + jr z, .next1 + push hl + push bc + ld b, 0 + dec a + ld c, a + add hl, bc + ld a, SERIAL_NO_DATA_BYTE + ld [hl], a + pop bc + pop hl + jr .loop1 + +.next1 + ld hl, wc80f + dec c + jr nz, .loop1 + ld a, [wLinkMode] + cp LINK_TRADECENTER + jr nz, .skip_mail + ld hl, wca84 +.loop2 + ld a, [hli] + cp MAIL_MSG_LENGTH + jr nz, .loop2 +.loop3 + ld a, [hli] + cp SERIAL_NO_DATA_BYTE + jr z, .loop3 + cp MAIL_MSG_LENGTH + jr z, .loop3 + dec hl + ld de, wca84 + ld bc, $190 ; 400 + call CopyBytes + ld hl, wca84 + ld bc, $c6 ; 198 +.loop4 + ld a, [hl] + cp MAIL_MSG_LENGTH + 1 + jr nz, .okay1 + ld [hl], SERIAL_NO_DATA_BYTE +.okay1 + inc hl + dec bc + ld a, b + or c + jr nz, .loop4 + ld de, wcb9e +.loop5 + ld a, [de] + inc de + cp SERIAL_PATCH_LIST_PART_TERMINATOR + jr z, .start_copying_mail + ld hl, wcb4a + dec a + ld b, $0 + ld c, a + add hl, bc + ld [hl], SERIAL_NO_DATA_BYTE + jr .loop5 + +.start_copying_mail + ld hl, wca84 + ld de, wc8f4 + ld b, PARTY_LENGTH +.copy_mail_loop + push bc + ld bc, MAIL_MSG_LENGTH + 1 + call CopyBytes + ld a, LOW(MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1)) + add e + ld e, a + ld a, HIGH(MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1)) + adc d + ld d, a + pop bc + dec b + jr nz, .copy_mail_loop + ld de, wc8f4 + ld b, PARTY_LENGTH +.fix_mail_loop + push bc + ld a, LOW(MAIL_MSG_LENGTH + 1) + add e + ld e, a + ld a, HIGH(MAIL_MSG_LENGTH + 1) + adc d + ld d, a + ld bc, MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1) + call CopyBytes + pop bc + dec b + jr nz, .fix_mail_loop + ld de, wca0e + xor a + ld [de], a + +.skip_mail + ld hl, wLinkPlayerName + ld de, wOTPlayerName + ld bc, NAME_LENGTH + call CopyBytes + ld de, wOTPartyCount + ld bc, 1 + PARTY_LENGTH + 1 + call CopyBytes + ld de, wOTPlayerID + ld bc, 2 + call CopyBytes + ld de, wOTPartyMons + ld bc, wOTPartyDataEnd - wOTPartyMons + call CopyBytes + ld a, LOW(wOTPartyMonOT) + ld [wUnusedCFFE], a + ld a, HIGH(wOTPartyMonOT) + ld [wUnusedCFFE + 1], a + ld de, MUSIC_NONE + call PlayMusic + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + ld c, 66 + call z, DelayFrames + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr nz, .ready_to_trade + ld a, CAL + ld [wOtherTrainerClass], a + call ClearTilemap + call WaitBGMap + ld hl, wOptions + ld a, [hl] + push af + and 1 << STEREO + or TEXT_DELAY_MED + ld [hl], a + ld hl, wOTPlayerName + ld de, wOTClassName + ld bc, NAME_LENGTH + call CopyBytes + call ReturnToMapFromSubmenu + + ; LET'S DO THIS + ld a, [wDisableTextAcceleration] + push af + ld a, 1 + ld [wDisableTextAcceleration], a + + predef StartBattle + + pop af + ld [wDisableTextAcceleration], a + pop af + ld [wOptions], a + farcall LoadPokemonData + jp Function28a04 + +.ready_to_trade + ld de, MUSIC_ROUTE_30 + call PlayMusic + jp InitTradeMenuDisplay + +LinkTimeout: + ld de, .LinkTimeoutText + ld b, 10 +.loop + call DelayFrame + call LinkDataReceived + dec b + jr nz, .loop + xor a + ld [hld], a + ld [hl], a + ldh [hVBlank], a + push de + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + pop hl + bccoord 1, 14 + jp PlaceHLTextAtBC + +.LinkTimeoutText: + text_far _LinkTimeoutText + text_end + +ExchangeBytes: + ld a, TRUE + ldh [hSerialIgnoringInitialData], a +.loop + ld a, [hl] + ldh [hSerialSend], a + call Serial_ExchangeByte + push bc + ld b, a + inc hl + ld a, 48 +.delay_cycles + dec a + jr nz, .delay_cycles + ldh a, [hSerialIgnoringInitialData] + and a + ld a, b + pop bc + jr z, .load + dec hl + xor a + ldh [hSerialIgnoringInitialData], a + jr .loop + +.load + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .loop + ret + +String_PleaseWait: + db "PLEASE WAIT!@" + +ClearLinkData: + ld hl, wLinkData + ld bc, wLinkDataEnd - wLinkData +.loop + xor a + ld [hli], a + dec bc + ld a, b + or c + jr nz, .loop + ret + +FixDataForLinkTransfer: + ld hl, wd0dc + ld a, SERIAL_PREAMBLE_BYTE + ld b, wLinkBattleRNs - wd0dc +.loop1 + ld [hli], a + dec b + jr nz, .loop1 + ld b, wTempEnemyMonSpecies - wLinkBattleRNs +.loop2 + call Random + cp SERIAL_PREAMBLE_BYTE + jr nc, .loop2 + ld [hli], a + dec b + jr nz, .loop2 + ld hl, wc508 + ld a, SERIAL_PREAMBLE_BYTE + ld [hli], a + ld [hli], a + ld [hli], a + ld b, $c8 + xor a +.loop3 + ld [hli], a + dec b + jr nz, .loop3 + ld hl, wTimeCapsulePartyMon1 - 1 + PARTY_LENGTH + ld de, wc512 + lb bc, 0, 0 +.loop4 + inc c + ld a, c + cp SERIAL_PREAMBLE_BYTE + jr z, .next1 + ld a, b + dec a + jr nz, .next2 + push bc + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + ld b, $d + jr z, .got_value + ld b, $27 +.got_value + ld a, c + cp b + pop bc + jr z, .done +.next2 + inc hl + ld a, [hl] + cp SERIAL_NO_DATA_BYTE + jr nz, .loop4 + ld a, c + ld [de], a + inc de + ld [hl], SERIAL_PATCH_LIST_PART_TERMINATOR + jr .loop4 + +.next1 + ld a, SERIAL_PATCH_LIST_PART_TERMINATOR + ld [de], a + inc de + lb bc, 1, 0 + jr .loop4 + +.done + ld a, SERIAL_PATCH_LIST_PART_TERMINATOR + ld [de], a + ret + +Link_PrepPartyData_Gen1: + ld de, wLinkData + ld a, SERIAL_PREAMBLE_BYTE + ld b, PARTY_LENGTH +.loop1 + ld [de], a + inc de + dec b + jr nz, .loop1 + ld hl, wPlayerName + ld bc, NAME_LENGTH + call CopyBytes + push de + ld hl, wPartyCount + ld a, [hli] + ld [de], a + inc de +.loop2 + ld a, [hli] + cp -1 + jr z, .done_party + ld [wTempSpecies], a + push hl + push de + callfar ConvertMon_2to1 + pop de + pop hl + ld a, [wTempSpecies] + ld [de], a + inc de + jr .loop2 + +.done_party + ld [de], a + pop de + ld hl, 1 + PARTY_LENGTH + 1 + add hl, de + ld d, h + ld e, l + ld hl, wPartyMon1Species + ld c, PARTY_LENGTH +.mon_loop + push bc + call .ConvertPartyStruct2to1 + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + dec c + jr nz, .mon_loop + ld hl, wPartyMonOT + call .copy_ot_nicks + ld hl, wPartyMonNicknames +.copy_ot_nicks + ld bc, PARTY_LENGTH * NAME_LENGTH + jp CopyBytes + +.ConvertPartyStruct2to1: + ld b, h + ld c, l + push de + push bc + ld a, [hl] + ld [wTempSpecies], a + callfar ConvertMon_2to1 + pop bc + pop de + ld a, [wTempSpecies] + ld [de], a + inc de + ld hl, MON_HP + add hl, bc + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + xor a + ld [de], a + inc de + ld hl, MON_STATUS + add hl, bc + ld a, [hl] + ld [de], a + inc de + ld a, [bc] + cp MAGNEMITE + jr z, .steel_type + cp MAGNETON + jr nz, .skip_steel + +.steel_type + ld a, ELECTRIC + ld [de], a + inc de + ld [de], a + inc de + jr .done_steel + +.skip_steel + push bc + dec a + ld hl, BaseData + BASE_TYPES + ld bc, BASE_DATA_SIZE + call AddNTimes + ld bc, BASE_CATCH_RATE - BASE_TYPES + ld a, BANK(BaseData) + call FarCopyBytes + pop bc + +.done_steel + push bc + ld hl, MON_ITEM + add hl, bc + ld bc, MON_HAPPINESS - MON_ITEM + call CopyBytes + pop bc + + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [de], a + ld [wCurPartyLevel], a + inc de + + push bc + ld hl, MON_MAXHP + add hl, bc + ld bc, MON_SAT - MON_MAXHP + call CopyBytes + pop bc + + push de + push bc + + ld a, [bc] + dec a + push bc + ld b, 0 + ld c, a + ld hl, KantoMonSpecials + add hl, bc + ld a, BANK(KantoMonSpecials) + call GetFarByte + ld [wBaseSpecialAttack], a + pop bc + + ld hl, MON_STAT_EXP - 1 + add hl, bc + ld c, STAT_SATK + ld b, TRUE + predef CalcMonStatC + + pop bc + pop de + + ldh a, [hQuotient + 2] + ld [de], a + inc de + ldh a, [hQuotient + 3] + ld [de], a + inc de + ld h, b + ld l, c + ret + +Link_PrepPartyData_Gen2: + ld de, wLinkData + ld a, SERIAL_PREAMBLE_BYTE + ld b, PARTY_LENGTH +.loop1 + ld [de], a + inc de + dec b + jr nz, .loop1 + ld hl, wPlayerName + ld bc, NAME_LENGTH + call CopyBytes + ld hl, wPartyCount + ld bc, 1 + PARTY_LENGTH + 1 + call CopyBytes + ld hl, wPlayerID + ld bc, 2 + call CopyBytes + ld hl, wPartyMon1Species + ld bc, PARTY_LENGTH * PARTYMON_STRUCT_LENGTH + call CopyBytes + ld hl, wPartyMonOT + ld bc, PARTY_LENGTH * NAME_LENGTH + call CopyBytes + ld hl, wPartyMonNicknames + ld bc, PARTY_LENGTH * MON_NAME_LENGTH + call CopyBytes + +; Okay, we did all that. Now, are we in the trade center? + ld a, [wLinkMode] + cp LINK_TRADECENTER + ret nz + +; Fill 5 bytes at wc8f4 with $20 + ld de, wc8f4 + ld a, $20 + call Function285d3 + +; Copy all the mail messages to wc9f9 + ld a, BANK(sPartyMail) + call OpenSRAM + ld hl, sPartyMail + ld b, PARTY_LENGTH +.loop2 + push bc + ld bc, MAIL_MSG_LENGTH + 1 + call CopyBytes + ld bc, sPartyMon1MailEnd - sPartyMon1MailAuthor + add hl, bc + pop bc + dec b + jr nz, .loop2 +; Copy the mail data to wcabf + ld hl, sPartyMail + ld b, PARTY_LENGTH +.loop3 + push bc + ld bc, MAIL_MSG_LENGTH + 1 + add hl, bc + ld bc, sPartyMon1MailEnd - sPartyMon1MailAuthor + call CopyBytes + pop bc + dec b + jr nz, .loop3 + + call CloseSRAM + ld hl, wc8f9 + ld bc, PARTY_LENGTH * (sPartyMon1MailAuthor - sPartyMon1Mail) +.loop4 + ld a, [hl] + cp SERIAL_NO_DATA_BYTE + jr nz, .skip2 + ld [hl], sPartyMon1MailAuthor - sPartyMon1Mail + +.skip2 + inc hl + dec bc + ld a, b + or c + jr nz, .loop4 + ld hl, wc9bf + ld de, wca13 + ld b, PARTY_LENGTH * (sPartyMon1MailEnd - sPartyMon1MailAuthor) + ld c, $0 +.loop5 + inc c + ld a, [hl] + cp SERIAL_NO_DATA_BYTE + jr nz, .skip3 + ld [hl], SERIAL_PATCH_LIST_PART_TERMINATOR + ld a, c + ld [de], a + inc de + +.skip3 + inc hl + dec b + jr nz, .loop5 + ld a, SERIAL_PATCH_LIST_PART_TERMINATOR + ld [de], a + ret + +Function285d3: + ld c, 5 +.loop + ld [de], a + inc de + dec c + jr nz, .loop + ret + +Function285db: + push hl + ld d, h + ld e, l + ld bc, wLinkOTPartyMonTypes + ld hl, wcae8 + ld a, c + ld [hli], a + ld [hl], b + ld hl, wOTPartyMon1Species + ld c, PARTY_LENGTH +.loop + push bc + call .ConvertToGen2 + pop bc + dec c + jr nz, .loop + pop hl + ld bc, PARTY_LENGTH * REDMON_STRUCT_LENGTH + add hl, bc + ld de, wOTPartyMonOT + ld bc, PARTY_LENGTH * NAME_LENGTH + call CopyBytes + ld de, wOTPartyMonNicknames + ld bc, PARTY_LENGTH * MON_NAME_LENGTH + jp CopyBytes + +.ConvertToGen2: + ld b, h + ld c, l + ld a, [de] + inc de + push bc + push de + ld [wTempSpecies], a + callfar ConvertMon_1to2 + pop de + pop bc + ld a, [wTempSpecies] + ld [bc], a + ld [wCurSpecies], a + ld hl, MON_HP + add hl, bc + ld a, [de] + inc de + ld [hli], a + ld a, [de] + inc de + ld [hl], a + inc de + ld hl, MON_STATUS + add hl, bc + ld a, [de] + inc de + ld [hl], a + ld hl, wcae8 + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [de] + ld [hli], a + inc de + ld a, [de] + ld [hli], a + inc de + ld a, l + ld [wcae8], a + ld a, h + ld [wcae8 + 1], a + push bc + ld hl, MON_ITEM + add hl, bc + push hl + ld h, d + ld l, e + pop de + push bc + ld a, [hli] + ld b, a + call TimeCapsule_ReplaceTeruSama + ld a, b + ld [de], a + inc de + pop bc + ld bc, $19 + call CopyBytes + pop bc + ld d, h + ld e, l + ld hl, $1f + add hl, bc + ld a, [de] + inc de + ld [hl], a + ld [wCurPartyLevel], a + push bc + ld hl, $24 + add hl, bc + push hl + ld h, d + ld l, e + pop de + ld bc, 8 + call CopyBytes + pop bc + call GetBaseData + push de + push bc + ld d, h + ld e, l + ld hl, MON_STAT_EXP - 1 + add hl, bc + ld c, STAT_SATK + ld b, TRUE + predef CalcMonStatC + pop bc + pop hl + ldh a, [hQuotient + 2] + ld [hli], a + ldh a, [hQuotient + 3] + ld [hli], a + push hl + push bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + ld c, STAT_SDEF + ld b, TRUE + predef CalcMonStatC + pop bc + pop hl + ldh a, [hQuotient + 2] + ld [hli], a + ldh a, [hQuotient + 3] + ld [hli], a + push hl + ld hl, $1b + add hl, bc + ld a, $46 + ld [hli], a + xor a + ld [hli], a + ld [hli], a + ld [hl], a + pop hl + inc de + inc de + ret + +TimeCapsule_ReplaceTeruSama: + ld a, b + and a + ret z + push hl + ld hl, TimeCapsule_CatchRateItems +.loop + ld a, [hli] + and a + jr z, .end + cp b + jr z, .found + inc hl + jr .loop + +.found + ld b, [hl] + +.end + pop hl + ret + +INCLUDE "data/items/catch_rate_items.asm" + +Link_CopyOTData: +.loop + ld a, [hli] + cp SERIAL_NO_DATA_BYTE + jr z, .loop + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .loop + ret + +Link_CopyRandomNumbers: + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + ret z + ld hl, wEnemyMonSpecies + call Link_FindFirstNonControlCharacter_AllowZero + ld de, wLinkBattleRNs + ld c, 10 +.loop + ld a, [hli] + cp SERIAL_NO_DATA_BYTE + jr z, .loop + cp SERIAL_PREAMBLE_BYTE + jr z, .loop + ld [de], a + inc de + dec c + jr nz, .loop + ret + +Link_FindFirstNonControlCharacter_SkipZero: +.loop + ld a, [hli] + and a + jr z, .loop + cp SERIAL_PREAMBLE_BYTE + jr z, .loop + cp SERIAL_NO_DATA_BYTE + jr z, .loop + dec hl + ret + +Link_FindFirstNonControlCharacter_AllowZero: +.loop + ld a, [hli] + cp SERIAL_PREAMBLE_BYTE + jr z, .loop + cp SERIAL_NO_DATA_BYTE + jr z, .loop + dec hl + ret + +InitTradeMenuDisplay: + call ClearTilemap + call LoadTradeScreenBorder + call Function28dcf + call Function28a16 + xor a + ld hl, wOtherPlayerLinkMode + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld a, 1 + ld [wMenuCursorY], a + inc a + ld [wPlayerLinkAction], a + jp LinkTrade_PlayerPartyMenu + +LinkTrade_OTPartyMenu: + ld a, OTPARTYMON + ld [wMonType], a + ld a, A_BUTTON | D_UP | D_DOWN + ld [wMenuJoypadFilter], a + ld a, [wOTPartyCount] + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, 9 + ld [w2DMenuCursorInitY], a + ld a, 6 + ld [w2DMenuCursorInitX], a + ld a, 1 + ld [wMenuCursorX], a + ln a, 1, 0 + ld [w2DMenuCursorOffsets], a + ld a, MENU_UNUSED_3 + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + +LinkTradeOTPartymonMenuLoop: + call ScrollingMenuJoypad + and a + jp z, LinkTradePartiesMenuMasterLoop + bit A_BUTTON_F, a + jr z, .not_a_button + ld a, INIT_ENEMYOT_LIST + ld [wInitListType], a + callfar InitList + ld hl, wOTPartyMon1Species + call LinkMonStatsScreen + jp LinkTradePartiesMenuMasterLoop + +.not_a_button + bit D_UP_F, a + jr z, .not_d_up + ld a, [wMenuCursorY] + ld b, a + ld a, [wOTPartyCount] + cp b + jp nz, LinkTradePartiesMenuMasterLoop + xor a + ld [wMonType], a + call HideCursor + ld a, [wPartyCount] + ld [wMenuCursorY], a + jr LinkTrade_PlayerPartyMenu + +.not_d_up + bit D_DOWN_F, a + jp z, LinkTradePartiesMenuMasterLoop + jp Function289c2 + +LinkTrade_PlayerPartyMenu: + xor a + ld [wMonType], a + ld a, A_BUTTON | D_UP | D_DOWN + ld [wMenuJoypadFilter], a + ld a, [wPartyCount] + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, 1 + ld [w2DMenuCursorInitY], a + ld a, 6 + ld [w2DMenuCursorInitX], a + ld a, 1 + ld [wMenuCursorX], a + ln a, 1, 0 + ld [w2DMenuCursorOffsets], a + ld a, MENU_UNUSED_3 + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + +LinkTradePartymonMenuLoop: + call ScrollingMenuJoypad + and a + jr nz, .check_joypad + jp LinkTradePartiesMenuMasterLoop + +.check_joypad + bit A_BUTTON_F, a + jr z, .not_a_button + jp Function2884a + +.not_a_button + bit D_DOWN_F, a + jr z, .not_d_down + ld a, [wMenuCursorY] + dec a + jp nz, LinkTradePartiesMenuMasterLoop + ld a, OTPARTYMON + ld [wMonType], a + call HideCursor + ld a, 1 + ld [wMenuCursorY], a + jp LinkTrade_OTPartyMenu + +.not_d_down + bit D_UP_F, a + jr z, LinkTradePartiesMenuMasterLoop + ld a, [wMenuCursorY] + ld b, a + ld a, [wPartyCount] + cp b + jr nz, LinkTradePartiesMenuMasterLoop + call HideCursor + ld a, 1 + ld [wMenuCursorY], a + jp LinkTrade_PlayerPartyMenu + +LinkTradePartiesMenuMasterLoop: + ld a, [wMonType] + and a + jp z, LinkTradePartymonMenuLoop ; PARTYMON + jp LinkTradeOTPartymonMenuLoop ; OTPARTYMON + +Function2884a: + call HideCursor + call LoadTilemapToTempTilemap + call PlaceHollowCursor + ld a, [wMenuCursorY] + push af + hlcoord 0, 15 + ld b, 1 + ld c, 18 + call LinkTextboxAtHL + hlcoord 2, 16 + ld de, .String_Stats_Trade + call PlaceString + +.joy_loop + ld a, " " + ldcoord_a 11, 16 + ld a, A_BUTTON | B_BUTTON | D_RIGHT + ld [wMenuJoypadFilter], a + ld a, 1 + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, 16 + ld [w2DMenuCursorInitY], a + ld a, 1 + ld [w2DMenuCursorInitX], a + ld a, 1 + ld [wMenuCursorY], a + ld [wMenuCursorX], a + ln a, 2, 0 + ld [w2DMenuCursorOffsets], a + xor a + ld [w2DMenuFlags1], a + ld [w2DMenuFlags2], a + call ScrollingMenuJoypad + bit D_RIGHT_F, a + jr nz, .d_right + bit B_BUTTON_F, a + jr z, .show_stats +.b_button + pop af + ld [wMenuCursorY], a + call SafeLoadTempTilemapToTilemap + jp LinkTrade_PlayerPartyMenu + +.d_right + ld a, " " + ldcoord_a 1, 16 + ld a, A_BUTTON | B_BUTTON | D_LEFT + ld [wMenuJoypadFilter], a + ld a, 1 + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, 16 + ld [w2DMenuCursorInitY], a + ld a, 11 + ld [w2DMenuCursorInitX], a + ld a, 1 + ld [wMenuCursorY], a + ld [wMenuCursorX], a + ln a, 2, 0 + ld [w2DMenuCursorOffsets], a + xor a + ld [w2DMenuFlags1], a + ld [w2DMenuFlags2], a + call ScrollingMenuJoypad + bit D_LEFT_F, a + jp nz, .joy_loop + bit B_BUTTON_F, a + jr nz, .b_button + jr .try_trade + +.show_stats + pop af + ld [wMenuCursorY], a + ld a, INIT_PLAYEROT_LIST + ld [wInitListType], a + callfar InitList + call LinkMonStatsScreen + call SafeLoadTempTilemapToTilemap + jp LinkTrade_PlayerPartyMenu + +.try_trade + call PlaceHollowCursor + pop af + ld [wMenuCursorY], a + dec a + ld [wceed], a + ld [wPlayerLinkAction], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld a, [wOtherPlayerLinkMode] + cp $f + jp z, InitTradeMenuDisplay + ld [wceee], a + call Function28a3c + ld c, 100 + call DelayFrames + farcall ValidateOTTrademon + jr c, .abnormal + farcall Functionfb6ed + jp nc, LinkTrade + xor a + ld [wce57], a + ld [wOtherPlayerLinkAction], a + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + ld hl, .LinkTradeCantBattleText + bccoord 1, 14 + call PlaceHLTextAtBC + jr .cancel_trade + +.abnormal + xor a + ld [wce57], a + ld [wOtherPlayerLinkAction], a + ld a, [wceee] + ld hl, wOTPartySpecies + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + ld hl, .LinkAbnormalMonText + bccoord 1, 14 + call PlaceHLTextAtBC + +.cancel_trade + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + hlcoord 1, 14 + ld de, String_TooBadTheTradeWasCanceled + call PlaceString + ld a, $1 + ld [wPlayerLinkAction], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld c, 100 + call DelayFrames + jp InitTradeMenuDisplay + +.LinkTradeCantBattleText: + text_far _LinkTradeCantBattleText + text_end + +.String_Stats_Trade: + db "STATS TRADE@" + +.LinkAbnormalMonText: + text_far _LinkAbnormalMonText + text_end + +Function289c2: + ld a, [wMenuCursorY] + cp 1 + jp nz, LinkTradePartiesMenuMasterLoop + call HideCursor +Function289cd: +.loop1 + ld a, "▶" + ldcoord_a 1, 16 +.loop2 + call JoyTextDelay + ldh a, [hJoyLast] + and a + jr z, .loop2 + bit A_BUTTON_F, a + jr nz, .a_button + bit D_UP_F, a + jr z, .loop2 + ld a, " " + ldcoord_a 1, 16 + ld a, [wOTPartyCount] + ld [wMenuCursorY], a + jp LinkTrade_OTPartyMenu + +.a_button + ld a, "▷" + ldcoord_a 1, 16 + ld a, $f + ld [wPlayerLinkAction], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld a, [wOtherPlayerLinkMode] + cp $f + jr nz, .loop1 +Function28a04: + xor a + ld [wd8b7], a + xor a + ldh [rSB], a + ldh [hSerialSend], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ret + +Function28a16: + hlcoord 0, 16 + ld a, "┘" + ld bc, 2 * SCREEN_WIDTH + call ByteFill + hlcoord 1, 16 + ld a, " " + ld bc, SCREEN_WIDTH - 2 + call ByteFill + hlcoord 2, 16 + ld de, .Cancel + jp PlaceString + +.Cancel: + db "CANCEL@" + +Function28a3c: + ld a, [wOtherPlayerLinkMode] + hlcoord 6, 9 + ld bc, SCREEN_WIDTH + call AddNTimes + ld [hl], "▷" + ret + +LinkMonStatsScreen: + ld a, [wMenuCursorY] + dec a + ld [wCurPartyMon], a + call LowVolume + predef StatsScreenInit + ld a, [wCurPartyMon] + inc a + ld [wMenuCursorY], a + call ClearTilemap + call ClearBGPalettes + call MaxVolume + call LoadTradeScreenBorder + call SetTradeRoomBGPals + call WaitBGMap + call Function28dcf + jp Function28a16 + +LinkTrade: + xor a + ld [wce57], a + ld [wOtherPlayerLinkAction], a + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + ld a, [wceed] + ld hl, wPartySpecies + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, wStringBuffer1 + ld de, wceef + ld bc, MON_NAME_LENGTH + call CopyBytes + ld a, [wceee] + ld hl, wOTPartySpecies + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, LinkAskTradeForText + bccoord 1, 14 + call PlaceHLTextAtBC + call LoadTilemapToTempTilemap + hlcoord 10, 7 + ld b, 3 + ld c, 7 + call LinkTextboxAtHL + ld de, String28d44 + hlcoord 12, 8 + call PlaceString + ld a, 8 + ld [w2DMenuCursorInitY], a + ld a, 11 + ld [w2DMenuCursorInitX], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, 2 + ld [w2DMenuNumRows], a + xor a + ld [w2DMenuFlags1], a + ld [w2DMenuFlags2], a + ld a, $20 + ld [w2DMenuCursorOffsets], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuJoypadFilter], a + ld a, 1 + ld [wMenuCursorY], a + ld [wMenuCursorX], a + call ScrollingMenuJoypad + push af + call SafeLoadTempTilemapToTilemap + pop af + bit 1, a + jr nz, .asm_28b16 + ld a, [wMenuCursorY] + dec a + jr z, .asm_28b34 + +.asm_28b16 + ld a, $1 + ld [wPlayerLinkAction], a + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + hlcoord 1, 14 + ld de, String_TooBadTheTradeWasCanceled + call PlaceString + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + jp Function28d3c + +.asm_28b34 + ld a, $2 + ld [wPlayerLinkAction], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld a, [wOtherPlayerLinkMode] + dec a + jr nz, .asm_28b58 + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + hlcoord 1, 14 + ld de, String_TooBadTheTradeWasCanceled + call PlaceString + jp Function28d3c + +.asm_28b58 + ld hl, sPartyMail + ld a, [wceed] + ld bc, MAIL_STRUCT_LENGTH + call AddNTimes + ld a, BANK(sPartyMail) + call OpenSRAM + ld d, h + ld e, l + ld bc, MAIL_STRUCT_LENGTH + add hl, bc + ld a, [wceed] + ld c, a +.asm_28b73 + inc c + ld a, c + cp PARTY_LENGTH + jr z, .asm_28b83 + push bc + ld bc, MAIL_STRUCT_LENGTH + call CopyBytes + pop bc + jr .asm_28b73 + +.asm_28b83 + ld hl, sPartyMail + ld a, [wPartyCount] + dec a + ld bc, MAIL_STRUCT_LENGTH + call AddNTimes + push hl + ld hl, wc8f4 + ld a, [wceee] + ld bc, MAIL_STRUCT_LENGTH + call AddNTimes + pop de + ld bc, MAIL_STRUCT_LENGTH + call CopyBytes + call CloseSRAM + ld hl, wPlayerName + ld de, wPlayerTrademonSenderName + ld bc, NAME_LENGTH + call CopyBytes + ld a, [wceed] + ld hl, wPartySpecies + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wPlayerTrademonSpecies], a + push af + ld a, [wceed] + ld hl, wPartyMonOT + call SkipNames + ld de, wPlayerTrademonOTName + ld bc, NAME_LENGTH + call CopyBytes + ld hl, wPartyMon1ID + ld a, [wceed] + call GetPartyLocation + ld a, [hli] + ld [wPlayerTrademonID], a + ld a, [hl] + ld [wPlayerTrademonID + 1], a + ld hl, wPartyMon1DVs + ld a, [wceed] + call GetPartyLocation + ld a, [hli] + ld [wPlayerTrademonDVs], a + ld a, [hl] + ld [wPlayerTrademonDVs + 1], a + ld hl, wOTPlayerName + ld de, wOTTrademonSenderName + ld bc, NAME_LENGTH + call CopyBytes + ld a, [wceee] + ld hl, wOTPartySpecies + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wOTTrademonSpecies], a + ld a, [wceee] + ld hl, wOTPartyMonOT + call SkipNames + ld de, wOTTrademonOTName + ld bc, NAME_LENGTH + call CopyBytes + ld hl, wOTPartyMon1ID + ld a, [wceee] + call GetPartyLocation + ld a, [hli] + ld [wOTTrademonID], a + ld a, [hl] + ld [wOTTrademonID + 1], a + ld hl, wOTPartyMon1DVs + ld a, [wceee] + call GetPartyLocation + ld a, [hli] + ld [wOTTrademonDVs], a + ld a, [hl] + ld [wOTTrademonDVs + 1], a + ld a, [wceed] + ld [wCurPartyMon], a + ld hl, wPartySpecies + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wceed], a + xor a ; REMOVE_PARTY + ld [wPokemonWithdrawDepositParameter], a + callfar RemoveMonFromPartyOrBox + ld a, [wPartyCount] + dec a + ld [wCurPartyMon], a + ld a, TRUE + ld [wForceEvolution], a + ld a, [wceee] + push af + ld hl, wOTPartySpecies + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wceee], a + ld c, 100 + call DelayFrames + call ClearTilemap + call LoadFontsBattleExtra + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .player_2 + predef TradeAnimation + jr .done_animation + +.player_2 + predef TradeAnimationPlayer2 + +.done_animation + pop af + ld c, a + ld [wCurPartyMon], a + ld hl, wOTPartySpecies + ld d, 0 + ld e, a + add hl, de + ld a, [hl] + ld [wCurPartySpecies], a + ld hl, wOTPartyMon1Species + ld a, c + call GetPartyLocation + ld de, wTempMonSpecies + ld bc, PARTYMON_STRUCT_LENGTH + call CopyBytes + predef AddTempmonToParty + ld a, [wPartyCount] + dec a + ld [wCurPartyMon], a + callfar EvolvePokemon + call ClearTilemap + call LoadTradeScreenBorder + call SetTradeRoomBGPals + call WaitBGMap + ld b, $1 + pop af + ld c, a + cp MEW + jr z, .loop + ld a, [wCurPartySpecies] + cp MEW + jr z, .loop + ld b, $2 + ld a, c + cp CELEBI + jr z, .loop + ld a, [wCurPartySpecies] + cp CELEBI + jr z, .loop + ld b, $0 + +.loop + ld a, b + ld [wPlayerLinkAction], a + push bc + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + pop bc + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + jr z, .save + ld a, b + and a + jr z, .save + ld a, [wOtherPlayerLinkAction] + cp b + jr nz, .loop + +.save + farcall SaveAfterLinkTrade + ld c, 40 + call DelayFrames + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call LinkTextboxAtHL + hlcoord 1, 14 + ld de, String28d56 + call PlaceString + ld c, 50 + call DelayFrames + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + jp z, Gen2ToGen1LinkComms + jp Gen2ToGen2LinkComms + +Function28d3c: + ld c, 100 + call DelayFrames + jp InitTradeMenuDisplay + +String28d44: + db "TRADE" + next "CANCEL@" + +LinkAskTradeForText: + text_far _LinkAskTradeForText + text_end + +String28d56: + db "Trade completed!@" + +String_TooBadTheTradeWasCanceled: + db "Too bad! The trade" + next "was canceled!@" + +LinkTextboxAtHL: + push hl + ld a, $78 + ld [hli], a + inc a + call .PlaceRow + inc a + ld [hl], a + pop hl + ld de, SCREEN_WIDTH + add hl, de +.loop + push hl + ld a, $7b + ld [hli], a + ld a, " " + call .PlaceRow + ld [hl], $77 + pop hl + ld de, SCREEN_WIDTH + add hl, de + dec b + jr nz, .loop + + ld a, $7c + ld [hli], a + ld a, $76 + call .PlaceRow + ld [hl], $7d + ret + +.PlaceRow + ld d, c +.row_loop + ld [hli], a + dec d + jr nz, .row_loop + ret + +LoadTradeScreenBorder: + ld de, LinkCommsBorderGFX + ld hl, vTiles2 tile $76 + lb bc, BANK(LinkCommsBorderGFX), 9 + jp Get2bpp + +SetTradeRoomBGPals: + ld b, SCGB_DIPLOMA + call GetSGBLayout + jp SetPalettes + +Function28dcf: + hlcoord 0, 0 + ld b, 6 + ld c, 18 + call LinkTextboxAtHL + hlcoord 0, 8 + ld b, 6 + ld c, 18 + call LinkTextboxAtHL + farcall PlaceTradePartnerNamesAndParty + ret + +INCLUDE "engine/movie/trade_animation.asm" + +CheckTimeCapsuleCompatibility: +; Checks to see if your party is compatible with the Gen 1 games. +; Returns the following in wScriptVar: +; 0: Party is okay +; 1: At least one Pokémon was introduced in Gen 2 +; 2: At least one Pokémon has a move that was introduced in Gen 2 +; 3: At least one Pokémon is holding mail + +; If any party Pokémon was introduced in the Gen 2 games, don't let it in. + ld hl, wPartySpecies + ld b, PARTY_LENGTH +.loop + ld a, [hli] + cp -1 + jr z, .checkitem + cp JOHTO_POKEMON + jr nc, .mon_too_new + dec b + jr nz, .loop + +; If any party Pokémon is holding mail, don't let it in. +.checkitem + ld a, [wPartyCount] + ld b, a + ld hl, wPartyMon1Item +.itemloop + push hl + push bc + ld d, [hl] + farcall ItemIsMail + pop bc + pop hl + jr c, .mon_has_mail + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + dec b + jr nz, .itemloop + +; If any party Pokémon has a move that was introduced in the Gen 2 games, don't let it in. + ld hl, wPartyMon1Moves + ld a, [wPartyCount] + ld b, a +.move_loop + ld c, NUM_MOVES +.move_next + ld a, [hli] + cp STRUGGLE + 1 + jr nc, .move_too_new + dec c + jr nz, .move_next + ld de, PARTYMON_STRUCT_LENGTH - NUM_MOVES + add hl, de + dec b + jr nz, .move_loop + xor a + jr .done + +.mon_too_new + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld a, $1 + jr .done + +.move_too_new + push bc + ld [wNamedObjectIndexBuffer], a + call GetMoveName + call CopyName1 + pop bc + call Function29ab3 + ld a, $2 + jr .done + +.mon_has_mail + call Function29ab3 + ld a, $3 + +.done + ld [wScriptVar], a + ret + +Function29ab3: + ld a, [wPartyCount] + sub b + ld c, a + inc c + ld b, 0 + ld hl, wPartyCount + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ret + +EnterTimeCapsule: + ld a, $4 + call Link_EnsureSync + ld c, 40 + call DelayFrames + xor a + ldh [hVBlank], a + inc a ; LINK_TIMECAPSULE + ld [wLinkMode], a + ret + +WaitForOtherPlayerToExit: + ld c, 3 + call DelayFrames + ld a, CONNECTION_NOT_ESTABLISHED + ldh [hSerialConnectionStatus], a + xor a + ldh [rSB], a + ldh [hSerialReceive], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld c, 3 + call DelayFrames + xor a + ldh [rSB], a + ldh [hSerialReceive], a + ld a, (0 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + ld c, 3 + call DelayFrames + xor a + ldh [rSB], a + ldh [hSerialReceive], a + ldh [rSC], a + ld c, 3 + call DelayFrames + ld a, CONNECTION_NOT_ESTABLISHED + ldh [hSerialConnectionStatus], a + ld hl, wLinkTimeoutFrames + xor a + ld [hli], a + ld [hl], a + ldh [hVBlank], a + ld [wLinkMode], a + ret + +SetBitsForLinkTradeRequest: + ld a, LINK_TRADECENTER - 1 + ld [wPlayerLinkAction], a + ld [wChosenCableClubRoom], a + ret + +SetBitsForBattleRequest: + ld a, LINK_COLOSSEUM - 1 + ld [wPlayerLinkAction], a + ld [wChosenCableClubRoom], a + ret + +SetBitsForTimeCapsuleRequest: + ld a, $2 + ldh [rSB], a + xor a + ldh [hSerialReceive], a + ld a, (0 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + xor a ; LINK_TIMECAPSULE - 1 + ld [wPlayerLinkAction], a + ld [wChosenCableClubRoom], a + ret + +WaitForLinkedFriend: + ld a, [wPlayerLinkAction] + and a + jr z, .no_link_action + ld a, $2 + ldh [rSB], a + xor a + ldh [hSerialReceive], a + ld a, (0 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + call DelayFrame + call DelayFrame + call DelayFrame + +.no_link_action + ld a, $2 + ld [wLinkTimeoutFrames + 1], a + ld a, $ff + ld [wLinkTimeoutFrames], a +.loop + ldh a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .connected + cp USING_EXTERNAL_CLOCK + jr z, .connected + ld a, CONNECTION_NOT_ESTABLISHED + ldh [hSerialConnectionStatus], a + ld a, $2 + ldh [rSB], a + xor a + ldh [hSerialReceive], a + ld a, (0 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (0 << rSC_CLOCK) + ldh [rSC], a + ld a, [wLinkTimeoutFrames] + dec a + ld [wLinkTimeoutFrames], a + jr nz, .not_done + ld a, [wLinkTimeoutFrames + 1] + dec a + ld [wLinkTimeoutFrames + 1], a + jr z, .done + +.not_done + ld a, $1 + ldh [rSB], a + ld a, (0 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + ld a, (1 << rSC_ON) | (1 << rSC_CLOCK) + ldh [rSC], a + call DelayFrame + jr .loop + +.connected + call LinkDataReceived + call DelayFrame + call LinkDataReceived + ld c, 50 + call DelayFrames + ld a, $1 + ld [wScriptVar], a + ret + +.done + xor a + ld [wScriptVar], a + ret + +CheckLinkTimeout: + ld a, $1 + ld [wPlayerLinkAction], a + ld hl, wLinkTimeoutFrames + ld a, $3 + ld [hli], a + xor a + ld [hl], a + call WaitBGMap + ld a, $2 + ldh [hVBlank], a + call DelayFrame + call DelayFrame + call Link_CheckCommunicationError + xor a + ldh [hVBlank], a + ld a, [wScriptVar] + and a + ret nz + jp Link_ResetSerialRegistersAfterLinkClosure + +Function29bf4: + ld a, $5 + ld [wPlayerLinkAction], a + ld hl, wLinkTimeoutFrames + ld a, $3 + ld [hli], a + xor a + ld [hl], a + call WaitBGMap + ld a, $2 + ldh [hVBlank], a + call DelayFrame + call DelayFrame + call Link_CheckCommunicationError + ld a, [wScriptVar] + and a + jr z, .vblank + ld bc, -1 +.wait + dec bc + ld a, b + or c + jr nz, .wait + ld a, [wOtherPlayerLinkMode] + cp $5 + jr nz, .script_var + ld a, $6 + ld [wPlayerLinkAction], a + ld hl, wLinkTimeoutFrames + ld a, $1 + ld [hli], a + ld [hl], $32 + call Link_CheckCommunicationError + ld a, [wOtherPlayerLinkMode] + cp $6 + jr z, .vblank + +.script_var + xor a + ld [wScriptVar], a + ret + +.vblank + xor a + ldh [hVBlank], a + ret + +Link_CheckCommunicationError: + xor a + ldh [hSerialReceivedNewData], a + call WaitLinkTransfer + ld hl, wLinkTimeoutFrames + ld a, [hli] + inc a + jr nz, .load_true + ld a, [hl] + inc a + jr nz, .load_true + ld b, 10 + +.acknowledge_serial +.loop + call DelayFrame + call LinkDataReceived + dec b + jr nz, .loop + + xor a + jr .load_scriptvar + +.load_true + ld a, $1 + +.load_scriptvar + ld [wScriptVar], a + ld hl, wLinkTimeoutFrames + xor a + ld [hli], a + ld [hl], a + ret + +TryQuickSave: + ld a, [wChosenCableClubRoom] + push af + farcall Link_SaveGame + ld a, TRUE + jr nc, .return_result + xor a ; FALSE +.return_result + ld [wScriptVar], a + ld c, 30 + call DelayFrames + pop af + ld [wChosenCableClubRoom], a + ret + +CheckBothSelectedSameRoom: + ld a, [wChosenCableClubRoom] + call Link_EnsureSync + push af + call LinkDataReceived + call DelayFrame + call LinkDataReceived + pop af + ld b, a + ld a, [wChosenCableClubRoom] + cp b + jr nz, .fail + ld a, [wChosenCableClubRoom] + inc a + ld [wLinkMode], a + xor a + ldh [hVBlank], a + ld a, TRUE + ld [wScriptVar], a + ret + +.fail + xor a ; FALSE + ld [wScriptVar], a + ret + +TimeCapsule: + ld a, LINK_TIMECAPSULE + ld [wLinkMode], a + call DisableSpriteUpdates + callfar LinkCommunications + call EnableSpriteUpdates + xor a + ldh [hVBlank], a + ret + +TradeCenter: + ld a, LINK_TRADECENTER + ld [wLinkMode], a + call DisableSpriteUpdates + callfar LinkCommunications + call EnableSpriteUpdates + xor a + ldh [hVBlank], a + ret + +Colosseum: + ld a, LINK_COLOSSEUM + ld [wLinkMode], a + call DisableSpriteUpdates + callfar LinkCommunications + call EnableSpriteUpdates + xor a + ldh [hVBlank], a + ret + +CloseLink: + ld c, 3 + call DelayFrames + jp Link_ResetSerialRegistersAfterLinkClosure + +FailedLinkToPast: + ld c, 40 + call DelayFrames + ld a, $e + jp Link_EnsureSync + +Link_ResetSerialRegistersAfterLinkClosure: + ld c, 3 + call DelayFrames + ld a, CONNECTION_NOT_ESTABLISHED + ldh [hSerialConnectionStatus], a + ld a, $2 + ldh [rSB], a + xor a + ldh [hSerialReceive], a + ldh [rSC], a + ret + +Link_EnsureSync: + add $d0 + ld [wPlayerLinkAction], a + ld [wce57], a + ld a, $2 + ldh [hVBlank], a + call DelayFrame + call DelayFrame +.receive_loop + call Serial_ExchangeLinkMenuSelection + ld a, [wOtherPlayerLinkMode] + ld b, a + and $f0 + cp $d0 + jr z, .done + ld a, [wOtherPlayerLinkAction] + ld b, a + and $f0 + cp $d0 + jr nz, .receive_loop + +.done + xor a + ldh [hVBlank], a + ld a, b + and $f + ret + +CableClubCheckWhichChris: + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + ld a, TRUE + jr z, .yes + dec a ; FALSE + +.yes + ld [wScriptVar], a + ret + +LinkCommsBorderGFX: +INCBIN "gfx/trade/border_tiles.2bpp" + +Unreferenced_Function29fe4: + ld a, BANK(sPartyMail) + call OpenSRAM + ld d, FALSE + ld b, CHECK_FLAG + predef SmallFarFlagAction + call CloseSRAM + ld a, c + and a + ret diff --git a/engine/link/mystery_gift.asm b/engine/link/mystery_gift.asm new file mode 100644 index 00000000..55a35982 --- /dev/null +++ b/engine/link/mystery_gift.asm @@ -0,0 +1,1077 @@ +DoMysteryGift: + call ClearTilemap + call ClearSprites + call WaitBGMap + farcall InitMysteryGiftLayout + hlcoord 3, 8 + ld de, .String_PressAToLink_BToCancel + call PlaceString + call WaitBGMap + farcall PrepMysteryGiftDataToSend + call MysteryGift_ClearTrainerData + ld a, $2 + ld [wc901], a + ld a, $14 + ld [wc902], a + ldh a, [rIE] + push af + + call Function29fc9 + + ld d, a + xor a + ldh [rIF], a + pop af + ldh [rIE], a + push de + call ClearTilemap + call EnableLCD + call WaitBGMap + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + pop de + hlcoord 2, 8 + ld a, d + ld de, .MysteryGiftCanceledText ; Link has been canceled + cp $10 + jp z, .LinkCanceled + cp $6c + jp nz, .CommunicationError + ld a, [wc800] + cp 3 + jr z, .skip_checks + call .CheckAlreadyGotFiveGiftsToday + ld hl, .MysteryGiftFiveADayText ; Only 5 gifts a day + jp nc, .PrintTextAndExit + call .CheckAlreadyGotAGiftFromThatPerson + ld hl, .MysteryGiftOneADayText ; Only one gift a day per person + jp c, .PrintTextAndExit +.skip_checks + ld a, [wMysteryGiftPlayerBackupItem] + and a + jr nz, .GiftWaiting + ld a, [wMysteryGiftPartnerBackupItem] + and a + jr nz, .FriendNotReady + ld a, [wc800] + cp 3 + jr z, .skip_append_save + call .AddMysteryGiftPartnerID + ld a, [wc800] + cp 4 + jr z, .skip_append_save + call .SaveMysteryGiftTrainerName +.skip_append_save + ld a, [wMysteryGiftPartnerSentDeco] + and a + jr z, .item + ld a, [wMysteryGiftPartnerWhichDeco] + ld c, a + farcall MysteryGiftGetDecoration + push bc + call MysteryGift_CheckAndSetDecorationAlreadyReceived + pop bc + jr nz, .item + callfar GetDecorationName_c + ld h, d + ld l, e + ld de, wStringBuffer1 + ld bc, ITEM_NAME_LENGTH + call CopyBytes + ld hl, .MysteryGiftSentHomeText ; sent decoration to home + jr .PrintTextAndExit + +.item + call GetMysteryGiftBank + ld a, [wMysteryGiftPartnerWhichItem] + ld c, a + farcall MysteryGiftGetItemHeldEffect + ld a, c + ld [sBackupMysteryGiftItem], a + ld [wNamedObjectIndexBuffer], a + call CloseSRAM + call GetItemName + ld hl, .MysteryGiftSentText ; sent item + jr .PrintTextAndExit + +.LinkCanceled: + ld hl, .MysteryGiftCanceledText ; Link has been canceled + jr .PrintTextAndExit + +.CommunicationError: + ld hl, .MysteryGiftCommErrorText ; Communication error + call PrintText + jp DoMysteryGift + +.GiftWaiting: + ld hl, .RetrieveMysteryGiftText ; receive gift at counter + jr .PrintTextAndExit + +.FriendNotReady: + ld hl, .YourFriendIsNotReadyText ; friend not ready + +.PrintTextAndExit: + call PrintText + ld a, LCDC_DEFAULT + ldh [rLCDC], a + ret + +.String_PressAToLink_BToCancel: + db "Press A to" + next "link IR-Device" + next "Press B to" + next "cancel it." + db "@" + +.MysteryGiftCanceledText: + text_far _MysteryGiftCanceledText + text_end + +.MysteryGiftCommErrorText: + text_far _MysteryGiftCommErrorText + text_end + +.RetrieveMysteryGiftText: + text_far _RetrieveMysteryGiftText + text_end + +.YourFriendIsNotReadyText: + text_far _YourFriendIsNotReadyText + text_end + +.MysteryGiftFiveADayText: + text_far _MysteryGiftFiveADayText + text_end + +.MysteryGiftOneADayText: + text_far _MysteryGiftOneADayText + text_end + +.MysteryGiftSentText: + text_far _MysteryGiftSentText + text_end + +.MysteryGiftSentHomeText: + text_far _MysteryGiftSentHomeText + text_end + +.CheckAlreadyGotFiveGiftsToday: + call GetMysteryGiftBank + ld a, [sNumDailyMysteryGiftPartnerIDs] + cp $5 + jp CloseSRAM + +.CheckAlreadyGotAGiftFromThatPerson: + call GetMysteryGiftBank + ld a, [wMysteryGiftPartnerID] + ld b, a + ld a, [wMysteryGiftPartnerID + 1] + ld c, a + ld a, [sNumDailyMysteryGiftPartnerIDs] + ld d, a + ld hl, sDailyMysteryGiftPartnerIDs +.loop + ld a, d + and a + jr z, .No + ld a, [hli] + cp b + jr nz, .skip + ld a, [hl] + cp c + jr z, .Yes +.skip + inc hl + dec d + jr .loop +.Yes: + scf +.No: + jp CloseSRAM + +.AddMysteryGiftPartnerID: + call GetMysteryGiftBank + ld hl, sNumDailyMysteryGiftPartnerIDs + ld a, [hl] + inc [hl] + ld hl, sDailyMysteryGiftPartnerIDs ; inc hl + ld e, a + ld d, $0 + add hl, de + add hl, de + ld a, [wMysteryGiftPartnerID] + ld [hli], a + ld a, [wMysteryGiftPartnerID + 1] + ld [hl], a + jp CloseSRAM + +.SaveMysteryGiftTrainerName: + call GetMysteryGiftBank + ld a, $1 + ld [sMysteryGiftTrainerHouseFlag], a + ld hl, wMysteryGiftPartnerName + ld de, sMysteryGiftPartnerName + ld bc, NAME_LENGTH + call CopyBytes + ld a, $1 + ld [de], a + inc de + ld hl, wMysteryGiftTrainerData + ld bc, (1 + 1 + NUM_MOVES) * PARTY_LENGTH + 2 + call CopyBytes + jp CloseSRAM + +Function29fc9: + farcall ClearChannels + call Function2a18c + +.loop2 + call Function2a1c4 + call Function2a20b + ldh a, [hMGStatusFlags] + cp $10 + jp z, Function2a103 + cp $6c + jr nz, .loop2 + + ldh a, [hPrintNumBuffer + 8] + cp $2 + jr z, Function2a055 + ld hl, hPrintNumBuffer + ld b, $1 + call Function2a184 + jr nz, .ly_loop + call Function2a07c + jp nz, Function2a103 + jr Function2a03d + ; Delay frame +.ly_loop + ldh a, [rLY] + cp LY_VBLANK + jr c, .ly_loop + ld c, LOW(rRP) + ld a, $c0 + ldh [c], a + ld b, 240 ; This might have been intended as a 4-second timeout buffer. + ; However, it is reset with each frame. +.loop3 + push bc + call MysteryGift_ReadJoypad + + ld b, $2 + ld c, LOW(rRP) + ; Delay frame +.ly_loop2 + ldh a, [c] + and b + ld b, a + ldh a, [rLY] + cp LY_VBLANK + jr nc, .ly_loop2 +.ly_loop3 + ldh a, [c] + and b + ld b, a + ldh a, [rLY] + cp LY_VBLANK + jr c, .ly_loop3 + + ld a, b + pop bc + dec b + jr z, .loop2 ; we never jump here + or a + jr nz, .loop2 + ; Check if we've pressed the B button + ldh a, [hMGJoypadReleased] + bit B_BUTTON_F, a + jr z, .loop3 + ld a, $10 + ldh [hMGStatusFlags], a + jp Function2a103 + +Function2a037: + call Function2a073 + jp nz, Function2a103 +; fall through +Function2a03d: + call Function2a166 + jp nz, Function2a103 + call Function2a0bb + jp nz, Function2a103 + call Function2a171 + jp nz, Function2a103 + call Function2a461 + jp Function2a103 + +Function2a055: + call Function2a0bb + jp nz, Function2a103 + call Function2a171 + jp nz, Function2a103 + call Function2a073 + jp nz, Function2a103 + call Function2a166 + jp nz, Function2a103 + call Function2a45c + jp Function2a103 + +Function2a073: + ld hl, hPrintNumBuffer + ld b, $1 + call Function2a184 + ret nz +; fall through +Function2a07c: + call Function2a461 + ldh a, [hMGStatusFlags] + cp $6c + ret nz + ldh a, [hPrintNumBuffer] + cp $96 + jp nz, Function2a160 + ld a, $90 + ldh [hPrintNumBuffer], a + call Function2a166 + ret nz + ld hl, hPrintNumBuffer + ld b, $1 + call Function2a17c + ret nz + call Function2a45c + ldh a, [hMGStatusFlags] + cp $6c + ret nz + call Function2a171 + ret nz + ld hl, wMysteryGiftTrainerData + ld a, [wc902] + ld b, a + call Function2a184 + ret nz + call Function2a461 + ldh a, [hMGStatusFlags] + cp $6c + ret + +Function2a0bb: + ld a, $96 + ldh [hPrintNumBuffer], a + ld hl, hPrintNumBuffer + ld b, $1 + call Function2a17c + ret nz + call Function2a45c + ldh a, [hMGStatusFlags] + cp $6c + ret nz + call Function2a171 + ret nz + ld hl, hPrintNumBuffer + ld b, $1 + call Function2a184 + ret nz + call Function2a461 + ldh a, [hMGStatusFlags] + cp $6c + ret nz + ldh a, [hPrintNumBuffer] + cp $90 + jp nz, Function2a160 + call Function2a166 + ret nz + ld hl, wLinkData + ld a, [wc902] + ld b, a + call Function2a17c + ret nz + call Function2a45c + ldh a, [hMGStatusFlags] + cp $6c + ret + +Function2a103: + nop + ldh a, [hMGStatusFlags] + cp $10 + jr z, .quit + cp $6c + jr nz, .quit + ld hl, wc901 + dec [hl] + jr z, .quit + ld hl, wMysteryGiftTrainerData + ld de, wMysteryGiftPartnerData + ld bc, wMysteryGiftPartnerDataEnd - wMysteryGiftPartnerData + call CopyBytes + ld a, [wMysteryGiftTrainerData] + cp $3 + jr nc, .quit + farcall StagePartyDataForMysteryGift + call MysteryGift_ClearTrainerData + ld a, $26 + ld [wc902], a + ldh a, [hPrintNumBuffer + 8] + cp $2 + jr z, .asm_2a143 + call Function2a171 + jr nz, Function2a103 + jp Function2a037 + +.asm_2a143 + call Function2a166 + jr nz, Function2a103 + jp Function2a055 + +.quit: + xor a + ldh [rIF], a + ldh a, [rIE] + or 1 << VBLANK + ldh [rIE], a + ei + call DelayFrame + ldh a, [hMGStatusFlags] + push af + call Function2a1ce + pop af + ret + +Function2a160: + ld a, $80 + ldh [hMGStatusFlags], a + and a + ret + +Function2a166: + call Function2a1c4 + call Function2a274 + ldh a, [hMGStatusFlags] + cp $6c + ret + +Function2a171: + call Function2a1c4 + call Function2a22c + ldh a, [hMGStatusFlags] + cp $6c + ret + +Function2a17c: + call Function2a2c1 + ldh a, [hMGStatusFlags] + cp $6c + ret + +Function2a184: + call Function2a385 + ldh a, [hMGStatusFlags] + cp $6c + ret + +Function2a18c: + call Function2a1a2 + ld a, 1 << TIMER + ldh [rIE], a + xor a + ldh [rIF], a + call Function2a1c4 + xor a + ld b, a +.asm_2a19b + inc a + jr nz, .asm_2a19b + inc b + jr nz, .asm_2a19b + ret + +Function2a1a2: + xor a + ldh [rTAC], a + ld a, $fe + ldh [rTMA], a + ldh [rTIMA], a + ld a, $2 + ldh [rTAC], a + or $4 + ldh [rTAC], a + ret + +Function2a1b4: + xor a + ldh [rTAC], a + ldh [rTMA], a + ldh [rTIMA], a + ld a, $2 + ldh [rTAC], a + or $4 + ldh [rTAC], a + ret + +Function2a1c4: + ld a, $c0 + call Function2a2ba + ld a, $1 + ldh [hPrintNumBuffer + 8], a + ret + +Function2a1ce: + xor a + call Function2a2ba + ld a, $2 + ldh [rTAC], a + ret + +Function2a1d7: + inc d + ret z + xor a + ldh [rIF], a + halt + ldh a, [c] + bit 1, a + jr z, Function2a1d7 + or a + ret + +Function2a1e5: + inc d + ret z + xor a + ldh [rIF], a + halt + ldh a, [c] + bit 1, a + jr nz, Function2a1e5 + or a + ret + +Function2a1f3: + ld a, $c1 + ldh [c], a +.wait + dec d + ret z + xor a + ldh [rIF], a + halt + jr .wait + +Function2a1ff: + ld a, $c0 + ldh [c], a +.wait + dec d + ret z + xor a + ldh [rIF], a + halt + jr .wait + +Function2a20b: + ld d, $0 + ld e, d + ld a, $1 + ldh [hPrintNumBuffer + 8], a +.loop + call MysteryGift_ReadJoypad + ld b, $2 + ld c, LOW(rRP) + ldh a, [hMGJoypadReleased] + bit B_BUTTON_F, a + jr z, .next + ld a, $10 + ldh [hMGStatusFlags], a + ret + +.next + bit 0, a + jr nz, Function2a268 + ldh a, [c] + and b + jr nz, .loop + +Function2a22c: + ld c, LOW(rRP) + ld d, $0 + ld e, d + call Function2a1e5 + jp z, Function2a370 + ld d, e + call Function2a1d7 + jp z, Function2a370 + call Function2a1e5 + jp z, Function2a370 + call Function2a1d7 + jp z, Function2a370 + ld a, $6c + ldh [hMGStatusFlags], a + ld d, $3d + call Function2a1ff + ld d, $5 + call Function2a1f3 + ld d, $15 + call Function2a1ff + ld d, $5 + call Function2a1f3 + ld d, $5 + call Function2a1ff + ret + +Function2a268: + ; Wait a random amount of time + call Random + ld e, a + and $f + ld d, a +.loop + dec de + ld a, d + or e + jr nz, .loop +Function2a274: + ld a, $2 + ldh [hPrintNumBuffer + 8], a + ld c, LOW(rRP) + ld d, $0 + ld e, d + ld d, $3d + call Function2a1ff + ld d, $5 + call Function2a1f3 + ld d, $15 + call Function2a1ff + ld d, $5 + call Function2a1f3 + ld d, $5 + call Function2a1ff + ld d, e + call Function2a1e5 + jp z, Function2a370 + ld d, e + call Function2a1d7 + jp z, Function2a370 + call Function2a1e5 + jp z, Function2a370 + call Function2a1d7 + jp z, Function2a370 + ld d, $3d + call Function2a1ff + ld a, $6c + ldh [hMGStatusFlags], a + ret + +Function2a2ba: + ldh [rRP], a + ld a, $ff + ldh [hMGStatusFlags], a + ret + +Function2a2c1: + xor a + ldh [hPrintNumBuffer + 4], a + ldh [hPrintNumBuffer + 5], a + push hl + push bc + ld c, LOW(rRP) + ld d, $3d + call Function2a1ff + ld hl, hPrintNumBuffer + 1 + ld a, $5a + ld [hli], a + ld [hl], b + dec hl + ld b, $2 + call Function2a304 + pop bc + pop hl + call Function2a304 + ldh a, [hPrintNumBuffer + 4] + ldh [hPrintNumBuffer + 1], a + ldh a, [hPrintNumBuffer + 5] + ldh [hPrintNumBuffer + 2], a + push hl + ld hl, hPrintNumBuffer + 1 + ld b, $2 + call Function2a304 + ld hl, hMGStatusFlags + ld b, $1 + call Function2a3dd + ldh a, [hPrintNumBuffer + 1] + ldh [hPrintNumBuffer + 4], a + ldh a, [hPrintNumBuffer + 2] + ldh [hPrintNumBuffer + 5], a + pop hl + ret + +Function2a304: + ld c, LOW(rRP) + ld d, $5 + call Function2a1ff + ld d, $5 + call Function2a1f3 + ld d, $15 + call Function2a1ff + ld a, b + cpl + ld b, a + ld a, $f4 + ldh [rTMA], a +.asm_2a31c + inc b + jr z, .asm_2a35c + ld a, $8 + ldh [hPrintNumBuffer + 3], a + ld a, [hli] + ld e, a + ldh a, [hPrintNumBuffer + 4] + add e + ldh [hPrintNumBuffer + 4], a + ldh a, [hPrintNumBuffer + 5] + adc 0 + ldh [hPrintNumBuffer + 5], a +.asm_2a330 + xor a + ldh [rIF], a + halt + ld a, $c1 + ldh [rRP], a + ld d, $1 + ld a, e + rlca + ld e, a + jr nc, .asm_2a341 + inc d +.asm_2a341 + ldh a, [rTIMA] + cp $f8 + jr c, .asm_2a341 + ld a, $c0 + ldh [rRP], a + dec d + jr z, .asm_2a353 + xor a + ldh [rIF], a + halt +.asm_2a353 + ldh a, [hPrintNumBuffer + 3] + dec a + jr z, .asm_2a31c + ldh [hPrintNumBuffer + 3], a + jr .asm_2a330 +.asm_2a35c + ld a, $fe + ldh [rTMA], a + xor a + ldh [rIF], a + halt + ld d, $5 + call Function2a1f3 + ld d, $11 + call Function2a1ff + ret + +Function2a370: + ldh a, [hMGStatusFlags] + or $2 + ldh [hMGStatusFlags], a + ret + +Function2a377: + ldh a, [hMGStatusFlags] + or $1 + ldh [hMGStatusFlags], a + ret + +Function2a37e: + ldh a, [hMGStatusFlags] + or $80 + ldh [hMGStatusFlags], a + ret + +Function2a385: + xor a + ldh [hPrintNumBuffer + 4], a + ldh [hPrintNumBuffer + 5], a + push bc + push hl + ld hl, hPrintNumBuffer + 1 + ld b, $2 + call Function2a3dd + ldh a, [hPrintNumBuffer + 2] + ldh [hPrintNumBuffer + 7], a + ld b, a + pop hl + pop af + cp b + jp c, Function2a37e + ldh a, [hPrintNumBuffer + 1] + cp $5a + jp nz, Function2a37e + call Function2a3dd + ldh a, [hPrintNumBuffer + 4] + ld d, a + ldh a, [hPrintNumBuffer + 5] + ld e, a + push hl + push de + ld hl, hPrintNumBuffer + 1 + ld b, $2 + call Function2a3dd + pop de + ld hl, hPrintNumBuffer + 1 + ld a, [hli] + xor d + ld b, a + ld a, [hl] + xor e + or b + call nz, Function2a377 + push de + ld d, $3d + call Function2a1ff + ld hl, hMGStatusFlags + ld b, $1 + call Function2a304 + pop de + pop hl + ld a, d + ldh [hPrintNumBuffer + 4], a + ld a, e + ldh [hPrintNumBuffer + 5], a + ret + +Function2a3dd: + ld c, LOW(rRP) + ld d, $0 + call Function2a1e5 + jp z, Function2a370 + ld d, $0 + call Function2a1d7 + jp z, Function2a370 + ld d, $0 + call Function2a1e5 + jp z, Function2a370 + ld a, b + cpl + ld b, a + xor a + ldh [hMGPrevTIMA], a + call Function2a1b4 +.asm_2a400 + inc b + jr z, .asm_2a448 + ld a, $8 + ldh [hPrintNumBuffer + 3], a +.asm_2a407 + ld d, $0 +.asm_2a409 + inc d + jr z, .asm_2a413 + ldh a, [c] + bit 1, a + jr z, .asm_2a409 + ld d, $0 +.asm_2a413 + inc d + jr z, .asm_2a41b + ldh a, [c] + bit 1, a + jr nz, .asm_2a413 +.asm_2a41b + ldh a, [hMGPrevTIMA] + ld d, a + ldh a, [rTIMA] + ldh [hMGPrevTIMA], a + sub d + cp $12 + jr c, .asm_2a42b + set 0, e + jr .asm_2a42d +.asm_2a42b + res 0, e +.asm_2a42d + ldh a, [hPrintNumBuffer + 3] + dec a + ldh [hPrintNumBuffer + 3], a + jr z, .asm_2a439 + ld a, e + rlca + ld e, a + jr .asm_2a407 +.asm_2a439 + ld a, e + ld [hli], a + ldh a, [hPrintNumBuffer + 4] + add e + ldh [hPrintNumBuffer + 4], a + ldh a, [hPrintNumBuffer + 5] + adc 0 + ldh [hPrintNumBuffer + 5], a + jr .asm_2a400 +.asm_2a448 + call Function2a1a2 + xor a + ldh [rIF], a + ld d, $0 + call Function2a1d7 + jp z, Function2a370 + ld d, $10 + call Function2a1ff + ret + +Function2a45c: + ld b, $0 + jp Function2a2c1 + +Function2a461: + ld b, $0 + jp Function2a385 + +MysteryGift_ReadJoypad: +; We can only get four inputs at a time. +; We take d-pad first for no particular reason. + ld a, R_DPAD + ldh [rJOYP], a +; Read twice to give the request time to take. + ldh a, [rJOYP] + ldh a, [rJOYP] + +; The Joypad register output is in the lo nybble (inversed). +; We make the hi nybble of our new container d-pad input. + cpl + and $f + swap a + +; We'll keep this in b for now. + ld b, a + +; Buttons make 8 total inputs (A, B, Select, Start). +; We can fit this into one byte. + ld a, R_BUTTONS + ldh [rJOYP], a +; Wait for input to stabilize. +rept 6 + ldh a, [rJOYP] +endr +; Buttons take the lo nybble. + cpl + and $f + or b + ld c, a +; To get the delta we xor the last frame's input with the new one. + ldh a, [hMGJoypadPressed] + xor c +; Released this frame: + and c + ldh [hMGJoypadReleased], a +; Pressed this frame: + ld a, c + ldh [hMGJoypadPressed], a + ld a, $30 +; Reset the joypad register since we're done with it. + ldh [rJOYP], a + ret + +MysteryGift_CheckAndSetDecorationAlreadyReceived: + call GetMysteryGiftBank + ld d, $0 + ld b, CHECK_FLAG + ld hl, sMysteryGiftDecorationsReceived + predef_id SmallFarFlagAction + push hl + push bc + call Predef + call CloseSRAM + ld a, c + and a + pop bc + pop hl + ret nz + call GetMysteryGiftBank + ld b, SET_FLAG + predef SmallFarFlagAction + call CloseSRAM + xor a + ret + +MysteryGift_CopyReceivedDecosToPC: + call GetMysteryGiftBank + ld c, $0 +.loop + push bc + ld d, $0 + ld b, CHECK_FLAG + ld hl, sMysteryGiftDecorationsReceived + predef SmallFarFlagAction + ld a, c + and a + pop bc + jr z, .skip + push bc + callfar SetSpecificDecorationFlag + pop bc +.skip + inc c + ld a, c + cp TrophyIDs - DecorationIDs + jr c, .loop + jp CloseSRAM + +UnlockMysteryGift: + call GetMysteryGiftBank + ld hl, sMysteryGiftUnlocked + ld a, [hl] + inc a + jr nz, .ok + ld [hld], a + ld [hl], a +.ok + jp CloseSRAM + +Function2a4f6: + call GetMysteryGiftBank + ld a, [sNumDailyMysteryGiftPartnerIDs] + cp $ff + jr z, .okay + xor a + ld [sNumDailyMysteryGiftPartnerIDs], a +.okay + jp CloseSRAM + +BackupMysteryGift: + call GetMysteryGiftBank + ld hl, sMysteryGiftItem + ld de, sBackupMysteryGiftItem + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + jp CloseSRAM + +RestoreMysteryGift: + call GetMysteryGiftBank + ld hl, sBackupMysteryGiftItem + ld de, sMysteryGiftItem + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + jp CloseSRAM + +MysteryGift_ClearTrainerData: + ld hl, wMysteryGiftTrainerData + xor a + ld b, wMysteryGiftTrainerDataEnd - wMysteryGiftTrainerData +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +GetMysteryGiftBank: + ld a, BANK(sBackupMysteryGiftItem) + jp OpenSRAM diff --git a/engine/link/mystery_gift_2.asm b/engine/link/mystery_gift_2.asm new file mode 100644 index 00000000..493db05c --- /dev/null +++ b/engine/link/mystery_gift_2.asm @@ -0,0 +1,150 @@ +PrepMysteryGiftDataToSend: + ld de, wMysteryGiftStaging + ld a, $1 + GS_VERSION + ld [de], a + inc de ; wc701 + ld a, BANK(sGameData) + call OpenSRAM + ld hl, sPlayerData + wPlayerID - wPlayerData + ld a, [hli] + ld [de], a + ld b, a + inc de ; wc702 + ld a, [hl] + ld [de], a + ld c, a + inc de ; wc703 + push bc + ld hl, sPlayerData + wPlayerName - wPlayerData + ld bc, NAME_LENGTH + call CopyBytes + push de ; wc70e + ld hl, sPokemonData + wPokedexCaught - wPokemonData + ld b, wEndPokedexCaught - wPokedexCaught + call CountSetBits + pop de + pop bc + ld a, [wNumSetBits] + ld [de], a + inc de ; wc70f + call CloseSRAM + call Random + and 1 + ld [de], a + inc de ; wc710 + call .RandomSample + ld [de], a + inc de ; wc711 + ld a, c + ld c, b + ld b, a + call .RandomSample + ld [de], a + inc de ; wc712 + ld a, BANK(sBackupMysteryGiftItem) + call OpenSRAM + ld a, [sBackupMysteryGiftItem] + ld [de], a + inc de + ld a, [sBackupMysteryGiftItem + 1] + ld [de], a + ld a, $14 + ld [wc900], a + call CloseSRAM + ld hl, wMysteryGiftStaging + ld de, wMysteryGiftPlayerData + ld bc, wMysteryGiftPlayerDataEnd - wMysteryGiftPlayerData + jp CopyBytes + +.RandomSample: + push de + call Random + cp 10 percent + jr c, .tenpercent + call Random + and %111 + ld d, a + rl d + ld e, $80 +.loop + rlc e + dec a + jr nz, .loop + ld a, e + and c + jr z, .skip + ld a, $1 +.skip + add d + jr .done + +.tenpercent + call Random + cp 20 percent - 1 + jr c, .twopercent + call Random + and %011 + ld d, a + rl d + ld e, $80 +.loop2 + rlc e + dec a + jr nz, .loop2 + ld a, e + and b + jr z, .skip2 + ld a, $1 +.skip2 + add d + add $10 + jr .done + +.twopercent + call Random + cp 20 percent - 1 + jr c, .pointfourpercent + ld a, b + swap a + and $7 + add $18 + jr .done + +.pointfourpercent + ld a, b + and $80 + ld a, $20 + jr z, .done + ld a, $21 + +.done + pop de + ret + +MysteryGiftGetItemHeldEffect: + ld a, c + cp MysteryGiftItems.End - MysteryGiftItems + jr nc, MysteryGiftFallbackItem + ld hl, MysteryGiftItems + ld b, 0 + add hl, bc + ld c, [hl] + ret + +MysteryGiftGetDecoration: + ld a, c + cp MysteryGiftDecos.End - MysteryGiftDecos + jr nc, MysteryGiftFallbackItem + ld hl, MysteryGiftDecos + ld b, 0 + add hl, bc + ld c, [hl] + ret + +MysteryGiftFallbackItem: + ld c, DECO_POLKADOT_BED ; GREAT_BALL + ret + +INCLUDE "data/items/mystery_gift_items.asm" + +INCLUDE "data/decorations/mystery_gift_decos.asm" diff --git a/engine/link/place_waiting_text.asm b/engine/link/place_waiting_text.asm index dc1fe215..5c31c314 100755 --- a/engine/link/place_waiting_text.asm +++ b/engine/link/place_waiting_text.asm @@ -22,3 +22,6 @@ PlaceWaitingText:: .Waiting: db "Waiting...!@" + +DummyPredef1: + ret diff --git a/engine/main_menu.asm b/engine/main_menu.asm deleted file mode 100755 index 6f460a5c..00000000 --- a/engine/main_menu.asm +++ /dev/null @@ -1,1093 +0,0 @@ -MainMenu_: - ld de, MUSIC_NONE - call PlayMusic - call DelayFrame - ld de, MUSIC_MAIN_MENU - ld a, e - ld [wMapMusic], a - call PlayMusic -.asm_5a60 - xor a - ld [wDisableTextAcceleration], a - call Function5bf7 - ld b, $8 - call GetSGBLayout - ld hl, wGameTimerPause - res 0, [hl] - call Function5ae4 - ld [wWhichIndexSet], a - call Function5b27 - ld hl, .MenuDataHeader - call LoadMenuHeader - call Function5b0a - call CloseWindow - jr c, .asm_5a94 - call ClearTilemap - ld a, [wMenuSelection] - ld hl, .Jumptable - rst JumpTable - jr .asm_5a60 - -.asm_5a94 - jp StartTitleScreen - -.MenuDataHeader: - db $40 - db 00, 00 - db 07, 14 - dw .MenuData2 - db 1 - -.MenuData2: - db $80 - db 0 - dw MainMenuItems - dw PlaceMenuStrings - dw .Strings - -.Strings: - db "CONTINUE@" - db "NEW GAME@" - db "OPTION@" - db "MYSTERY GIFT@" - -.Jumptable: - dw MainMenu_Continue ; 5dd9 - dw MainMenu_NewGame ; 5c1e - dw MainMenu_Options ; 5c17 - dw MainMenu_MysteryGift ; 5c07 - -CONTINUE EQU 0 -NEW_GAME EQU 1 -OPTION EQU 2 -MYSTERY_GIFT EQU 3 - -MainMenuItems: - db 2 - db NEW_GAME - db OPTION - db -1 - - db 3 - db CONTINUE - db NEW_GAME - db OPTION - db -1 - - db 4 - db CONTINUE - db NEW_GAME - db OPTION - db MYSTERY_GIFT - db -1 - -Function5ae4: ; 5ae4 (1:5ae4) - nop - nop - nop - ld a, [wSaveFileExists] - and a - jr nz, .asm_5af0 - ld a, $0 - ret - -.asm_5af0 - ldh a, [hCGB] - cp $1 - ld a, $1 - ret nz - ld a, $0 - call OpenSRAM - ld a, [$abe5] - cp $ff - call CloseSRAM - ld a, $1 - ret z - ld a, $2 - ret - -Function5b0a: ; 5b0a (1:5b0a) - call SetUpMenu -.asm_5b0d - call Function5b27 - call GetScrollingMenuJoypad - ld a, [wMenuJoypad] - cp $2 - jr z, .asm_5b25 - cp $1 - jr z, .asm_5b20 - jr .asm_5b0d - -.asm_5b20 - call PlayClickSFX - and a - ret - -.asm_5b25 - scf - ret - -Function5b27: ; 5b27 (1:5b27) - ld a, [wSaveFileExists] - and a - ret z - xor a - ldh [hBGMapMode], a - call Function5b45 - ld hl, wOptions - ld a, [hl] - push af - set 4, [hl] - call Function5b5b - pop af - ld [wOptions], a - ld a, $1 - ldh [hBGMapMode], a - ret - -Function5b45: ; 5b45 (1:5b45) - call CheckRTCStatus - and $80 - jr nz, .asm_5b57 - hlcoord 0, 12 - ld b, $4 - ld c, $d - call Textbox - ret - -.asm_5b57 - call SpeechTextbox - ret - -Function5b5b: ; 5b5b (1:5b5b) - ld a, [wSaveFileExists] - and a - ret z - call CheckRTCStatus - and $80 - jp nz, Function5b9c - call UpdateTime - hlcoord 1, 13 - ld bc, IncGradGBPalTable_11 + 1 - call ClearBox - call GetWeekday - ld b, a - decoord 1, 14 - call Function5bb8 - decoord 4, 16 - ldh a, [hHours] - ld c, a - farcall PrintHour - ld [hl], $9c - inc hl - ld de, hMinutes - lb bc, PRINTNUM_LEADINGZEROS | 1, 2 - call PrintNum - ret - -.min - db "min.@" - -Function5b9c: ; 5b9c (1:5b9c) - hlcoord 1, 14 - ld de, .TimeNotSet - call PlaceString - ret - -.TimeNotSet - db "TIME NOT SET@" - -.UnusedText - text_far _ClockTimeUnknownText - db "@" - -Function5bb8: ; 5bb8 (1:5bb8) - push de - ld hl, .Days - ld a, b - call GetNthString - ld d, h - ld e, l - pop hl - call PlaceString - ld h, b - ld l, c - ld de, .Day - call PlaceString - ret - -.Days: - db "SUN@" - db "MON@" - db "TUES@" - db "WEDNES@" - db "THURS@" - db "FRI@" - db "SATUR@" -.Day: - db "DAY@" - -Function5bf7: ; 5bf7 (1:5bf7) - xor a - ldh [hMapAnims], a - call ClearTilemap - call LoadFontsExtra - call Functiond9e - call ClearWindowData - ret - -MainMenu_MysteryGift: - call UpdateTime - farcall Function11934 - farcall Function29dff - ret - -MainMenu_Options: - farcall OptionsMenu - ret - -MainMenu_NewGame: - xor a - ld [wDebugFlags], a - call Function5c3a - call Function5bf7 - call OakSpeech - call InitializeWorld - ld a, $0 - ld [wceec], a - ld a, $f1 - ldh [hMapEntryMethod], a - jp FinishContinueFunction - -Function5c3a: ; 5c3a (1:5c3a) - xor a - ldh [hBGMapMode], a - call Function5c41 - ret - -Function5c41: ; 5c41 (1:5c41) - ld hl, wVirtualOAM - ld bc, wOptions - wVirtualOAM - xor a - call ByteFill - - ld hl, wGameData - ld bc, wGameDataEnd - wGameData - xor a - call ByteFill - - ldh a, [rLY] - ldh [hSecondsBackup], a - call DelayFrame - ldh a, [hRandomSub] - ld [wPlayerID], a - - ldh a, [rLY] - ldh [hSecondsBackup], a - call DelayFrame - ldh a, [hRandomAdd] - ld [wPlayerID + 1], a - - ld hl, wPartyCount - call Function5d15 - - xor a - ld [wCurBox], a - ld [wSavedAtLeastOnce], a - - call Function5d1a - - ld a, BANK(sBoxCount) - call OpenSRAM - ld hl, sBoxCount - call Function5d15 - call CloseSRAM - - ld hl, wNumItems - call Function5d15 - ld hl, wNumKeyItems - call Function5d15 - ld hl, wNumBalls - call Function5d15 - ld hl, wPCItems - call Function5d15 - - xor a - ld [wRoamMon1Species], a - ld [wRoamMon2Species], a - ld [wRoamMon3Species], a - ld a, $ff - ld [wRoamMon1MapGroup], a - ld [wRoamMon2MapGroup], a - ld [wRoamMon3MapGroup], a - ld [wRoamMon1MapNumber], a - ld [wRoamMon2MapNumber], a - ld [wRoamMon3MapNumber], a - - ld a, BANK(s0_abe2) - call OpenSRAM - ld hl, s0_abe2 - xor a - ld [hli], a - dec a - ld [hl], a - call CloseSRAM - - call LoadOrRegenerateLuckyIDNumber - call InitializeMagikarpHouse - - xor a - ld [wMonType], a - - ld [wJohtoBadges], a - ld [wKantoBadges], a - - ld [wCoins], a - ld [wCoins + 1], a - -IF START_MONEY / $10000 - ld a, START_MONEY / $10000 -ENDC - ld [wMoney], a - ld a, START_MONEY / $100 % $100 - ld [wMoney + 1], a - ld a, START_MONEY % $100 - ld [wMoney + 2], a - - xor a - ld [wd961], a - - ld hl, wMomItemTriggerBalance - ld [hl], 2300 / $10000 - inc hl - ld [hl], 2300 / $100 % $100 - inc hl - ld [hl], 2300 % $100 - - call Function5d5d - - farcall InitDecorations - - farcall DeletePartyMonMail - - call ResetGameTime - ret - -Function5d15: ; 5d15 (1:5d15) - xor a - ld [hli], a - dec a - ld [hl], a - ret - -Function5d1a: ; 5d1a (1:5d1a) - ld hl, wBoxNames - ld c, $0 -.asm_5d1f - push hl - ld de, .Box - call CopyName2 - dec hl - ld a, c - inc a - cp 10 - jr c, .asm_5d32 - sub 10 - ld [hl], "1" - inc hl -.asm_5d32 - add "0" - ld [hli], a - ld [hl], "@" - pop hl - ld de, 9 - add hl, de - inc c - ld a, c - cp NUM_BOXES - jr c, .asm_5d1f - ret - -.Box db "BOX@" - -InitializeMagikarpHouse: ; 5d47 (1:5d47) - ld hl, wBestMagikarpLengthFeet - ld a, 3 - ld [hli], a - ld a, 6 - ld [hli], a - ld de, .Ralph - call CopyName2 - ret - -.Ralph db "RALPH@" - -Function5d5d: ; 5d5d (1:5d5d) - ld hl, .Rival - ld de, wRivalName - call .CopyName - ld hl, .Mom - ld de, wMomsName - call .CopyName - ld hl, .Red - ld de, wRedsName - call .CopyName - ld hl, .Green - ld de, wGreensName -.CopyName: - ld bc, NAME_LENGTH - call CopyBytes - ret - -.Rival: db "???@" -.Red: db "RED@" -.Green: db "GREEN@" -.Mom: db "MOM@" - -InitializeWorld: ; 5d97 (1:5d97) - call ShrinkPlayer - farcall SpawnPlayer - farcall InitializeStartDay_ - ret - -LoadOrRegenerateLuckyIDNumber: ; 5da7 (1:5da7) - ld a, $0 - call OpenSRAM - ld a, [wCurDay] - inc a - ld b, a - ld a, [s0_ac68] - cp b - ld a, [s0_ac6a] - ld c, a - ld a, [s0_ac69] - jr z, .asm_5dc9 - ld a, b - ld [s0_ac68], a - call Random - ld c, a - call Random -.asm_5dc9 - ld [wd9e9], a - ld [s0_ac69], a - ld a, c - ld [wd9ea], a - ld [s0_ac6a], a - jp CloseSRAM - -MainMenu_Continue: - farcall TryLoadSaveFile - jr c, .asm_5e41 - call LoadStandardMenuHeader - call DisplaySaveInfoOnContinue - ld a, $1 - ldh [hBGMapMode], a - ld c, 20 - call DelayFrames - call ConfirmContinue - jr nc, .asm_5dfa - call CloseWindow - jr .asm_5e41 - -.asm_5dfa - call Continue_CheckRTC_RestartClock - jr nc, .asm_5e04 - call CloseWindow - jr .asm_5e41 - -.asm_5e04 - ld a, $8 - ld [wMusicFade], a - ld a, MUSIC_NONE % $100 - ld [wMusicFadeID], a - ld a, MUSIC_NONE / $100 - ld [wMusicFadeID + 1], a - call ClearBGPalettes - call CloseWindow - call ClearTilemap - ld c, 20 - call DelayFrames - farcall JumpRoamMons - farcall MysteryGift_CopyReceivedDecosToPC - farcall ClockContinue - ld a, [wd1db] - cp $1 - jr z, .asm_5e42 - ld a, $f2 - ldh [hMapEntryMethod], a - jp FinishContinueFunction - -.asm_5e41 - ret - -.asm_5e42 - ld a, $e - ld [wceec], a - call PostCreditsSpawn - jp FinishContinueFunction - -SpawnAfterRed: ; 5e4d (1:5e4d) - ld a, $1a - ld [wceec], a -PostCreditsSpawn: ; 5e52 (1:5e52) - xor a - ld [wd1db], a - ld a, $f1 - ldh [hMapEntryMethod], a - ret - -ConfirmContinue: ; 5e5b (1:5e5b) - call DelayFrame - call GetJoypad - ld hl, hJoyPressed - bit 0, [hl] - jr nz, .asm_5e6e - bit 1, [hl] - jr z, ConfirmContinue - scf - ret - -.asm_5e6e - ret - -Continue_CheckRTC_RestartClock: ; 5e6f (1:5e6f) - call CheckRTCStatus - and $80 - jr z, .asm_5e82 - ld a, $8 - ld hl, $4021 - rst FarCall - ld a, c - and a - jr z, .asm_5e82 - scf - ret - -.asm_5e82 - xor a - ret - -FinishContinueFunction: ; 5e84 (1:5e84) - xor a - ld [wDontPlayMapMusicOnReload], a - ld hl, wGameTimerPause - set 0, [hl] - farcall OverworldLoop - ld a, [wd1db] - cp $2 - jr z, .asm_5e9d - jp Reset - -.asm_5e9d - call SpawnAfterRed - jr FinishContinueFunction - -DisplaySaveInfoOnContinue: ; 5ea2 (1:5ea2) - call CheckRTCStatus - and $80 - jr z, .asm_5eb0 - lb de, 4, 8 - call DisplayContinueDataWithRTCError - ret - -.asm_5eb0 - lb de, 4, 8 - call DisplayNormalContinueData - ret - -DisplayNormalContinueData: ; 5eb7 (1:5eb7) - call Continue_LoadMenuHeader - call Continue_DisplayBadgesDex - call Continue_PrintGameTime - call LoadFontsExtra - call UpdateSprites - ret - -DisplayContinueDataWithRTCError: ; 5ec7 (1:5ec7) - call Continue_LoadMenuHeader - call Continue_DisplayBadgesDex - call Continue_UnknownGameTime - call LoadFontsExtra - call UpdateSprites - ret - -Continue_LoadMenuHeader: ; 5ed7 (1:5ed7) - xor a - ldh [hBGMapMode], a - ld hl, .MenuDataHeader_Dex - CheckFlag ENGINE_POKEDEX - jr nz, .asm_5ee7 - ld hl, .MenuDataHeader_NoDex -.asm_5ee7 - call _OffsetMenuHeader - call MenuBox - call PlaceVerticalMenuItems - ret - -.MenuDataHeader_Dex: - db $40 - db 00, 00 - db 09, 15 - dw .MenuData2_Dex - db 1 - -.MenuData2_Dex - db $00 - db 4 - db "PLAYER <PLAYER>@" - db "BADGES@" - db "#DEX@" - db "TIME@" - -.MenuDataHeader_NoDex: - db $40 - db 00, 00 - db 09, 15 - dw .MenuData2_NoDex - db 1 - -.MenuData2_NoDex - db $00 - db 4 - db "PLAYER <PLAYER>@" - db "BADGES@" - db " @" - db "TIME@" - -Continue_DisplayBadgesDex: ; 5f36 (1:5f36) - call MenuBoxCoord2Tile - push hl - decoord 13, 4, 0 - add hl, de - call Continue_DisplayBadgeCount - pop hl - push hl - decoord 12, 6, 0 - add hl, de - call Continue_DisplayPokedexNumCaught - pop hl - ret - -Continue_PrintGameTime: ; 5f4c (1:5f4c) - decoord 9, 8, 0 - add hl, de - call Continue_DisplayGameTime - ret - -Continue_UnknownGameTime: ; 5f54 (1:5f54) - decoord 9, 8, 0 - add hl, de - ld de, .three_question_marks - call PlaceString - ret - -.three_question_marks - db " ???@" - -Continue_DisplayBadgeCount: ; 5f64 (1:5f64) - push hl - ld hl, wJohtoBadges - ld b, $2 - call CountSetBits - pop hl - ld de, wd151 - lb bc, 1, 2 - jp PrintNum - -Continue_DisplayPokedexNumCaught: ; 5f77 (1:5f77) - CheckFlag ENGINE_POKEDEX - ret z - push hl - ld hl, wPokedexCaught -IF NUM_POKEMON % 8 - ld b, NUM_POKEMON / 8 + 1 -ELSE - ld b, NUM_POKEMON / 8 -ENDC - call CountSetBits - pop hl - ld de, wd151 - lb bc, 1, 3 - jp PrintNum - -Continue_DisplayGameTime: ; 5f90 (1:5f90) - ld de, wGameTimeHours - lb bc, 2, 3 - call PrintNum - ld [hl], $6d - inc hl - ld de, wGameTimeMinutes - lb bc, PRINTNUM_LEADINGZEROS | 1, 2 - jp PrintNum - -OakSpeech: ; 5fa5 (1:5fa5) - farcall InitClock ; What time is it? - - call RotateFourPalettesLeft - call ClearTilemap - - ld de, MUSIC_ROUTE_30 - call PlayMusic - - call RotateFourPalettesRight - call RotateThreePalettesRight - - xor a - ld [wCurPartySpecies], a - ld a, POKEMON_PROF - ld [wTrainerClass], a - call Intro_PrepTrainerPic - - ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS - call GetSGBLayout - - call Intro_FadeInFrontpic - - ld hl, OakText1 - call PrintText - - call RotateThreePalettesRight - call ClearTilemap - - ld a, MARILL - ld [wCurSpecies], a - ld [wCurPartySpecies], a - call GetBaseData - hlcoord 6, 4 - hlcoord 6, 4 ; TriHard - call PrepMonFrontpic - - xor a - ld [wTempMonDVs], a - ld [wTempMonDVs + 1], a - ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS - call GetSGBLayout - - call Intro_WipeInFrontpic - - ld hl, OakText2 - call PrintText - - ld hl, OakText4 - call PrintText - - call RotateThreePalettesRight - call ClearTilemap - - xor a - ld [wCurPartySpecies], a - ld a, POKEMON_PROF - ld [wTrainerClass], a - call Intro_PrepTrainerPic - - ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS - call GetSGBLayout - - call Intro_FadeInFrontpic - - ld hl, OakText5 - call PrintText - - call RotateThreePalettesRight - call ClearTilemap - - xor a - ld [wCurPartySpecies], a - ld a, CAL - ld [wTrainerClass], a - call Intro_PrepTrainerPic - - ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS - call GetSGBLayout - - call Intro_FadeInFrontpic - - ld hl, OakText6 - call PrintText - - call NamePlayer - - ld hl, OakText7 - call PrintText - ret - -OakText1: - text_far _OakText1 - db "@" - -OakText2: - text_far _OakText2 - text_asm - ld a, MARILL - call PlayMonCry - call WaitSFX - ld hl, OakText3 ; $606c - ret - -OakText3: - text_far _OakText3 - db "@" - -OakText4: - text_far _OakText4 - db "@" - -OakText5: - text_far _OakText5 - db "@" - -OakText6: - text_far _OakText6 - db "@" - -OakText7: - text_far _OakText7 - db "@" - -NamePlayer: ; 6085 (1:6085) - call MovePlayerPicRight - ld hl, .PlayerNamingChoices ; $60d9 - call SelectPresetName - ld a, [wMenuCursorY] - dec a - jr z, .NewName - ld de, wPlayerName - call StorePlayerName - farcall ApplyMonOrTrainerPals - call MovePlayerPicLeft - ret - -.NewName - ld b, $1 - ld de, wPlayerName - farcall NamingScreen - call RotateThreePalettesRight - call ClearTilemap - call LoadFontsExtra - call WaitBGMap - xor a - ld [wCurPartySpecies], a - ld a, CAL - ld [wTrainerClass], a - call Intro_PrepTrainerPic - ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS - call GetSGBLayout - call RotateThreePalettesLeft - ld hl, wPlayerName - ld de, .GoldSilver - call InitName - ret - -.PlayerNamingChoices: - db $40 - db 00, 00 - db 11, 10 - dw .MenuData2 - db 1 - -.MenuData2: - db $91 - db 5 - db "NEW NAME@" -.GoldSilver: -IF DEF(GOLD) - db "GOLD@" - db "HIRO@" - db "TAYLOR@" - db "KARL@" -ENDC -IF DEF(SILVER) - db "SILVER@" - db "KAMON@" - db "OSCAR@" - db "MAX@" -ENDC - db 2, "NAME@" - -SelectPresetName: ; 6108 (1:6108) - call LoadMenuHeader - call VerticalMenu - ld a, [wMenuCursorY] - dec a - call CopyNameFromMenu - call CloseWindow - ret - -StorePlayerName: ; 6119 (1:6119) - ld hl, wStringBuffer2 - ld bc, NAME_LENGTH - call CopyBytes - ret - -ShrinkPlayer: ; 6123 (1:6123) - ldh a, [hROMBank] - push af - - ld a, 0 << 7 | 32 ; fade out - ld [wMusicFade], a - ld de, MUSIC_NONE - ld a, e - ld [wMusicFadeID], a - ld a, d - ld [wMusicFadeID + 1], a - - ld de, SFX_ESCAPE_ROPE - call PlaySFX - pop af - rst Bankswitch - - ld c, 8 - call DelayFrames - - ld hl, Shrink1Pic - ld b, BANK(Shrink1Pic) - call ShrinkFrame - - ld c, 8 - call DelayFrames - - ld hl, Shrink2Pic - ld b, BANK(Shrink2Pic) - call ShrinkFrame - - ld c, 8 - call DelayFrames - - hlcoord 6, 5 - ld b, 7 - ld c, 7 - call ClearBox - - ld c, 3 - call DelayFrames - - call Intro_PlacePlayerSprite - call LoadFontsExtra - - ld c, 50 - call DelayFrames - - call RotateThreePalettesRight - call ClearTilemap - ret - -MovePlayerPicRight: ; 617e (1:617e) - hlcoord 6, 4 - ld de, $1 - jr MovePlayerPic - -MovePlayerPicLeft: ; 6186 (1:6186) - hlcoord 13, 4 - ld de, -1 -MovePlayerPic - ld c, $8 -.asm_618e - push bc - push hl - push de - xor a - ldh [hBGMapMode], a - lb bc, 7, 7 - predef PlaceGraphic - xor a - ldh [hBGMapThird], a - call WaitBGMap - call DelayFrame - pop de - pop hl - add hl, de - pop bc - dec c - jr nz, .asm_618e - ret - -Intro_FadeInFrontpic: ; 61ad (1:61ad) - ld hl, IntroFadePalettes - ld b, $6 -.asm_61b2 - ld a, [hli] - call DmgToCgbBGPals - ld c, $a - call DelayFrames - dec b - jr nz, .asm_61b2 - ret - -IntroFadePalettes: - db %01010100 - db %10101000 - db %11111100 - db %11111000 - db %11110100 - db %11100100 - -Intro_WipeInFrontpic: ; 61c5 (1:61c5) - ld a, $77 - ldh [hWX], a - call DelayFrame - ld a, $e4 - call DmgToCgbBGPals -.asm_61d1 - call DelayFrame - ldh a, [hWX] - sub $8 - cp $ff - ret z - ldh [hWX], a - jr .asm_61d1 - -Intro_PrepTrainerPic: ; 61df, 61e0 (1:61df, 1:61e0) - ld de, $9000 - ld a, $14 - ld hl, $58a0 - rst FarCall - xor a - ldh [hGraphicStartTile], a - hlcoord 6, 4 - lb bc, 7, 7 - predef PlaceGraphic - ret - -ShrinkFrame: ; 61f7 (1:61f7) - ld de, $9000 - ld c, $31 - predef DecompressGet2bpp - xor a - ldh [hGraphicStartTile], a - hlcoord 6, 4 - lb bc, 7, 7 - predef PlaceGraphic - ret - -Intro_PlacePlayerSprite: ; 6210 (1:6210) - ld de, PlayerSpriteGFX - lb bc, BANK(PlayerSpriteGFX), 12 - ld hl, $8000 - call Request2bpp - ld hl, wVirtualOAM - ld de, .OAMData - ld a, [de] - inc de - ld c, a -.asm_6225 - ld a, [de] - inc de - ld [hli], a - ld a, [de] - inc de - ld [hli], a - ld a, [de] - inc de - ld [hli], a - xor a - ld [hli], a - dec c - jr nz, .asm_6225 - ret - -.OAMData - db 4 - db 9 * 8 + 4, 9 * 8, 0 - db 9 * 8 + 4, 10 * 8, 1 - db 10 * 8 + 4, 9 * 8, 2 - db 10 * 8 + 4, 10 * 8, 3 diff --git a/engine/math.asm b/engine/math/math.asm index cdac2d37..d5df3c34 100755 --- a/engine/math.asm +++ b/engine/math/math.asm @@ -1,11 +1,10 @@ -_Multiply:: ; 67bd - +_Multiply:: ; hMultiplier is one byte. ld a, 8 ld b, a xor a - ldh [hProduct], a + ldh [hMultiplicand - 1], a ldh [hMathBuffer + 1], a ldh [hMathBuffer + 2], a ldh [hMathBuffer + 3], a @@ -37,7 +36,7 @@ _Multiply:: ; 67bd ldh a, [hMathBuffer + 1] ld c, a - ldh a, [hProduct] + ldh a, [hMultiplicand - 1] adc c ldh [hMathBuffer + 1], a @@ -59,9 +58,9 @@ _Multiply:: ; 67bd rla ldh [hMultiplicand + 0], a - ldh a, [hProduct] + ldh a, [hMultiplicand - 1] rla - ldh [hProduct], a + ldh [hMultiplicand - 1], a jr .loop @@ -80,7 +79,7 @@ _Multiply:: ; 67bd ret -_Divide:: ; 681d +_Divide:: xor a ldh [hMathBuffer + 0], a ldh [hMathBuffer + 1], a @@ -173,18 +172,18 @@ _Divide:: ; 681d .done ldh a, [hDividend + 1] - ldh [hDivisor], a + ldh [hRemainder], a ldh a, [hMathBuffer + 4] - ldh [hDividend + 3], a + ldh [hQuotient + 3], a ldh a, [hMathBuffer + 3] - ldh [hDividend + 2], a + ldh [hQuotient + 2], a ldh a, [hMathBuffer + 2] - ldh [hDividend + 1], a + ldh [hQuotient + 1], a ldh a, [hMathBuffer + 1] - ldh [hDividend + 0], a + ldh [hQuotient + 0], a ret diff --git a/engine/math/sine.asm b/engine/math/sine.asm new file mode 100644 index 00000000..5db3bd60 --- /dev/null +++ b/engine/math/sine.asm @@ -0,0 +1,7 @@ +_Sine:: +; a = d * sin(e * pi/256) + ld a, e + calc_sine_wave .SineWave + +.SineWave: + sine_table $100 diff --git a/engine/menus/empty_sram.asm b/engine/menus/empty_sram.asm new file mode 100644 index 00000000..264f0813 --- /dev/null +++ b/engine/menus/empty_sram.asm @@ -0,0 +1,19 @@ +EmptyAllSRAMBanks: + ld a, 0 + call .EmptyBank + ld a, 1 + call .EmptyBank + ld a, 2 + call .EmptyBank + ld a, 3 + call .EmptyBank + ret + +.EmptyBank: + call OpenSRAM + ld hl, SRAM_Begin + ld bc, SRAM_End - SRAM_Begin + xor a + call ByteFill + call CloseSRAM + ret diff --git a/engine/menus/intro_menu.asm b/engine/menus/intro_menu.asm new file mode 100644 index 00000000..c85b56f6 --- /dev/null +++ b/engine/menus/intro_menu.asm @@ -0,0 +1,1133 @@ +MainMenu_NewGame: +NewGame: + xor a + ld [wDebugFlags], a + call ResetWRAM + call ClearTilemapEtc + call OakSpeech + call InitializeWorld + + ld a, SPAWN_HOME + ld [wDefaultSpawnpoint], a + + ld a, MAPSETUP_WARP + ldh [hMapEntryMethod], a + jp FinishContinueFunction + +ResetWRAM: + xor a + ldh [hBGMapMode], a + call _ResetWRAM + ret + +_ResetWRAM: + ld hl, wVirtualOAM + ld bc, wOptions - wVirtualOAM + xor a + call ByteFill + + ld hl, wGameData + ld bc, wGameDataEnd - wGameData + xor a + call ByteFill + + ldh a, [rLY] + ldh [hUnusedBackup], a + call DelayFrame + ldh a, [hRandomSub] + ld [wPlayerID], a + + ldh a, [rLY] + ldh [hUnusedBackup], a + call DelayFrame + ldh a, [hRandomAdd] + ld [wPlayerID + 1], a + + ld hl, wPartyCount + call .InitList + + xor a + ld [wCurBox], a + ld [wSavedAtLeastOnce], a + + call SetDefaultBoxNames + + ld a, BANK(sBoxCount) + call OpenSRAM + ld hl, sBoxCount + call .InitList + call CloseSRAM + + ld hl, wNumItems + call .InitList + + ld hl, wNumKeyItems + call .InitList + + ld hl, wNumBalls + call .InitList + + ld hl, wNumPCItems + call .InitList + + xor a + ld [wRoamMon1Species], a + ld [wRoamMon2Species], a + ld [wRoamMon3Species], a + ld a, -1 + ld [wRoamMon1MapGroup], a + ld [wRoamMon2MapGroup], a + ld [wRoamMon3MapGroup], a + ld [wRoamMon1MapNumber], a + ld [wRoamMon2MapNumber], a + ld [wRoamMon3MapNumber], a + + ld a, BANK(sMysteryGiftItem) + call OpenSRAM + ld hl, sMysteryGiftItem + xor a + ld [hli], a + dec a + ld [hl], a + call CloseSRAM + + call LoadOrRegenerateLuckyIDNumber + call InitializeMagikarpHouse + + xor a + ld [wMonType], a + + ld [wJohtoBadges], a + ld [wKantoBadges], a + + ld [wCoins], a + ld [wCoins + 1], a + +if START_MONEY >= $10000 + ld a, HIGH(START_MONEY >> 8) +endc + ld [wMoney], a + ld a, HIGH(START_MONEY) ; mid + ld [wMoney + 1], a + ld a, LOW(START_MONEY) + ld [wMoney + 2], a + + xor a + ld [wWhichMomItem], a + + ld hl, wMomItemTriggerBalance + ld [hl], HIGH(MOM_MONEY >> 8) + inc hl + ld [hl], HIGH(MOM_MONEY) ; mid + inc hl + ld [hl], LOW(MOM_MONEY) + + call InitializeNPCNames + + farcall InitDecorations + + farcall DeletePartyMonMail + + call ResetGameTime + ret + +.InitList: +; Loads 0 in the count and -1 in the first item or mon slot. + xor a + ld [hli], a + dec a + ld [hl], a + ret + +SetDefaultBoxNames: + ld hl, wBoxNames + ld c, 0 +.loop + push hl + ld de, .Box + call CopyName2 + dec hl + ld a, c + inc a + cp 10 + jr c, .less + sub 10 + ld [hl], "1" + inc hl + +.less + add "0" + ld [hli], a + ld [hl], "@" + pop hl + ld de, 9 + add hl, de + inc c + ld a, c + cp NUM_BOXES + jr c, .loop + ret + +.Box: + db "BOX@" + +InitializeMagikarpHouse: + ld hl, wBestMagikarpLengthFeet + ld a, $3 + ld [hli], a + ld a, $6 + ld [hli], a + ld de, .Ralph + call CopyName2 + ret + +.Ralph: + db "RALPH@" + +InitializeNPCNames: + ld hl, .Rival + ld de, wRivalName + call .Copy + + ld hl, .Mom + ld de, wMomsName + call .Copy + + ld hl, .Red + ld de, wRedsName + call .Copy + + ld hl, .Green + ld de, wGreensName + +.Copy: + ld bc, NAME_LENGTH + call CopyBytes + ret + +.Rival: db "???@" +.Red: db "RED@" +.Green: db "GREEN@" +.Mom: db "MOM@" + +InitializeWorld: + call ShrinkPlayer + farcall SpawnPlayer + farcall _InitializeStartDay + ret + +LoadOrRegenerateLuckyIDNumber: + ld a, BANK(sLuckyIDNumber) + call OpenSRAM + ld a, [wCurDay] + inc a + ld b, a + ld a, [sLuckyNumberDay] + cp b + ld a, [sLuckyIDNumber + 1] + ld c, a + ld a, [sLuckyIDNumber] + jr z, .skip + ld a, b + ld [sLuckyNumberDay], a + call Random + ld c, a + call Random + +.skip + ld [wLuckyIDNumber], a + ld [sLuckyIDNumber], a + ld a, c + ld [wLuckyIDNumber + 1], a + ld [sLuckyIDNumber + 1], a + jp CloseSRAM + +MainMenu_Continue: +Continue: + farcall TryLoadSaveFile + jr c, .FailToLoad + call LoadStandardMenuHeader + call DisplaySaveInfoOnContinue + ld a, $1 + ldh [hBGMapMode], a + ld c, 20 + call DelayFrames + call ConfirmContinue + jr nc, .Check1Pass + call CloseWindow + jr .FailToLoad + +.Check1Pass: + call Continue_CheckRTC_RestartClock + jr nc, .Check2Pass + call CloseWindow + jr .FailToLoad + +.Check2Pass: + ld a, $8 + ld [wMusicFade], a + ld a, LOW(MUSIC_NONE) + ld [wMusicFadeID], a + ld a, HIGH(MUSIC_NONE) + ld [wMusicFadeID + 1], a + call ClearBGPalettes + call CloseWindow + call ClearTilemap + ld c, 20 + call DelayFrames + farcall JumpRoamMons + farcall MysteryGift_CopyReceivedDecosToPC ; Mystery Gift + farcall ClockContinue + ld a, [wSpawnAfterChampion] + cp SPAWN_LANCE + jr z, .SpawnAfterE4 + ld a, MAPSETUP_CONTINUE + ldh [hMapEntryMethod], a + jp FinishContinueFunction + +.FailToLoad: + ret + +.SpawnAfterE4: + ld a, SPAWN_NEW_BARK + ld [wDefaultSpawnpoint], a + call PostCreditsSpawn + jp FinishContinueFunction + +SpawnAfterRed: + ld a, SPAWN_MT_SILVER + ld [wDefaultSpawnpoint], a + +PostCreditsSpawn: + xor a + ld [wSpawnAfterChampion], a + ld a, MAPSETUP_WARP + ldh [hMapEntryMethod], a + ret + +ConfirmContinue: +.loop + call DelayFrame + call GetJoypad + ld hl, hJoyPressed + bit A_BUTTON_F, [hl] + jr nz, .PressA + bit B_BUTTON_F, [hl] + jr z, .loop + scf + ret + +.PressA: + ret + +Continue_CheckRTC_RestartClock: + call CheckRTCStatus + and %10000000 ; Day count exceeded 16383 + jr z, .pass + farcall RestartClock + ld a, c + and a + jr z, .pass + scf + ret + +.pass + xor a + ret + +FinishContinueFunction: +.loop + xor a + ld [wDontPlayMapMusicOnReload], a + ld hl, wGameTimerPause + set GAMETIMERPAUSE_TIMER_PAUSED_F, [hl] + farcall OverworldLoop + ld a, [wSpawnAfterChampion] + cp SPAWN_RED + jr z, .AfterRed + jp Reset + +.AfterRed: + call SpawnAfterRed + jr .loop + +DisplaySaveInfoOnContinue: + call CheckRTCStatus + and %10000000 + jr z, .clock_ok + lb de, 4, 8 + call DisplayContinueDataWithRTCError + ret + +.clock_ok + lb de, 4, 8 + call DisplayNormalContinueData + ret + +DisplayNormalContinueData: + call Continue_LoadMenuHeader + call Continue_DisplayBadgesDex + call Continue_PrintGameTime + call LoadFontsExtra + call UpdateSprites + ret + +DisplayContinueDataWithRTCError: + call Continue_LoadMenuHeader + call Continue_DisplayBadgesDex + call Continue_UnknownGameTime + call LoadFontsExtra + call UpdateSprites + ret + +Continue_LoadMenuHeader: + xor a + ldh [hBGMapMode], a + ld hl, .MenuHeader_Dex + ld a, [wStatusFlags] + bit STATUSFLAGS_POKEDEX_F, a + jr nz, .show_menu + ld hl, .MenuHeader_NoDex + +.show_menu + call _OffsetMenuHeader + call MenuBox + call PlaceVerticalMenuItems + ret + +.MenuHeader_Dex: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 15, 9 + dw .MenuData_Dex + db 1 ; default option + +.MenuData_Dex: + db 0 ; flags + db 4 ; items + db "PLAYER <PLAYER>@" + db "BADGES@" + db "#DEX@" + db "TIME@" + +.MenuHeader_NoDex: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 15, 9 + dw .MenuData_NoDex + db 1 ; default option + +.MenuData_NoDex: + db 0 ; flags + db 4 ; items + db "PLAYER <PLAYER>@" + db "BADGES@" + db " @" + db "TIME@" + +Continue_DisplayBadgesDex: + call MenuBoxCoord2Tile + push hl + decoord 13, 4, 0 + add hl, de + call Continue_DisplayBadgeCount + pop hl + push hl + decoord 12, 6, 0 + add hl, de + call Continue_DisplayPokedexNumCaught + pop hl + ret + +Continue_PrintGameTime: + decoord 9, 8, 0 + add hl, de + call Continue_DisplayGameTime + ret + +Continue_UnknownGameTime: + decoord 9, 8, 0 + add hl, de + ld de, .three_question_marks + call PlaceString + ret + +.three_question_marks + db " ???@" + +Continue_DisplayBadgeCount: + push hl + ld hl, wJohtoBadges + ld b, 2 + call CountSetBits + pop hl + ld de, wNumSetBits + lb bc, 1, 2 + jp PrintNum + +Continue_DisplayPokedexNumCaught: + ld a, [wStatusFlags] + bit STATUSFLAGS_POKEDEX_F, a + ret z + push hl + ld hl, wPokedexCaught +if NUM_POKEMON % 8 + ld b, NUM_POKEMON / 8 + 1 +else + ld b, NUM_POKEMON / 8 +endc + call CountSetBits + pop hl + ld de, wNumSetBits + lb bc, 1, 3 + jp PrintNum + +Continue_DisplayGameTime: + ld de, wGameTimeHours + lb bc, 2, 3 + call PrintNum + ld [hl], "<COLON>" + inc hl + ld de, wGameTimeMinutes + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + jp PrintNum + +OakSpeech: + farcall InitClock + call RotateFourPalettesLeft + call ClearTilemap + + ld de, MUSIC_ROUTE_30 + call PlayMusic + + call RotateFourPalettesRight + call RotateThreePalettesRight + xor a + ld [wCurPartySpecies], a + ld a, POKEMON_PROF + ld [wTrainerClass], a + call Intro_PrepTrainerPic + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call Intro_RotatePalettesLeftFrontpic + + ld hl, OakText1 + call PrintText + call RotateThreePalettesRight + call ClearTilemap + + ld a, MARILL + ld [wCurSpecies], a + ld [wCurPartySpecies], a + call GetBaseData + + hlcoord 6, 4 + hlcoord 6, 4 ; TriHard + call PrepMonFrontpic + + xor a + ld [wTempMonDVs], a + ld [wTempMonDVs + 1], a + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call Intro_WipeInFrontpic + + ld hl, OakText2 + call PrintText + ld hl, OakText4 + call PrintText + call RotateThreePalettesRight + call ClearTilemap + + xor a + ld [wCurPartySpecies], a + ld a, POKEMON_PROF + ld [wTrainerClass], a + call Intro_PrepTrainerPic + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call Intro_RotatePalettesLeftFrontpic + + ld hl, OakText5 + call PrintText + call RotateThreePalettesRight + call ClearTilemap + + xor a + ld [wCurPartySpecies], a + ld a, CAL + ld [wTrainerClass], a + call Intro_PrepTrainerPic + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call Intro_RotatePalettesLeftFrontpic + + ld hl, OakText6 + call PrintText + call NamePlayer + ld hl, OakText7 + call PrintText + ret + +OakText1: + text_far _OakText1 + text_end + +OakText2: + text_far _OakText2 + text_asm + ld a, MARILL + call PlayMonCry + call WaitSFX + ld hl, OakText3 + ret + +OakText3: + text_far _OakText3 + text_end + +OakText4: + text_far _OakText4 + text_end + +OakText5: + text_far _OakText5 + text_end + +OakText6: + text_far _OakText6 + text_end + +OakText7: + text_far _OakText7 + text_end + +NamePlayer: + call MovePlayerPicRight + ld hl, NameMenuHeader + call ShowPlayerNamingChoices + ld a, [wMenuCursorY] + dec a + jr z, .NewName + ld de, wPlayerName + call StorePlayerName + farcall ApplyMonOrTrainerPals + call MovePlayerPicLeft + ret + +.NewName: + ld b, NAME_PLAYER + ld de, wPlayerName + farcall NamingScreen + + call RotateThreePalettesRight + call ClearTilemap + + call LoadFontsExtra + call WaitBGMap + + xor a + ld [wCurPartySpecies], a + ld a, CAL + ld [wTrainerClass], a + call Intro_PrepTrainerPic + + ld b, SCGB_TRAINER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + call RotateThreePalettesLeft + + ld hl, wPlayerName + ld de, PlayerNameArray + call InitName + ret + +INCLUDE "data/player_names.asm" + +ShowPlayerNamingChoices: + call LoadMenuHeader + call VerticalMenu + ld a, [wMenuCursorY] + dec a + call CopyNameFromMenu + call CloseWindow + ret + +StorePlayerName: + ld hl, wStringBuffer2 + ld bc, NAME_LENGTH + call CopyBytes + ret + +ShrinkPlayer: + ldh a, [hROMBank] + push af + + ld a, 32 ; fade time + ld [wMusicFade], a + ld de, MUSIC_NONE + ld a, e + ld [wMusicFadeID], a + ld a, d + ld [wMusicFadeID + 1], a + + ld de, SFX_ESCAPE_ROPE + call PlaySFX + pop af + rst Bankswitch + + ld c, 8 + call DelayFrames + + ld hl, Shrink1Pic + ld b, BANK(Shrink1Pic) + call ShrinkFrame + + ld c, 8 + call DelayFrames + + ld hl, Shrink2Pic + ld b, BANK(Shrink2Pic) + call ShrinkFrame + + ld c, 8 + call DelayFrames + + hlcoord 6, 5 + ld b, 7 + ld c, 7 + call ClearBox + + ld c, 3 + call DelayFrames + + call Intro_PlaceChrisSprite + call LoadFontsExtra + + ld c, 50 + call DelayFrames + + call RotateThreePalettesRight + call ClearTilemap + ret + +MovePlayerPicRight: + hlcoord 6, 4 + ld de, $1 + jr MovePlayerPic + +MovePlayerPicLeft: + hlcoord 13, 4 + ld de, -1 +MovePlayerPic: + ld c, $8 +.loop + push bc + push hl + push de + xor a + ldh [hBGMapMode], a + lb bc, 7, 7 + predef PlaceGraphic + xor a + ldh [hBGMapThird], a + call WaitBGMap + call DelayFrame + pop de + pop hl + add hl, de + pop bc + dec c + jr nz, .loop + ret + +Intro_RotatePalettesLeftFrontpic: + ld hl, IntroFadePalettes + ld b, IntroFadePalettes.End - IntroFadePalettes +.loop + ld a, [hli] + call DmgToCgbBGPals + ld c, 10 + call DelayFrames + dec b + jr nz, .loop + ret + +IntroFadePalettes: + dc 1, 1, 1, 0 + dc 2, 2, 2, 0 + dc 3, 3, 3, 0 + dc 3, 3, 2, 0 + dc 3, 3, 1, 0 + dc 3, 2, 1, 0 +.End + +Intro_WipeInFrontpic: + ld a, $77 + ldh [hWX], a + call DelayFrame + ld a, %11100100 + call DmgToCgbBGPals +.loop + call DelayFrame + ldh a, [hWX] + sub $8 + cp -1 + ret z + ldh [hWX], a + jr .loop + +Intro_PrepTrainerPic: + ld de, vTiles2 + farcall GetTrainerPic + xor a + ldh [hGraphicStartTile], a + hlcoord 6, 4 + lb bc, 7, 7 + predef PlaceGraphic + ret + +ShrinkFrame: + ld de, vTiles2 + ld c, 7 * 7 + predef DecompressGet2bpp + xor a + ldh [hGraphicStartTile], a + hlcoord 6, 4 + lb bc, 7, 7 + predef PlaceGraphic + ret + +Intro_PlaceChrisSprite: + ld de, ChrisSpriteGFX + lb bc, BANK(ChrisSpriteGFX), 12 + ld hl, vTiles0 + call Request2bpp + + ld hl, wVirtualOAMSprite00 + ld de, .sprites + ld a, [de] + inc de + + ld c, a +.loop + ld a, [de] + inc de + ld [hli], a ; y + ld a, [de] + inc de + ld [hli], a ; x + ld a, [de] + inc de + ld [hli], a ; tile id + xor a ; PAL_OW_RED + ld [hli], a + dec c + jr nz, .loop + ret + +.sprites + db 4 + ; y pxl, x pxl, tile offset + db 9 * 8 + 4, 9 * 8, 0 + db 9 * 8 + 4, 10 * 8, 1 + db 10 * 8 + 4, 9 * 8, 2 + db 10 * 8 + 4, 10 * 8, 3 + +IntroSequence: + callfar Copyright_GFPresents + jr c, StartTitleScreen + callfar GoldSilverIntro + + ; fallthrough + +StartTitleScreen: + call TitleScreen + call DelayFrame +.loop + call RunTitleScreen + jr nc, .loop + + call ClearSprites + call ClearBGPalettes + + ld hl, rLCDC + res rLCDC_SPRITE_SIZE, [hl] ; 8x8 + call ClearTilemap + xor a + ldh [hLCDCPointer], a + ld b, SCGB_DIPLOMA + call GetSGBLayout + call UpdateTimePals + ld a, [wIntroSceneFrameCounter] + cp $5 + jr c, .ok + xor a +.ok + 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 + +.dw + dw MainMenu + dw DeleteSaveData + dw IntroSequence + dw IntroSequence + dw ResetClock + +INCLUDE "engine/movie/title.asm" + +RunTitleScreen: + call Function63fe + ld a, [wJumptableIndex] + bit 7, a + jr nz, .done_title + call TitleScreenScene + ld a, $1 + ldh [hOAMUpdate], a + farcall PlaySpriteAnimations + xor a + ldh [hOAMUpdate], a + call Function64b1 + call DelayFrame + and a + ret + +.done_title + scf + ret + +Function63fe: +IF DEF(_GOLD) + ldh a, [hVBlankCounter] + and $7 + ret nz +ENDC + ld hl, wLYOverrides + $5f + ld a, [hl] + dec a + ld bc, 2 * SCREEN_WIDTH + call ByteFill + ret + +TitleScreenScene: + ld e, a + ld d, 0 + ld hl, .scenes + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.scenes + dw TitleScreenTimer + dw TitleScreenMain + dw TitleScreenEnd + +.Unreferenced_NextScene: + ld hl, wJumptableIndex + inc [hl] + ret + +TitleScreenTimer: +; Next scene + ld hl, wJumptableIndex + inc [hl] + +; Start a timer + ld hl, wTitleScreenTimer +IF DEF(_GOLD) + ld de, 84 * 60 + 16 +ELIF DEF(_SILVER) + ld de, 73 * 60 + 36 +ENDC + ld [hl], e + inc hl + ld [hl], d + ret + +TitleScreenMain: +; Run the timer down. + ld hl, wTitleScreenTimer + ld e, [hl] + inc hl + ld d, [hl] + ld a, e + or d + jr z, .end + + dec de + ld [hl], d + dec hl + ld [hl], e + +; Save data can be deleted by pressing Up + B + Select. + call GetJoypad + ld hl, hJoyDown + ld a, [hl] + and D_UP + B_BUTTON + SELECT + cp D_UP + B_BUTTON + SELECT + jr z, .delete_save_data + +; Clock can be reset by pressing Down + B + Select. + ld a, [hl] + and D_DOWN + B_BUTTON + SELECT + cp D_DOWN + B_BUTTON + SELECT + jr z, .clock_reset + ld a, [hl] + and START | A_BUTTON + jr nz, .incave + ret + +.incave + ld a, 0 + jr .done + +.delete_save_data + ld a, 1 + +.done + ld [wIntroSceneFrameCounter], a + +; Return to the intro sequence. + ld hl, wJumptableIndex + set 7, [hl] + ret + +.end +; Next scene + ld hl, wJumptableIndex + inc [hl] + +; Fade out the title screen music + xor a ; MUSIC_NONE + ld [wMusicFadeID], a + ld [wMusicFadeID + 1], a + ld hl, wMusicFade + ld [hl], 8 ; 1 second + + ld hl, wTitleScreenTimer + inc [hl] + ret + +.clock_reset + ld a, 4 + ld [wIntroSceneFrameCounter], a + +; Return to the intro sequence. + ld hl, wJumptableIndex + set 7, [hl] + ret + +TitleScreenEnd: +; Wait until the music is done fading. + + ld hl, wTitleScreenTimer + inc [hl] + + ld a, [wMusicFade] + and a + ret nz + + ld a, 2 + ld [wIntroSceneFrameCounter], a + +; Back to the intro. + ld hl, wJumptableIndex + set 7, [hl] + ret + +DeleteSaveData: + farcall _DeleteSaveData + jp Init + +ResetClock: + farcall _ResetClock + jp Init + +Function64b1: + ; If bit 0 or 1 of [wTitleScreenTimer] is set, we don't need to be here. + ld a, [wTitleScreenTimer] + and %00000011 + ret nz +IF DEF(_GOLD) + ld bc, wSpriteAnim10 + ld hl, SPRITEANIMSTRUCT_FRAME + add hl, bc + ld l, [hl] + ld h, 0 + add hl, hl + add hl, hl + ld de, .Data_64e0 + add hl, de + ; If bit 2 of [wTitleScreenTimer] is set, get the second dw; else, get the first dw + ld a, [wTitleScreenTimer] + and %00000100 + srl a + srl a + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + and a + ret z + ld e, a + ld d, [hl] +ELIF DEF(_SILVER) + depixel 15, 11, 4, 0 +ENDC + ld a, SPRITE_ANIM_INDEX_GS_TITLE_TRAIL + call InitSpriteAnimStruct + ret + +IF DEF(_GOLD) +.Data_64e0: +; frame 0 y, x; frame 1 y, x + db 11 * 8 + 4, 10 * 8, 0 * 8, 0 * 8 + db 11 * 8 + 4, 13 * 8, 11 * 8 + 4, 11 * 8 + db 11 * 8 + 4, 13 * 8, 11 * 8 + 4, 15 * 8 + db 11 * 8 + 4, 17 * 8, 11 * 8 + 4, 15 * 8 + db 0 * 8, 0 * 8, 11 * 8 + 4, 15 * 8 + db 0 * 8, 0 * 8, 11 * 8 + 4, 11 * 8 +ENDC + +Copyright: + call ClearTilemap + call LoadFontsExtra + ld de, CopyrightGFX + ld hl, vTiles2 tile $60 + lb bc, BANK(CopyrightGFX), 30 + call Request2bpp + hlcoord 2, 7 + ld de, CopyrightString + jp PlaceString + +CopyrightString: + ; ©1995-2000 Nintendo + db $60, $61, $62, $63, $7a, $7b, $7c, $7d + db $65, $66, $67, $68, $69, $6a + + ; ©1995-2000 Creatures inc. + next $60, $61, $62, $63, $7a, $7b, $7c, $7d + db $6b, $6c, $6d, $6e, $6f, $70, $71, $72 + + ; ©1995-2000 GAME FREAK inc. + next $60, $61, $62, $63, $7a, $7b, $7c, $7d + db $73, $74, $75, $76, $77, $78, $79, $71, $72 + + db "@" + +GameInit:: + call ClearWindowData + farcall TryLoadSaveData + jp IntroSequence diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm new file mode 100644 index 00000000..4e9113a8 --- /dev/null +++ b/engine/menus/main_menu.asm @@ -0,0 +1,253 @@ +MainMenu: + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + ld de, MUSIC_MAIN_MENU + ld a, e + ld [wMapMusic], a + call PlayMusic +.loop + xor a + ld [wDisableTextAcceleration], a + call ClearTilemapEtc + ld b, SCGB_DIPLOMA + call GetSGBLayout + ld hl, wGameTimerPause + res GAMETIMERPAUSE_TIMER_PAUSED_F, [hl] + call MainMenu_GetWhichMenu + ld [wWhichIndexSet], a + call MainMenu_PrintCurrentTimeAndDay + ld hl, .MenuHeader + call LoadMenuHeader + call MainMenuJoypadLoop + call CloseWindow + jr c, .quit + call ClearTilemap + ld a, [wMenuSelection] + ld hl, .Jumptable + rst JumpTable + jr .loop + +.quit + jp StartTitleScreen + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 14, 7 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR ; flags + db 0 ; items + dw MainMenuItems + dw PlaceMenuStrings + dw .Strings + +.Strings: + db "CONTINUE@" + db "NEW GAME@" + db "OPTION@" + db "MYSTERY GIFT@" + +.Jumptable: + dw MainMenu_Continue + dw MainMenu_NewGame + dw MainMenu_Options + dw MainMenu_MysteryGift + +CONTINUE EQU 0 +NEW_GAME EQU 1 +OPTION EQU 2 +MYSTERY_GIFT EQU 3 + +MainMenuItems: + +NewGameMenu: + db 2 + db NEW_GAME + db OPTION + db -1 + +ContinueMenu: + db 3 + db CONTINUE + db NEW_GAME + db OPTION + db -1 + +MysteryMenu: + db 4 + db CONTINUE + db NEW_GAME + db OPTION + db MYSTERY_GIFT + db -1 + +MainMenu_GetWhichMenu: + nop + nop + nop + ld a, [wSaveFileExists] + and a + jr nz, .next + ld a, $0 ; New Game + ret + +.next + ldh a, [hCGB] + cp $1 + ld a, $1 + ret nz + ld a, BANK(sNumDailyMysteryGiftPartnerIDs) + call OpenSRAM + ld a, [sNumDailyMysteryGiftPartnerIDs] + cp -1 + call CloseSRAM + ld a, $1 ; Continue + ret z + ld a, $2 ; New Game + ret + +MainMenuJoypadLoop: + call SetUpMenu +.loop + call MainMenu_PrintCurrentTimeAndDay + call GetScrollingMenuJoypad + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .b_button + cp A_BUTTON + jr z, .a_button + jr .loop + +.a_button + call PlayClickSFX + and a + ret + +.b_button + scf + ret + +MainMenu_PrintCurrentTimeAndDay: + ld a, [wSaveFileExists] + and a + ret z + xor a + ldh [hBGMapMode], a + call .PlaceBox + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call .PlaceTime + pop af + ld [wOptions], a + ld a, $1 + ldh [hBGMapMode], a + ret + +.PlaceBox: + call CheckRTCStatus + and $80 + jr nz, .TimeFail + hlcoord 0, 12 + ld b, 4 + ld c, 13 + call Textbox + ret + +.TimeFail: + call SpeechTextbox + ret + +.PlaceTime: + ld a, [wSaveFileExists] + and a + ret z + call CheckRTCStatus + and %10000000 ; Day count exceeded 16383 + jp nz, .PrintTimeNotSet + call UpdateTime + hlcoord 1, 13 + lb bc, 4, 13 + call ClearBox + call GetWeekday + ld b, a + decoord 1, 14 + call .PlaceCurrentDay + decoord 4, 16 + ldh a, [hHours] + ld c, a + farcall PrintHour + ld [hl], ":" + inc hl + ld de, hMinutes + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret + +.min +; unused + db "min.@" + +.PrintTimeNotSet: + hlcoord 1, 14 + ld de, .TimeNotSet + call PlaceString + ret + +.TimeNotSet: + db "TIME NOT SET@" + +.MainMenuTimeUnknownText: + text_far _MainMenuTimeUnknownText + text_end + +.PlaceCurrentDay: + push de + ld hl, .Days + ld a, b + call GetNthString + ld d, h + ld e, l + pop hl + call PlaceString + ld h, b + ld l, c + ld de, .Day + call PlaceString + ret + +.Days: + db "SUN@" + db "MON@" + db "TUES@" + db "WEDNES@" + db "THURS@" + db "FRI@" + db "SATUR@" +.Day: + db "DAY@" + +ClearTilemapEtc: + xor a + ldh [hMapAnims], a + call ClearTilemap + call LoadFontsExtra + call LoadStandardFont + call ClearWindowData + ret + +MainMenu_MysteryGift: +MysteryGift: + call UpdateTime + farcall DoMysteryGiftIfDayHasPassed + farcall DoMysteryGift + ret + +MainMenu_Options: +OptionsMenu: + farcall _OptionsMenu + ret diff --git a/engine/menus/menu.asm b/engine/menus/menu.asm new file mode 100644 index 00000000..b678d714 --- /dev/null +++ b/engine/menus/menu.asm @@ -0,0 +1,675 @@ +_2DMenu_:: + xor a + ldh [hBGMapMode], a + call MenuBox + call Place2DMenuItemStrings + call UpdateSprites + call ApplyTilemap + call Init2DMenuCursorPosition + call StaticMenuJoypad + call MenuClickSound + ld a, [wMenuDataFlags] + bit 1, a + jr z, .skip + call GetMenuJoypad + bit SELECT_F, a + jr nz, .quit1 + +.skip + ld a, [wMenuDataFlags] + bit 0, a + jr nz, .skip2 + call GetMenuJoypad + bit B_BUTTON_F, a + jr nz, .quit2 + +.skip2 + ld a, [w2DMenuNumCols] + ld c, a + ld a, [wMenuCursorY] + dec a + call SimpleMultiply + ld c, a + ld a, [wMenuCursorX] + add c + ld [wMenuCursorBuffer], a + and a + ret + +.quit1 + scf + ret + +.quit2 + scf + ret + +Get2DMenuNumberOfColumns: + ld a, [wMenuData_2DMenuDimensions] + and $f + ret + +Get2DMenuNumberOfRows: + ld a, [wMenuData_2DMenuDimensions] + swap a + and $f + ret + +Place2DMenuItemStrings: + ld hl, wMenuData_2DMenuItemStringsAddr + ld e, [hl] + inc hl + ld d, [hl] + call GetMenuTextStartCoord + call Coord2Tile + call Get2DMenuNumberOfRows + ld b, a +.row + push bc + push hl + call Get2DMenuNumberOfColumns + ld c, a +.col + push bc + ld a, [wMenuData_2DMenuItemStringsBank] + call Place2DMenuItemName + inc de + ld a, [wMenuData_2DMenuSpacing] + ld c, a + ld b, 0 + add hl, bc + pop bc + dec c + jr nz, .col + pop hl + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + ld hl, wMenuData_2DMenuFunctionAddr + ld a, [hli] + ld h, [hl] + ld l, a + or h + ret z + ld a, [wMenuData_2DMenuFunctionBank] + rst FarCall + ret + +Init2DMenuCursorPosition: + call GetMenuTextStartCoord + ld a, b + ld [w2DMenuCursorInitY], a + dec c + ld a, c + ld [w2DMenuCursorInitX], a + call Get2DMenuNumberOfRows + ld [w2DMenuNumRows], a + call Get2DMenuNumberOfColumns + ld [w2DMenuNumCols], a + call .InitFlags_a + call .InitFlags_b + call .InitFlags_c + ld a, [w2DMenuNumCols] + ld e, a + ld a, [wMenuCursorBuffer] + ld b, a + xor a + ld d, 0 +.loop + inc d + add e + cp b + jr c, .loop + sub e + ld c, a + ld a, b + sub c + and a + jr z, .reset1 + cp e + jr z, .okay1 + jr c, .okay1 +.reset1 + ld a, 1 +.okay1 + ld [wMenuCursorX], a + ld a, [w2DMenuNumRows] + ld e, a + ld a, d + and a + jr z, .reset2 + cp e + jr z, .okay2 + jr c, .okay2 +.reset2 + ld a, 1 +.okay2 + ld [wMenuCursorY], a + xor a + ld [wCursorOffCharacter], a + ld [wCursorCurrentTile], a + ld [wCursorCurrentTile + 1], a + ret + +.InitFlags_a: + xor a + ld hl, w2DMenuFlags1 + ld [hli], a + ld [hld], a + ld a, [wMenuDataFlags] + bit 5, a + ret z + set 5, [hl] + set 4, [hl] + ret + +.InitFlags_b: + ld a, [wMenuData_2DMenuSpacing] + or $20 + ld [w2DMenuCursorOffsets], a + ret + +.InitFlags_c: + ld hl, wMenuDataFlags + ld a, A_BUTTON + bit 0, [hl] + jr nz, .skip + or B_BUTTON +.skip + bit 1, [hl] + jr z, .skip2 + or SELECT +.skip2 + ld [wMenuJoypadFilter], a + ret + +_StaticMenuJoypad:: + call Place2DMenuCursor +_ScrollingMenuJoypad:: + ld hl, w2DMenuFlags2 + res 7, [hl] + ldh a, [hBGMapMode] + push af + +.menu_joypad_loop + call Move2DMenuCursor + ldh a, [hOAMUpdate] + push af + ld a, $1 + ldh [hOAMUpdate], a + call WaitBGMap + pop af + ldh [hOAMUpdate], a + xor a + ldh [hBGMapMode], a + +.loopRTC + call UpdateTimeAndPals + call Menu_WasButtonPressed + jr c, .pressed + ld a, [w2DMenuFlags1] + bit 7, a + jp nz, .done + jr .loopRTC + +.pressed + call _2DMenuInterpretJoypad + jp c, .done + ld a, [w2DMenuFlags1] + bit 7, a + jr nz, .done + call GetMenuJoypad + ld b, a + ld a, [wMenuJoypadFilter] + and b + jp z, .menu_joypad_loop + +.done + pop af + ldh [hBGMapMode], a + call GetMenuJoypad + ret + +Menu_WasButtonPressed: + ld a, [w2DMenuFlags1] + bit 6, a + jr z, .skip_to_joypad + callfar PlaySpriteAnimationsAndDelayFrame + +.skip_to_joypad + call JoyTextDelay + call GetMenuJoypad + and a + ret z + scf + ret + +_2DMenuInterpretJoypad: + call GetMenuJoypad + bit A_BUTTON_F, a + jp nz, .a_b_start_select + bit B_BUTTON_F, a + jp nz, .a_b_start_select + bit SELECT_F, a + jp nz, .a_b_start_select + bit START_F, a + jp nz, .a_b_start_select + bit D_RIGHT_F, a + jr nz, .d_right + bit D_LEFT_F, a + jr nz, .d_left + bit D_UP_F, a + jr nz, .d_up + bit D_DOWN_F, a + jr nz, .d_down + and a + ret + +.set_bit_7 + ld hl, w2DMenuFlags2 + set 7, [hl] + scf + ret + +.d_down + ld hl, wMenuCursorY + ld a, [w2DMenuNumRows] + cp [hl] + jr z, .check_wrap_around_down + inc [hl] + xor a + ret + +.check_wrap_around_down + ld a, [w2DMenuFlags1] + bit 5, a + jr nz, .wrap_around_down + bit 3, a + jp nz, .set_bit_7 + xor a + ret + +.wrap_around_down + ld [hl], $1 + xor a + ret + +.d_up + ld hl, wMenuCursorY + ld a, [hl] + dec a + jr z, .check_wrap_around_up + ld [hl], a + xor a + ret + +.check_wrap_around_up + ld a, [w2DMenuFlags1] + bit 5, a + jr nz, .wrap_around_up + bit 2, a + jp nz, .set_bit_7 + xor a + ret + +.wrap_around_up + ld a, [w2DMenuNumRows] + ld [hl], a + xor a + ret + +.d_left + ld hl, wMenuCursorX + ld a, [hl] + dec a + jr z, .check_wrap_around_left + ld [hl], a + xor a + ret + +.check_wrap_around_left + ld a, [w2DMenuFlags1] + bit 4, a + jr nz, .wrap_around_left + bit 1, a + jp nz, .set_bit_7 + xor a + ret + +.wrap_around_left + ld a, [w2DMenuNumCols] + ld [hl], a + xor a + ret + +.d_right + ld hl, wMenuCursorX + ld a, [w2DMenuNumCols] + cp [hl] + jr z, .check_wrap_around_right + inc [hl] + xor a + ret + +.check_wrap_around_right + ld a, [w2DMenuFlags1] + bit 4, a + jr nz, .wrap_around_right + bit 0, a + jp nz, .set_bit_7 + xor a + ret + +.wrap_around_right + ld [hl], $1 + xor a + ret + +.a_b_start_select + xor a + ret + +Move2DMenuCursor: + ld hl, wCursorCurrentTile + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [hl] + cp "▶" + jr nz, Place2DMenuCursor + ld a, [wCursorOffCharacter] + ld [hl], a +Place2DMenuCursor: + ld a, [w2DMenuCursorInitY] + ld b, a + ld a, [w2DMenuCursorInitX] + ld c, a + call Coord2Tile + ld a, [w2DMenuCursorOffsets] + swap a + and $f + ld c, a + ld a, [wMenuCursorY] + ld b, a + xor a + dec b + jr z, .got_row +.row_loop + add c + dec b + jr nz, .row_loop + +.got_row + ld c, SCREEN_WIDTH + call AddNTimes + ld a, [w2DMenuCursorOffsets] + and $f + ld c, a + ld a, [wMenuCursorX] + ld b, a + xor a + dec b + jr z, .got_col +.col_loop + add c + dec b + jr nz, .col_loop + +.got_col + ld c, a + add hl, bc + ld a, [hl] + cp "▶" + jr z, .cursor_on + ld [wCursorOffCharacter], a + ld [hl], "▶" + +.cursor_on + ld a, l + ld [wCursorCurrentTile], a + ld a, h + ld [wCursorCurrentTile + 1], a + ret + +_PushWindow:: + xor a ; BANK(sWindowStack) + call OpenSRAM + + ld hl, wWindowStackPointer + ld e, [hl] + inc hl + ld d, [hl] + push de + ld b, $10 + ld hl, wMenuFlags +.loop + ld a, [hli] + ld [de], a + dec de + dec b + jr nz, .loop + +; If bit 6 or 7 of the menu flags is set, set bit 0 of the address +; at 7:[wWindowStackPointer], and draw the menu using the coordinates from the header. +; Otherwise, reset bit 0 of 7:[wWindowStackPointer]. + ld a, [wMenuFlags] + bit 6, a + jr nz, .bit_6 + bit 7, a + jr z, .not_bit_7 + +.bit_6 + ld hl, wWindowStackPointer + ld a, [hli] + ld h, [hl] + ld l, a + set 0, [hl] + call MenuBoxCoord2Tile + call GetMenuBoxDims + inc b + inc c + call .ret ; empty function + +.row + push bc + push hl + +.col + ld a, [hli] + ld [de], a + dec de + dec c + jr nz, .col + + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + jr .done + +.not_bit_7 + pop hl ; last-pushed register was de + push hl + ld a, [hld] + ld l, [hl] + ld h, a + res 0, [hl] + +.done + pop hl + call .ret ; empty function + ld a, h + ld [de], a + dec de + ld a, l + ld [de], a + dec de + ld hl, wWindowStackPointer + ld [hl], e + inc hl + ld [hl], d + + call CloseSRAM + ld hl, wWindowStackSize + inc [hl] + ret + +.ret + ret + +_ExitMenu:: + xor a + ldh [hBGMapMode], a + + xor a ; BANK(sWindowStack) + call OpenSRAM + + call GetWindowStackTop + ld a, l + or h + jp z, Error_Cant_ExitMenu + ld a, l + ld [wWindowStackPointer], a + ld a, h + ld [wWindowStackPointer + 1], a + call PopWindow + ld a, [wMenuFlags] + bit 0, a + jr z, .loop + ld d, h + ld e, l + call RestoreTileBackup + +.loop + call GetWindowStackTop + ld a, h + or l + jr z, .done + call PopWindow + +.done + call CloseSRAM + ld hl, wWindowStackSize + dec [hl] + call Function2434b + ld a, [wSpriteUpdatesEnabled] + cp 0 + ret z + call ReloadPalettes + ret + +Function2434b: + ld a, [wVramState] + bit 0, a + ret z + xor a ; sScratch + call OpenSRAM + hlcoord 0, 0 + ld de, sScratch + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call CopyBytes + call CloseSRAM + call OverworldTextModeSwitch + xor a ; sScratch + call OpenSRAM + ld hl, sScratch + decoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT +.loop + ld a, [hl] + cp $61 + jr c, .next + ld [de], a +.next + inc hl + inc de + dec bc + ld a, c + or b + jr nz, .loop + call CloseSRAM + ret + +Error_Cant_ExitMenu: + ld hl, .WindowPoppingErrorText + call PrintText + call WaitBGMap +.infinite_loop + jr .infinite_loop + +.WindowPoppingErrorText: + text_far _WindowPoppingErrorText + text_end + +_InitVerticalMenuCursor:: + ld a, [wMenuDataFlags] + ld b, a + ld hl, w2DMenuCursorInitY + ld a, [wMenuBorderTopCoord] + inc a + bit 6, b + jr nz, .skip_offset + inc a +.skip_offset + ld [hli], a +; w2DMenuCursorInitX + ld a, [wMenuBorderLeftCoord] + inc a + ld [hli], a +; w2DMenuNumRows + ld a, [wMenuDataItems] + ld [hli], a +; w2DMenuNumCols + ld a, 1 + ld [hli], a +; w2DMenuFlags1 + ld [hl], $0 + bit 5, b + jr z, .skip_bit_5 + set 5, [hl] +.skip_bit_5 + ld a, [wMenuFlags] + bit 4, a + jr z, .skip_bit_6 + set 6, [hl] +.skip_bit_6 + inc hl +; w2DMenuFlags2 + xor a + ld [hli], a +; w2DMenuCursorOffsets + ln a, 2, 0 + ld [hli], a +; wMenuJoypadFilter + ld a, A_BUTTON + bit 0, b + jr nz, .skip_bit_1 + add B_BUTTON +.skip_bit_1 + ld [hli], a +; wMenuCursorY + ld a, [wMenuCursorBuffer] + and a + jr z, .load_at_the_top + ld c, a + ld a, [wMenuDataItems] + cp c + jr nc, .load_position +.load_at_the_top + ld c, 1 +.load_position + ld [hl], c + inc hl +; wMenuCursorX + ld a, 1 + ld [hli], a +; wCursorOffCharacter, wCursorCurrentTile + xor a + ld [hli], a + ld [hli], a + ld [hli], a + ret diff --git a/engine/menus/menu_2.asm b/engine/menus/menu_2.asm new file mode 100644 index 00000000..2fd65e2b --- /dev/null +++ b/engine/menus/menu_2.asm @@ -0,0 +1,298 @@ +PlaceMenuItemName: + push de + ld a, [wMenuSelection] + ld [wNamedObjectIndexBuffer], a + call GetItemName + pop hl + call PlaceString + ret + +PlaceMenuItemQuantity: + push de + ld a, [wMenuSelection] + ld [wCurItem], a + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + pop hl + and a + jr nz, .done + ld de, $15 + add hl, de + ld [hl], "×" + inc hl + ld de, wMenuSelectionQuantity + lb bc, 1, 2 + call PrintNum + +.done + ret + +PlaceMoneyTopRight: + ld hl, MenuHeader_0x24a3d + call CopyMenuHeader + jr PlaceMoneyTextbox + +PlaceMoneyBottomLeft: + ld hl, MenuHeader_0x24a45 + call CopyMenuHeader + jr PlaceMoneyTextbox + +PlaceMoneyAtTopLeftOfTextbox: + ld hl, MenuHeader_0x24a3d + lb de, 0, 11 + call OffsetMenuHeader + +PlaceMoneyTextbox: + call MenuBox + call MenuBoxCoord2Tile + ld de, SCREEN_WIDTH + 1 + add hl, de + ld de, wMoney + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + ret + +MenuHeader_0x24a3d: + db MENU_BACKUP_TILES ; flags + menu_coords 11, 0, SCREEN_WIDTH - 1, 2 + dw NULL + db 1 ; default option + +MenuHeader_0x24a45: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 11, 8, 13 + dw NULL + db 1 ; default option + +DisplayCoinCaseBalance: + ; Place a text box of size 1x7 at 11, 0. + hlcoord 11, 0 + ld b, 1 + ld c, 7 + call Textbox + hlcoord 12, 0 + ld de, CoinString + call PlaceString + hlcoord 17, 1 + ld de, ShowMoney_TerminatorString + call PlaceString + ld de, wCoins + lb bc, 2, 4 + hlcoord 13, 1 + call PrintNum + ret + +DisplayMoneyAndCoinBalance: + hlcoord 5, 0 + ld b, 3 + ld c, 13 + call Textbox + hlcoord 6, 1 + ld de, MoneyString + call PlaceString + hlcoord 12, 1 + ld de, wMoney + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + hlcoord 6, 3 + ld de, CoinString + call PlaceString + hlcoord 15, 3 + ld de, wCoins + lb bc, 2, 4 + call PrintNum + ret + +MoneyString: + db "MONEY@" +CoinString: + db "COIN@" +ShowMoney_TerminatorString: + db "@@" + +Unreferenced_Function24ab8: +; related to safari? + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + hlcoord 0, 0 + ld b, 3 + ld c, 7 + call Textbox + hlcoord 1, 1 + ld de, wSafariTimeRemaining + lb bc, 2, 3 + call PrintNum + hlcoord 4, 1 + ld de, .slash_500 + call PlaceString + hlcoord 1, 3 + ld de, .booru_ko + call PlaceString + hlcoord 5, 3 + ld de, wSafariBallsRemaining + lb bc, 1, 2 + call PrintNum + pop af + ld [wOptions], a + ret + +.slash_500 + db "/500@" +.booru_ko + db "ボール こ@" + +StartMenu_DrawBugContestStatusBox: + hlcoord 0, 0 + ld b, 5 + ld c, 17 + call Textbox + ret + +StartMenu_PrintBugContestStatus: + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call StartMenu_DrawBugContestStatusBox + hlcoord 1, 5 + ld de, .Balls_EN + call PlaceString + hlcoord 8, 5 + ld de, wParkBallsRemaining + lb bc, PRINTNUM_LEFTALIGN | 1, 2 + call PrintNum + hlcoord 1, 1 + ld de, .CAUGHT + call PlaceString + ld a, [wContestMon] + and a + ld de, .None + jr z, .no_contest_mon + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + +.no_contest_mon + hlcoord 8, 1 + call PlaceString + ld a, [wContestMon] + and a + jr z, .skip_level + hlcoord 1, 3 + ld de, .LEVEL + call PlaceString + ld a, [wContestMonLevel] + ld h, b + ld l, c + inc hl + ld c, 3 + call Print8BitNumLeftAlign + +.skip_level + pop af + ld [wOptions], a + ret + +.Balls_JP: + db "ボール こ@" +.CAUGHT: + db "CAUGHT@" +.Balls_EN: + db "BALLS:@" +.None: + db "None@" +.LEVEL: + db "LEVEL@" + +Kurt_SelectApricorn: + call FindApricornsInBag + jr c, .nope + ld hl, .MenuHeader + call LoadMenuHeader + call DoNthMenu + call CloseWindow + jr c, .nope + ld a, [wMenuSelection] + jr .done + +.nope + xor a ; FALSE + +.done + ld c, a + ret + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 14, 17 + dw .MenuData + db 1 ; default option + +.MenuData: + db SCROLLINGMENU_ENABLE_SELECT | SCROLLINGMENU_ENABLE_FUNCTION3 + dbw 0, wBuffer1 + dw .Name + dw NULL + +.Name: + ld a, [wMenuSelection] + and a + jp nz, PlaceMenuItemName + ld h, d + ld l, e + ld de, .Cancel + call PlaceString + ret + +.Cancel + db "CANCEL@" + +FindApricornsInBag: +; Checks the bag for Apricorns. + ld hl, wBuffer1 + xor a + ld [hli], a + dec a + ld bc, 10 + call ByteFill + + ld hl, ApricornBalls +.loop + ld a, [hl] + cp -1 + jr z, .done + push hl + ld [wCurItem], a + ld hl, wNumItems + call CheckItem + pop hl + jr nc, .nope + ld a, [hl] + call .addtobuffer +.nope + inc hl + inc hl + jr .loop + +.done + xor a + call .addtobuffer + ld a, [wBuffer1] + cp 1 + ret nz + scf + ret + +.addtobuffer + push hl + ld hl, wBuffer1 + inc [hl] + ld e, [hl] + ld d, 0 + add hl, de + ld [hl], a + pop hl + ret + +INCLUDE "data/items/apricorn_balls.asm" diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm new file mode 100644 index 00000000..34e2c6f2 --- /dev/null +++ b/engine/menus/naming_screen.asm @@ -0,0 +1,1377 @@ +NAMINGSCREEN_CURSOR EQU $7e + +NAMINGSCREEN_BORDER EQU "■" ; $60 +NAMINGSCREEN_MIDDLELINE EQU "→" ; $eb +NAMINGSCREEN_UNDERLINE EQU "<DOT>" ; $f2 + +_NamingScreen: + call DisableSpriteUpdates + call NamingScreen + call ReturnToMapWithSpeechTextbox + ret + +NamingScreen: + ld hl, wNamingScreenDestinationPointer + ld [hl], e + inc hl + ld [hl], d + ld hl, wNamingScreenType + ld [hl], b + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + ldh a, [hMapAnims] + push af + xor a + ldh [hMapAnims], a + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + call .SetUpNamingScreen + call DelayFrame +.loop + call NamingScreenJoypadLoop + jr nc, .loop + pop af + ldh [hInMenu], a + pop af + ldh [hMapAnims], a + pop af + ld [wOptions], a + call ClearJoypad + ret + +.SetUpNamingScreen: + call ClearBGPalettes + ld b, SCGB_DIPLOMA + call GetSGBLayout + call DisableLCD + call LoadNamingScreenGFX + call NamingScreen_InitText + ld a, LCDC_DEFAULT + ldh [rLCDC], a + call .GetNamingScreenSetup + call WaitBGMap + call WaitTop + call SetPalettes + call NamingScreen_InitNameEntry + ret + +.GetNamingScreenSetup: + ld a, [wNamingScreenType] + maskbits NUM_NAME_TYPES + 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 + +.Jumptable: +; entries correspond to NAME_* constants + dw .Pokemon + dw .Player + dw .Rival + dw .Mom + dw .Box + dw .Pokemon + dw .Pokemon + dw .Pokemon + +.Pokemon: + ld a, [wCurPartySpecies] + ld [wTempIconSpecies], a + ld hl, LoadMenuMonIcon + ld a, BANK(LoadMenuMonIcon) + ld e, MONICON_NAMINGSCREEN + rst FarCall + ld a, [wCurPartySpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + hlcoord 5, 2 + call PlaceString + ld l, c + ld h, b + ld de, .NicknameStrings + call PlaceString + inc de + hlcoord 5, 4 + call PlaceString + farcall GetGender + jr c, .genderless + ld a, "♂" + jr nz, .place_gender + ld a, "♀" +.place_gender + hlcoord 1, 2 + ld [hl], a +.genderless + call .StoreMonIconParams + ret + +.NicknameStrings: + db "'S@" + db "NICKNAME?@" + +.Player: + ld de, ChrisSpriteGFX + call .LoadSprite + hlcoord 5, 2 + ld de, .PlayerNameString + call PlaceString + call .StoreSpriteIconParams + ret + +.PlayerNameString: + db "YOUR NAME?@" + +.Rival: + ld de, SilverSpriteGFX + call .LoadSprite + hlcoord 5, 2 + ld de, .RivalNameString + call PlaceString + call .StoreSpriteIconParams + ret + +.RivalNameString: + db "RIVAL'S NAME?@" + +.Mom: + ld de, MomSpriteGFX + call .LoadSprite + hlcoord 5, 2 + ld de, .MomNameString + call PlaceString + call .StoreSpriteIconParams + ret + +.MomNameString: + db "MOTHER'S NAME?@" + +.Box: + ld de, PokeBallSpriteGFX + ld hl, vTiles0 tile $00 + lb bc, BANK(PokeBallSpriteGFX), 4 + call Request2bpp + xor a + ld hl, wSpriteAnimDict + ld [hli], a + ld [hl], a + depixel 4, 4, 4, 0 + ld a, SPRITE_ANIM_INDEX_RED_WALK + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], $0 + hlcoord 5, 2 + ld de, .BoxNameString + call PlaceString + call .StoreBoxIconParams + ret + +.BoxNameString: + db "BOX NAME?@" + +.LoadSprite: + push de + ld hl, vTiles0 tile $00 + lb bc, BANK(ChrisSpriteGFX), 4 + call Request2bpp + pop de + ld hl, 12 tiles + add hl, de + ld e, l + ld d, h + ld hl, vTiles0 tile $04 + lb bc, BANK(ChrisSpriteGFX), 4 + call Request2bpp + xor a + ld hl, wSpriteAnimDict + ld [hli], a + ld [hl], a + lb de, $24, $20 + ld a, SPRITE_ANIM_INDEX_RED_WALK + call InitSpriteAnimStruct + ret + +.StoreMonIconParams: + ld a, MON_NAME_LENGTH - 1 + hlcoord 5, 6 + jr .StoreParams + +.StoreSpriteIconParams: + ld a, PLAYER_NAME_LENGTH - 1 + hlcoord 5, 6 + jr .StoreParams + +.StoreBoxIconParams: + ld a, BOX_NAME_LENGTH - 1 + hlcoord 5, 4 + jr .StoreParams + +.StoreParams: + ld [wNamingScreenMaxNameLength], a + ld a, l + ld [wNamingScreenStringEntryCoord], a + ld a, h + ld [wNamingScreenStringEntryCoord + 1], a + ret + +NamingScreen_IsTargetBox: + push bc + push af + ld a, [wNamingScreenType] + sub $3 + ld b, a + pop af + dec b + pop bc + ret + +NamingScreen_InitText: + call WaitTop + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, NAMINGSCREEN_BORDER + call ByteFill + hlcoord 1, 1 + lb bc, 6, 18 + call NamingScreen_IsTargetBox + jr nz, .not_box + lb bc, 4, 18 + +.not_box + call ClearBox + ld de, NameInputUpper +NamingScreen_ApplyTextInputMode: + call NamingScreen_IsTargetBox + jr nz, .not_box + ld hl, BoxNameInputLower - NameInputLower + add hl, de + ld d, h + ld e, l + +.not_box + push de + hlcoord 1, 8 + lb bc, 7, 18 + call NamingScreen_IsTargetBox + jr nz, .not_box_2 + hlcoord 1, 6 + lb bc, 9, 18 + +.not_box_2 + call ClearBox + hlcoord 1, 16 + lb bc, 1, 18 + call ClearBox + pop de + hlcoord 2, 8 + ld b, $5 + call NamingScreen_IsTargetBox + jr nz, .row + hlcoord 2, 6 + ld b, $6 + +.row + ld c, $11 +.col + ld a, [de] + ld [hli], a + inc de + dec c + jr nz, .col + push de + ld de, 2 * SCREEN_WIDTH - $11 + add hl, de + pop de + dec b + jr nz, .row + ret + +NamingScreenJoypadLoop: + call JoyTextDelay + ld a, [wJumptableIndex] + bit 7, a + jr nz, .quit + call .RunJumptable + farcall PlaySpriteAnimationsAndDelayFrame + call .UpdateStringEntry + call DelayFrame + and a + ret + +.quit + callfar ClearSpriteAnims + call ClearSprites + xor a + ldh [hSCX], a + ldh [hSCY], a + scf + ret + +.UpdateStringEntry: + xor a + ldh [hBGMapMode], a + hlcoord 1, 5 + call NamingScreen_IsTargetBox + jr nz, .got_coords + hlcoord 1, 3 + +.got_coords + lb bc, 1, 18 + call ClearBox + ld hl, wNamingScreenDestinationPointer + ld e, [hl] + inc hl + ld d, [hl] + ld hl, wNamingScreenStringEntryCoord + ld a, [hli] + ld h, [hl] + ld l, a + call PlaceString + ld a, $1 + ldh [hBGMapMode], a + ret + +.RunJumptable: + 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 + +.Jumptable: + dw .InitCursor + dw .ReadButtons + +.InitCursor: + depixel 10, 3 + call NamingScreen_IsTargetBox + jr nz, .got_cursor_position + ld d, 8 * 8 +.got_cursor_position + ld a, SPRITE_ANIM_INDEX_NAMING_SCREEN_CURSOR + call InitSpriteAnimStruct + ld a, c + ld [wNamingScreenCursorObjectPointer], a + ld a, b + ld [wNamingScreenCursorObjectPointer + 1], a + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + ld [hl], a + ld hl, wJumptableIndex + inc [hl] + ret + +.ReadButtons: + ld hl, hJoyPressed + ld a, [hl] + and A_BUTTON + jr nz, .a + ld a, [hl] + and B_BUTTON + jr nz, .b + ld a, [hl] + and START + jr nz, .start + ld a, [hl] + and SELECT + jr nz, .select + ret + +.a + call .GetCursorPosition + cp $1 + jr z, .select + cp $2 + jr z, .b + cp $3 + jr z, .end + call NamingScreen_GetLastCharacter + call NamingScreen_TryAddCharacter + ret nc + +.start + ld hl, wNamingScreenCursorObjectPointer + ld c, [hl] + inc hl + ld b, [hl] + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], $8 + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld [hl], $4 + call NamingScreen_IsTargetBox + ret nz + inc [hl] + ret + +.b + call NamingScreen_DeleteCharacter + ret + +.end + call NamingScreen_StoreEntry + ld hl, wJumptableIndex + set 7, [hl] + ret + +.select + ld hl, wNamingScreenLetterCase + ld a, [hl] + xor 1 + ld [hl], a + jr z, .upper + ld de, NameInputLower + call NamingScreen_ApplyTextInputMode + ret + +.upper + ld de, NameInputUpper + call NamingScreen_ApplyTextInputMode + ret + +.GetCursorPosition: + ld hl, wNamingScreenCursorObjectPointer + ld c, [hl] + inc hl + ld b, [hl] + +NamingScreen_GetCursorPosition: + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + push bc + ld b, $4 + call NamingScreen_IsTargetBox + jr nz, .not_box + inc b +.not_box + cp b + pop bc + jr nz, .not_bottom_row + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + cp $3 + jr c, .case_switch + cp $6 + jr c, .delete + ld a, $3 + ret + +.case_switch + ld a, $1 + ret + +.delete + ld a, $2 + ret + +.not_bottom_row + xor a + ret + +NamingScreen_AnimateCursor: + call .GetDPad + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + ld e, a + swap e + ld hl, SPRITEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], e + ld d, $4 + call NamingScreen_IsTargetBox + jr nz, .ok + inc d +.ok + cp d + ld de, .LetterEntries + ld a, SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR - SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR ; 0 + jr nz, .ok2 + ld de, .CaseDelEnd + ld a, SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR_BIG - SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR ; 1 +.ok2 + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + add [hl] ; default SPRITE_ANIM_FRAMESET_TEXT_ENTRY_CURSOR + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], a + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld l, [hl] + ld h, $0 + add hl, de + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.LetterEntries: + db $00, $10, $20, $30, $40, $50, $60, $70, $80 + +.CaseDelEnd: + db $00, $00, $00, $30, $30, $30, $60, $60, $60 + +.GetDPad: + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .up + ld a, [hl] + and D_DOWN + jr nz, .down + ld a, [hl] + and D_LEFT + jr nz, .left + ld a, [hl] + and D_RIGHT + jr nz, .right + ret + +.right + call NamingScreen_GetCursorPosition + and a + jr nz, .asm_11e76 + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + cp $8 + jr nc, .asm_11e73 + inc [hl] + ret + +.asm_11e73 + ld [hl], $0 + ret + +.asm_11e76 + cp $3 + jr nz, .asm_11e7b + xor a +.asm_11e7b + ld e, a + add a + add e + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], a + ret + +.left + call NamingScreen_GetCursorPosition + and a + jr nz, .asm_11e97 + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + and a + jr z, .asm_11e94 + dec [hl] + ret + +.asm_11e94 + ld [hl], $8 + ret + +.asm_11e97 + cp $1 + jr nz, .asm_11e9d + ld a, $4 +.asm_11e9d + dec a + dec a + ld e, a + add a + add e + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], a + ret + +.down + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + call NamingScreen_IsTargetBox + jr nz, .asm_11eb8 + cp $5 + jr nc, .asm_11ebe + inc [hl] + ret + +.asm_11eb8 + cp $4 + jr nc, .asm_11ebe + inc [hl] + ret + +.asm_11ebe + ld [hl], $0 + ret + +.up + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + and a + jr z, .asm_11ecb + dec [hl] + ret + +.asm_11ecb + ld [hl], $4 + call NamingScreen_IsTargetBox + ret nz + inc [hl] + ret + +NamingScreen_TryAddCharacter: + ld a, [wNamingScreenLastCharacter] + ld hl, Dakutens + cp "゙" ; $e5 + jr z, asm_11f06 + ld hl, Handakutens + cp "゚" ; $e4 + jr z, asm_11f06 + +MailComposition_TryAddCharacter: + ld a, [wNamingScreenMaxNameLength] + ld c, a + ld a, [wNamingScreenCurNameLength] + cp c + ret nc + + ld a, [wNamingScreenLastCharacter] + +NamingScreen_LoadNextCharacter: + call NamingScreen_GetTextCursorPosition + ld [hl], a + +NamingScreen_AdvanceCursor_CheckEndOfString: + ld hl, wNamingScreenCurNameLength + inc [hl] + call NamingScreen_GetTextCursorPosition + ld a, [hl] + cp "@" + jr z, .end_of_string + ld [hl], NAMINGSCREEN_UNDERLINE + and a + ret + +.end_of_string + scf + ret + +asm_11f06: + ld a, [wNamingScreenCurNameLength] + and a + ret z + push hl + ld hl, wNamingScreenCurNameLength + dec [hl] + call NamingScreen_GetTextCursorPosition + ld c, [hl] + pop hl + +.loop + ld a, [hli] + cp $ff + jr z, NamingScreen_AdvanceCursor_CheckEndOfString + cp c + jr z, .done + inc hl + jr .loop + +.done + ld a, [hl] + jr NamingScreen_LoadNextCharacter + +INCLUDE "data/text/dakutens.asm" + +NamingScreen_DeleteCharacter: + ld hl, wNamingScreenCurNameLength + ld a, [hl] + and a + ret z + dec [hl] + call NamingScreen_GetTextCursorPosition + ld [hl], NAMINGSCREEN_UNDERLINE + inc hl + ld a, [hl] + cp NAMINGSCREEN_UNDERLINE + ret nz + ld [hl], NAMINGSCREEN_MIDDLELINE + ret + +NamingScreen_GetTextCursorPosition: + push af + ld hl, wNamingScreenDestinationPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wNamingScreenCurNameLength] + ld e, a + ld d, 0 + add hl, de + pop af + ret + +NamingScreen_InitNameEntry: +; load NAMINGSCREEN_UNDERLINE, (NAMINGSCREEN_MIDDLELINE * [wNamingScreenMaxNameLength]), "@" into the dw address at wNamingScreenDestinationPointer + ld hl, wNamingScreenDestinationPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld [hl], NAMINGSCREEN_UNDERLINE + inc hl + ld a, [wNamingScreenMaxNameLength] + dec a + ld c, a + ld a, NAMINGSCREEN_MIDDLELINE +.loop + ld [hli], a + dec c + jr nz, .loop + ld [hl], "@" + ret + +NamingScreen_StoreEntry: + ld hl, wNamingScreenDestinationPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wNamingScreenMaxNameLength] + ld c, a +.loop + ld a, [hl] + cp NAMINGSCREEN_MIDDLELINE + jr z, .terminator + cp NAMINGSCREEN_UNDERLINE + jr nz, .not_terminator +.terminator + ld [hl], "@" +.not_terminator + inc hl + dec c + jr nz, .loop + ret + +NamingScreen_GetLastCharacter: + ld hl, wNamingScreenCursorObjectPointer + ld c, [hl] + inc hl + ld b, [hl] + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + sub $8 + srl a + srl a + srl a + ld e, a + ld hl, SPRITEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + add [hl] + sub $10 + srl a + srl a + srl a + ld d, a + hlcoord 0, 0 + ld bc, SCREEN_WIDTH +.loop + ld a, d + and a + jr z, .done + add hl, bc + dec d + jr .loop + +.done + add hl, de + ld a, [hl] + ld [wNamingScreenLastCharacter], a + ret + +LoadNamingScreenGFX: + call ClearSprites + callfar ClearSpriteAnims + call LoadStandardFont + call LoadFontsExtra + + ld de, NamingScreenGFX_MiddleLine + ld hl, vTiles0 tile NAMINGSCREEN_MIDDLELINE + lb bc, BANK(NamingScreenGFX_MiddleLine), 1 + call Get1bpp + + ld de, NamingScreenGFX_UnderLine + ld hl, vTiles0 tile NAMINGSCREEN_UNDERLINE + lb bc, BANK(NamingScreenGFX_UnderLine), 1 + call Get1bpp + + ld de, vTiles2 tile NAMINGSCREEN_BORDER + ld hl, NamingScreenGFX_Border + ld bc, 1 tiles + ld a, BANK(NamingScreenGFX_Border) + call FarCopyBytes + + ld de, vTiles0 tile NAMINGSCREEN_CURSOR + ld hl, NamingScreenGFX_Cursor + ld bc, 2 tiles + ld a, BANK(NamingScreenGFX_Cursor) + call FarCopyBytes + + ld a, $5 + ld hl, wSpriteAnimDict + 9 * 2 + ld [hli], a + ld [hl], NAMINGSCREEN_CURSOR + xor a + ldh [hSCY], a + ld [wGlobalAnimYOffset], a + ldh [hSCX], a + ld [wGlobalAnimXOffset], a + ld [wJumptableIndex], a + ld [wNamingScreenLetterCase], a + ldh [hBGMapMode], a + ld [wNamingScreenCurNameLength], a + ld a, $7 + ldh [hWX], a + ret + +NamingScreenGFX_Border: +INCBIN "gfx/naming_screen/border.2bpp" + +NamingScreenGFX_Cursor: +INCBIN "gfx/naming_screen/cursor.2bpp" + +INCLUDE "data/text/name_input_chars.asm" + +NamingScreenGFX_End: ; unused +INCBIN "gfx/naming_screen/end.1bpp" + +NamingScreenGFX_MiddleLine: +INCBIN "gfx/naming_screen/middle_line.1bpp" + +NamingScreenGFX_UnderLine: +INCBIN "gfx/naming_screen/underline.1bpp" + +_ComposeMailMessage: + ld hl, wNamingScreenDestinationPointer + ld [hl], e + inc hl + ld [hl], d + ldh a, [hMapAnims] + push af + xor a + ldh [hMapAnims], a + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + call .InitBlankMail + call DelayFrame + +.loop + call .DoMailEntry + jr nc, .loop + + pop af + ldh [hInMenu], a + pop af + ldh [hMapAnims], a + ret + +.InitBlankMail: + call ClearBGPalettes + call DisableLCD + call LoadNamingScreenGFX + ld de, vTiles0 tile $00 + ld hl, .MailIcon + ld bc, 8 tiles + ld a, BANK(.MailIcon) + call FarCopyBytes + xor a + ld hl, wSpriteAnimDict + ld [hli], a + ld [hl], a + + ; init mail icon + depixel 3, 2 + ld a, SPRITE_ANIM_INDEX_PARTY_MON + call InitSpriteAnimStruct + + ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID + add hl, bc + ld [hl], $0 + call .InitCharset + ld a, LCDC_DEFAULT + ldh [rLCDC], a + call .initwNamingScreenMaxNameLength + ld b, SCGB_DIPLOMA + call GetSGBLayout + call WaitBGMap + call WaitTop + ld a, %11100100 + call DmgToCgbBGPals + ld a, %11100100 + call DmgToCgbObjPal0 + call NamingScreen_InitNameEntry + ld hl, wNamingScreenDestinationPointer + ld e, [hl] + inc hl + ld d, [hl] + ld hl, MAIL_LINE_LENGTH + add hl, de + ld [hl], "<NEXT>" + ret + +.MailIcon: +INCBIN "gfx/icons/mail_big.2bpp" + +.initwNamingScreenMaxNameLength + ld a, MAIL_MSG_LENGTH + 1 + ld [wNamingScreenMaxNameLength], a + ret + +.UnusedString11f7a: + db "メールを かいてね@" + +.InitCharset: + call WaitTop + hlcoord 0, 0 + ld bc, 6 * SCREEN_WIDTH + ld a, NAMINGSCREEN_BORDER + call ByteFill + hlcoord 0, 6 + ld bc, 12 * SCREEN_WIDTH + ld a, " " + call ByteFill + hlcoord 1, 1 + lb bc, 4, SCREEN_WIDTH - 2 + call ClearBox + ld de, MailEntry_Uppercase + +.PlaceMailCharset: + hlcoord 1, 7 + ld b, 6 +.next + ld c, SCREEN_WIDTH - 1 +.loop_ + ld a, [de] + ld [hli], a + inc de + dec c + jr nz, .loop_ + push de + ld de, SCREEN_WIDTH + 1 + add hl, de + pop de + dec b + jr nz, .next + ret + +.DoMailEntry: + call JoyTextDelay + ld a, [wJumptableIndex] + bit 7, a + jr nz, .exit_mail + call .DoJumptable + farcall PlaySpriteAnimationsAndDelayFrame + call .Update + call DelayFrame + and a + ret + +.exit_mail + callfar ClearSpriteAnims + call ClearSprites + xor a + ldh [hSCX], a + ldh [hSCY], a + scf + ret + +.Update: + xor a + ldh [hBGMapMode], a + hlcoord 1, 1 + lb bc, 4, 18 + call ClearBox + ld hl, wNamingScreenDestinationPointer + ld e, [hl] + inc hl + ld d, [hl] + hlcoord 2, 2 + call PlaceString + ld a, $1 + ldh [hBGMapMode], a + ret + +.DoJumptable: + 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 + +.Jumptable: + dw .init_blinking_cursor + dw .process_joypad + +.init_blinking_cursor + depixel 9, 2 + ld a, SPRITE_ANIM_INDEX_COMPOSE_MAIL_CURSOR + call InitSpriteAnimStruct + ld a, c + ld [wNamingScreenCursorObjectPointer], a + ld a, b + ld [wNamingScreenCursorObjectPointer + 1], a + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + ld [hl], a + ld hl, wJumptableIndex + inc [hl] + ret + +.process_joypad + ld hl, hJoyPressed + ld a, [hl] + and A_BUTTON + jr nz, .a + ld a, [hl] + and B_BUTTON + jr nz, .b + ld a, [hl] + and START + jr nz, .start + ld a, [hl] + and SELECT + jr nz, .select + ret + +.a + call NamingScreen_PressedA_GetCursorCommand + cp $1 + jr z, .select + cp $2 + jr z, .b + cp $3 + jr z, .finished + call NamingScreen_GetLastCharacter + call MailComposition_TryAddLastCharacter + jr c, .start + ld hl, wNamingScreenCurNameLength + ld a, [hl] + cp MAIL_LINE_LENGTH + ret nz + inc [hl] + call NamingScreen_GetTextCursorPosition + ld [hl], NAMINGSCREEN_UNDERLINE + dec hl + ld [hl], "<NEXT>" + ret + +.start + ld hl, wNamingScreenCursorObjectPointer + ld c, [hl] + inc hl + ld b, [hl] + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], $9 + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld [hl], $5 + ret + +.b + call NamingScreen_DeleteCharacter + ld hl, wNamingScreenCurNameLength + ld a, [hl] + cp MAIL_LINE_LENGTH + ret nz + dec [hl] + call NamingScreen_GetTextCursorPosition + ld [hl], NAMINGSCREEN_UNDERLINE + inc hl + ld [hl], "<NEXT>" + ret + +.finished + call NamingScreen_StoreEntry + ld hl, wJumptableIndex + set 7, [hl] + ret + +.select + ld hl, wNamingScreenLetterCase + ld a, [hl] + xor 1 + ld [hl], a + jr nz, .switch_to_lowercase + ld de, MailEntry_Uppercase + call .PlaceMailCharset + ret + +.switch_to_lowercase + ld de, MailEntry_Lowercase + call .PlaceMailCharset + ret + +; called from engine/sprite_anims.asm + +ComposeMail_AnimateCursor: + call .GetDPad + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + ld e, a + swap e + ld hl, SPRITEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], e + cp $5 + ld de, .LetterEntries + ld a, 0 + jr nz, .got_pointer + ld de, .CaseDelEnd + ld a, 1 +.got_pointer + ld hl, SPRITEANIMSTRUCT_0E + add hl, bc + add [hl] + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], a + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld l, [hl] + ld h, 0 + add hl, de + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.LetterEntries: + db $00, $10, $20, $30, $40, $50, $60, $70, $80, $90 + +.CaseDelEnd: + db $00, $00, $00, $30, $30, $30, $60, $60, $60, $60 + +.GetDPad: + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .up + ld a, [hl] + and D_DOWN + jr nz, .down + ld a, [hl] + and D_LEFT + jr nz, .left + ld a, [hl] + and D_RIGHT + jr nz, .right + ret + +.right + call ComposeMail_GetCursorPosition + and a + jr nz, .case_del_done_right + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + cp $9 + jr nc, .wrap_around_letter_right + inc [hl] + ret + +.wrap_around_letter_right + ld [hl], $0 + ret + +.case_del_done_right + cp $3 + jr nz, .wrap_around_command_right + xor a +.wrap_around_command_right + ld e, a + add a + add e + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], a + ret + +.left + call ComposeMail_GetCursorPosition + and a + jr nz, .caps_del_done_left + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + and a + jr z, .wrap_around_letter_left + dec [hl] + ret + +.wrap_around_letter_left + ld [hl], $9 + ret + +.caps_del_done_left + cp $1 + jr nz, .wrap_around_command_left + ld a, $4 +.wrap_around_command_left + dec a + dec a + ld e, a + add a + add e + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], a + ret + +.down + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + cp $5 + jr nc, .wrap_around_down + inc [hl] + ret + +.wrap_around_down + ld [hl], $0 + ret + +.up + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + and a + jr z, .wrap_around_up + dec [hl] + ret + +.wrap_around_up + ld [hl], $5 + ret + +NamingScreen_PressedA_GetCursorCommand: + ld hl, wNamingScreenCursorObjectPointer + ld c, [hl] + inc hl + ld b, [hl] + +ComposeMail_GetCursorPosition: + ld hl, SPRITEANIMSTRUCT_0D + add hl, bc + ld a, [hl] + cp $5 + jr nz, .letter + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + cp $3 + jr c, .case + cp $6 + jr c, .del + ld a, $3 + ret + +.case + ld a, $1 + ret + +.del + ld a, $2 + ret + +.letter + xor a + ret + +MailComposition_TryAddLastCharacter: + ld a, [wNamingScreenLastCharacter] + ld hl, Dakutens + cp "゙" ; $e5 + jr z, .asm_1258b + ld hl, Handakutens + cp "゚" ; $e4 + jp nz, MailComposition_TryAddCharacter + +.asm_1258b + ld a, [wNamingScreenCurNameLength] + and a + ret z + cp $11 + jr nz, .asm_1259c + push hl + ld hl, wNamingScreenCurNameLength + dec [hl] + dec [hl] + jr .asm_125a1 + +.asm_1259c + push hl + ld hl, wNamingScreenCurNameLength + dec [hl] + +.asm_125a1 + call NamingScreen_GetTextCursorPosition + ld c, [hl] + pop hl +.asm_125a6 + ld a, [hli] + cp $ff + jp z, NamingScreen_AdvanceCursor_CheckEndOfString + cp c + jr z, .asm_125b2 + inc hl + jr .asm_125a6 + +.asm_125b2 + ld a, [hl] + jp NamingScreen_LoadNextCharacter + +INCLUDE "data/text/mail_input_chars.asm" diff --git a/engine/menus/save.asm b/engine/menus/save.asm new file mode 100644 index 00000000..f8207204 --- /dev/null +++ b/engine/menus/save.asm @@ -0,0 +1,1092 @@ +SaveMenu: + call LoadStandardMenuHeader + lb de, 4, 0 + farcall DisplayNormalContinueData + call SpeechTextbox + call UpdateSprites + farcall SaveMenu_CopyTilemapAtOnce + ld hl, WouldYouLikeToSaveTheGameText + call SaveTheGame_yesorno + jr nz, .refused + call AskOverwriteSaveFile + jr c, .refused + call PauseGameLogic + call SavingDontTurnOffThePower + call ResumeGameLogic + call ExitMenu + and a + ret + +.refused + call ExitMenu + call ReloadPalettes + farcall SaveMenu_CopyTilemapAtOnce + scf + ret + +SaveAfterLinkTrade: + call PauseGameLogic + farcall StageRTCTimeForSave + farcall BackupMysteryGift + call SavePokemonData + call SaveChecksum + call SaveBackupPokemonData + call SaveBackupChecksum + farcall BackupPartyMonMail + farcall SaveRTC + call ResumeGameLogic + ret + +ChangeBoxSaveGame: + push de + ld hl, ChangeBoxSaveText + call MenuTextbox + call YesNoBox + call ExitMenu + jr c, .refused + call AskOverwriteSaveFile + jr c, .refused + call PauseGameLogic + call SaveBox + pop de + ld a, e + ld [wCurBox], a + call LoadBox + call SavingDontTurnOffThePower + call ResumeGameLogic + and a + ret +.refused + pop de + ret + +Link_SaveGame: + call AskOverwriteSaveFile + jr c, .refused + call PauseGameLogic + call SavingDontTurnOffThePower + call ResumeGameLogic + and a + +.refused + ret + +MoveMonWOMail_SaveGame: + call PauseGameLogic + push de + call SaveBox + pop de + ld a, e + ld [wCurBox], a + call LoadBox + call ResumeGameLogic + ret + +MoveMonWOMail_InsertMon_SaveGame: + call PauseGameLogic + push de + call SaveBox + pop de + ld a, e + ld [wCurBox], a + ld a, TRUE + ld [wSaveFileExists], a + farcall StageRTCTimeForSave + farcall BackupMysteryGift + call ValidateSave + call SaveOptions + call SavePlayerData + call SavePokemonData + call SaveChecksum + call ValidateBackupSave + call SaveBackupOptions + call SaveBackupPlayerData + call SaveBackupPokemonData + call SaveBackupChecksum + farcall BackupPartyMonMail + farcall SaveRTC + call LoadBox + call ResumeGameLogic + ld de, SFX_SAVE + call PlaySFX + ld c, 24 + call DelayFrames + ret + +StartMoveMonWOMail_SaveGame: + ld hl, MoveMonWOMailSaveText + call MenuTextbox + call YesNoBox + call ExitMenu + jr c, .refused + call AskOverwriteSaveFile + jr c, .refused + call PauseGameLogic + call SavingDontTurnOffThePower + call ResumeGameLogic + and a + ret + +.refused + scf + ret + +PauseGameLogic: + ld a, TRUE + ld [wGameLogicPaused], a + ret + +ResumeGameLogic: + xor a ; FALSE + ld [wGameLogicPaused], a + ret + +AddHallOfFameEntry: + ld a, BANK(sHallOfFame) + call OpenSRAM + ld hl, sHallOfFame + HOF_LENGTH * (NUM_HOF_TEAMS - 1) - 1 + ld de, sHallOfFame + HOF_LENGTH * NUM_HOF_TEAMS - 1 + ld bc, HOF_LENGTH * (NUM_HOF_TEAMS - 1) +.loop + ld a, [hld] + ld [de], a + dec de + dec bc + ld a, c + or b + jr nz, .loop + ld hl, wHallOfFamePokemonList + ld de, sHallOfFame + ld bc, wHallOfFamePokemonListEnd - wHallOfFamePokemonList + 1 + call CopyBytes + call CloseSRAM + ret + +SaveGameData: + call _SaveGameData + ret + +AskOverwriteSaveFile: + ld a, [wSaveFileExists] + and a + jr z, .erase + call CompareLoadedAndSavedPlayerID + jr z, .yoursavefile + ld hl, AnotherSaveFileText + call SaveTheGame_yesorno + jr nz, .refused + jr .erase + +.yoursavefile + ld hl, AlreadyASaveFileText + call SaveTheGame_yesorno + jr nz, .refused + jr .ok + +.erase + call ErasePreviousSave + +.ok + and a + ret + +.refused + scf + ret + +SaveTheGame_yesorno: + ld b, BANK(WouldYouLikeToSaveTheGameText) + call MapTextbox + call LoadMenuTextbox + lb bc, 0, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + dec a + call CloseWindow + push af + call ReloadPalettes + pop af + and a + ret + +CompareLoadedAndSavedPlayerID: + ld a, BANK(sPlayerData) + call OpenSRAM + ld hl, sPlayerData + (wPlayerID - wPlayerData) + ld a, [hli] + ld c, [hl] + ld b, a + call CloseSRAM + ld a, [wPlayerID] + cp b + ret nz + ld a, [wPlayerID + 1] + cp c + ret + +SavingDontTurnOffThePower: + ; Prevent joypad interrupts + xor a + ldh [hJoypadReleased], a + ldh [hJoypadPressed], a + ldh [hJoypadSum], a + ldh [hJoypadDown], a + ; Save the text speed setting to the stack + ld a, [wOptions] + push af + ; Set the text speed to medium + ld a, TEXT_DELAY_MED + ld [wOptions], a + ; SAVING... DON'T TURN OFF THE POWER. + ld hl, SavingDontTurnOffThePowerText + call PrintText + ; Restore the text speed setting + pop af + ld [wOptions], a + ; Wait for 16 frames + ld c, 16 + call DelayFrames + call _SaveGameData + ; wait 32 frames + ld c, 32 + call DelayFrames + ; copy the original text speed setting to the stack + ld a, [wOptions] + push af + ; set text speed to medium + ld a, TEXT_DELAY_MED + ld [wOptions], a + ; <PLAYER> saved the game! + ld hl, SavedTheGameText + call PrintText + ; restore the original text speed setting + pop af + ld [wOptions], a + ld de, SFX_SAVE + call WaitPlaySFX + call WaitSFX + ; wait 30 frames + ld c, 30 + call DelayFrames + ret + +_SaveGameData: + ld a, TRUE + ld [wSaveFileExists], a + farcall StageRTCTimeForSave + farcall BackupMysteryGift + call ValidateSave + call SaveOptions + call SavePlayerData + call SavePokemonData + call SaveBox + call SaveChecksum + call ValidateBackupSave + call SaveBackupOptions + call SaveBackupPlayerData + call SaveBackupPokemonData + call SaveBackupChecksum + call UpdateStackTop + farcall BackupPartyMonMail + farcall SaveRTC + ret + +UpdateStackTop: +; sStackTop appears to be unused. +; It could have been used to debug stack overflow during saving. + call FindStackTop + ld a, BANK(sStackTop) + call OpenSRAM + ld a, [sStackTop + 0] + ld e, a + ld a, [sStackTop + 1] + ld d, a + or e + jr z, .update + ld a, e + sub l + ld a, d + sbc h + jr c, .done + +.update + ld a, l + ld [sStackTop + 0], a + ld a, h + ld [sStackTop + 1], a + +.done + call CloseSRAM + ret + +FindStackTop: +; Find the furthest point that sp has traversed to. +; This is distinct from the current value of sp. + ld hl, wStackTop - $fc +.loop + ld a, [hl] + or a + ret nz + inc hl + jr .loop + +ErasePreviousSave: + call EraseBoxes + call EraseHallOfFame + call EraseLinkBattleStats + call EraseMysteryGift + ld a, BANK(sStackTop) + call OpenSRAM + xor a + ld [sStackTop + 0], a + ld [sStackTop + 1], a + call CloseSRAM + ld a, $1 + ld [wSavedAtLeastOnce], a + ret + +EraseLinkBattleStats: + ld a, BANK(sLinkBattleStats) + call OpenSRAM + ld hl, sLinkBattleStats + ld bc, sLinkBattleStatsEnd - sLinkBattleStats + xor a + call ByteFill + jp CloseSRAM + +EraseMysteryGift: + ld a, BANK(sBackupMysteryGiftItem) + call OpenSRAM + ld hl, sBackupMysteryGiftItem + ld bc, sBackupMysteryGiftItemEnd - sBackupMysteryGiftItem + xor a + call ByteFill + jp CloseSRAM + +EraseHallOfFame: + ld a, BANK(sHallOfFame) + call OpenSRAM + ld hl, sHallOfFame + ld bc, sHallOfFameEnd - sHallOfFame + xor a + call ByteFill + jp CloseSRAM + +ValidateSave: + ld a, BANK(sCheckValue1) ; aka BANK(sCheckValue2) + call OpenSRAM + ld a, SAVE_CHECK_VALUE_1 + ld [sCheckValue1], a + ld a, SAVE_CHECK_VALUE_2 + ld [sCheckValue2], a + jp CloseSRAM + +SaveOptions: + ld a, BANK(sOptions) + call OpenSRAM + ld hl, wOptions + ld de, sOptions + ld bc, wOptionsEnd - wOptions + call CopyBytes + ld a, [wOptions] + and $ff ^ (1 << NO_TEXT_SCROLL) + ld [sOptions], a + jp CloseSRAM + +SavePlayerData: + ld a, BANK(sPlayerData) + call OpenSRAM + ld hl, wPlayerData + ld de, sPlayerData + ld bc, wPlayerDataEnd - wPlayerData + call CopyBytes + ld hl, wCurMapData + ld de, sCurMapData + ld bc, wCurMapDataEnd - wCurMapData + call CopyBytes + jp CloseSRAM + +SavePokemonData: + ld a, BANK(sPokemonData) + call OpenSRAM + ld hl, wPokemonData + ld de, sPokemonData + ld bc, wPokemonDataEnd - wPokemonData + call CopyBytes + call CloseSRAM + ret + +SaveBox: + call GetBoxAddress + call SaveBoxAddress + ret + +SaveChecksum: + ld hl, sGameData + ld bc, sGameDataEnd - sGameData + ld a, BANK(sGameData) + call OpenSRAM + call Checksum + ld a, e + ld [sChecksum + 0], a + ld a, d + ld [sChecksum + 1], a + call CloseSRAM + ret + +ValidateBackupSave: + ld a, BANK(sBackupCheckValue1) ; aka BANK(sBackupCheckValue2) + call OpenSRAM + ld a, SAVE_CHECK_VALUE_1 + ld [sBackupCheckValue1], a + ld a, SAVE_CHECK_VALUE_2 + ld [sBackupCheckValue2], a + call CloseSRAM + ret + +SaveBackupOptions: + ld a, BANK(sBackupOptions) + call OpenSRAM + ld hl, wOptions + ld de, sBackupOptions + ld bc, wOptionsEnd - wOptions + call CopyBytes + call CloseSRAM + ret + +SaveBackupPlayerData: + ld a, BANK(sBackupPlayerData3) + call OpenSRAM + ld hl, wPlayerData3 + ld de, sBackupPlayerData3 + ld bc, wPlayerData3End - wPlayerData3 + call CopyBytes + ld a, BANK(sBackupPlayerData1) + call OpenSRAM + ld hl, wPlayerData1 + ld de, sBackupPlayerData1 + ld bc, wPlayerData1End - wPlayerData1 + call CopyBytes + ld a, BANK(sBackupPlayerData2) + call OpenSRAM + ld hl, wPlayerData2 + ld de, sBackupPlayerData2 + ld bc, wPlayerData2End - wPlayerData2 + call CopyBytes + ld a, BANK(sBackupCurMapData) + call OpenSRAM + ld hl, wCurMapData + ld de, sBackupCurMapData + ld bc, wCurMapDataEnd - wCurMapData + call CopyBytes + call CloseSRAM + ret + +SaveBackupPokemonData: + ld a, BANK(sBackupPokemonData) + call OpenSRAM + ld hl, wPokemonData + ld de, sBackupPokemonData + ld bc, wPokemonDataEnd - wPokemonData + call CopyBytes + call CloseSRAM + ret + +SaveBackupChecksum: + ld a, BANK(sBackupPlayerData3) + call OpenSRAM + ld hl, sBackupPlayerData3 + ld bc, wPlayerData3End - wPlayerData3 + call Checksum + push de + ld hl, sBackupPokemonData + ld bc, wPokemonDataEnd - wPokemonData + call Checksum + pop hl + add hl, de + ld a, BANK(sBackupPlayerData1) + call OpenSRAM + push hl + ld hl, sBackupPlayerData1 + ld bc, wPlayerData1End - wPlayerData1 + call Checksum + pop hl + add hl, de + ld a, BANK(sBackupPlayerData2) + call OpenSRAM + push hl + ld hl, sBackupPlayerData2 + ld bc, wPlayerData2End - wPlayerData2 + call Checksum + pop hl + add hl, de + ld a, BANK(sBackupCurMapData) + call OpenSRAM + push hl + ld hl, sBackupCurMapData + ld bc, wCurMapDataEnd - wCurMapData + call Checksum + pop hl + add hl, de + ld a, l + ld [sBackupChecksum + 0], a + ld a, h + ld [sBackupChecksum + 1], a + call CloseSRAM + ret + +TryLoadSaveFile: + call VerifyChecksum + jr nz, .backup + call LoadPlayerData + call LoadPokemonData + call LoadBox + farcall RestorePartyMonMail + farcall RestoreMysteryGift + call ValidateBackupSave + call SaveBackupOptions + call SaveBackupPlayerData + call SaveBackupPokemonData + call SaveBackupChecksum + and a + ret + +.backup + call VerifyBackupChecksum + jr nz, .corrupt + call LoadBackupPlayerData + call LoadBackupPokemonData + call LoadBox + farcall RestorePartyMonMail + farcall RestoreMysteryGift + call ValidateSave + call SaveOptions + call SavePlayerData + call SavePokemonData + call SaveChecksum + and a + ret + +.corrupt + ld a, [wOptions] + push af + set NO_TEXT_SCROLL, a + ld [wOptions], a + ld hl, SaveFileCorruptedText + call PrintText + pop af + ld [wOptions], a + scf + ret + +TryLoadSaveData: + xor a ; FALSE + ld [wSaveFileExists], a + call CheckPrimarySaveFile + ld a, [wSaveFileExists] + and a + jr z, .backup + + ld a, BANK(sPlayerData) + call OpenSRAM + ld hl, sPlayerData + wStartDay - wPlayerData + ld de, wStartDay + ld bc, $e + call CopyBytes + call CloseSRAM + ret + +.backup + call CheckBackupSaveFile + ld a, [wSaveFileExists] + and a + jr z, .corrupt + + ld a, BANK(sBackupPlayerData1) + call OpenSRAM + ld hl, sBackupPlayerData1 + wStartDay - wPlayerData + ld de, wStartDay + ld bc, $e + call CopyBytes + call CloseSRAM + ret + +.corrupt + ld hl, DefaultOptions + ld de, wOptions + ld bc, wOptionsEnd - wOptions + call CopyBytes + call ClearClock + ret + +INCLUDE "data/default_options.asm" + +CheckPrimarySaveFile: + ld a, BANK(sCheckValue1) ; aka BANK(sCheckValue2) + call OpenSRAM + ld a, [sCheckValue1] + cp SAVE_CHECK_VALUE_1 + jr nz, .nope + ld a, [sCheckValue2] + cp SAVE_CHECK_VALUE_2 + jr nz, .nope + ld hl, sOptions + ld de, wOptions + ld bc, wOptionsEnd - wOptions + call CopyBytes + call CloseSRAM + call CheckTextDelay + ld a, TRUE + ld [wSaveFileExists], a + +.nope + call CloseSRAM + ret + +CheckBackupSaveFile: + ld a, BANK(sBackupCheckValue1) ; aka BANK(sBackupCheckValue2) + call OpenSRAM + ld a, [sBackupCheckValue1] + cp SAVE_CHECK_VALUE_1 + jr nz, .nope + ld a, [sBackupCheckValue2] + cp SAVE_CHECK_VALUE_2 + jr nz, .nope + ld hl, sBackupOptions + ld de, wOptions + ld bc, wOptionsEnd - wOptions + call CopyBytes + call CheckTextDelay + ld a, $2 + ld [wSaveFileExists], a + +.nope + call CloseSRAM + ret + +CheckTextDelay: +; Fix options if text delay is invalid + ld hl, wTextboxFlags + res NO_TEXT_DELAY_F, [hl] + ld a, [wOptions] + and TEXT_DELAY_MASK + cp TEXT_DELAY_FAST + ret z + cp TEXT_DELAY_MED + ret z + cp TEXT_DELAY_SLOW + ret z + ld a, [wOptions] + and $ff ^ TEXT_DELAY_MASK + or (1 << FAST_TEXT_DELAY_F) | (1 << NO_TEXT_DELAY_F) + ld [wOptions], a + ret + +LoadPlayerData: + ld a, BANK(sPlayerData) + call OpenSRAM + ld hl, sPlayerData + ld de, wPlayerData + ld bc, wPlayerDataEnd - wPlayerData + call CopyBytes + ld hl, sCurMapData + ld de, wCurMapData + ld bc, wCurMapDataEnd - wCurMapData + call CopyBytes + call CloseSRAM + ret + +LoadPokemonData: + ld a, BANK(sPokemonData) + call OpenSRAM + ld hl, sPokemonData + ld de, wPokemonData + ld bc, wPokemonDataEnd - wPokemonData + call CopyBytes + call CloseSRAM + ret + +LoadBox: + call GetBoxAddress + call LoadBoxAddress + ret + +VerifyChecksum: + ld hl, sGameData + ld bc, sGameDataEnd - sGameData + ld a, BANK(sGameData) + call OpenSRAM + call Checksum + ld a, [sChecksum + 0] + cp e + jr nz, .fail + ld a, [sChecksum + 1] + cp d +.fail + push af + call CloseSRAM + pop af + ret + +LoadBackupPlayerData: + ld a, BANK(sBackupPlayerData3) + call OpenSRAM + ld hl, sBackupPlayerData3 + ld de, wPlayerData3 + ld bc, wPlayerData3End - wPlayerData3 + call CopyBytes + + ld a, BANK(sBackupPlayerData1) + call OpenSRAM + ld hl, sBackupPlayerData1 + ld de, wPlayerData1 + ld bc, wPlayerData1End - wPlayerData1 + call CopyBytes + + ld a, BANK(sBackupPlayerData2) + call OpenSRAM + ld hl, sBackupPlayerData2 + ld de, wPlayerData2 + ld bc, wPlayerData2End - wPlayerData2 + call CopyBytes + + ld a, BANK(sBackupCurMapData) + call OpenSRAM + ld hl, sBackupCurMapData + ld de, wCurMapData + ld bc, wCurMapDataEnd - wCurMapData + call CopyBytes + call CloseSRAM + ret + +LoadBackupPokemonData: + ld a, BANK(sBackupPokemonData) + call OpenSRAM + ld hl, sBackupPokemonData + ld de, wPokemonData + ld bc, wPokemonDataEnd - wPokemonData + call CopyBytes + call CloseSRAM + ret + +VerifyBackupChecksum: + ld a, BANK(sBackupPokemonData) + call OpenSRAM + ld hl, sBackupPokemonData + ld bc, wPokemonDataEnd - wPokemonData + call Checksum + push de + + ld hl, sBackupPlayerData3 + ld bc, wPlayerData3End - wPlayerData3 + call Checksum + pop hl + add hl, de + + ld a, BANK(sBackupPlayerData1) + call OpenSRAM + push hl + ld hl, sBackupPlayerData1 + ld bc, wPlayerData1End - wPlayerData1 + call Checksum + pop hl + add hl, de + + ld a, BANK(sBackupPlayerData2) + call OpenSRAM + push hl + ld hl, sBackupPlayerData2 + ld bc, wPlayerData2End - wPlayerData2 + call Checksum + pop hl + add hl, de + + ld a, BANK(sBackupCurMapData) + call OpenSRAM + push hl + ld hl, sBackupCurMapData + ld bc, wCurMapDataEnd - wCurMapData + call Checksum + pop hl + add hl, de + ld d, h + ld e, l + ld a, [sBackupChecksum + 0] + cp e + jr nz, .fail + ld a, [sBackupChecksum + 1] + cp d +.fail + push af + call CloseSRAM + pop af + ret + +GetBoxAddress: + ld a, [wCurBox] + cp NUM_BOXES + jr c, .ok + xor a + ld [wCurBox], a + +.ok + ld e, a + ld d, 0 + ld hl, BoxAddresses +rept 5 + add hl, de +endr + ld a, [hli] + push af + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld h, [hl] + ld l, a + pop af + ret + +SaveBoxAddress: +; Save box via wBoxPartialData. +; We do this in three steps because the size of wBoxPartialData is less than +; the size of sBox. + push hl +; Load the first part of the active box. + push af + push de + ld a, BANK(sBox) + call OpenSRAM + ld hl, sBox + ld de, wBoxPartialData + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + pop de + pop af +; Save it to the target box. + push af + push de + call OpenSRAM + ld hl, wBoxPartialData + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + +; Load the second part of the active box. + ld a, BANK(sBox) + call OpenSRAM + ld hl, sBox + (wBoxPartialDataEnd - wBoxPartialData) + ld de, wBoxPartialData + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + pop de + pop af + + ld hl, (wBoxPartialDataEnd - wBoxPartialData) + add hl, de + ld e, l + ld d, h +; Save it to the next part of the target box. + push af + push de + call OpenSRAM + ld hl, wBoxPartialData + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + +; Load the third and final part of the active box. + ld a, BANK(sBox) + call OpenSRAM + ld hl, sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2 + ld de, wBoxPartialData + ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e + call CopyBytes + call CloseSRAM + pop de + pop af + + ld hl, (wBoxPartialDataEnd - wBoxPartialData) + add hl, de + ld e, l + ld d, h +; Save it to the final part of the target box. + call OpenSRAM + ld hl, wBoxPartialData + ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e + call CopyBytes + call CloseSRAM + + pop hl + ret + +LoadBoxAddress: +; Load box via wBoxPartialData. +; We do this in three steps because the size of wBoxPartialData is less than +; the size of sBox. + push hl + ld l, e + ld h, d +; Load part 1 + push af + push hl + call OpenSRAM + ld de, wBoxPartialData + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + ld a, BANK(sBox) + call OpenSRAM + ld hl, wBoxPartialData + ld de, sBox + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + pop hl + pop af + + ld de, (wBoxPartialDataEnd - wBoxPartialData) + add hl, de +; Load part 2 + push af + push hl + call OpenSRAM + ld de, wBoxPartialData + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + ld a, BANK(sBox) + call OpenSRAM + ld hl, wBoxPartialData + ld de, sBox + (wBoxPartialDataEnd - wBoxPartialData) + ld bc, (wBoxPartialDataEnd - wBoxPartialData) + call CopyBytes + call CloseSRAM + pop hl + pop af +; Load part 3 + ld de, (wBoxPartialDataEnd - wBoxPartialData) + add hl, de + call OpenSRAM + ld de, wBoxPartialData + ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e + call CopyBytes + call CloseSRAM + ld a, BANK(sBox) + call OpenSRAM + ld hl, wBoxPartialData + ld de, sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2 + ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e + call CopyBytes + call CloseSRAM + + pop hl + ret + +EraseBoxes: + ld hl, BoxAddresses + ld c, NUM_BOXES +.next + push bc + ld a, [hli] + call OpenSRAM + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + xor a + ld [de], a + inc de + ld a, -1 + ld [de], a + inc de + ld bc, sBoxEnd - (sBox + 2) +.clear + xor a + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .clear + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, -1 + ld [de], a + inc de + xor a + ld [de], a + call CloseSRAM + pop bc + dec c + jr nz, .next + ret + +BoxAddresses: +; dbww bank, address, address + dbww BANK(sBox1), sBox1, sBox1End + dbww BANK(sBox2), sBox2, sBox2End + dbww BANK(sBox3), sBox3, sBox3End + dbww BANK(sBox4), sBox4, sBox4End + dbww BANK(sBox5), sBox5, sBox5End + dbww BANK(sBox6), sBox6, sBox6End + dbww BANK(sBox7), sBox7, sBox7End + dbww BANK(sBox8), sBox8, sBox8End + dbww BANK(sBox9), sBox9, sBox9End + dbww BANK(sBox10), sBox10, sBox10End + dbww BANK(sBox11), sBox11, sBox11End + dbww BANK(sBox12), sBox12, sBox12End + dbww BANK(sBox13), sBox13, sBox13End + dbww BANK(sBox14), sBox14, sBox14End + +Checksum: + ld de, 0 +.loop + ld a, [hli] + add e + ld e, a + ld a, 0 + adc d + ld d, a + dec bc + ld a, b + or c + jr nz, .loop + ret + +WouldYouLikeToSaveTheGameText: + text_far _WouldYouLikeToSaveTheGameText + text_end + +SavingDontTurnOffThePowerText: + text_far _SavingDontTurnOffThePowerText + text_end + +SavedTheGameText: + text_far _SavedTheGameText + text_end + +AlreadyASaveFileText: + text_far _AlreadyASaveFileText + text_end + +AnotherSaveFileText: + text_far _AnotherSaveFileText + text_end + +SaveFileCorruptedText: + text_far _SaveFileCorruptedText + text_end + +ChangeBoxSaveText: + text_far _ChangeBoxSaveText + text_end + +MoveMonWOMailSaveText: + text_far _MoveMonWOMailSaveText + text_end diff --git a/engine/menus/scrolling_menu.asm b/engine/menus/scrolling_menu.asm new file mode 100644 index 00000000..f051e71c --- /dev/null +++ b/engine/menus/scrolling_menu.asm @@ -0,0 +1,519 @@ +_InitScrollingMenu:: + xor a + ld [wMenuJoypad], a + ldh [hBGMapMode], a + inc a + ldh [hInMenu], a + call InitScrollingMenuCursor + call ScrollingMenu_InitFlags + call ScrollingMenu_ValidateSwitchItem + call ScrollingMenu_InitDisplay + call ApplyTilemap + xor a + ldh [hBGMapMode], a + ret + +_ScrollingMenu:: +.loop + call ScrollingMenuJoyAction + jp c, .exit + call z, .zero + jr .loop + +.exit + call MenuClickSound + ld [wMenuJoypad], a + ld a, 0 + ldh [hInMenu], a + ret + +.zero + call ScrollingMenu_InitDisplay + ld a, 1 + ldh [hBGMapMode], a + ld c, 3 + call DelayFrames + xor a + ldh [hBGMapMode], a + ret + +ScrollingMenu_InitDisplay: + xor a + ldh [hBGMapMode], a + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call ScrollingMenu_UpdateDisplay + call ScrollingMenu_PlaceCursor + call ScrollingMenu_CheckCallFunction3 + pop af + ld [wOptions], a + ret + +ScrollingMenuJoyAction: +.loop + call ScrollingMenuJoypad + ldh a, [hJoyLast] + and D_PAD + ld b, a + ldh a, [hJoyPressed] + and BUTTONS + or b + bit A_BUTTON_F, a + jp nz, .a_button + bit B_BUTTON_F, a + jp nz, .b_button + bit SELECT_F, a + jp nz, .select + bit START_F, a + jp nz, .start + bit D_RIGHT_F, a + jp nz, .d_right + bit D_LEFT_F, a + jp nz, .d_left + bit D_UP_F, a + jp nz, .d_up + bit D_DOWN_F, a + jp nz, .d_down + jr .loop + +.unreferenced ; unused + ld a, -1 + and a + ret + +.a_button + call PlaceHollowCursor + ld a, [wMenuCursorY] + dec a + call ScrollingMenu_GetListItemCoordAndFunctionArgs + ld a, [wMenuSelection] + ld [wCurItem], a + ld a, [wMenuSelectionQuantity] + ld [wItemQuantityBuffer], a + call ScrollingMenu_GetCursorPosition + dec a + ld [wScrollingMenuCursorPosition], a + ld [wCurItemQuantity], a + ld a, [wMenuSelection] + cp -1 + jr z, .b_button + ld a, A_BUTTON + scf + ret + +.b_button + ld a, B_BUTTON + scf + ret + +.select + ld a, [wMenuDataFlags] + bit 7, a + jp z, xor_a_dec_a + ld a, [wMenuCursorY] + dec a + call ScrollingMenu_GetListItemCoordAndFunctionArgs + ld a, [wMenuSelection] + cp -1 + jp z, xor_a_dec_a + call ScrollingMenu_GetCursorPosition + dec a + ld [wScrollingMenuCursorPosition], a + ld a, SELECT + scf + ret + +.start + ld a, [wMenuDataFlags] + bit 6, a + jp z, xor_a_dec_a + ld a, START + scf + ret + +.d_left + ld hl, w2DMenuFlags2 + bit 7, [hl] + jp z, xor_a_dec_a + ld a, [wMenuDataFlags] + bit 3, a + jp z, xor_a_dec_a + ld a, D_LEFT + scf + ret + +.d_right + ld hl, w2DMenuFlags2 + bit 7, [hl] + jp z, xor_a_dec_a + ld a, [wMenuDataFlags] + bit 2, a + jp z, xor_a_dec_a + ld a, D_RIGHT + scf + ret + +.d_up + ld hl, w2DMenuFlags2 + bit 7, [hl] + jp z, xor_a + ld hl, wMenuScrollPosition + ld a, [hl] + and a + jr z, .xor_dec_up + dec [hl] + jp xor_a + +.xor_dec_up + jp xor_a_dec_a + +.d_down + ld hl, w2DMenuFlags2 + bit 7, [hl] + jp z, xor_a + ld hl, wMenuScrollPosition + ld a, [wMenuData_ScrollingMenuHeight] + add [hl] + ld b, a + ld a, [wScrollingMenuListSize] + cp b + jr c, .xor_dec_down + inc [hl] + jp xor_a + +.xor_dec_down + jp xor_a_dec_a + +ScrollingMenu_GetCursorPosition: + ld a, [wMenuScrollPosition] + ld c, a + ld a, [wMenuCursorY] + add c + ld c, a + ret + +ScrollingMenu_ClearLeftColumn: + call MenuBoxCoord2Tile + ld de, SCREEN_WIDTH + add hl, de + ld de, 2 * SCREEN_WIDTH + ld a, [wMenuData_ScrollingMenuHeight] +.loop + ld [hl], " " + add hl, de + dec a + jr nz, .loop + ret + +InitScrollingMenuCursor: + ld hl, wMenuData_ItemsPointerAddr + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wMenuData_ItemsPointerBank] + call GetFarByte + ld [wScrollingMenuListSize], a + ld a, [wMenuData_ScrollingMenuHeight] + ld c, a + ld a, [wMenuScrollPosition] + add c + ld c, a + ld a, [wScrollingMenuListSize] + inc a + cp c + jr nc, .skip + ld a, [wMenuData_ScrollingMenuHeight] + ld c, a + ld a, [wScrollingMenuListSize] + inc a + sub c + jr nc, .store + xor a + +.store + ld [wMenuScrollPosition], a + +.skip + ld a, [wMenuScrollPosition] + ld c, a + ld a, [wMenuCursorBuffer] + add c + ld b, a + ld a, [wScrollingMenuListSize] + inc a + cp b + jr c, .wrap + jr nc, .done + +.wrap + xor a + ld [wMenuScrollPosition], a + ld a, $1 + ld [wMenuCursorBuffer], a + +.done + ret + +ScrollingMenu_InitFlags: + ld a, [wMenuDataFlags] + ld c, a + ld a, [wScrollingMenuListSize] + ld b, a + ld a, [wMenuBorderTopCoord] + add 1 + ld [w2DMenuCursorInitY], a + ld a, [wMenuBorderLeftCoord] + add 0 + ld [w2DMenuCursorInitX], a + ld a, [wMenuData_ScrollingMenuHeight] + cp b + jr c, .no_extra_row + jr z, .no_extra_row + ld a, b + inc a +.no_extra_row + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld a, $8c + bit 2, c + jr z, .skip_set_0 + set 0, a + +.skip_set_0 + bit 3, c + jr z, .skip_set_1 + set 1, a + +.skip_set_1 + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + ld a, $20 + ld [w2DMenuCursorOffsets], a + ld a, A_BUTTON | B_BUTTON | D_UP | D_DOWN + bit 7, c + jr z, .disallow_select + add SELECT + +.disallow_select + bit 6, c + jr z, .disallow_start + add START + +.disallow_start + ld [wMenuJoypadFilter], a + ld a, [w2DMenuNumRows] + ld b, a + ld a, [wMenuCursorBuffer] + and a + jr z, .reset_cursor + cp b + jr z, .cursor_okay + jr c, .cursor_okay + +.reset_cursor + ld a, 1 + +.cursor_okay + ld [wMenuCursorY], a + ld a, 1 + ld [wMenuCursorX], a + xor a + ld [wCursorCurrentTile], a + ld [wCursorCurrentTile + 1], a + ld [wCursorOffCharacter], a + ret + +ScrollingMenu_ValidateSwitchItem: + ld a, [wScrollingMenuListSize] + ld c, a + ld a, [wSwitchItem] + and a + jr z, .done + dec a + cp c + jr c, .done + xor a + ld [wSwitchItem], a + +.done + ret + +ScrollingMenu_UpdateDisplay: + call ClearWholeMenuBox + ld a, [wMenuDataFlags] + bit 4, a ; place arrows + jr z, .okay + ld a, [wMenuScrollPosition] + and a + jr z, .okay + ld a, [wMenuBorderTopCoord] + ld b, a + ld a, [wMenuBorderRightCoord] + ld c, a + call Coord2Tile + ld [hl], "▲" + +.okay + call MenuBoxCoord2Tile + ld bc, SCREEN_WIDTH + 1 + add hl, bc + ld a, [wMenuData_ScrollingMenuHeight] + ld b, a + ld c, $0 +.loop + ld a, [wMenuScrollPosition] + add c + ld [wScrollingMenuCursorPosition], a + ld a, c + call ScrollingMenu_GetListItemCoordAndFunctionArgs + ld a, [wMenuSelection] + cp -1 + jr z, .cancel + push bc + push hl + call ScrollingMenu_CallFunctions1and2 + pop hl + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop bc + inc c + ld a, c + cp b + jr nz, .loop + ld a, [wMenuDataFlags] + bit 4, a ; place arrows + jr z, .done + ld a, [wMenuBorderBottomCoord] + ld b, a + ld a, [wMenuBorderRightCoord] + ld c, a + call Coord2Tile + ld [hl], "▼" + +.done + ret + +.cancel + ld a, [wMenuDataFlags] + bit 0, a ; call function on cancel + jr nz, .call_function + ld de, .string_24787 + call PlaceString + ret + +.string_24787 + db "CANCEL@" + +.call_function + ld d, h + ld e, l + ld hl, wMenuData_ScrollingMenuFunction1 + jp CallPointerAt + +ScrollingMenu_CallFunctions1and2: + push hl + ld d, h + ld e, l + ld hl, wMenuData_ScrollingMenuFunction1 + call CallPointerAt + pop hl + ld a, [wMenuData_ScrollingMenuWidth] + and a + jr z, .done + ld e, a + ld d, $0 + add hl, de + ld d, h + ld e, l + ld hl, wMenuData_ScrollingMenuFunction2 + call CallPointerAt + +.done + ret + +ScrollingMenu_PlaceCursor: + ld a, [wSwitchItem] + and a + jr z, .done + ld b, a + ld a, [wMenuScrollPosition] + cp b + jr nc, .done + ld c, a + ld a, [wMenuData_ScrollingMenuHeight] + add c + cp b + jr c, .done + ld a, b + sub c + dec a + add a + add $1 + ld c, a + ld a, [wMenuBorderTopCoord] + add c + ld b, a + ld a, [wMenuBorderLeftCoord] + add $0 + ld c, a + call Coord2Tile + ld [hl], "▷" + +.done + ret + +ScrollingMenu_CheckCallFunction3: + ld a, [wMenuDataFlags] + bit 5, a ; call function 3 + ret z + bit 1, a ; call function 3 if not switching items + jr z, .call + ld a, [wSwitchItem] + and a + ret nz + +.call + ld a, [wMenuCursorY] + dec a + call ScrollingMenu_GetListItemCoordAndFunctionArgs + ld hl, wMenuData_ScrollingMenuFunction3 + call CallPointerAt + ret + +ScrollingMenu_GetListItemCoordAndFunctionArgs: + push de + push hl + ld e, a + ld a, [wMenuScrollPosition] + add e + ld e, a + ld d, $0 + ld hl, wMenuData_ItemsPointerAddr + ld a, [hli] + ld h, [hl] + ld l, a + inc hl ; items + ld a, [wMenuData_ScrollingMenuItemFormat] + cp SCROLLINGMENU_ITEMS_NORMAL + jr z, .got_spacing + cp SCROLLINGMENU_ITEMS_QUANTITY + jr z, .pointless_jump +.pointless_jump + add hl, de +.got_spacing + add hl, de + ld a, [wMenuData_ItemsPointerBank] + call GetFarByte + ld [wMenuSelection], a + ld [wCurItem], a + inc hl + ld a, [wMenuData_ItemsPointerBank] + call GetFarByte + ld [wMenuSelectionQuantity], a + pop hl + pop de + ret diff --git a/engine/menus/start_menu.asm b/engine/menus/start_menu.asm new file mode 100644 index 00000000..dbadf637 --- /dev/null +++ b/engine/menus/start_menu.asm @@ -0,0 +1,541 @@ +; StartMenu.Items indexes + const_def + const STARTMENUITEM_POKEDEX ; 0 + const STARTMENUITEM_POKEMON ; 1 + const STARTMENUITEM_PACK ; 2 + const STARTMENUITEM_STATUS ; 3 + const STARTMENUITEM_SAVE ; 4 + const STARTMENUITEM_OPTION ; 5 + const STARTMENUITEM_EXIT ; 6 + const STARTMENUITEM_POKEGEAR ; 7 + const STARTMENUITEM_QUIT ; 8 + +StartMenu:: + call ClearWindowData + + ld de, SFX_MENU + call PlaySFX + + farcall ReanchorBGMap_NoOAMUpdate + + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + ld hl, .MenuHeader + jr z, .GotMenuData + ld hl, .ContestMenuHeader + +.GotMenuData: + call LoadMenuHeader + call .SetUpMenuItems + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + call .DrawMenuAccount + call DrawVariableLengthMenuBox + call .DrawBugContestStatusBox + call SafeUpdateSprites + call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap + farcall LoadFonts_NoOAMUpdate + call .DrawBugContestStatus + call UpdateTimePals + jr .Select + +.Reopen: + call UpdateSprites + call UpdateTimePals + call .SetUpMenuItems + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + +.Select: + call .GetInput + jr c, .Exit + call ._DrawMenuAccount + ld a, [wMenuCursorBuffer] + ld [wBattleMenuCursorBuffer], a + call PlayClickSFX + call PlaceHollowCursor + call .OpenMenu + +; Menu items have different return functions. +; For example, saving exits the menu. + ld hl, .MenuReturns + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.MenuReturns: + dw .Reopen + dw .Exit + dw .ExitMenuCallFuncCloseText + dw .ExitMenuRunScriptCloseText + dw .ExitMenuRunScript + dw .ReturnEnd + dw .ReturnRedraw + +.Exit: + ldh a, [hOAMUpdate] + push af + ld a, 1 + ldh [hOAMUpdate], a + call LoadFontsExtra + pop af + ldh [hOAMUpdate], a +.ReturnEnd: + call ExitMenu +.ReturnEnd2: + call CloseText + call UpdateTimePals + ret + +.GetInput: +; Return carry on exit, and no-carry on selection. + xor a + ldh [hBGMapMode], a + call ._DrawMenuAccount + call SetUpMenu + ld a, $ff + ld [wMenuSelection], a +.loop + call .PrintMenuAccount + call GetScrollingMenuJoypad + ld a, [wMenuJoypad] + cp B_BUTTON + jr z, .b + cp A_BUTTON + jr z, .a + jr .loop +.a + call PlayClickSFX + and a + ret +.b + scf + ret + +.ExitMenuRunScript: + call ExitMenu + ld a, HMENURETURN_SCRIPT + ldh [hMenuReturn], a + ret + +.ExitMenuRunScriptCloseText: + call ExitMenu + ld a, HMENURETURN_SCRIPT + ldh [hMenuReturn], a + jr .ReturnEnd2 + +.ExitMenuCallFuncCloseText: + call ExitMenu + ld hl, wQueuedScriptAddr + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wQueuedScriptBank] + rst FarCall + jr .ReturnEnd2 + +.ReturnRedraw: + call .Clear + jp .Reopen + +.Clear: + call ClearBGPalettes + call Call_ExitMenu + call ReloadTilesetAndPalettes + call .DrawMenuAccount + call DrawVariableLengthMenuBox + call .DrawBugContestStatus + call UpdateSprites + call ReloadPalettes + call FinishExitMenu + ret + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 10, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .MenuData + db 1 ; default selection + +.ContestMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 10, 2, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .MenuData + db 1 ; default selection + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_WRAP | STATICMENU_ENABLE_START ; flags + dn 0, 0 ; rows, columns + dw wMenuItemsList + dw .MenuString + dw .Items + +.Items: +; entries correspond to STARTMENUITEM_* constants + dw StartMenu_Pokedex, .PokedexString, .PokedexDesc + dw StartMenu_Pokemon, .PartyString, .PartyDesc + dw StartMenu_Pack, .PackString, .PackDesc + dw StartMenu_Status, .StatusString, .StatusDesc + dw StartMenu_Save, .SaveString, .SaveDesc + dw StartMenu_Option, .OptionString, .OptionDesc + dw StartMenu_Exit, .ExitString, .ExitDesc + dw StartMenu_Pokegear, .PokegearString, .PokegearDesc + dw StartMenu_Quit, .QuitString, .QuitDesc + +.PokedexString: db "#DEX@" +.PartyString: db "#MON@" +.PackString: db "PACK@" +.StatusString: db "<PLAYER>@" +.SaveString: db "SAVE@" +.OptionString: db "OPTION@" +.ExitString: db "EXIT@" +.PokegearString: db "<POKE>GEAR@" +.QuitString: db "QUIT@" + +.PokedexDesc: + db "#MON" + next "database@" + +.PartyDesc: + db "Party <PKMN>" + next "status@" + +.PackDesc: + db "Contains" + next "items@" + +.PokegearDesc: + db "Trainer's" + next "key device@" + +.StatusDesc: + db "Your own" + next "status@" + +.SaveDesc: + db "Save your" + next "progress@" + +.OptionDesc: + db "Change" + next "settings@" + +.ExitDesc: + db "Close this" + next "menu@" + +.QuitDesc: + db "Quit and" + next "be judged.@" + +.OpenMenu: + ld a, [wMenuSelection] + call .GetMenuAccountTextPointer + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.MenuString: + push de + ld a, [wMenuSelection] + call .GetMenuAccountTextPointer + inc hl + inc hl + ld a, [hli] + ld d, [hl] + ld e, a + pop hl + call PlaceString + ret + +.MenuDesc: + push de + ld a, [wMenuSelection] + cp $ff + jr z, .none + call .GetMenuAccountTextPointer +rept 4 + inc hl +endr + ld a, [hli] + ld d, [hl] + ld e, a + pop hl + call PlaceString + ret +.none + pop de + ret + +.GetMenuAccountTextPointer: + ld e, a + ld d, 0 + ld hl, wMenuDataPointerTableAddr + ld a, [hli] + ld h, [hl] + ld l, a +rept 6 + add hl, de +endr + ret + +.SetUpMenuItems: + xor a + ld [wWhichIndexSet], a + call .FillMenuList + + ld hl, wStatusFlags + bit STATUSFLAGS_POKEDEX_F, [hl] + jr z, .no_pokedex + ld a, STARTMENUITEM_POKEDEX + call .AppendMenuList +.no_pokedex + + ld a, [wPartyCount] + and a + jr z, .no_pokemon + ld a, STARTMENUITEM_POKEMON + call .AppendMenuList +.no_pokemon + + ld a, [wLinkMode] + and a + jr nz, .no_pack + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + jr nz, .no_pack + ld a, STARTMENUITEM_PACK + call .AppendMenuList +.no_pack + + ld hl, wPokegearFlags + bit POKEGEAR_OBTAINED_F, [hl] + jr z, .no_pokegear + ld a, STARTMENUITEM_POKEGEAR + call .AppendMenuList +.no_pokegear + + ld a, STARTMENUITEM_STATUS + call .AppendMenuList + + ld a, [wLinkMode] + and a + jr nz, .no_save + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + ld a, STARTMENUITEM_QUIT + jr nz, .write + ld a, STARTMENUITEM_SAVE +.write + call .AppendMenuList +.no_save + + ld a, STARTMENUITEM_OPTION + call .AppendMenuList + ld a, STARTMENUITEM_EXIT + call .AppendMenuList + ld a, c + ld [wMenuItemsList], a + ret + +.FillMenuList: + xor a + ld hl, wMenuItemsList + ld [hli], a + ld a, -1 + ld bc, wMenuItemsListEnd - (wMenuItemsList + 1) + call ByteFill + ld de, wMenuItemsList + 1 + ld c, 0 + ret + +.AppendMenuList: + ld [de], a + inc de + inc c + ret + +.DrawMenuAccount: + jp ._DrawMenuAccount + +.PrintMenuAccount: + call .IsMenuAccountOn + ret z + call ._DrawMenuAccount + decoord 0, 14 + jp .MenuDesc + +._DrawMenuAccount: + call .IsMenuAccountOn + ret z + hlcoord 0, 13 + lb bc, 5, 10 + call ClearBox + hlcoord 0, 13 + ld b, 3 + ld c, 8 + jp TextboxPalette + +.IsMenuAccountOn: + ld a, [wOptions2] + and 1 << MENU_ACCOUNT + ret + +.DrawBugContestStatusBox: + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + ret z + farcall StartMenu_DrawBugContestStatusBox + ret + +.DrawBugContestStatus: + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + jr nz, .contest + ret +.contest + farcall StartMenu_PrintBugContestStatus + ret + +StartMenu_Exit: +; Exit the menu. + + ld a, 1 + ret + +StartMenu_Quit: +; Retire from the bug catching contest. + + ld hl, .StartMenuContestEndText + call StartMenuYesNo + jr c, .DontEndContest + ld a, BANK(BugCatchingContestReturnToGateScript) + ld hl, BugCatchingContestReturnToGateScript + call FarQueueScript + ld a, 4 + ret + +.DontEndContest: + ld a, 0 + ret + +.StartMenuContestEndText: + text_far _StartMenuContestEndText + text_end + +StartMenu_Save: +; Save the game. + + call BufferScreen + farcall SaveMenu + jr nc, .asm_12ce0 + ld a, 0 + ret +.asm_12ce0 + ld a, 1 + ret + +StartMenu_Option: +; Game options. + + call FadeToMenu + farcall OptionsMenu + ld a, 6 + ret + +StartMenu_Status: +; Player status. + + call FadeToMenu + farcall TrainerCard + call CloseSubmenu + ld a, 0 + ret + +StartMenu_Pokedex: + ld a, [wPartyCount] + and a + jr z, .asm_12de0 + + call FadeToMenu + farcall Pokedex + call CloseSubmenu + +.asm_12de0 + ld a, 0 + ret + +StartMenu_Pokegear: + call FadeToMenu + farcall PokeGear + call CloseSubmenu + ld a, 0 + ret + +StartMenu_Pack: + call FadeToMenu + farcall Pack + ld a, [wPackUsedItem] + and a + jr nz, .used_item + call CloseSubmenu + ld a, 0 + ret + +.used_item + call ExitAllMenus + ld a, 4 + ret + +StartMenu_Pokemon: + ld a, [wPartyCount] + and a + jr z, .return + + call FadeToMenu + +.choosemenu + xor a + ld [wPartyMenuActionText], a ; Choose a POKéMON. + call ClearBGPalettes + +.menu + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + +.menunoreload + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes ; load regular palettes? + call DelayFrame + farcall PartyMenuSelect + jr c, .return ; if cancelled or pressed B + + call PokemonActionSubmenu + cp 3 + jr z, .menu + cp 0 + jr z, .choosemenu + cp 1 + jr z, .menunoreload + cp 2 + jr z, .quit + +.return + call CloseSubmenu + ld a, 0 + ret + +.quit + ld a, b + push af + call ExitAllMenus + pop af + ret diff --git a/engine/menus/trainer_card.asm b/engine/menus/trainer_card.asm new file mode 100644 index 00000000..7061d4bd --- /dev/null +++ b/engine/menus/trainer_card.asm @@ -0,0 +1,624 @@ +; TrainerCard.Jumptable indexes + const_def + const TRAINERCARDSTATE_PAGE1_LOADGFX ; 0 + const TRAINERCARDSTATE_PAGE1_JOYPAD ; 1 + const TRAINERCARDSTATE_PAGE2_LOADGFX ; 2 + const TRAINERCARDSTATE_PAGE2_JOYPAD ; 3 + const TRAINERCARDSTATE_PAGE3_LOADGFX ; 4 + const TRAINERCARDSTATE_PAGE3_JOYPAD ; 5 + const TRAINERCARDSTATE_QUIT ; 6 + +TrainerCard: + ld a, [wVramState] + push af + xor a + ld [wVramState], a + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call .InitRAM +.loop + call UpdateTime + call JoyTextDelay + ld a, [wJumptableIndex] + bit 7, a + jr nz, .quit + ldh a, [hJoyLast] + and B_BUTTON + jr nz, .quit + call .RunJumptable + call DelayFrame + jr .loop + +.quit + pop af + ld [wOptions], a + pop af + ld [wVramState], a + ret + +.InitRAM: + call ClearBGPalettes + call ClearSprites + call ClearTilemap + call DisableLCD + + ld hl, ChrisCardPic + ld de, vTiles2 + ld bc, 41 tiles + ld a, BANK(ChrisCardPic) + call FarCopyBytes + + ld hl, CardStatusGFX + ld de, vTiles2 tile $29 + ld bc, 86 tiles + ld a, BANK(CardStatusGFX) + call FarCopyBytes + + call TrainerCard_PrintTopHalfOfCard + + hlcoord 0, 8 + ld d, 6 + call TrainerCard_InitBorder + + call EnableLCD + call WaitBGMap + ld b, SCGB_TRAINER_CARD + call GetSGBLayout + call SetPalettes + call WaitBGMap + ld hl, wJumptableIndex + xor a ; TRAINERCARDSTATE_PAGE1_LOADGFX + ld [hli], a ; wJumptableIndex + ld [hli], a ; wTrainerCardBadgeFrameCounter + ld [hli], a ; wTrainerCardBadgeTileID + ld [hl], a ; wTrainerCardBadgeAttributes + ret + +.RunJumptable: + jumptable .Jumptable, wJumptableIndex + +.Jumptable: +; entries correspond to TRAINERCARDSTATE_* constants + dw TrainerCard_Page1_LoadGFX + dw TrainerCard_Page1_Joypad + dw TrainerCard_Page2_LoadGFX + dw TrainerCard_Page2_Joypad + dw TrainerCard_Page3_LoadGFX + dw TrainerCard_Page3_Joypad + dw TrainerCard_Quit + +TrainerCard_IncrementJumptable: + ld hl, wJumptableIndex + inc [hl] + ret + +TrainerCard_Quit: + ld hl, wJumptableIndex + set 7, [hl] + ret + +TrainerCard_Page1_LoadGFX: + call ClearSprites + hlcoord 0, 8 + ld d, 6 + call TrainerCard_InitBorder + call WaitBGMap + ld de, CardStatusGFX + ld hl, vTiles2 tile $29 + lb bc, BANK(CardStatusGFX), 86 + call Request2bpp + call TrainerCard_Page1_PrintDexCaught_GameTime + call TrainerCard_IncrementJumptable + ret + +TrainerCard_Page1_Joypad: + call TrainerCard_Page1_PrintGameTime + ld hl, hJoyLast + ld a, [hl] + and D_RIGHT | A_BUTTON + jr nz, .pressed_right_a + ret + +.pressed_right_a + ld a, TRAINERCARDSTATE_PAGE2_LOADGFX + ld [wJumptableIndex], a + ret + +.Unreferenced_KantoCheck: + ld a, [wKantoBadges] + and a + ret z + ld a, TRAINERCARDSTATE_PAGE3_LOADGFX + ld [wJumptableIndex], a + ret + +TrainerCard_Page2_LoadGFX: + call ClearSprites + hlcoord 0, 8 + ld d, 6 + call TrainerCard_InitBorder + call WaitBGMap + ld de, LeaderGFX + ld hl, vTiles2 tile $29 + lb bc, BANK(LeaderGFX), 86 + call Request2bpp + ld de, BadgeGFX + ld hl, vTiles0 tile $00 + lb bc, BANK(BadgeGFX), 44 + call Request2bpp + call TrainerCard_Page2_3_InitObjectsAndStrings + call TrainerCard_IncrementJumptable + ret + +TrainerCard_Page2_Joypad: + ld hl, TrainerCard_JohtoBadgesOAM + call TrainerCard_Page2_3_AnimateBadges + ld hl, hJoyLast + ld a, [hl] + and A_BUTTON + jr nz, .Quit + ld a, [hl] + and D_LEFT + jr nz, .d_left + ret + +.d_left + ld a, TRAINERCARDSTATE_PAGE1_LOADGFX + ld [wJumptableIndex], a + ret + +.Unreferenced_KantoCheck: + ld a, [wKantoBadges] + and a + ret z + ld a, TRAINERCARDSTATE_PAGE3_LOADGFX + ld [wJumptableIndex], a + ret + +.Quit: + ld a, TRAINERCARDSTATE_QUIT + ld [wJumptableIndex], a + ret + +TrainerCard_Page3_LoadGFX: + call ClearSprites + hlcoord 0, 8 + ld d, 6 + call TrainerCard_InitBorder + call WaitBGMap + ld de, LeaderGFX2 + ld hl, vTiles2 tile $29 + lb bc, BANK(LeaderGFX2), 86 + call Request2bpp + ld de, BadgeGFX2 + ld hl, vTiles0 tile $00 + lb bc, BANK(BadgeGFX2), 44 + call Request2bpp + call TrainerCard_Page2_3_InitObjectsAndStrings + call TrainerCard_IncrementJumptable + ret + +TrainerCard_Page3_Joypad: + ld hl, TrainerCard_JohtoBadgesOAM + call TrainerCard_Page2_3_AnimateBadges + ld hl, hJoyLast + ld a, [hl] + and D_LEFT + jr nz, .left + ld a, [hl] + and D_RIGHT + jr nz, .right + ret + +.left + ld a, TRAINERCARDSTATE_PAGE2_LOADGFX + ld [wJumptableIndex], a + ret + +.right + ld a, TRAINERCARDSTATE_PAGE1_LOADGFX + ld [wJumptableIndex], a + ret + +TrainerCard_PrintTopHalfOfCard: + hlcoord 0, 0 + ld d, 5 + call TrainerCard_InitBorder + hlcoord 2, 2 + ld de, .Name_Money + call PlaceString + hlcoord 2, 4 + ld de, .ID_No + call TrainerCardSetup_PlaceTilemapString + hlcoord 7, 2 + ld de, wPlayerName + call PlaceString + hlcoord 5, 4 + ld de, wPlayerID + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + hlcoord 7, 6 + ld de, wMoney + lb bc, PRINTNUM_MONEY | 3, 6 + call PrintNum + hlcoord 1, 3 + ld de, .HorizontalDivider + call TrainerCardSetup_PlaceTilemapString + hlcoord 14, 1 + ld de, SCREEN_WIDTH + xor a + ld b, 7 + +.row + ld c, 5 + push hl + +.col + ld [hli], a + inc a + dec c + jr nz, .col + pop hl + add hl, de + dec b + jr nz, .row + ret + +.Name_Money: + db "NAME/" + next "" + next "MONEY@" + +.ID_No: + db $27, $28, -1 ; ID NO + +.HorizontalDivider: + db $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $25, $26, -1 ; ____________> + +TrainerCard_Page1_PrintDexCaught_GameTime: + hlcoord 2, 10 + ld de, .Dex_PlayTime + call PlaceString + hlcoord 12, 15 + ld de, .Badges + call PlaceString + ld hl, wPokedexCaught + ld b, wEndPokedexCaught - wPokedexCaught + call CountSetBits + ld de, wNumSetBits + hlcoord 15, 10 + lb bc, 1, 3 + call PrintNum + call TrainerCard_Page1_PrintGameTime + hlcoord 2, 8 + ld de, .StatusTilemap + call TrainerCardSetup_PlaceTilemapString + ld a, [wStatusFlags] + bit STATUSFLAGS_POKEDEX_F, a + ret nz + hlcoord 1, 9 + lb bc, 2, 17 + call ClearBox + ret + +.Dex_PlayTime: + db "#DEX" + next "PLAY TIME@" + + db "@" ; unused + +.Badges: + db "BADGES▶@" + +.StatusTilemap: + db $29, $2a, $2b, $2c, $2d, -1 + +TrainerCard_Page2_3_InitObjectsAndStrings: + hlcoord 2, 8 + ld de, .BadgesTilemap + call TrainerCardSetup_PlaceTilemapString + hlcoord 2, 10 + ld a, $29 + ld c, 4 +.loop + call TrainerCard_Page2_3_PlaceLeadersFaces +rept 4 + inc hl +endr + dec c + jr nz, .loop + hlcoord 2, 13 + ld a, $51 + ld c, 4 +.loop2 + call TrainerCard_Page2_3_PlaceLeadersFaces +rept 4 + inc hl +endr + dec c + jr nz, .loop2 + xor a + ld [wTrainerCardBadgeFrameCounter], a + ld hl, TrainerCard_JohtoBadgesOAM + call TrainerCard_Page2_3_OAMUpdate + ret + +.BadgesTilemap: + db $79, $7a, $7b, $7c, $7d, -1 ; "BADGES" + +TrainerCardSetup_PlaceTilemapString: +.loop + ld a, [de] + cp -1 + ret z + ld [hli], a + inc de + jr .loop + +TrainerCard_InitBorder: + ld e, SCREEN_WIDTH +.loop1 + ld a, $23 + ld [hli], a + dec e + jr nz, .loop1 + + ld a, $23 + ld [hli], a + ld e, SCREEN_HEIGHT - 1 + ld a, " " +.loop2 + ld [hli], a + dec e + jr nz, .loop2 + + ld a, $4 + ld [hli], a + ld a, $23 + ld [hli], a +.loop3 + ld a, $23 + ld [hli], a + + ld e, SCREEN_HEIGHT + ld a, " " +.loop4 + ld [hli], a + dec e + jr nz, .loop4 + + ld a, $23 + ld [hli], a + dec d + jr nz, .loop3 + + ld a, $23 + ld [hli], a + ld a, $24 + ld [hli], a + + ld e, SCREEN_HEIGHT - 1 + ld a, " " +.loop5 + ld [hli], a + dec e + jr nz, .loop5 + ld a, $23 + ld [hli], a + ld e, SCREEN_WIDTH +.loop6 + ld a, $23 + ld [hli], a + dec e + jr nz, .loop6 + ret + +TrainerCard_Page2_3_PlaceLeadersFaces: + push de + push hl + ld [hli], a + inc a + ld [hli], a + inc a + ld [hli], a + inc a + ld [hli], a + inc a + ld de, SCREEN_WIDTH - 3 + add hl, de + ld [hli], a + inc a + ld [hli], a + inc a + ld [hli], a + inc a + ld de, SCREEN_WIDTH - 3 + add hl, de + ld [hli], a + inc a + ld [hli], a + inc a + ld [hli], a + inc a + pop hl + pop de + ret + +TrainerCard_Page1_PrintGameTime: + hlcoord 11, 12 + ld de, wGameTimeHours + lb bc, 2, 4 + call PrintNum + inc hl + ld de, wGameTimeMinutes + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ldh a, [hVBlankCounter] + and $1f + ret nz + hlcoord 15, 12 + ld a, [hl] + xor " " ^ $2e ; alternate between space and small colon ($2e) tiles + ld [hl], a + ret + +TrainerCard_Page2_3_AnimateBadges: + ldh a, [hVBlankCounter] + and %111 + ret nz + ld a, [wTrainerCardBadgeFrameCounter] + inc a + and %111 + ld [wTrainerCardBadgeFrameCounter], a + jr TrainerCard_Page2_3_OAMUpdate + +TrainerCard_Page2_3_OAMUpdate: +; copy flag array pointer + ld a, [hli] + ld e, a + ld a, [hli] +; get flag array + ld d, a + ld a, [de] + ld c, a + ld de, wVirtualOAMSprite00 + ld b, NUM_JOHTO_BADGES +.loop + srl c + push bc + jr nc, .skip_badge + push hl + ld a, [hli] ; y + ld b, a + ld a, [hli] ; x + ld c, a + ld a, [hli] ; pal + ld [wTrainerCardBadgeAttributes], a + ld a, [wTrainerCardBadgeFrameCounter] + add l + ld l, a + ld a, 0 + adc h + ld h, a + ld a, [hl] + ld [wTrainerCardBadgeTileID], a + call .PrepOAM + pop hl +.skip_badge + ld bc, $b ; 3 + 2 * 4 + add hl, bc + pop bc + dec b + jr nz, .loop + ret + +.PrepOAM: + ld a, [wTrainerCardBadgeTileID] + and 1 << 7 + jr nz, .xflip + ld hl, .facing1 + jr .loop2 + +.xflip + ld hl, .facing2 +.loop2 + ld a, [hli] + cp -1 + ret z + add b + ld [de], a ; y + inc de + + ld a, [hli] + add c + ld [de], a ; x + inc de + + ld a, [wTrainerCardBadgeTileID] + and $ff ^ (1 << 7) + add [hl] + ld [de], a ; tile id + inc hl + inc de + + ld a, [wTrainerCardBadgeAttributes] + add [hl] + ld [de], a ; attributes + inc hl + inc de + jr .loop2 + +.facing1 + dbsprite 0, 0, 0, 0, $00, 0 + dbsprite 1, 0, 0, 0, $01, 0 + dbsprite 0, 1, 0, 0, $02, 0 + dbsprite 1, 1, 0, 0, $03, 0 + db -1 + +.facing2 + dbsprite 0, 0, 0, 0, $01, 0 | X_FLIP + dbsprite 1, 0, 0, 0, $00, 0 | X_FLIP + dbsprite 0, 1, 0, 0, $03, 0 | X_FLIP + dbsprite 1, 1, 0, 0, $02, 0 | X_FLIP + db -1 + +TrainerCard_JohtoBadgesOAM: +; Template OAM data for each badge on the trainer card. +; Format: + ; y, x, palette + ; cycle 1: face tile, in1 tile, in2 tile, in3 tile + ; cycle 2: face tile, in1 tile, in2 tile, in3 tile + + dw wJohtoBadges + + ; Zephyrbadge + db $68, $18, 0 + db $00, $20, $24, $20 | (1 << 7) + db $00, $20, $24, $20 | (1 << 7) + + ; Hivebadge + db $68, $38, 0 + db $04, $20, $24, $20 | (1 << 7) + db $04, $20, $24, $20 | (1 << 7) + + ; Plainbadge + db $68, $58, 0 + db $08, $20, $24, $20 | (1 << 7) + db $08, $20, $24, $20 | (1 << 7) + + ; Fogbadge + db $68, $78, 0 + db $0c, $20, $24, $20 | (1 << 7) + db $0c, $20, $24, $20 | (1 << 7) + + ; Mineralbadge + db $80, $38, 0 + db $10, $20, $24, $20 | (1 << 7) + db $10, $20, $24, $20 | (1 << 7) + + ; Stormbadge + db $80, $18, 0 + db $14, $20, $24, $20 | (1 << 7) + db $14, $20, $24, $20 | (1 << 7) + + ; Glacierbadge + db $80, $58, 0 + db $18, $20, $24, $20 | (1 << 7) + db $18, $20, $24, $20 | (1 << 7) + + ; Risingbadge + ; X-flips on alternate cycles. + db $80, $78, 0 + db $1c, $20, $24, $20 | (1 << 7) + db $1c | (1 << 7), $20, $24, $20 | (1 << 7) + +ChrisCardPic: INCBIN "gfx/trainer_card/chris_card.2bpp" +CardGFX: INCBIN "gfx/trainer_card/trainer_card.2bpp" +CardStatusGFX: INCBIN "gfx/trainer_card/card_status.2bpp" + +LeaderGFX: INCBIN "gfx/trainer_card/leaders.2bpp" +LeaderGFX2: INCBIN "gfx/trainer_card/leaders.2bpp" +BadgeGFX: INCBIN "gfx/trainer_card/badges.2bpp" +BadgeGFX2: INCBIN "gfx/trainer_card/badges.2bpp" diff --git a/engine/movement_pattern.asm b/engine/movement_pattern.asm deleted file mode 100755 index 1909f480..00000000 --- a/engine/movement_pattern.asm +++ /dev/null @@ -1,651 +0,0 @@ -RestoreDefaultMovement: - ld hl, $1 - add hl, bc - ld a, [hl] - cp $ff - jr z, .asm_4756 - push bc - call GetMapObject - ld hl, $4 - add hl, bc - ld a, [hl] - pop bc - ret - -.asm_4756 - ld a, $6 - ret - -ClearObjectMovementByteIndex: - ld hl, $1b - add hl, bc - ld [hl], $0 - ret - -IncrementObjectMovementByteIndex: - ld hl, $1b - add hl, bc - inc [hl] - ret - -DecrementObjectMovementByteIndex: - ld hl, $1b - add hl, bc - dec [hl] - ret - -MovementAnonymousJumptable: - ld hl, $1b - add hl, bc - ld a, [hl] - pop hl - rst JumpTable - ret - -ClearObjectStructField28: - ld hl, $1c - add hl, bc - ld [hl], $0 - ret - -IncrementObjectStructField28: - ld hl, $1c - add hl, bc - inc [hl] - ret - -Object28AnonymousJumptable: - ld hl, $1c - add hl, bc - ld a, [hl] - pop hl - rst JumpTable - ret - -GetValueObjectStructField28: - ld hl, $1c - add hl, bc - ld a, [hl] - ret - -SetValueObjectStructField28: - ld hl, $1c - add hl, bc - ld [hl], a - ret - -ObjectMovementReset: ; 4795 (1:4795) - ld hl, $10 - add hl, bc - ld d, [hl] - ld hl, $11 - add hl, bc - ld e, [hl] - push bc - call GetCoordTile - pop bc - ld hl, $e - add hl, bc - ld [hl], a - call CopyNextCoordsTileToStandingCoordsTile - call EndSpriteMovement - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -MapObjectMovementPattern: ; 47b6 (1:47b6) - call ClearObjectStructField28 - call GetSpriteMovementFunction - ld a, [hl] - ld hl, .Pointers - rst JumpTable - ret - -.Pointers: - dw Function47fa - dw Function47fb - dw Function4805 - dw Function4811 - dw Function481b - dw Function482a - dw Function4842 - dw Function4855 - dw Function485b - dw Function4861 - dw Function4867 - dw Function486a - dw Function486d - dw Function4870 - dw Function4876 - dw Function4879 - dw Function487f - dw Function4885 - dw Function48d8 - dw Function49be - dw Function49fa - dw Function4931 - dw Function4947 - dw Function4a95 - dw Function4966 - dw Function495d - dw Function4a1f - dw Function4a62 - -Function47fa: - ret - -Function47fb: ; 47fb (1:47fb) - call Random - ldh a, [hRandom] - and $1 - jp Function4ac9 - -Function4805: ; 4805 (1:4805) - call Random - ldh a, [hRandom] - and $1 - or $2 - jp Function4ac9 - -Function4811: ; 4811 (1:4811) - call Random - ldh a, [hRandom] - and $3 - jp Function4ac9 - -Function481b: ; 481b (1:481b) - call Random - ldh a, [hRandom] - and $c - ld hl, $8 - add hl, bc - ld [hl], a - jp Function4af6 - -Function482a: ; 482a (1:482a) - ld hl, $8 - add hl, bc - ld a, [hl] - and $c - ld d, a - call Random - ldh a, [hRandom] - and $c - cp d - jr nz, .asm_483e - xor $c -.asm_483e - ld [hl], a - jp Function4aff - -Function4842: ; 4842 (1:4842) - call Function4603 - call EndSpriteMovement - ld hl, $b - add hl, bc - ld [hl], $1 - ld hl, $9 - add hl, bc - ld [hl], $5 - ret - -Function4855: ; 4855 (1:4855) - ld hl, $4fa8 - jp Function4fe9 - -Function485b: ; 485b (1:485b) - ld hl, $4fbd - jp Function4fe9 - -Function4861: ; 4861 (1:4861) - ld hl, $4fce - jp Function4fe9 - -Function4867: ; 4867 (1:4867) - jp Function4fdf - -Function486a: ; 486a (1:486a) - jp Function4fdf - -Function486d: ; 486d (1:486d) - jp Function4fdf - -Function4870: ; 4870 (1:4870) - ld hl, $4fa8 - jp Function4fe9 - -Function4876: ; 4876 (1:4876) - jp Function4fdf - -Function4879: ; 4879 (1:4879) - ld hl, $5485 - jp Function4fe9 - -Function487f: ; 487f (1:487f) - ld hl, $4fb6 - jp Function4fe9 - -Function4885: ; 4885 (1:4885) - call MovementAnonymousJumptable - dw .asm_488c - dw .asm_48d1 - -.asm_488c - ld hl, $e - add hl, bc - ld a, [hl] - call CheckPitTile - jr z, .asm_48ce - ld hl, $5 - add hl, bc - bit 2, [hl] - res 2, [hl] - jr z, .asm_48c7 - ld hl, $20 - add hl, bc - ld a, [hl] - and $3 - or $0 - call InitStep - call CheckNPCMovementPermissions - jr c, .asm_48c4 - ld de, $1b - call PlaySFX - call Function54d7 - call UpdateGrassPriority - ld hl, $9 - add hl, bc - ld [hl], $f - ret - -.asm_48c4 - call Function4603 -.asm_48c7 - ld hl, $7 - add hl, bc - ld [hl], $ff - ret - -.asm_48ce - call IncrementObjectMovementByteIndex -.asm_48d1 - ld hl, $7 - add hl, bc - ld [hl], $ff - ret - -Function48d8: ; 48d8 (1:48d8) - ld hl, $10 - add hl, bc - ld d, [hl] - ld hl, $11 - add hl, bc - ld e, [hl] - ld hl, $20 - add hl, bc - ld a, [hl] - push bc - call GetObjectStruct - ld hl, $7 - add hl, bc - ld a, [hl] - cp $ff - jr z, .asm_4923 - ld hl, $12 - add hl, bc - ld a, [hl] - cp d - jr z, .asm_4906 - jr c, .asm_4902 - ld a, $3 - jr .asm_4916 - -.asm_4902 - ld a, $2 - jr .asm_4916 - -.asm_4906 - ld hl, $13 - add hl, bc - ld a, [hl] - cp e - jr z, .asm_4923 - jr c, .asm_4914 - ld a, $0 - jr .asm_4916 - -.asm_4914 - ld a, $1 -.asm_4916 - ld d, a - ld hl, $7 - add hl, bc - ld a, [hl] - and $c - or d - pop bc - jp Function53b1 - -.asm_4923 - pop bc - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $b - add hl, bc - ld [hl], $1 - ret - -Function4931: ; 4931 (1:4931) - call EndSpriteMovement - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $b - add hl, bc - ld [hl], $9 - ld hl, $9 - add hl, bc - ld [hl], $4 - ret - -Function4947: ; 4947 (1:4947) - call EndSpriteMovement - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $b - add hl, bc - ld [hl], $a - ld hl, $9 - add hl, bc - ld [hl], $4 - ret - -Function495d: ; 495d (1:495d) - call MovementAnonymousJumptable - dw Function496f - dw Function4975 - dw Function4991 - -Function4966: ; 4966 (1:4966) - call MovementAnonymousJumptable - dw Function496f - dw Function4975 - dw Function499d - -Function496f: - call EndSpriteMovement - call IncrementObjectMovementByteIndex -Function4975: - ld hl, $b - add hl, bc - ld [hl], $1 - ld hl, $20 - add hl, bc - ld a, [hl] - ld a, $10 - ld hl, $a - add hl, bc - ld [hl], a - ld hl, $9 - add hl, bc - ld [hl], $3 - call IncrementObjectMovementByteIndex - ret - -Function4991: - ld de, .data - call Function49a9 - jr Function495d - -.data - db OW_RIGHT, OW_LEFT, OW_DOWN, OW_UP - -Function499d: - ld de, .data - call Function49a9 - jr Function4966 - -.data - db OW_LEFT, OW_RIGHT, OW_UP, OW_DOWN - -Function49a9: ; 49a9 (1:49a9) - ld hl, $8 - add hl, bc - ld a, [hl] - and $c - rrca - rrca - push hl - ld l, a - ld h, $0 - add hl, de - ld a, [hl] - pop hl - ld [hl], a - call DecrementObjectMovementByteIndex - ret - -Function49be: ; 49be (1:49be) - call Function4a81 - ld hl, $b - add hl, bc - ld [hl], $7 - ld hl, $a - add hl, de - ld a, [hl] - inc a - add a - add $0 - ld hl, $a - add hl, bc - ld [hl], a - ld hl, $7 - add hl, de - ld a, [hl] - and $3 - ld d, $e - cp $0 - jr z, .asm_49e8 - cp $1 - jr z, .asm_49e8 - ld d, $c -.asm_49e8 - ld hl, $1a - add hl, bc - ld [hl], d - ld hl, $19 - add hl, bc - ld [hl], $0 - ld hl, $9 - add hl, bc - ld [hl], $13 - ret - -Function49fa: ; 49fa (1:49fa) - call EndSpriteMovement - call Function4a81 - ld hl, $b - add hl, bc - ld [hl], $8 - ld hl, $a - add hl, bc - ld [hl], $0 - ld hl, $1a - add hl, bc - ld [hl], $f0 - ld hl, $19 - add hl, bc - ld [hl], $0 - ld hl, $9 - add hl, bc - ld [hl], $13 - ret - -Function4a1f: ; 4a1f (1:4a1f) - call EndSpriteMovement - call Function4a81 - ld hl, $b - add hl, bc - ld [hl], $e - ld hl, $a - add hl, de - ld a, [hl] - inc a - add a - ld hl, $a - add hl, bc - ld [hl], a - ld hl, $7 - add hl, de - ld a, [hl] - and $3 - ld e, a - ld d, $0 - ld hl, .data - add hl, de - add hl, de - ld d, [hl] - inc hl - ld e, [hl] - ld hl, $19 - add hl, bc - ld [hl], d - ld hl, $1a - add hl, bc - ld [hl], e - ld hl, $9 - add hl, bc - ld [hl], $13 - ret - -.data - ; x, y - db 0, -4 - db 0, 8 - db 6, 2 - db -6, 2 - -Function4a62: ; 4a62 (1:4a62) - call EndSpriteMovement - call Function4a81 - ld hl, $b - add hl, bc - ld [hl], $f - ld hl, $a - add hl, de - ld a, [hl] - add $ff - ld hl, $a - add hl, bc - ld [hl], a - ld hl, $9 - add hl, bc - ld [hl], $13 - ret - -Function4a81: ; 4a81 (1:4a81) - ld hl, $20 - add hl, bc - ld a, [hl] - push bc - call GetObjectStruct - ld d, b - ld e, c - pop bc - ld hl, $1d - add hl, bc - ld [hl], e - inc hl - ld [hl], d - ret - -Function4a95: ; 4a95 (1:4a95) - call EndSpriteMovement - ld hl, $b - add hl, bc - ld [hl], $0 - ld hl, $20 - add hl, bc - ld a, [hl] - call Function4ab7 - ld hl, $a - add hl, bc - ld [hl], e - ld hl, $1e - add hl, bc - ld [hl], a - ld hl, $9 - add hl, bc - ld [hl], $15 - ret - -Function4ab7: ; 4ab7 (1:4ab7) - ld d, a - and $3f - ld e, a - ld a, d - rlca - rlca - and $3 - ld d, a - inc d - ld a, $1 -.asm_4ac4 - dec d - ret z - add a - jr .asm_4ac4 - -Function4ac9: ; 4ac9 (1:4ac9) - call InitStep - call CheckNPCMovementPermissions - jr c, .asm_4af0 - call UpdateGrassPriority - ld hl, $b - add hl, bc - ld [hl], $2 - ld hl, wCenteredObject - ldh a, [hConnectionStripLength] - cp [hl] - jr z, .asm_4ae9 - ld hl, $9 - add hl, bc - ld [hl], $7 - ret - -.asm_4ae9 - ld hl, $9 - add hl, bc - ld [hl], $6 - ret - -.asm_4af0 - call EndSpriteMovement - call Function4603 -Function4af6: ; 4af6 (1:4af6) - call Random - ldh a, [hRandom] - and $7f - jr asm_4b06 - -Function4aff: ; 4aff (1:4aff) - call Random - ldh a, [hRandomAdd] - and $1f -asm_4b06 - ld hl, $a - add hl, bc - ld [hl], a - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $b - add hl, bc - ld [hl], $1 - ld hl, $9 - add hl, bc - ld [hl], $3 - ret diff --git a/engine/movie/gamefreak_presents.asm b/engine/movie/gamefreak_presents.asm index 7e9519f4..2676c9f6 100644 --- a/engine/movie/gamefreak_presents.asm +++ b/engine/movie/gamefreak_presents.asm @@ -41,9 +41,9 @@ Copyright_GFPresents: ; e49a8 (39:49a8) call GFPresents_PlayFrame jr nc, .loop - ; high bits of wJumpTableIndex are recycled for some flags + ; high bits of wJumptableIndex are recycled for some flags ; this was set if user canceled by pressing a button - ld a, [wJumpTableIndex] + ld a, [wJumptableIndex] bit 6, a jr nz, .canceled @@ -68,16 +68,16 @@ GFPresents_Init: ; e49f3 (39:49f3) lb bc, BANK(GFPresentsGFX2), 5 call Request2bpp - farcall ClearAnimatedObjectBuffer + farcall ClearSpriteAnims - ld hl, wAnimatedObjectDynamicVTileOffsets + ld hl, wSpriteAnimDict ld a, 6 ld [hli], a ld a, $8d ld [hl], a xor a - ld [wJumpTableIndex], a + ld [wJumptableIndex], a ld [$ce64], a ld [wIntroSceneTimer], a ldh [hSCX], a @@ -102,13 +102,13 @@ GFPresents_PlayFrame: ; e4a37 (39:4a37) and BUTTONS jr nz, .pressed_button - ; high bits of wJumpTableIndex are recycled for some flags + ; high bits of wJumptableIndex are recycled for some flags ; this is set when the sequence finished - ld a, [wJumpTableIndex] + ld a, [wJumptableIndex] bit 7, a jr nz, .finish - farcall AnimatedObjects_PlayFrame + farcall PlaySpriteAnimations call GFPresents_HandleFrame call DelayFrame @@ -118,12 +118,12 @@ GFPresents_PlayFrame: ; e4a37 (39:4a37) ret .pressed_button - ; high bits of wJumpTableIndex are recycled for some flags - ld hl, wJumpTableIndex + ; high bits of wJumptableIndex are recycled for some flags + ld hl, wJumptableIndex set 6, [hl] .finish - callfar ClearAnimatedObjectBuffer + callfar ClearSpriteAnims call ClearTilemap call ClearSprites @@ -136,7 +136,7 @@ GFPresents_PlayFrame: ; e4a37 (39:4a37) GFPresents_HandleFrame: ; e4a6d (39:4a6d) ; Dispatch to the current scene handler - ld a, [wJumpTableIndex] + ld a, [wJumptableIndex] ld e, a ld d, 0 ld hl, .scenes @@ -156,7 +156,7 @@ GFPresents_HandleFrame: ; e4a6d (39:4a6d) dw GFPresents_SetDoneFlag GFPresents_NextScene: ; e4a88 (39:4a88) - ld hl, wJumpTableIndex + ld hl, wJumptableIndex inc [hl] ret @@ -257,7 +257,7 @@ GFPresents_PlacePresents: ; e4af4 (39:4af4) GFPresents_SetDoneFlag: ; e4b0d (39:4b0d) ; Tell GFPresents_PlayFrame and TitleScreenFrame (01:63da) that we're finished. - ld hl, wJumpTableIndex + ld hl, wJumptableIndex set 7, [hl] ret diff --git a/engine/movie/title.asm b/engine/movie/title.asm new file mode 100644 index 00000000..93345798 --- /dev/null +++ b/engine/movie/title.asm @@ -0,0 +1,192 @@ +TitleScreen: + call ClearBGPalettes + xor a + ld [wTimeOfDayPal], a + ld de, MUSIC_NONE + call PlayMusic + call ClearTilemap + call DisableLCD + call ClearSprites + xor a + ldh [hBGMapMode], a + ldh [hMapAnims], a + ldh [hSCY], a + ldh [hSCX], a + + ld hl, vTiles0 + ld bc, $200 tiles + xor a + call ByteFill + farcall ClearSpriteAnims + + ld hl, TitleScreenGFX1 + ld de, vTiles2 + ld a, BANK(TitleScreenGFX1) + call FarDecompress + + ld hl, TitleScreenGFX2 + ld de, vTiles1 + ld a, BANK(TitleScreenGFX2) + call FarDecompress + + ld hl, TitleScreenGFX4 + ld de, vTiles0 + ld a, BANK(TitleScreenGFX4) + call FarDecompress + + ld hl, TitleScreenGFX3 + ld de, vTiles1 tile $78 + ld bc, 8 tiles + ld a, BANK(TitleScreenGFX3) + call FarCopyBytes + + call FillTitleScreenPals + call Function63b6 + ld hl, wSpriteAnimDict + xor a + ld [hli], a + ld [hl], a + ld hl, rLCDC + set rLCDC_SPRITE_SIZE, [hl] + call EnableLCD + xor a + ld hl, wJumptableIndex + ld [hli], a ; wJumptableIndex + ld [hli], a ; wIntroSceneFrameCounter + ld [hli], a ; wTitleScreenTimer + ld [hl], a ; wTitleScreenTimer + 1 + ld de, $6058 + ld a, SPRITE_ANIM_INDEX_GS_INTRO_HO_OH + call InitSpriteAnimStruct + ld hl, wSpriteAnim1 + ld de, wSpriteAnim10 + ld bc, NUM_SPRITE_ANIM_STRUCTS + call CopyBytes + ld hl, wSpriteAnim1 + ld [hl], $0 + ld hl, wLYOverrides + ld bc, wLYOverridesEnd - wLYOverrides + xor a + call ByteFill + +; Let LCD Stat know we're messing around with SCX + ld a, LOW(rSCX) + ldh [hLCDCPointer], a + ld b, SCGB_GS_TITLE_SCREEN + call GetSGBLayout + call LoadTitleScreenPals + ld de, MUSIC_TITLE + call PlayMusic + ret + +LoadTitleScreenPals: + ldh a, [hCGB] + and a + jr nz, .cgb + ldh a, [hSGB] + and a + jr nz, .sgb + ld a, %11011000 + ldh [rBGP], a +IF DEF(_GOLD) + ld a, %11111111 + ldh [rOBP0], a + ld a, %11111000 + ldh [rOBP1], a +ELIF DEF(_SILVER) + ld a, %11110000 + ldh [rOBP0], a + ld a, %11110000 + ldh [rOBP1], a +ENDC + ret + +.sgb + ld a, %11100100 + ldh [rBGP], a +IF DEF(_GOLD) + ld a, %11111111 + ldh [rOBP0], a + ld a, %11100100 + ldh [rOBP1], a +ELIF DEF(_SILVER) + ld a, %11110000 + ldh [rOBP0], a + ld a, %11100000 + ldh [rOBP1], a +ENDC + ret + +.cgb + ld a, %11100100 + call DmgToCgbBGPals +IF DEF(_SILVER) + ld a, %11100000 +ENDC + call DmgToCgbObjPal0 + ret + +FillTitleScreenPals: + ldh a, [hCGB] + and a + ret z + ld a, 1 + ldh [rVBK], a + hlbgcoord 0, 0 + ld bc, 18 * BG_MAP_WIDTH + xor a + call ByteFill + ld hl, vBGMap2 + lb bc, 7, SCREEN_WIDTH + ld a, 1 + call DrawTitleGraphic + hlbgcoord 5, 6, vBGMap2 + lb bc, 1, 10 + ld a, 3 + call DrawTitleGraphic + hlbgcoord 0, 12, vBGMap2 + ld bc, 5 * BG_MAP_WIDTH + ld a, 4 + call ByteFill + ld a, 0 + ldh [rVBK], a + ret + +DrawTitleGraphic: +.bgrows + push bc + push hl +.col + ld [hli], a + dec c + jr nz, .col + pop hl + ld bc, BG_MAP_WIDTH + add hl, bc + pop bc + dec b + jr nz, .bgrows + ret + +Function63b6: + ld hl, GSIntroTilemap + debgcoord 0, 0 +.asm_63bc + ld a, BANK(GSIntroTilemap) + call GetFarByte + cp -1 + jr z, .asm_63ca + inc hl + ld [de], a + inc de + jr .asm_63bc + +.asm_63ca + ldh a, [hCGB] + and a + ret nz + hlbgcoord 0, 11 + ld bc, BG_MAP_WIDTH + ld a, "@" + call ByteFill + ret diff --git a/engine/movie/trade_animation.asm b/engine/movie/trade_animation.asm new file mode 100644 index 00000000..410c3c7c --- /dev/null +++ b/engine/movie/trade_animation.asm @@ -0,0 +1,1389 @@ +TRADEANIM_RIGHT_ARROW EQU "▶" ; $ed +TRADEANIM_LEFT_ARROW EQU "▼" ; $ee + +; TradeAnim_TubeAnimJumptable.Jumptable indexes + const_def + const TRADEANIMSTATE_0 ; 0 + const TRADEANIMSTATE_1 ; 1 + const TRADEANIMSTATE_2 ; 2 + const TRADEANIMSTATE_3 ; 3 +TRADEANIMJUMPTABLE_LENGTH EQU const_value + +TradeAnimation: + ld hl, wPlayerTrademonSenderName + ld de, wOTTrademonSenderName + call LinkTradeAnim_LoadTradePlayerNames + ld hl, wPlayerTrademonSpecies + ld de, wOTTrademonSpecies + call LinkTradeAnim_LoadTradeMonSpecies + ld de, .script + jr RunTradeAnimScript + +.script + tradeanim_setup_givemon_scroll + tradeanim_show_givemon_data + tradeanim_do_givemon_scroll + tradeanim_wait_80 + tradeanim_poof + tradeanim_rocking_ball + tradeanim_enter_link_tube + tradeanim_wait_anim + tradeanim_bulge_through_tube + tradeanim_wait_anim + tradeanim_textbox_scroll + tradeanim_give_trademon_sfx + tradeanim_tube_to_ot + tradeanim_sent_to_ot_text + tradeanim_scroll_out_right + + tradeanim_ot_sends_text_1 + tradeanim_ot_bids_farewell + tradeanim_scroll_out_right + tradeanim_get_trademon_sfx + tradeanim_tube_to_player + tradeanim_enter_link_tube + tradeanim_drop_ball + tradeanim_exit_link_tube + tradeanim_wait_anim + tradeanim_show_getmon_data + tradeanim_poof + tradeanim_wait_anim + tradeanim_frontpic_scroll + tradeanim_wait_80 + tradeanim_textbox_scroll + tradeanim_take_care_of_text + tradeanim_scroll_out_right + tradeanim_end + +TradeAnimationPlayer2: + ld hl, wOTTrademonSenderName + ld de, wPlayerTrademonSenderName + call LinkTradeAnim_LoadTradePlayerNames + ld hl, wOTTrademonSpecies + ld de, wPlayerTrademonSpecies + call LinkTradeAnim_LoadTradeMonSpecies + ld de, .script + jr RunTradeAnimScript + +.script + tradeanim_ot_sends_text_2 + tradeanim_ot_bids_farewell + tradeanim_scroll_out_right + tradeanim_get_trademon_sfx + tradeanim_tube_to_ot + tradeanim_enter_link_tube + tradeanim_drop_ball + tradeanim_exit_link_tube + tradeanim_wait_anim + tradeanim_show_getmon_data + tradeanim_poof + tradeanim_wait_anim + tradeanim_frontpic_scroll + tradeanim_wait_80 + tradeanim_textbox_scroll + tradeanim_take_care_of_text + tradeanim_scroll_out_right + + tradeanim_setup_givemon_scroll + tradeanim_show_givemon_data + tradeanim_do_givemon_scroll + tradeanim_wait_80 + tradeanim_poof + tradeanim_rocking_ball + tradeanim_enter_link_tube + tradeanim_wait_anim + tradeanim_bulge_through_tube + tradeanim_wait_anim + tradeanim_textbox_scroll + tradeanim_give_trademon_sfx + tradeanim_tube_to_player + tradeanim_sent_to_ot_text + tradeanim_scroll_out_right + tradeanim_end + +RunTradeAnimScript: + ld hl, wTradeAnimAddress + ld [hl], e + inc hl + ld [hl], d + ldh a, [hMapAnims] + push af + xor a + ldh [hMapAnims], a + ld hl, wVramState + ld a, [hl] + push af + res 0, [hl] + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call .TradeAnimLayout + ld de, MUSIC_EVOLUTION + call PlayMusic2 +.anim_loop + call DoTradeAnimation + jr nc, .anim_loop + pop af + ld [wOptions], a + pop af + ld [wVramState], a + pop af + ldh [hMapAnims], a + ret + +.TradeAnimLayout: + xor a + ld [wJumptableIndex], a + call ClearBGPalettes + call ClearSprites + call ClearTilemap + call DisableLCD + call LoadFontsBattleExtra + callfar ClearSpriteAnims + ldh a, [hCGB] + and a + jr z, .NotCGB + ld a, $1 + ldh [rVBK], a + ld hl, vTiles0 + ld bc, sScratch - vTiles0 + xor a + call ByteFill + ld a, $0 + ldh [rVBK], a + +.NotCGB: + hlbgcoord 0, 0 + ld bc, sScratch - vBGMap0 + ld a, " " + call ByteFill + ld hl, TradeGameBoyLZ + ld de, vTiles2 tile $31 + call Decompress + ld hl, TradeArrowRightGFX + ld de, vTiles0 tile TRADEANIM_RIGHT_ARROW + ld bc, 1 tiles + ld a, BANK(TradeArrowRightGFX) + call FarCopyBytes + ld hl, TradeArrowLeftGFX + ld de, vTiles0 tile TRADEANIM_LEFT_ARROW + ld bc, 1 tiles + ld a, BANK(TradeArrowLeftGFX) + call FarCopyBytes + xor a + ldh [hSCX], a + ldh [hSCY], a + ld a, $7 + ldh [hWX], a + ld a, $90 + ldh [hWY], a + call EnableLCD + call LoadTradeBallAndCableGFX + ld a, [wPlayerTrademonSpecies] + ld hl, wPlayerTrademonDVs + ld de, vTiles0 + call TradeAnim_GetFrontpic + ld a, [wOTTrademonSpecies] + ld hl, wOTTrademonDVs + ld de, vTiles0 tile $31 + call TradeAnim_GetFrontpic + ld a, [wPlayerTrademonSpecies] + ld de, wPlayerTrademonSpeciesName + call TradeAnim_GetNickname + ld a, [wOTTrademonSpecies] + ld de, wOTTrademonSpeciesName + call TradeAnim_GetNickname + call TradeAnim_NormalPals + ret + +DoTradeAnimation: + ld a, [wJumptableIndex] + bit 7, a + jr nz, .finished + call .DoTradeAnimCommand + callfar PlaySpriteAnimations + ld hl, wce65 + inc [hl] + call DelayFrame + and a + ret + +.finished + call LoadStandardFont + scf + ret + +.DoTradeAnimCommand: + 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 + +.JumpTable: +; entries correspond to macros/scripts/trade_anims.asm enumeration + dw TradeAnim_AdvanceScriptPointer ; 00 + dw TradeAnim_ShowGivemonData ; 01 + dw TradeAnim_ShowGetmonData ; 02 + dw TradeAnim_EnterLinkTube1 ; 03 + dw TradeAnim_EnterLinkTube2 ; 04 + dw TradeAnim_ExitLinkTube ; 05 + dw TradeAnim_TubeToOT1 ; 06 + dw TradeAnim_TubeToOT2 ; 07 + dw TradeAnim_TubeToOT3 ; 08 + dw TradeAnim_TubeToOT4 ; 09 + dw TradeAnim_TubeToOT5 ; 0a + dw TradeAnim_TubeToOT6 ; 0b + dw TradeAnim_TubeToOT7 ; 0c + dw TradeAnim_TubeToOT8 ; 0d + dw TradeAnim_TubeToPlayer1 ; 0e + dw TradeAnim_TubeToPlayer2 ; 0f + dw TradeAnim_TubeToPlayer3 ; 10 + dw TradeAnim_TubeToPlayer4 ; 11 + dw TradeAnim_TubeToPlayer5 ; 12 + dw TradeAnim_TubeToPlayer6 ; 13 + dw TradeAnim_TubeToPlayer7 ; 14 + dw TradeAnim_TubeToPlayer8 ; 15 + dw TradeAnim_SentToOTText ; 16 + dw TradeAnim_OTBidsFarewell ; 17 + dw TradeAnim_TakeCareOfText ; 18 + dw TradeAnim_OTSendsText1 ; 19 + dw TradeAnim_OTSendsText2 ; 1a + dw TradeAnim_SetupGivemonScroll ; 1b + dw TradeAnim_DoGivemonScroll ; 1c + dw TradeAnim_FrontpicScrollStart ; 1d + dw TradeAnim_TextboxScrollStart ; 1e + dw TradeAnim_ScrollOutRight ; 1f + dw TradeAnim_ScrollOutRight2 ; 20 + dw TradeAnim_Wait80 ; 21 + dw TradeAnim_RockingBall ; 22 + dw TradeAnim_DropBall ; 23 + dw TradeAnim_WaitAnim ; 24 + dw TradeAnim_Poof ; 25 + dw TradeAnim_BulgeThroughTube ; 26 + dw TradeAnim_GiveTrademonSFX ; 27 + dw TradeAnim_GetTrademonSFX ; 28 + dw TradeAnim_End ; 29 + +TradeAnim_IncrementJumptableIndex: + ld hl, wJumptableIndex + inc [hl] + ret + +TradeAnim_AdvanceScriptPointer: + ld hl, wTradeAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + ld a, [de] + ld [wJumptableIndex], a + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +TradeAnim_End: + ld hl, wJumptableIndex + set 7, [hl] + ret + +TradeAnim_TubeToOT1: + ld a, TRADEANIM_RIGHT_ARROW + call TradeAnim_PlaceTrademonStatsOnTubeAnim + ld a, [wLinkTradeSendmonSpecies] + ld [wTempIconSpecies], a + xor a + depixel 5, 11, 4, 0 + ld b, $0 + jr TradeAnim_InitTubeAnim + +TradeAnim_TubeToPlayer1: + ld a, TRADEANIM_LEFT_ARROW + call TradeAnim_PlaceTrademonStatsOnTubeAnim + ld a, [wLinkTradeGetmonSpecies] + ld [wTempIconSpecies], a + ld a, TRADEANIMSTATE_2 + depixel 9, 18, 4, 4 + ld b, $4 +TradeAnim_InitTubeAnim: + push bc + push de + push bc + push de + + push af + call DisableLCD + callfar ClearSpriteAnims + hlbgcoord 20, 3 + ld bc, 12 + ld a, $60 + call ByteFill + pop af + + call TradeAnim_TubeAnimJumptable + + xor a + ldh [hSCX], a + ld a, $7 + ldh [hWX], a + ld a, $70 + ldh [hWY], a + call EnableLCD + call LoadTradeBubbleGFX + + pop de + ld a, SPRITE_ANIM_INDEX_TRADEMON_ICON + call InitSpriteAnimStruct + + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + pop bc + ld [hl], b + + pop de + ld a, SPRITE_ANIM_INDEX_TRADEMON_BUBBLE + call InitSpriteAnimStruct + + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + pop bc + ld [hl], b + + call WaitBGMap + ld b, SCGB_TRADE_TUBE + call GetSGBLayout + ld a, %11100100 ; 3,2,1,0 + call DmgToCgbBGPals + ld a, %11010000 + call DmgToCgbObjPal0 + + call TradeAnim_IncrementJumptableIndex + ld a, 92 + ld [wFrameCounter], a + ret + +TradeAnim_TubeToOT2: + call TradeAnim_FlashBGPals + ldh a, [hSCX] + add $2 + ldh [hSCX], a + cp $50 + ret nz + ld a, TRADEANIMSTATE_1 + call TradeAnim_TubeAnimJumptable + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToOT3: + call TradeAnim_FlashBGPals + ldh a, [hSCX] + add $2 + ldh [hSCX], a + cp $a0 + ret nz + ld a, TRADEANIMSTATE_2 + call TradeAnim_TubeAnimJumptable + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToOT4: + call TradeAnim_FlashBGPals + ldh a, [hSCX] + add $2 + ldh [hSCX], a + and a + ret nz + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToPlayer3: + call TradeAnim_FlashBGPals + ldh a, [hSCX] + sub $2 + ldh [hSCX], a + cp $b0 + ret nz + ld a, TRADEANIMSTATE_1 + call TradeAnim_TubeAnimJumptable + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToPlayer4: + call TradeAnim_FlashBGPals + ldh a, [hSCX] + sub $2 + ldh [hSCX], a + cp $60 + ret nz + xor a ; TRADEANIMSTATE_0 + call TradeAnim_TubeAnimJumptable + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToPlayer5: + call TradeAnim_FlashBGPals + ldh a, [hSCX] + sub $2 + ldh [hSCX], a + and a + ret nz + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToOT6: +TradeAnim_TubeToPlayer6: + ld a, 128 + ld [wFrameCounter], a + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_TubeToOT8: +TradeAnim_TubeToPlayer8: + call ClearBGPalettes + call ClearTilemap + call ClearSprites + call DisableLCD + callfar ClearSpriteAnims + hlbgcoord 0, 0 + ld bc, sScratch - vBGMap0 + ld a, " " + call ByteFill + xor a + ldh [hSCX], a + ld a, $90 + ldh [hWY], a + call EnableLCD + call LoadTradeBallAndCableGFX + call WaitBGMap + call TradeAnim_NormalPals + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_TubeToOT5: +TradeAnim_TubeToOT7: +TradeAnim_TubeToPlayer2: +TradeAnim_TubeToPlayer7: + call TradeAnim_FlashBGPals + ld hl, wFrameCounter + ld a, [hl] + and a + jr z, .done + dec [hl] + ret + +.done + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_GiveTrademonSFX: + call TradeAnim_AdvanceScriptPointer + ld de, SFX_GIVE_TRADEMON + call PlaySFX + ret + +TradeAnim_GetTrademonSFX: + call TradeAnim_AdvanceScriptPointer + ld de, SFX_GET_TRADEMON + call PlaySFX + ret + +TradeAnim_TubeAnimJumptable: + maskbits TRADEANIMJUMPTABLE_LENGTH + 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 + +.Jumptable: +; entries correspond to TRADEANIMSTATE_* constants + dw .Zero + dw .One + dw .Two + dw .Three + +.Zero: +.Three: + call TradeAnim_BlankTilemap + hlcoord 9, 3 + ld [hl], $5b + inc hl + ld bc, 10 + ld a, $60 + call ByteFill + hlcoord 3, 2 + call TradeAnim_CopyTradeGameBoyTilemap + ret + +.One: + call TradeAnim_BlankTilemap + hlcoord 0, 3 + ld bc, SCREEN_WIDTH + ld a, $60 + call ByteFill + ret + +.Two: + call TradeAnim_BlankTilemap + hlcoord 0, 3 + ld bc, $11 + ld a, $60 + call ByteFill + hlcoord 17, 3 + ld a, $5d + ld [hl], a + + ld a, $61 + ld de, SCREEN_WIDTH + ld c, $3 +.loop + add hl, de + ld [hl], a + dec c + jr nz, .loop + + add hl, de + ld a, $5f + ld [hld], a + ld a, $5b + ld [hl], a + hlcoord 10, 6 + call TradeAnim_CopyTradeGameBoyTilemap + ret + +TradeAnim_CopyTradeGameBoyTilemap: + ld de, TradeGameBoyTilemap + lb bc, 8, 6 + call TradeAnim_CopyBoxFromDEtoHL + ret + +TradeAnim_PlaceTrademonStatsOnTubeAnim: + push af + call ClearBGPalettes + call WaitTop + ld a, HIGH(vBGMap1) + ldh [hBGMapAddress + 1], a + call ClearTilemap + hlcoord 0, 0 + ld bc, SCREEN_WIDTH + ld a, "─" + call ByteFill + hlcoord 0, 1 + ld de, wLinkPlayer1Name + call PlaceString + ld hl, wLinkPlayer2Name + ld de, 0 +.find_name_end_loop + ld a, [hli] + cp "@" + jr z, .done + dec de + jr .find_name_end_loop + +.done + hlcoord 0, 4 + add hl, de + ld de, wLinkPlayer2Name + call PlaceString + hlcoord 7, 2 + ld bc, 6 + pop af + call ByteFill + call WaitBGMap + call WaitTop + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + call ClearTilemap + ret + +TradeAnim_EnterLinkTube1: + call ClearTilemap + call WaitTop + ld a, $a0 + ldh [hSCX], a + call DelayFrame + hlcoord 8, 2 + ld de, TradeLinkTubeTilemap + lb bc, 3, 12 + call TradeAnim_CopyBoxFromDEtoHL + call WaitBGMap + ld b, SCGB_TRADE_TUBE + call GetSGBLayout + ld a, %11100100 ; 3,2,1,0 + call DmgToCgbBGPals + lb de, %11100100, %11100100 ; 3,2,1,0, 3,2,1,0 + call DmgToCgbObjPals + ld de, SFX_POTION + call PlaySFX + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_EnterLinkTube2: + ldh a, [hSCX] + and a + jr z, .done + add $4 + ldh [hSCX], a + ret + +.done + ld c, 80 + call DelayFrames + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_ExitLinkTube: + ldh a, [hSCX] + cp $a0 + jr z, .done + sub $4 + ldh [hSCX], a + ret + +.done + call ClearTilemap + xor a + ldh [hSCX], a + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_SetupGivemonScroll: + ld a, $8f + ldh [hWX], a + ld a, $88 + ldh [hSCX], a + ld a, $50 + ldh [hWY], a + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_DoGivemonScroll: + ldh a, [hWX] + cp $7 + jr z, .done + sub $4 + ldh [hWX], a + ldh a, [hSCX] + sub $4 + ldh [hSCX], a + ret + +.done + ld a, $7 + ldh [hWX], a + xor a + ldh [hSCX], a + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_FrontpicScrollStart: + ld a, $7 + ldh [hWX], a + ld a, $50 + ldh [hWY], a + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_TextboxScrollStart: + ld a, $7 + ldh [hWX], a + ld a, $90 + ldh [hWY], a + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_ScrollOutRight: + call WaitTop + ld a, HIGH(vBGMap1) + ldh [hBGMapAddress + 1], a + call WaitBGMap + ld a, $7 + ldh [hWX], a + xor a + ldh [hWY], a + call DelayFrame + call WaitTop + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + call ClearTilemap + call TradeAnim_IncrementJumptableIndex + ret + +TradeAnim_ScrollOutRight2: + ldh a, [hWX] + cp $a1 + jr nc, .done + inc a + inc a + ldh [hWX], a + ret + +.done + ld a, HIGH(vBGMap1) + ldh [hBGMapAddress + 1], a + call WaitBGMap + ld a, $7 + ldh [hWX], a + ld a, $90 + ldh [hWY], a + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_ShowGivemonData: + call ShowPlayerTrademonStats + ld a, [wPlayerTrademonSpecies] + ld [wCurPartySpecies], a + ld a, [wPlayerTrademonDVs] + ld [wTempMonDVs], a + ld a, [wPlayerTrademonDVs + 1] + ld [wTempMonDVs + 1], a + ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + ld a, %11100100 ; 3,2,1,0 + call DmgToCgbBGPals + call TradeAnim_ShowGivemonFrontpic + + ld a, [wPlayerTrademonSpecies] + call GetCryIndex + jr c, .skip_cry + ld e, c + ld d, b + call PlayCry +.skip_cry + + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_ShowGetmonData: + call ShowOTTrademonStats + ld a, [wOTTrademonSpecies] + ld [wCurPartySpecies], a + ld a, [wOTTrademonDVs] + ld [wTempMonDVs], a + ld a, [wOTTrademonDVs + 1] + ld [wTempMonDVs + 1], a + ld b, SCGB_PLAYER_OR_MON_FRONTPIC_PALS + call GetSGBLayout + ld a, %11100100 ; 3,2,1,0 + call DmgToCgbBGPals + call TradeAnim_ShowGetmonFrontpic + + ld a, [wOTTrademonSpecies] + call GetCryIndex + jr c, .skip_cry + ld e, c + ld d, b + call PlayCry +.skip_cry + + call TradeAnim_AdvanceScriptPointer + ret + +TradeAnim_GetFrontpic: + push de + push af + predef GetUnownLetter + pop af + ld [wCurPartySpecies], a + ld [wCurSpecies], a + call GetBaseData + pop de + predef GetMonFrontpic + ret + +TradeAnim_GetNickname: + push de + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, wStringBuffer1 + pop de + ld bc, NAME_LENGTH + call CopyBytes + ret + +TradeAnim_ShowGivemonFrontpic: + ld de, vTiles0 + jr TradeAnim_ShowFrontpic + +TradeAnim_ShowGetmonFrontpic: + ld de, vTiles0 tile $31 +TradeAnim_ShowFrontpic: + call DelayFrame + ld hl, vTiles2 + lb bc, 10, $31 + call Request2bpp + call WaitTop + call TradeAnim_BlankTilemap + hlcoord 7, 2 + xor a + ldh [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + call WaitBGMap + ret + +TradeAnim_Wait80: + ld c, 80 + call DelayFrames + call TradeAnim_AdvanceScriptPointer + ret + +ShowPlayerTrademonStats: + ld de, wPlayerTrademonSpecies + ld a, [de] + cp EGG + jr z, TrademonStats_Egg + call TrademonStats_MonTemplate + ld de, wPlayerTrademonSpecies + call TrademonStats_PrintSpeciesNumber + ld de, wPlayerTrademonSpeciesName + call TrademonStats_PrintSpeciesName + ld de, wPlayerTrademonOTName + call TrademonStats_PrintOTName + ld de, wPlayerTrademonID + call TrademonStats_PrintTrademonID + call TrademonStats_WaitBGMap + ret + +ShowOTTrademonStats: + ld de, wOTTrademonSpecies + ld a, [de] + cp EGG + jr z, TrademonStats_Egg + call TrademonStats_MonTemplate + ld de, wOTTrademonSpecies + call TrademonStats_PrintSpeciesNumber + ld de, wOTTrademonSpeciesName + call TrademonStats_PrintSpeciesName + ld de, wOTTrademonOTName + call TrademonStats_PrintOTName + ld de, wOTTrademonID + call TrademonStats_PrintTrademonID + call TrademonStats_WaitBGMap + ret + +TrademonStats_MonTemplate: + call WaitTop + call TradeAnim_BlankTilemap + ld a, HIGH(vBGMap1) + ldh [hBGMapAddress + 1], a + hlcoord 3, 0 + ld b, $6 + ld c, $d + call Textbox + hlcoord 4, 0 + ld de, .OTMonData + call PlaceString + ret + +.OTMonData: + db "─── №." + next "" + next "OT/" + next "<ID>№.@" + +TrademonStats_Egg: + call WaitTop + call TradeAnim_BlankTilemap + ld a, HIGH(vBGMap1) + ldh [hBGMapAddress + 1], a + hlcoord 3, 0 + ld b, 6 + ld c, 13 + call Textbox + hlcoord 4, 2 + ld de, .EggData + call PlaceString + call TrademonStats_WaitBGMap + ret + +.EggData: + db "EGG" + next "OT/?????" + next "<ID>№.?????@" + +TrademonStats_WaitBGMap: + call WaitBGMap + call WaitTop + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + ret + +TrademonStats_PrintSpeciesNumber: + hlcoord 10, 0 + lb bc, PRINTNUM_LEADINGZEROS | 1, 3 + call PrintNum + ret + +TrademonStats_PrintSpeciesName: + hlcoord 4, 2 + call PlaceString + ret + +TrademonStats_PrintOTName: + hlcoord 7, 4 + call PlaceString + ret + +TrademonStats_PrintTrademonID: + hlcoord 7, 6 + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + ret + +TradeAnim_RockingBall: + depixel 10, 11, 4, 0 + ld a, SPRITE_ANIM_INDEX_TRADE_POKE_BALL + call InitSpriteAnimStruct + call TradeAnim_AdvanceScriptPointer + ld a, 64 + ld [wFrameCounter], a + ret + +TradeAnim_DropBall: + depixel 10, 11, 4, 0 + ld a, SPRITE_ANIM_INDEX_TRADE_POKE_BALL + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + ld [hl], $1 + ld hl, SPRITEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $dc + call TradeAnim_AdvanceScriptPointer + ld a, 56 + ld [wFrameCounter], a + ret + +TradeAnim_Poof: + depixel 10, 11, 4, 0 + ld a, SPRITE_ANIM_INDEX_TRADE_POOF + call InitSpriteAnimStruct + call TradeAnim_AdvanceScriptPointer + ld a, 16 + ld [wFrameCounter], a + ld de, SFX_BALL_POOF + call PlaySFX + ret + +TradeAnim_BulgeThroughTube: + ld a, %11100100 ; 3,2,1,0 + call DmgToCgbObjPal0 + depixel 5, 11 + ld a, SPRITE_ANIM_INDEX_TRADE_TUBE_BULGE + call InitSpriteAnimStruct + call TradeAnim_AdvanceScriptPointer + ld a, 128 + ld [wFrameCounter], a + ret + +TradeAnim_AnimateTrademonInTube: + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + 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 + +.Jumptable: + dw .InitTimer + dw .WaitTimer1 + dw .MoveRight + dw .MoveDown + dw .MoveUp + dw .MoveLeft + dw .WaitTimer2 + +.JumptableNext: + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + inc [hl] + ret + +.InitTimer: + call .JumptableNext + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], $80 + ret + +.WaitTimer1: + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + dec [hl] + and a + ret nz + call .JumptableNext + +.MoveRight: + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $94 + jr nc, .done_move_right + inc [hl] + ret + +.done_move_right + call .JumptableNext + +.MoveDown: + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $4c + jr nc, .done_move_down + inc [hl] + ret + +.done_move_down + ld hl, SPRITEANIMSTRUCT_INDEX + add hl, bc + ld [hl], $0 + ret + +.MoveUp: + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $2c + jr z, .done_move_up + dec [hl] + ret + +.done_move_up + call .JumptableNext + +.MoveLeft: + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $58 + jr z, .done_move_left + dec [hl] + ret + +.done_move_left + call .JumptableNext + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld [hl], $80 + ret + +.WaitTimer2: + ld hl, SPRITEANIMSTRUCT_0C + add hl, bc + ld a, [hl] + dec [hl] + and a + ret nz + ld hl, SPRITEANIMSTRUCT_INDEX + add hl, bc + ld [hl], $0 + ret + +TradeAnim_SentToOTText: + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + jr z, .time_capsule + ld hl, .MonNameSentToText + call PrintText + ld c, 189 + call DelayFrames + ld hl, .MonWasSentToText + call PrintText + call TradeAnim_Wait80Frames + ld c, 128 + call DelayFrames + call TradeAnim_AdvanceScriptPointer + ret + +.time_capsule + ld hl, .MonWasSentToText + call PrintText + call TradeAnim_Wait80Frames + call TradeAnim_AdvanceScriptPointer + ret + +.MonWasSentToText: + text_far _MonWasSentToText + text_end + +.MonNameSentToText: + text_far _MonNameSentToText + text_end + +TradeAnim_OTBidsFarewell: + ld hl, .BidsFarewellToMonText + call PrintText + call TradeAnim_Wait80Frames + ld hl, .MonNameBidsFarewellText + call PrintText + call TradeAnim_Wait80Frames + call TradeAnim_AdvanceScriptPointer + ret + +.BidsFarewellToMonText: + text_far _BidsFarewellToMonText + text_end + +.MonNameBidsFarewellText: + text_far _MonNameBidsFarewellText + text_end + +TradeAnim_TakeCareOfText: + call WaitTop + hlcoord 0, 10 + ld bc, 8 * SCREEN_WIDTH + ld a, " " + call ByteFill + call WaitBGMap + ld hl, .TakeGoodCareOfMonText + call PrintText + call TradeAnim_Wait80Frames + call TradeAnim_AdvanceScriptPointer + ret + +.TakeGoodCareOfMonText: + text_far _TakeGoodCareOfMonText + text_end + +TradeAnim_OTSendsText1: + ld hl, .ForYourMonSendsText + call PrintText + call TradeAnim_Wait80Frames + ld hl, .OTSendsText + call PrintText + call TradeAnim_Wait80Frames + ld c, 14 + call DelayFrames + call TradeAnim_AdvanceScriptPointer + ret + +.ForYourMonSendsText: + text_far _ForYourMonSendsText + text_end + +.OTSendsText: + text_far _OTSendsText + text_end + +TradeAnim_OTSendsText2: + ld hl, .WillTradeText + call PrintText + call TradeAnim_Wait80Frames + ld hl, .ForYourMonWillTradeText + call PrintText + call TradeAnim_Wait80Frames + ld c, 14 + call DelayFrames + call TradeAnim_AdvanceScriptPointer + ret + +.WillTradeText: + text_far _WillTradeText + text_end + +.ForYourMonWillTradeText: + text_far _ForYourMonWillTradeText + text_end + +TradeAnim_Wait80Frames: + ld c, 80 + call DelayFrames + ret + +TradeAnim_BlankTilemap: + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + call ByteFill + ret + +TradeAnim_CopyBoxFromDEtoHL: +.row + push bc + push hl +.col + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .col + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + ret + +TradeAnim_NormalPals: + ldh a, [hSGB] + and a + ld a, %11100100 ; 3,2,1,0 + jr z, .not_sgb + ld a, $f0 + +.not_sgb + call DmgToCgbObjPal0 + ld a, %11100100 ; 3,2,1,0 + call DmgToCgbBGPals + ret + +LinkTradeAnim_LoadTradePlayerNames: + push de + ld de, wLinkPlayer1Name + ld bc, NAME_LENGTH + call CopyBytes + pop hl + ld de, wLinkPlayer2Name + ld bc, NAME_LENGTH + call CopyBytes + ret + +LinkTradeAnim_LoadTradeMonSpecies: + ld a, [hl] + ld [wLinkTradeSendmonSpecies], a + ld a, [de] + ld [wLinkTradeGetmonSpecies], a + ret + +TradeAnim_FlashBGPals: + ld a, [wce65] + and $7 + ret nz + ldh a, [rBGP] + xor %00111100 + call DmgToCgbBGPals + ret + +LoadTradeBallAndCableGFX: + call DelayFrame + ld de, TradeBallGFX + ld hl, vTiles0 tile $62 + lb bc, BANK(TradeBallGFX), 6 + call Request2bpp + ld de, TradePoofGFX + ld hl, vTiles0 tile $68 + lb bc, BANK(TradePoofGFX), 12 + call Request2bpp + ld de, TradeCableGFX + ld hl, vTiles0 tile $74 + lb bc, BANK(TradeCableGFX), 4 + call Request2bpp + xor a + ld hl, wSpriteAnimDict + ld [hli], a + ld [hl], $62 + ret + +LoadTradeBubbleGFX: + call DelayFrame + ld e, MONICON_TRADE + callfar LoadMenuMonIcon + ld de, TradeBubbleGFX + ld hl, vTiles0 tile $72 + lb bc, BANK(TradeBubbleGFX), 4 + call Request2bpp + xor a + ld hl, wSpriteAnimDict + ld [hli], a + ld [hl], $62 + ret + +TradeAnim_WaitAnim: + ld hl, wFrameCounter + ld a, [hl] + and a + jr z, .done + dec [hl] + ret + +.done + call TradeAnim_AdvanceScriptPointer + ret + +Unreferenced_DebugTrade: +; This function is not referenced. +; It was meant for use in Japanese versions, so the +; constant used for copy length was changed by accident. + + ld hl, .DebugTradeData + + ld a, [hli] + ld [wPlayerTrademonSpecies], a + ld de, wPlayerTrademonSenderName + ld c, NAME_LENGTH + 2 ; JP: NAME_LENGTH_JAPANESE + 2 +.loop1 + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop1 + + ld a, [hli] + ld [wOTTrademonSpecies], a + ld de, wOTTrademonSenderName + ld c, NAME_LENGTH + 2 ; JP: NAME_LENGTH_JAPANESE + 2 +.loop2 + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop2 + ret + +debugtrade: MACRO +; species, ot name, ot id (?) + db \1, \2 + dw \3 +ENDM + +.DebugTradeData: + debugtrade VENUSAUR, "ゲーフり@@", $0123 ; GAME FREAK + debugtrade CHARIZARD, "クりーチャ@", $0456 ; Creatures Inc. + +TradeGameBoyTilemap: +; 6x8 + db $31, $32, $32, $32, $32, $33 + db $34, $35, $36, $36, $37, $38 + db $34, $39, $3a, $3a, $3b, $38 + db $3c, $3d, $3e, $3e, $3f, $40 + db $41, $42, $43, $43, $44, $45 + db $46, $47, $43, $48, $49, $4a + db $41, $43, $4b, $4c, $4d, $4e + db $4f, $50, $50, $50, $51, $52 + +TradeLinkTubeTilemap: +; 12x3 + db $43, $55, $56, $53, $53, $53, $53, $53, $53, $53, $53, $53 + db $43, $57, $58, $54, $54, $54, $54, $54, $54, $54, $54, $54 + db $43, $59, $5a, $43, $43, $43, $43, $43, $43, $43, $43, $43 + +TradeArrowRightGFX: INCBIN "gfx/trade/arrow_right.2bpp" +TradeArrowLeftGFX: INCBIN "gfx/trade/arrow_left.2bpp" +TradeCableGFX: INCBIN "gfx/trade/cable.2bpp" +TradeBubbleGFX: INCBIN "gfx/trade/bubble.2bpp" +TradeGameBoyLZ: INCBIN "gfx/trade/game_boy.2bpp.lz" +TradeBallGFX: INCBIN "gfx/trade/ball.2bpp" +TradePoofGFX: INCBIN "gfx/trade/poof.2bpp" diff --git a/engine/namingscreen.asm b/engine/namingscreen.asm deleted file mode 100644 index f907c463..00000000 --- a/engine/namingscreen.asm +++ /dev/null @@ -1,1391 +0,0 @@ -NamingScreen_: ; 11aa3 (4:5aa3) - call DisableSpriteUpdates - call NamingScreen - call ReturnToMapWithSpeechTextbox - ret - -NamingScreen: ; 11aad (4:5aad) - ld hl, wNamingScreenDestinationPointer - ld [hl], e - inc hl - ld [hl], d - ld hl, wNamingScreenType - ld [hl], b - ld hl, wOptions - ld a, [hl] - push af - set NO_TEXT_SCROLL, [hl] - ldh a, [hMapAnims] - push af - xor a - ldh [hMapAnims], a - ldh a, [hInMenu] - push af - ld a, $1 - ldh [hInMenu], a - call Function11ae4 - call DelayFrame -.asm_11ad1 - call Function11cd4 - jr nc, .asm_11ad1 - pop af - ldh [hInMenu], a - pop af - ldh [hMapAnims], a - pop af - ld [wOptions], a - call ClearJoypad - ret - -Function11ae4: ; 11ae4 (4:5ae4) - call ClearBGPalettes - ld b, $8 - call GetSGBLayout - call DisableLCD - call Function1201e - call Function11c67 - ld a, $e3 - ldh [rLCDC], a - call Function11b09 - call WaitBGMap - call WaitTop - call SetPalettes - call Function11fad - ret - -Function11b09: ; 11b09 (4:5b09) - ld a, [wNamingScreenType] - and $7 - 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 - -.Jumptable - dw Function11b2a - dw Function11b79 - dw Function11b97 - dw Function11bb8 - dw Function11bda - dw Function11b2a - dw Function11b2a - dw Function11b2a - -Function11b2a: - ld a, [wCurPartySpecies] - ld [wd151], a - ld hl, LoadMenuMonIcon - ld a, BANK(LoadMenuMonIcon) - ld e, $1 - rst FarCall - ld a, [wCurPartySpecies] - ld [wd151], a - call GetPokemonName - hlcoord 5, 2 - call PlaceString - ld l, c - ld h, b - ld de, .Strings - call PlaceString - inc de - hlcoord 5, 4 - call PlaceString - farcall GetGender - jr c, .asm_11b68 - ld a, "♂" - jr nz, .place_gender - ld a, "♀" -.place_gender - hlcoord 1, 2 - ld [hl], a -.asm_11b68 - call Function11c3a - ret - -.Strings: - db "'S@" - db "NICKNAME?@" - -Function11b79: - ld de, PlayerSpriteGFX ; $4000 - call Function11c11 - hlcoord 5, 2 - ld de, .String - call PlaceString - call Function11c41 - ret - -.String: - db "YOUR NAME?@" - -Function11b97: - ld de, SilverSpriteGFX ; $43c0 - call Function11c11 - hlcoord 5, 2 - ld de, .String - call PlaceString - call Function11c41 - ret - -.String: - db "RIVAL'S NAME?@" - -Function11bb8: - ld de, MomSpriteGFX ; $4fc0 - call Function11c11 - hlcoord 5, 2 - ld de, .String - call PlaceString - call Function11c41 - ret - -.String: - db "MOTHER'S NAME?@" - -Function11bda: - ld de, $7380 - ld hl, $8000 - lb bc, $31, 4 - call Request2bpp - xor a - ld hl, wMisc - ld [hli], a - ld [hl], a - lb de, $24, $20 - ld a, $1c - call InitSpriteAnimStruct - ld hl, $1 - add hl, bc - ld [hl], $0 - hlcoord 5, 2 - ld de, .String - call PlaceString - call Function11c48 - ret - -.String: - db "BOX NAME?@" - -Function11c11: ; 11c11 (4:5c11) - push de - ld hl, $8000 - lb bc, BANK(PlayerSpriteGFX), 4 - call Request2bpp - pop de - ld hl, $c0 - add hl, de - ld e, l - ld d, h - ld hl, $8040 - lb bc, BANK(PlayerSpriteGFX), 4 - call Request2bpp - xor a - ld hl, wMisc - ld [hli], a - ld [hl], a - lb de, $24, $20 - ld a, $1c - call InitSpriteAnimStruct - ret - -Function11c3a: ; 11c3a (4:5c3a) - ld a, $a - hlcoord 5, 6 - jr asm_11c4f - -Function11c41: ; 11c41 (4:5c41) - ld a, $7 - hlcoord 5, 6 - jr asm_11c4f - -Function11c48: ; 11c48 (4:5c48) - ld a, $8 - hlcoord 5, 4 - jr asm_11c4f - -asm_11c4f - ld [wc5d3], a - ld a, l - ld [wc5d8], a - ld a, h - ld [wc5d9], a - ret - -Function11c5b: ; 11c5b (4:5c5b) - push bc - push af - ld a, [wNamingScreenType] - sub $3 - ld b, a - pop af - dec b - pop bc - ret - -Function11c67: ; 11c67 (4:5c67) - call WaitTop - hlcoord 0, 0 - ld bc, SCREEN_HEIGHT * SCREEN_WIDTH - ld a, $60 - call ByteFill - hlcoord 1, 1 - lb bc, $6, $12 - call Function11c5b - jr nz, .asm_11c83 - lb bc, $4, $12 -.asm_11c83 - call ClearBox - ld de, NameInputUpper ; $616f -Function11c89: ; 11c89 (4:5c89) - call Function11c5b - jr nz, .asm_11c94 - ld hl, $55 - add hl, de - ld d, h - ld e, l -.asm_11c94 - push de - hlcoord 1, 8 - lb bc, $7, $12 - call Function11c5b - jr nz, .asm_11ca6 - hlcoord 1, 6 - lb bc, $9, $12 -.asm_11ca6 - call ClearBox - hlcoord 1, 16 - lb bc, $1, $12 - call ClearBox - pop de - hlcoord 2, 8 - ld b, $5 - call Function11c5b - jr nz, .asm_11cc2 - hlcoord 2, 6 - ld b, $6 -.asm_11cc2 - ld c, $11 -.asm_11cc4 - ld a, [de] - ld [hli], a - inc de - dec c - jr nz, .asm_11cc4 - push de - ld de, $17 - add hl, de - pop de - dec b - jr nz, .asm_11cc2 - ret - -Function11cd4: ; 11cd4 (4:5cd4) - call JoyTextDelay - ld a, [wce63] - bit 7, a - jr nz, .asm_11cef - call Function11d27 - farcall AnimatedObjects_PlayFrameAndDelay - call Function11cff - call DelayFrame - and a - ret - -.asm_11cef - callfar ClearAnimatedObjectBuffer - call ClearSprites - xor a - ldh [hSCX], a - ldh [hSCY], a - scf - ret - -Function11cff: ; 11cff (4:5cff) - xor a - ldh [hBGMapMode], a - hlcoord 1, 5 - call Function11c5b - jr nz, .asm_11d0d - hlcoord 1, 3 -.asm_11d0d - ld bc, $112 - call ClearBox - ld hl, wNamingScreenDestinationPointer - ld e, [hl] - inc hl - ld d, [hl] - ld hl, wc5d8 - ld a, [hli] - ld h, [hl] - ld l, a - call PlaceString - ld a, $1 - ldh [hBGMapMode], a - ret - -Function11d27: ; 11d27 (4:5d27) - ld a, [wce63] - ld e, a - ld d, $0 - ld hl, $5d36 - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - jp hl - -.Jumptable: - dw Function11d3a - dw Function11d60 - -Function11d3a: - lb de, $50, $18 - call Function11c5b - jr nz, .asm_11d44 - ld d, $40 -.asm_11d44 - ld a, $14 - call InitSpriteAnimStruct - ld a, c - ld [wc5d5], a - ld a, b - ld [wc5d6], a - ld hl, $1 - add hl, bc - ld a, [hl] - ld hl, $e - add hl, bc - ld [hl], a - ld hl, wce63 - inc [hl] - ret - -Function11d60: - ld hl, hJoyPressed - ld a, [hl] - and $1 - jr nz, .asm_11d78 - ld a, [hl] - and $2 - jr nz, .asm_11da6 - ld a, [hl] - and $8 - jr nz, .asm_11d8e - ld a, [hl] - and $4 - jr nz, .asm_11db3 - ret - -.asm_11d78 - call Function11dca - cp $1 - jr z, .asm_11db3 - cp $2 - jr z, .asm_11da6 - cp $3 - jr z, .asm_11daa - call Function11fde - call Function11ed3 - ret nc -.asm_11d8e - ld hl, wc5d5 - ld c, [hl] - inc hl - ld b, [hl] - ld hl, $c - add hl, bc - ld [hl], $8 - ld hl, $d - add hl, bc - ld [hl], $4 - call Function11c5b - ret nz - inc [hl] - ret - -.asm_11da6 - call Function11f89 - ret - -.asm_11daa - call Function11fc4 - ld hl, wce63 - set 7, [hl] - ret - -.asm_11db3 - ld hl, wce64 - ld a, [hl] - xor $1 - ld [hl], a - jr z, .asm_11dc3 - ld de, $60b4 - call Function11c89 - ret - -.asm_11dc3 - ld de, $616f - call Function11c89 - ret - -Function11dca: ; 11dca (4:5dca) - ld hl, wc5d5 - ld c, [hl] - inc hl - ld b, [hl] -Function11dd0: ; 11dd0 (4:5dd0) - ld hl, $d - add hl, bc - ld a, [hl] - push bc - ld b, $4 - call Function11c5b - jr nz, .asm_11dde - inc b -.asm_11dde - cp b - pop bc - jr nz, .asm_11df8 - ld hl, $c - add hl, bc - ld a, [hl] - cp $3 - jr c, .asm_11df2 - cp $6 - jr c, .asm_11df5 - ld a, $3 - ret - -.asm_11df2 - ld a, $1 - ret - -.asm_11df5 - ld a, $2 - ret - -.asm_11df8 - xor a - ret - -Function11dfa: - call Function11e4a - ld hl, $d - add hl, bc - ld a, [hl] - ld e, a - swap e - ld hl, $7 - add hl, bc - ld [hl], e - ld d, $4 - call Function11c5b - jr nz, .asm_11e12 - inc d -.asm_11e12 - cp d - ld de, .LetterEntries - ld a, $0 - jr nz, .asm_11e1f - ld de, .CaseDelEnd - ld a, $1 -.asm_11e1f - ld hl, $e - add hl, bc - add [hl] - ld hl, $1 - add hl, bc - ld [hl], a - ld hl, $c - add hl, bc - ld l, [hl] - ld h, $0 - add hl, de - ld a, [hl] - ld hl, $6 - add hl, bc - ld [hl], a - ret - -.LetterEntries: - db $00, $10, $20, $30, $40, $50, $60, $70, $80 - -.CaseDelEnd: - db $00, $00, $00, $30, $30, $30, $60, $60, $60 - -Function11e4a: ; 11e4a (4:5e4a) - ld hl, hJoyLast - ld a, [hl] - and $40 - jr nz, .asm_11ec1 - ld a, [hl] - and $80 - jr nz, .asm_11ea8 - ld a, [hl] - and $20 - jr nz, .asm_11e84 - ld a, [hl] - and $10 - jr nz, .asm_11e62 - ret - -.asm_11e62 - call Function11dd0 - and a - jr nz, .asm_11e76 - ld hl, $c - add hl, bc -.asm_11e6c - ld a, [hl] - cp $8 - jr nc, .asm_11e73 - inc [hl] - ret - -.asm_11e73 - ld [hl], $0 - ret - -.asm_11e76 - cp $3 - jr nz, .asm_11e7b - xor a -.asm_11e7b - ld e, a - add a - add e - ld hl, $c - add hl, bc - ld [hl], a - ret - -.asm_11e84 - call Function11dd0 - and a - jr nz, .asm_11e97 - ld hl, $c - add hl, bc - ld a, [hl] - and a - jr z, .asm_11e94 - dec [hl] - ret - -.asm_11e94 - ld [hl], $8 - ret - -.asm_11e97 - cp $1 - jr nz, .asm_11e9d - ld a, $4 -.asm_11e9d - dec a - dec a - ld e, a - add a - add e - ld hl, $c - add hl, bc - ld [hl], a - ret - -.asm_11ea8 - ld hl, $d - add hl, bc - ld a, [hl] - call Function11c5b - jr nz, .asm_11eb8 - cp $5 - jr nc, .asm_11ebe - inc [hl] - ret - -.asm_11eb8 - cp $4 - jr nc, .asm_11ebe - inc [hl] - ret - -.asm_11ebe - ld [hl], $0 - ret - -.asm_11ec1 - ld hl, $d - add hl, bc - ld a, [hl] - and a - jr z, .asm_11ecb - dec [hl] - ret - -.asm_11ecb - ld [hl], $4 - call Function11c5b - ret nz - inc [hl] - ret - -Function11ed3: ; 11ed3 (4:5ed3) - ld a, [wc5d7] - ld hl, Dakutens - cp $e5 - jr z, asm_11f06 - ld hl, Handakutens - cp $e4 - jr z, asm_11f06 -Function11ee4: ; 11ee4 (4:5ee4) - ld a, [wc5d3] - ld c, a - ld a, [wc5d2] - cp c - ret nc - ld a, [wc5d7] -asm_11ef0 - call Function11f9d - ld [hl], a -asm_11ef4 - ld hl, wc5d2 - inc [hl] - call Function11f9d - ld a, [hl] - cp $50 - jr z, .asm_11f04 - ld [hl], $f2 - and a - ret - -.asm_11f04 - scf - ret - -asm_11f06 - ld a, [wc5d2] - and a - ret z - push hl - ld hl, wc5d2 - dec [hl] - call Function11f9d - ld c, [hl] - pop hl -.asm_11f15 - ld a, [hli] - cp $ff - jr z, asm_11ef4 - cp c - jr z, .asm_11f20 - inc hl - jr .asm_11f15 - -.asm_11f20 - ld a, [hl] - jr asm_11ef0 - -Dakutens: ; Dummied out - db "かが", "きぎ", "くぐ", "けげ", "こご" - db "さざ", "しじ", "すず", "せぜ", "そぞ" - db "ただ", "ちぢ", "つづ", "てで", "とど" - db "はば", "ひび", "ふぶ", "へべ", "ほぼ" - db "カガ", "キギ", "クグ", "ケゲ", "コゴ" - db "サザ", "シジ", "スズ", "セゼ", "ソゾ" - db "タダ", "チヂ", "ツヅ", "テデ", "トド" - db "ハバ", "ヒビ", "フブ", "へべ", "ホボ" - db $ff - -Handakutens: ; Dummied out - db "はぱ", "ひぴ", "ふぷ", "へぺ", "ほぽ" - db "ハパ", "ヒピ", "フプ", "へぺ", "ホポ" - db $ff - -Function11f89: ; 11f89 (4:5f89) - ld hl, wc5d2 - ld a, [hl] - and a - ret z - dec [hl] - call Function11f9d - ld [hl], $f2 - inc hl - ld a, [hl] - cp $f2 - ret nz - ld [hl], $eb - ret - -Function11f9d: ; 11f9d (4:5f9d) - push af - ld hl, wNamingScreenDestinationPointer - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wc5d2] - ld e, a - ld d, $0 - add hl, de - pop af - ret - -Function11fad: ; 11fad (4:5fad) - ld hl, wNamingScreenDestinationPointer - ld a, [hli] - ld h, [hl] - ld l, a - ld [hl], $f2 - inc hl - ld a, [wc5d3] - dec a - ld c, a - ld a, $eb -.asm_11fbd - ld [hli], a - dec c - jr nz, .asm_11fbd - ld [hl], $50 - ret - -Function11fc4: ; 11fc4 (4:5fc4) - ld hl, wNamingScreenDestinationPointer - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wc5d3] - ld c, a -.asm_11fce - ld a, [hl] - cp $eb - jr z, .asm_11fd7 - cp $f2 - jr nz, .asm_11fd9 -.asm_11fd7 - ld [hl], $50 -.asm_11fd9 - inc hl - dec c - jr nz, .asm_11fce - ret - -Function11fde: ; 11fde (4:5fde) - ld hl, wc5d5 - ld c, [hl] - inc hl - ld b, [hl] - ld hl, $6 - add hl, bc - ld a, [hl] - ld hl, $4 - add hl, bc - add [hl] - sub $8 - srl a - srl a - srl a - ld e, a - ld hl, $7 - add hl, bc - ld a, [hl] - ld hl, $5 - add hl, bc - add [hl] - sub $10 - srl a - srl a - srl a - ld d, a - hlcoord 0, 0 - ld bc, $14 -.asm_12010 - ld a, d - and a - jr z, .asm_12018 - add hl, bc - dec d - jr .asm_12010 - -.asm_12018 - add hl, de - ld a, [hl] - ld [wc5d7], a - ret - -Function1201e: ; 1201e (4:601e) - call ClearSprites - callfar ClearAnimatedObjectBuffer - call Functiond9e - call LoadFontsExtra - ld de, NamingScreenGFX_MiddleLine ; $6232 - ld hl, $8eb0 - lb bc, BANK(NamingScreenGFX_MiddleLine), 1 - call Get1bpp - ld de, NamingScreenGFX_UnderLine ; $623a - ld hl, $8f20 - lb bc, BANK(NamingScreenGFX_UnderLine), 1 - call Get1bpp - ld de, $9600 - ld hl, NamingScreenGFX_Border - ld bc, $10 - ld a, BANK(NamingScreenGFX_Border) - call FarCopyBytes - ld de, $87e0 - ld hl, NamingScreenGFX_Cursor - ld bc, $20 - ld a, BANK(NamingScreenGFX_Cursor) - call FarCopyBytes - ld a, $5 - ld hl, wAnimatedObjectDynamicVTileOffsets + 9 * 2 - ld [hli], a - ld [hl], $7e - xor a - ldh [hSCY], a - ld [wGlobalAnimYOffset], a - ldh [hSCX], a - ld [wGlobalAnimXOffset], a - ld [wce63], a - ld [wce64], a - ldh [hBGMapMode], a - ld [wc5d2], a - ld a, $7 - ldh [hWX], a - ret - -NamingScreenGFX_Border: INCBIN "gfx/namingscreen/border.2bpp" -NamingScreenGFX_Cursor: INCBIN "gfx/namingscreen/cursor.2bpp" - -NameInputLower: - db "a b c d e f g h i" - db "j k l m n o p q r" - db "s t u v w x y z " - db "× ( ) : ; [ ] <PK> <MN>" - db "UPPER DEL END " - -BoxNameInputLower: - db "a b c d e f g h i" - db "j k l m n o p q r" - db "s t u v w x y z " - db "é 'd 'l 'm 'r 's 't 'v 0" - db "1 2 3 4 5 6 7 8 9" - db "UPPER DEL END " - -NameInputUpper: - db "A B C D E F G H I" - db "J K L M N O P Q R" - db "S T U V W X Y Z " - db "- ? ! / . , " - db "lower DEL END " - -BoxNameInputUpper: - db "A B C D E F G H I" - db "J K L M N O P Q R" - db "S T U V W X Y Z " - db "× ( ) : ; [ ] <PK> <MN>" - db "- ? ! ♂ ♀ / . , &" - db "lower DEL END " - -NamingScreenGFX_ED: INCBIN "gfx/namingscreen/ed.1bpp" ; leftover from gen 1 -NamingScreenGFX_MiddleLine: INCBIN "gfx/namingscreen/middleline.1bpp" -NamingScreenGFX_UnderLine: INCBIN "gfx/namingscreen/underline.1bpp" - -ComposeMailMessage: - ld hl, wNamingScreenDestinationPointer - ld [hl], e - inc hl - ld [hl], d - ldh a, [hMapAnims] - push af - xor a - ldh [hMapAnims], a - ldh a, [hInMenu] - push af - ld a, $1 - ldh [hInMenu], a - call Function12267 - call DelayFrame -.asm_1225b - call Function1238d - jr nc, .asm_1225b - pop af - ldh [hInMenu], a - pop af - ldh [hMapAnims], a - ret - -Function12267: ; 12267 (4:6267) - call ClearBGPalettes - call DisableLCD - call Function1201e - ld de, $8000 - ld hl, MailIcon ; $62c1 - ld bc, $80 - ld a, BANK(MailIcon) - call FarCopyBytes - xor a - ld hl, wTilemapEnd - ld [hli], a - ld [hl], a - lb de, $18, $10 - ld a, $0 - call InitSpriteAnimStruct - ld hl, $2 - add hl, bc - ld [hl], $0 - call Function12351 - ld a, $e3 - ldh [rLCDC], a - call Function12341 - ld b, $8 - call GetSGBLayout - call WaitBGMap - call WaitTop - ld a, $e4 - call DmgToCgbBGPals - ld a, $e4 - call DmgToCgbObjPal0 - call Function11fad - ld hl, wNamingScreenDestinationPointer - ld e, [hl] - inc hl - ld d, [hl] - ld hl, $10 - add hl, de - ld [hl], $4e - ret - -MailIcon: INCBIN "gfx/namingscreen/mail_icon.2bpp" - -Function12341: ; 12341 (4:6341) - ld a, $21 - ld [wc5d3], a - ret - - db "メールを かいてね@" - -Function12351: ; 12351 (4:6351) - call WaitTop - hlcoord 0, 0 - ld bc, $78 - ld a, $60 - call ByteFill - hlcoord 0, 6 - ld bc, $f0 - ld a, $7f - call ByteFill - hlcoord 1, 1 - ld bc, IncGradGBPalTable_13 - call ClearBox - ld de, MailEntry_Uppercase -Function12376: ; 12376 (4:6376) - hlcoord 1, 7 - ld b, $6 -.asm_1237b - ld c, $13 -.asm_1237d - ld a, [de] - ld [hli], a - inc de - dec c - jr nz, .asm_1237d - push de - ld de, $15 - add hl, de - pop de - dec b - jr nz, .asm_1237b - ret - -Function1238d: ; 1238d (4:638d) - call JoyTextDelay - ld a, [wce63] - bit 7, a - jr nz, .asm_123a8 - call Function123d5 - farcall AnimatedObjects_PlayFrameAndDelay - call Function123b8 - call DelayFrame - and a - ret - -.asm_123a8 - callfar ClearAnimatedObjectBuffer - call ClearSprites - xor a - ldh [hSCX], a - ldh [hSCY], a - scf - ret - -Function123b8: ; 123b8 (4:63b8) - xor a - ldh [hBGMapMode], a - hlcoord 1, 1 - lb bc, 4, 18 - call ClearBox - ld hl, wNamingScreenDestinationPointer - ld e, [hl] - inc hl - ld d, [hl] - hlcoord 2, 2 - call PlaceString - ld a, $1 - ldh [hBGMapMode], a - ret - -Function123d5: ; 123d5 (4:63d5) - ld a, [wce63] - ld e, a - ld d, $0 - ld hl, .Jumptable ; $63e4 - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - jp hl - -.Jumptable: - dw Function123e8 - dw Function12407 - -Function123e8: - lb de, $48, $10 - ld a, $1b - call InitSpriteAnimStruct - ld a, c - ld [wc5d5], a - ld a, b - ld [wc5d6], a - ld hl, $1 - add hl, bc - ld a, [hl] - ld hl, $e - add hl, bc - ld [hl], a - ld hl, wce63 - inc [hl] - ret - -Function12407: - ld hl, hJoyPressed - ld a, [hl] - and $1 - jr nz, .asm_1241f - ld a, [hl] - and $2 - jr nz, .asm_1245a - ld a, [hl] - and $8 - jr nz, .asm_12447 - ld a, [hl] - and $4 - jr nz, .asm_12477 - ret - -.asm_1241f - call Function12552 - cp $1 - jr z, .asm_12477 - cp $2 - jr z, .asm_1245a - cp $3 - jr z, .asm_1246e - call Function11fde - call Function12579 - jr c, .asm_12447 - ld hl, wc5d2 - ld a, [hl] - cp $10 - ret nz - inc [hl] - call Function11f9d - ld [hl], $f2 - dec hl - ld [hl], $4e - ret - -.asm_12447 - ld hl, wc5d5 - ld c, [hl] - inc hl - ld b, [hl] - ld hl, $c - add hl, bc - ld [hl], $9 - ld hl, $d - add hl, bc - ld [hl], $5 - ret - -.asm_1245a - call Function11f89 - ld hl, wc5d2 - ld a, [hl] - cp $10 - ret nz - dec [hl] - call Function11f9d - ld [hl], $f2 - inc hl - ld [hl], $4e - ret - -.asm_1246e - call Function11fc4 - ld hl, wce63 - set 7, [hl] - ret - -.asm_12477 - ld hl, wce64 - ld a, [hl] - xor $1 - ld [hl], a - jr nz, .asm_12487 - ld de, MailEntry_Uppercase ; $65b6 - call Function12376 - ret - -.asm_12487 - ld de, MailEntry_Lowercase ; $6628 - call Function12376 - ret - -Function1248e: - call Function124d9 - ld hl, $d - add hl, bc - ld a, [hl] - ld e, a - swap e - ld hl, $7 - add hl, bc - ld [hl], e - cp $5 - ld de, .LetterEntries - ld a, $0 - jr nz, .asm_124ac - ld de, .CaseDelEnd - ld a, $1 -.asm_124ac - ld hl, $e - add hl, bc - add [hl] - ld hl, $1 - add hl, bc - ld [hl], a - ld hl, $c - add hl, bc - ld l, [hl] - ld h, $0 - add hl, de - ld a, [hl] - ld hl, $6 - add hl, bc - ld [hl], a - ret - -.LetterEntries: - db $00, $10, $20, $30, $40, $50, $60, $70, $80, $90 - -.CaseDelEnd: - db $00, $00, $00, $30, $30, $30, $60, $60, $60, $60 - -Function124d9: ; 124d9 (4:64d9) - ld hl, hJoyLast - ld a, [hl] - and $40 - jr nz, .asm_12545 - ld a, [hl] - and $80 - jr nz, .asm_12537 - ld a, [hl] - and $20 - jr nz, .asm_12513 - ld a, [hl] - and $10 - jr nz, .asm_124f1 - ret - -.asm_124f1 - call Function12558 - and a - jr nz, .asm_12505 - ld hl, $c -.asm_124f9 - add hl, bc - ld a, [hl] - cp $9 - jr nc, .asm_12502 - inc [hl] - ret - -.asm_12502 - ld [hl], $0 -.asm_12504 - ret - -.asm_12505 - cp $3 - jr nz, .asm_1250a - xor a -.asm_1250a - ld e, a - add a - add e - ld hl, $c - add hl, bc - ld [hl], a - ret - -.asm_12513 - call Function12558 - and a - jr nz, .asm_12526 - ld hl, $c - add hl, bc - ld a, [hl] - and a - jr z, .asm_12523 - dec [hl] - ret - -.asm_12523 - ld [hl], $9 - ret - -.asm_12526 - cp $1 - jr nz, .asm_1252c - ld a, $4 -.asm_1252c - dec a - dec a - ld e, a - add a - add e - ld hl, $c - add hl, bc - ld [hl], a -.asm_12536 - ret - -.asm_12537 - ld hl, $d - add hl, bc - ld a, [hl] - cp $5 - jr nc, .asm_12542 - inc [hl] - ret - -.asm_12542 - ld [hl], $0 - ret - -.asm_12545 - ld hl, $d - add hl, bc - ld a, [hl] - and a - jr z, .asm_1254f - dec [hl] - ret - -.asm_1254f - ld [hl], $5 - ret - -Function12552: ; 12552 (4:6552) - ld hl, wc5d5 - ld c, [hl] - inc hl - ld b, [hl] -Function12558: ; 12558 (4:6558) - ld hl, $d - add hl, bc - ld a, [hl] - cp $5 - jr nz, .asm_12577 - ld hl, $c - add hl, bc - ld a, [hl] - cp $3 - jr c, .asm_12571 - cp $6 - jr c, .asm_12574 - ld a, $3 - ret - -.asm_12571 - ld a, $1 - ret - -.asm_12574 - ld a, $2 - ret - -.asm_12577 - xor a - ret - -Function12579: ; 12579 (4:6579) - ld a, [wc5d7] - ld hl, $5f23 - cp $e5 - jr z, .asm_1258b - ld hl, $5f74 - cp $e4 - jp nz, Function11ee4 -.asm_1258b - ld a, [wc5d2] - and a - ret z - cp $11 - jr nz, .asm_1259c - push hl - ld hl, wc5d2 - dec [hl] - dec [hl] - jr .asm_125a1 - -.asm_1259c - push hl - ld hl, wc5d2 - dec [hl] -.asm_125a1 - call Function11f9d - ld c, [hl] - pop hl -.asm_125a6 - ld a, [hli] - cp $ff - jp z, asm_11ef4 - cp c - jr z, .asm_125b2 - inc hl - jr .asm_125a6 - -.asm_125b2 - ld a, [hl] - jp asm_11ef0 - -MailEntry_Uppercase: - db "A B C D E F G H I J" - db "K L M N O P Q R S T" - db "U V W X Y Z , ? !" - db "1 2 3 4 5 6 7 8 9 0" - db "<PK> <MN> <PO> <KE> é ♂ ♀ ¥ … ×" - db "lower DEL END " - -MailEntry_Lowercase: - db "a b c d e f g h i j" - db "k l m n o p q r s t" - db "u v w x y z . - /" - db "'d 'l 'm 'r 's 't 'v & ( )" - db "<``> <''> [ ] ' : ; " - db "UPPER DEL END " diff --git a/engine/overworld/decorations.asm b/engine/overworld/decorations.asm new file mode 100644 index 00000000..c9889472 --- /dev/null +++ b/engine/overworld/decorations.asm @@ -0,0 +1,1168 @@ +InitDecorations: + ld a, DECO_FEATHERY_BED + ld [wDecoBed], a + ld a, DECO_TOWN_MAP + ld [wDecoPoster], a + ret + +_PlayerDecorationMenu: + ld a, [wWhichIndexSet] + push af + ld hl, .MenuHeader + call LoadMenuHeader + xor a + ld [wBuffer5], a + ld a, $1 + ld [wBuffer6], a +.top_loop + ld a, [wBuffer6] + ld [wMenuCursorBuffer], a + call .FindCategoriesWithOwnedDecos + call DoNthMenu + ld a, [wMenuCursorY] + ld [wBuffer6], a + jr c, .exit_menu + ld a, [wMenuSelection] + ld hl, .pointers + call MenuJumptable + jr nc, .top_loop + +.exit_menu + call ExitMenu + pop af + ld [wWhichIndexSet], a + ld a, [wBuffer5] + ld c, a + ret + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 5, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR | STATICMENU_WRAP ; flags + db 0 ; items + dw wceed + dw PlaceNthMenuStrings + dw .pointers + +.pointers + dw DecoBedMenu, .bed + dw DecoCarpetMenu, .carpet + dw DecoPlantMenu, .plant + dw DecoPosterMenu, .poster + dw DecoConsoleMenu, .game + dw DecoOrnamentMenu, .ornament + dw DecoBigDollMenu, .big_doll + dw DecoExitMenu, .exit + +.bed db "BED@" +.carpet db "CARPET@" +.plant db "PLANT@" +.poster db "POSTER@" +.game db "GAME CONSOLE@" +.ornament db "ORNAMENT@" +.big_doll db "BIG DOLL@" +.exit db "EXIT@" + +.FindCategoriesWithOwnedDecos: + xor a + ld [wWhichIndexSet], a + call .ClearStringBuffer2 + call .FindOwndDecos + ld a, 7 + call .AppendToStringBuffer2 + ld hl, wStringBuffer2 + ld de, wceed + ld bc, ITEM_NAME_LENGTH + call CopyBytes + ret + +.ClearStringBuffer2: + ld hl, wStringBuffer2 + xor a + ld [hli], a + ld bc, ITEM_NAME_LENGTH - 1 + ld a, -1 + call ByteFill + ret + +.AppendToStringBuffer2: + ld hl, wStringBuffer2 + inc [hl] + ld e, [hl] + ld d, 0 + add hl, de + ld [hl], a + ret + +.FindOwndDecos: + ld hl, .dw +.loop + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + or e + jr z, .done + push hl + call _de_ + pop hl + jr nc, .next + ld a, [hl] + push hl + call .AppendToStringBuffer2 + pop hl +.next + inc hl + jr .loop +.done + ret + +.dw + dwb FindOwnedBeds, 0 ; bed + dwb FindOwnedCarpets, 1 ; carpet + dwb FindOwnedPlants, 2 ; plant + dwb FindOwnedPosters, 3 ; poster + dwb FindOwnedConsoles, 4 ; game console + dwb FindOwnedOrnaments, 5 ; ornament + dwb FindOwnedBigDolls, 6 ; big doll + dw 0 ; end + +Deco_FillTempWithMinusOne: + xor a + ld hl, wceed + ld [hli], a + ld a, -1 + ld bc, $10 + call ByteFill + ret + +CheckAllDecorationFlags: +.loop + ld a, [hli] + cp -1 + jr z, .done + push hl + push af + ld b, CHECK_FLAG + call DecorationFlagAction + ld a, c + and a + pop bc + ld a, b + call nz, AppendDecoIndex + pop hl + jr .loop + +.done + ret + +AppendDecoIndex: + ld hl, wceed + inc [hl] + ld e, [hl] + ld d, $0 + add hl, de + ld [hl], a + ret + +FindOwnedDecosInCategory: + push bc + push hl + call Deco_FillTempWithMinusOne + pop hl + call CheckAllDecorationFlags + pop bc + ld a, [wceed] + and a + ret z + + ld a, c + call AppendDecoIndex + ld a, 0 + call AppendDecoIndex + scf + ret + +DecoBedMenu: + call FindOwnedBeds + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedBeds: + ld hl, .beds + ld c, BEDS + jp FindOwnedDecosInCategory + +.beds + db DECO_FEATHERY_BED ; 2 + db DECO_PINK_BED ; 3 + db DECO_POLKADOT_BED ; 4 + db DECO_PIKACHU_BED ; 5 + db -1 + +DecoCarpetMenu: + call FindOwnedCarpets + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedCarpets: + ld hl, .carpets + ld c, CARPETS + jp FindOwnedDecosInCategory + +.carpets + db DECO_RED_CARPET ; 7 + db DECO_BLUE_CARPET ; 8 + db DECO_YELLOW_CARPET ; 9 + db DECO_GREEN_CARPET ; a + db -1 + +DecoPlantMenu: + call FindOwnedPlants + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedPlants: + ld hl, .plants + ld c, PLANTS + jp FindOwnedDecosInCategory + +.plants + db DECO_MAGNAPLANT ; c + db DECO_TROPICPLANT ; d + db DECO_JUMBOPLANT ; e + db -1 + +DecoPosterMenu: + call FindOwnedPosters + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedPosters: + ld hl, .posters + ld c, POSTERS + jp FindOwnedDecosInCategory + +.posters + db DECO_TOWN_MAP ; 10 + db DECO_PIKACHU_POSTER ; 11 + db DECO_CLEFAIRY_POSTER ; 12 + db DECO_JIGGLYPUFF_POSTER ; 13 + db -1 + +DecoConsoleMenu: + call FindOwnedConsoles + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedConsoles: + ld hl, .consoles + ld c, CONSOLES + jp FindOwnedDecosInCategory + +.consoles + db DECO_FAMICOM ; 15 + db DECO_SNES ; 16 + db DECO_N64 ; 17 + db DECO_VIRTUAL_BOY ; 18 + db -1 + +DecoOrnamentMenu: + call FindOwnedOrnaments + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedOrnaments: + ld hl, .ornaments + ld c, DOLLS + jp FindOwnedDecosInCategory + +.ornaments + 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_GOLD_TROPHY_DOLL ; 33 + db DECO_SILVER_TROPHY_DOLL ; 34 + db -1 + +DecoBigDollMenu: + call FindOwnedBigDolls + call PopulateDecoCategoryMenu + xor a + ret + +FindOwnedBigDolls: + ld hl, .big_dolls + ld c, BIG_DOLLS + jp FindOwnedDecosInCategory + +.big_dolls + db DECO_BIG_SNORLAX_DOLL ; 1a + db DECO_BIG_ONIX_DOLL ; 1b + db DECO_BIG_LAPRAS_DOLL ; 1c + db -1 + +DecoExitMenu: + scf + ret + +PopulateDecoCategoryMenu: + ld a, [wceed] + and a + jr z, .empty + cp 8 + jr nc, .beyond_eight + xor a + ld [wWhichIndexSet], a + ld hl, .NonscrollingMenuHeader + call LoadMenuHeader + call DoNthMenu + jr c, .no_action_1 + call DoDecorationAction2 + +.no_action_1 + call ExitMenu + ret + +.beyond_eight + ld hl, wceed + ld e, [hl] + dec [hl] + ld d, 0 + add hl, de + ld [hl], -1 + call LoadStandardMenuHeader + ld hl, .ScrollingMenuHeader + call CopyMenuHeader + xor a + ldh [hBGMapMode], a + call InitScrollingMenu + xor a + ld [wMenuScrollPosition], a + call ScrollingMenu + ld a, [wMenuJoypad] + cp 2 + jr z, .no_action_2 + call DoDecorationAction2 + +.no_action_2 + call ExitMenu + ret + +.empty + ld hl, .NothingToChooseText + call MenuTextboxBackup + ret + +.NothingToChooseText: + text_far _NothingToChooseText + text_end + +.NonscrollingMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .NonscrollingMenuData + db 1 ; default option + +.NonscrollingMenuData: + db STATICMENU_CURSOR | STATICMENU_WRAP ; flags + db 0 ; items + dw wceed + dw DecorationMenuFunction + dw DecorationAttributes + +.ScrollingMenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2 + dw .ScrollingMenuData + db 1 ; default option + +.ScrollingMenuData: + db SCROLLINGMENU_DISPLAY_ARROWS ; flags + db 8, 0 ; rows, columns + db SCROLLINGMENU_ITEMS_NORMAL ; item format + dbw 0, wceed ; text pointer + dba DecorationMenuFunction + dbw 0, 0 + dbw 0, 0 + +GetDecorationData: + ld hl, DecorationAttributes + ld bc, 6 + call AddNTimes + ret + +GetDecorationName: + push hl + call GetDecorationData + call GetDecoName + pop hl + call CopyName2 + ret + +DecorationMenuFunction: + ld a, [wMenuSelection] + push de + call GetDecorationData + call GetDecoName + pop hl + call PlaceString + ret + +DoDecorationAction2: + ld a, [wMenuSelection] + call GetDecorationData + ld de, 2 ; function 2 + add hl, de + ld a, [hl] + ld hl, .DecoActions + rst JumpTable + ret + +.DecoActions: + dw DecoAction_nothing + dw DecoAction_setupbed + dw DecoAction_putawaybed + dw DecoAction_setupcarpet + dw DecoAction_putawaycarpet + dw DecoAction_setupplant + dw DecoAction_putawayplant + dw DecoAction_setupposter + dw DecoAction_putawayposter + dw DecoAction_setupconsole + dw DecoAction_putawayconsole + dw DecoAction_setupbigdoll + dw DecoAction_putawaybigdoll + dw DecoAction_setupornament + dw DecoAction_putawayornament + +GetDecorationFlag: + call GetDecorationData + ld de, 3 ; event flag + add hl, de + ld a, [hli] + ld d, [hl] + ld e, a + ret + +DecorationFlagAction: + push bc + call GetDecorationFlag + pop bc + call EventFlagAction + ret + +GetDecorationSprite: + ld a, c + call GetDecorationData + ld de, 5 ; sprite + add hl, de + ld a, [hl] + ld c, a + ret + +INCLUDE "data/decorations/attributes.asm" + +INCLUDE "data/decorations/names.asm" + +GetDecoName: + ld a, [hli] + ld e, [hl] + ld bc, wStringBuffer2 + push bc + ld hl, .NameFunctions + rst JumpTable + pop de + ret + +.NameFunctions: + dw .invalid + dw .plant + dw .bed + dw .carpet + dw .poster + dw .doll + dw .bigdoll + +.invalid + ret + +.plant + ld a, e + jr .getdeconame + +.bed + call .plant + ld a, _BED + jr .getdeconame + +.carpet + call .plant + ld a, _CARPET + jr .getdeconame + +.poster + ld a, e + call .getpokename + ld a, _POSTER + jr .getdeconame + +.doll + ld a, e + call .getpokename + ld a, _DOLL + jr .getdeconame + +.bigdoll + push de + ld a, BIG_ + call .getdeconame + pop de + ld a, e + jr .getpokename + +.getpokename + push bc + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + pop bc + jr .copy + +.getdeconame + call ._getdeconame + jr .copy + +._getdeconame + push bc + ld hl, DecorationNames + call GetNthString + ld d, h + ld e, l + pop bc + ret + +.copy + ld h, b + ld l, c + call CopyName2 + dec hl + ld b, h + ld c, l + ret + +DecoAction_nothing: + scf + ret + +DecoAction_setupbed: + ld hl, wDecoBed + jp DecoAction_TrySetItUp + +DecoAction_putawaybed: + ld hl, wDecoBed + jp DecoAction_TryPutItAway + +DecoAction_setupcarpet: + ld hl, wDecoCarpet + jp DecoAction_TrySetItUp + +DecoAction_putawaycarpet: + ld hl, wDecoCarpet + jp DecoAction_TryPutItAway + +DecoAction_setupplant: + ld hl, wDecoPlant + jp DecoAction_TrySetItUp + +DecoAction_putawayplant: + ld hl, wDecoPlant + jp DecoAction_TryPutItAway + +DecoAction_setupposter: + ld hl, wDecoPoster + jp DecoAction_TrySetItUp + +DecoAction_putawayposter: + ld hl, wDecoPoster + jp DecoAction_TryPutItAway + +DecoAction_setupconsole: + ld hl, wDecoConsole + jp DecoAction_TrySetItUp + +DecoAction_putawayconsole: + ld hl, wDecoConsole + jp DecoAction_TryPutItAway + +DecoAction_setupbigdoll: + ld hl, wDecoBigDoll + jp DecoAction_TrySetItUp + +DecoAction_putawaybigdoll: + ld hl, wDecoBigDoll + jp DecoAction_TryPutItAway + +DecoAction_TrySetItUp: + ld a, [hl] + ld [wBuffer1], a + push hl + call DecoAction_SetItUp + jr c, .failed + ld a, 1 + ld [wBuffer5], a + pop hl + ld a, [wMenuSelection] + ld [hl], a + xor a + ret + +.failed + pop hl + xor a + ret + +DecoAction_SetItUp: +; See if there's anything of the same type already out + ld a, [wBuffer1] + and a + jr z, .nothingthere +; See if that item is already out + ld b, a + ld a, [wMenuSelection] + cp b + jr z, .alreadythere +; Put away the item that's already out, and set up the new one + ld a, [wMenuSelection] + ld hl, wStringBuffer4 + call GetDecorationName + ld a, [wBuffer1] + ld hl, wStringBuffer3 + call GetDecorationName + ld hl, PutAwayAndSetUpText + call MenuTextboxBackup + xor a + ret + +.nothingthere + ld a, [wMenuSelection] + ld hl, wStringBuffer3 + call GetDecorationName + ld hl, SetUpTheDecoText + call MenuTextboxBackup + xor a + ret + +.alreadythere + ld hl, AlreadySetUpText + call MenuTextboxBackup + scf + ret + +DecoAction_TryPutItAway: +; If there is no item of that type already set, there is nothing to put away. + ld a, [hl] + ld [wBuffer1], a + xor a + ld [hl], a + ld a, [wBuffer1] + and a + jr z, .nothingthere +; Put it away. + ld a, $1 + ld [wBuffer5], a + ld a, [wBuffer1] + ld [wMenuSelection], a + ld hl, wStringBuffer3 + call GetDecorationName + ld hl, PutAwayTheDecoText + call MenuTextboxBackup + xor a + ret + +.nothingthere + ld hl, NothingToPutAwayText + call MenuTextboxBackup + xor a + ret + +DecoAction_setupornament: + ld hl, WhichSidePutOnText + call DecoAction_AskWhichSide + jr c, .cancel + call DecoAction_SetItUp_Ornament + jr c, .cancel + ld a, $1 + ld [wBuffer5], a + jr DecoAction_FinishUp_Ornament + +.cancel + xor a + ret + +DecoAction_putawayornament: + ld hl, WhichSidePutAwayText + call DecoAction_AskWhichSide + jr nc, .incave + xor a + ret + +.incave + call DecoAction_PutItAway_Ornament + +DecoAction_FinishUp_Ornament: + call QueryWhichSide + ld a, [wSelectedDecoration] + ld [hl], a + ld a, [wOtherDecoration] + ld [de], a + xor a + ret + +DecoAction_SetItUp_Ornament: + ld a, [wSelectedDecoration] + and a + jr z, .nothingthere + ld b, a + ld a, [wMenuSelection] + cp b + jr z, .failed + ld a, b + ld hl, wStringBuffer3 + call GetDecorationName + ld a, [wMenuSelection] + ld hl, wStringBuffer4 + call GetDecorationName + ld a, [wMenuSelection] + ld [wSelectedDecoration], a + call .getwhichside + ld hl, PutAwayAndSetUpText + call MenuTextboxBackup + xor a + ret + +.nothingthere + ld a, [wMenuSelection] + ld [wSelectedDecoration], a + call .getwhichside + ld a, [wMenuSelection] + ld hl, wStringBuffer3 + call GetDecorationName + ld hl, SetUpTheDecoText + call MenuTextboxBackup + xor a + ret + +.failed + ld hl, AlreadySetUpText + call MenuTextboxBackup + scf + ret + +.getwhichside + ld a, [wMenuSelection] + ld b, a + ld a, [wOtherDecoration] + cp b + ret nz + xor a + ld [wOtherDecoration], a + ret + +WhichSidePutOnText: + text_far _WhichSidePutOnText + text_end + +DecoAction_PutItAway_Ornament: + ld a, [wSelectedDecoration] + and a + jr z, .nothingthere + ld hl, wStringBuffer3 + call GetDecorationName + ld a, $1 + ld [wBuffer5], a + xor a + ld [wSelectedDecoration], a + ld hl, PutAwayTheDecoText + call MenuTextboxBackup + xor a + ret + +.nothingthere + ld hl, NothingToPutAwayText + call MenuTextboxBackup + xor a + ret + +WhichSidePutAwayText: + text_far _WhichSidePutAwayText + text_end + +DecoAction_AskWhichSide: + call MenuTextbox + ld hl, MenuHeader_0x2707e + call GetMenu2 + call ExitMenu + call CopyMenuData + jr c, .nope + ld a, [wMenuCursorY] + cp 3 + jr z, .nope + ld [wBuffer2], a + call QueryWhichSide + ld a, [hl] + ld [wSelectedDecoration], a + ld a, [de] + ld [wOtherDecoration], a + xor a + ret + +.nope + scf + ret + +QueryWhichSide: + ld hl, wDecoRightOrnament + ld de, wDecoLeftOrnament + ld a, [wBuffer2] + cp 1 + ret z + push hl + ld h, d + ld l, e + pop de + ret + +MenuHeader_0x2707e: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, 12, 7 + dw MenuData_0x27086 + db 1 ; default option + +MenuData_0x27086: + db STATICMENU_CURSOR ; flags + db 3 ; items + db "RIGHT SIDE@" + db "LEFT SIDE@" + db "CANCEL@" + +PutAwayTheDecoText: + text_far _PutAwayTheDecoText + text_end + +NothingToPutAwayText: + text_far _NothingToPutAwayText + text_end + +SetUpTheDecoText: + text_far _SetUpTheDecoText + text_end + +PutAwayAndSetUpText: + text_far _PutAwayAndSetUpText + text_end + +AlreadySetUpText: + text_far _AlreadySetUpText + text_end + +GetDecorationName_c_de: + ld a, c + ld h, d + ld l, e + call GetDecorationName + ret + +DecorationFlagAction_c: + ld a, c + jp DecorationFlagAction + +GetDecorationName_c: + ld a, c + call GetDecorationID + ld hl, wStringBuffer1 + push hl + call GetDecorationName + pop de + ret + +SetSpecificDecorationFlag: + ld a, c + call GetDecorationID + ld b, SET_FLAG + call DecorationFlagAction + ret + +GetDecorationID: + push hl + push de + ld e, a + ld d, 0 + ld hl, DecorationIDs + add hl, de + ld a, [hl] + pop de + pop hl + ret + +SetAllDecorationFlags: + ld hl, DecorationIDs +.loop + ld a, [hli] + cp -1 + jr z, .done + push hl + ld b, SET_FLAG + call DecorationFlagAction + pop hl + jr .loop + +.done + ret + +INCLUDE "data/decorations/decorations.asm" + +DescribeDecoration:: + ld a, b + ld hl, .JumpTable + rst JumpTable + ret + +.JumpTable: +; entries correspond to DECODESC_* constants + dw DecorationDesc_Poster + dw DecorationDesc_LeftOrnament + dw DecorationDesc_RightOrnament + dw DecorationDesc_GiantOrnament + dw DecorationDesc_Console + +DecorationDesc_Poster: + ld a, [wDecoPoster] + ld hl, DecorationDesc_PosterPointers + ld de, 3 + call IsInArray + jr c, .nope + ld de, DecorationDesc_NullPoster + ld b, BANK(DecorationDesc_NullPoster) + ret + +.nope + ld b, BANK(DecorationDesc_TownMapPoster) + inc hl + ld a, [hli] + ld d, [hl] + ld e, a + ret + +DecorationDesc_PosterPointers: + dbw DECO_TOWN_MAP, DecorationDesc_TownMapPoster + dbw DECO_PIKACHU_POSTER, DecorationDesc_PikachuPoster + dbw DECO_CLEFAIRY_POSTER, DecorationDesc_ClefairyPoster + dbw DECO_JIGGLYPUFF_POSTER, DecorationDesc_JigglypuffPoster + db -1 + +DecorationDesc_TownMapPoster: + opentext + writetext .LookTownMapText + waitbutton + special OverworldTownMap + closetext + end + +.LookTownMapText: + text_far _LookTownMapText + text_end + +DecorationDesc_PikachuPoster: + jumptext .LookPikachuPosterText + +.LookPikachuPosterText: + text_far _LookPikachuPosterText + text_end + +DecorationDesc_ClefairyPoster: + jumptext .LookClefairyPosterText + +.LookClefairyPosterText: + text_far _LookClefairyPosterText + text_end + +DecorationDesc_JigglypuffPoster: + jumptext .LookJigglypuffPosterText + +.LookJigglypuffPosterText: + text_far _LookJigglypuffPosterText + text_end + +DecorationDesc_NullPoster: + end + +DecorationDesc_LeftOrnament: + ld a, [wDecoLeftOrnament] + jr DecorationDesc_OrnamentOrConsole + +DecorationDesc_RightOrnament: + ld a, [wDecoRightOrnament] + jr DecorationDesc_OrnamentOrConsole + +DecorationDesc_Console: + ld a, [wDecoConsole] + jr DecorationDesc_OrnamentOrConsole + +DecorationDesc_OrnamentOrConsole: + ld c, a + ld de, wStringBuffer3 + call GetDecorationName_c_de + ld b, BANK(.OrnamentConsoleScript) + ld de, .OrnamentConsoleScript + ret + +.OrnamentConsoleScript: + jumptext .LookAdorableDecoText + +.LookAdorableDecoText: + text_far _LookAdorableDecoText + text_end + +DecorationDesc_GiantOrnament: + ld b, BANK(.BigDollScript) + ld de, .BigDollScript + ret + +.BigDollScript: + jumptext .LookGiantDecoText + +.LookGiantDecoText: + text_far _LookGiantDecoText + text_end + +ToggleMaptileDecorations: + ; tile coordinates work the same way as for changeblock + lb de, 0, 4 ; bed coordinates + ld a, [wDecoBed] + call SetDecorationTile + lb de, 7, 4 ; plant coordinates + ld a, [wDecoPlant] + call SetDecorationTile + lb de, 6, 0 ; poster coordinates + ld a, [wDecoPoster] + call SetDecorationTile + call SetPosterVisibility + lb de, 0, 0 ; carpet top-left coordinates + call PadCoords_de + ld a, [wDecoCarpet] + and a + ret z + call _GetDecorationSprite + ld [hl], a + push af + lb de, 0, 2 ; carpet bottom-left coordinates + call PadCoords_de + pop af + inc a + ld [hli], a ; carpet bottom-left block + inc a + ld [hli], a ; carpet bottom-middle block + dec a + ld [hl], a ; carpet bottom-right block + ret + +SetPosterVisibility: + ld b, SET_FLAG + ld a, [wDecoPoster] + and a + jr nz, .ok + ld b, RESET_FLAG + +.ok + ld de, EVENT_PLAYERS_ROOM_POSTER + jp EventFlagAction + +SetDecorationTile: + push af + call PadCoords_de + pop af + and a + ret z + call _GetDecorationSprite + ld [hl], a + ret + +ToggleDecorationsVisibility: + ld de, EVENT_PLAYERS_HOUSE_2F_CONSOLE + ld hl, wVariableSprites + SPRITE_CONSOLE - SPRITE_VARS + ld a, [wDecoConsole] + call ToggleDecorationVisibility + ld de, EVENT_PLAYERS_HOUSE_2F_DOLL_1 + ld hl, wVariableSprites + SPRITE_DOLL_1 - SPRITE_VARS + ld a, [wDecoLeftOrnament] + call ToggleDecorationVisibility + ld de, EVENT_PLAYERS_HOUSE_2F_DOLL_2 + ld hl, wVariableSprites + SPRITE_DOLL_2 - SPRITE_VARS + ld a, [wDecoRightOrnament] + call ToggleDecorationVisibility + ld de, EVENT_PLAYERS_HOUSE_2F_BIG_DOLL + ld hl, wVariableSprites + SPRITE_BIG_DOLL - SPRITE_VARS + ld a, [wDecoBigDoll] + call ToggleDecorationVisibility + ret + +ToggleDecorationVisibility: + and a + jr z, .hide + call _GetDecorationSprite + ld [hl], a + ld b, RESET_FLAG + jp EventFlagAction + +.hide + ld b, SET_FLAG + jp EventFlagAction + +_GetDecorationSprite: + ld c, a + push de + push hl + farcall GetDecorationSprite + pop hl + pop de + ld a, c + ret + +PadCoords_de: +; adjusts coordinates, the same way as Script_changeblock + ld a, d + add 4 + ld d, a + ld a, e + add 4 + ld e, a + call GetBlockLocation + ret diff --git a/engine/overworld/events.asm b/engine/overworld/events.asm new file mode 100644 index 00000000..794fa074 --- /dev/null +++ b/engine/overworld/events.asm @@ -0,0 +1,1585 @@ +INCLUDE "constants.asm" + + +SECTION "Events", ROMX + +OverworldLoop:: + xor a ; MAPSTATUS_START + ld [wMapStatus], a +.loop + ld a, [wMapStatus] + ld hl, .jumps + rst JumpTable + ld a, [wMapStatus] + cp MAPSTATUS_DONE + jr nz, .loop +.done + ret + +.jumps +; entries correspond to MAPSTATUS_* constants + dw StartMap + dw EnterMap + dw HandleMap + dw .done + +DisableEvents: + xor a + ld [wScriptFlags3], a + ret + +EnableEvents:: + ld a, $ff + ld [wScriptFlags3], a + ret + +CheckBit5_ScriptFlags3: + ld hl, wScriptFlags3 + bit 5, [hl] + ret + +DisableWarpsConnxns: + ld hl, wScriptFlags3 + res 2, [hl] + ret + +DisableCoordEvents: + ld hl, wScriptFlags3 + res 1, [hl] + ret + +DisableStepCount: + ld hl, wScriptFlags3 + res 0, [hl] + ret + +DisableWildEncounters: + ld hl, wScriptFlags3 + res 4, [hl] + ret + +EnableWarpsConnxns: + ld hl, wScriptFlags3 + set 2, [hl] + ret + +EnableCoordEvents: + ld hl, wScriptFlags3 + set 1, [hl] + ret + +EnableStepCount: + ld hl, wScriptFlags3 + set 0, [hl] + ret + +EnableWildEncounters: + ld hl, wScriptFlags3 + set 4, [hl] + ret + +CheckWarpConnxnScriptFlag: + ld hl, wScriptFlags3 + bit 2, [hl] + ret + +CheckCoordEventScriptFlag: + ld hl, wScriptFlags3 + bit 1, [hl] + ret + +CheckStepCountScriptFlag: + ld hl, wScriptFlags3 + bit 0, [hl] + ret + +CheckWildEncountersScriptFlag: + ld hl, wScriptFlags3 + bit 4, [hl] + ret + +StartMap: + xor a + ld [wScriptRunning], a + ld hl, wMapStatus + ld bc, wMapStatusEnd - wMapStatus + call ByteFill + farcall InitCallReceiveDelay + call ClearJoypad +EnterMap: + xor a + ld [wXYComparePointer], a + ld [wXYComparePointer + 1], a + call SetUpFiveStepWildEncounterCooldown + farcall RunMapSetupScript + call DisableEvents + + ldh a, [hMapEntryMethod] + cp MAPSETUP_CONNECTION + jr nz, .dont_enable + call EnableEvents +.dont_enable + + ldh a, [hMapEntryMethod] + cp MAPSETUP_RELOADMAP + jr nz, .dontresetpoison + xor a + ld [wPoisonStepCount], a +.dontresetpoison + + xor a ; end map entry + ldh [hMapEntryMethod], a + ld a, MAPSTATUS_HANDLE + ld [wMapStatus], a + ret + +UnusedWait30Frames: + ld c, 30 + call DelayFrames + ret + +HandleMap: + call ResetOverworldDelay + call HandleMapTimeAndJoypad + farcall HandleCmdQueue ; no need to farcall + call MapEvents + +; Not immediately entering a connected map will cause problems. + ld a, [wMapStatus] + cp MAPSTATUS_HANDLE + ret nz + + call HandleMapObjects + call NextOverworldFrame + call HandleMapBackground + call CheckPlayerState + ret + +MapEvents: + ld a, [wMapEventStatus] + ld hl, .jumps + rst JumpTable + ret + +.jumps +; entries correspond to MAPEVENTS_* constants + dw .events + dw .no_events + +.events + call PlayerEvents + call DisableEvents + farcall ScriptEvents + ret + +.no_events + ret + +MaxOverworldDelay: + db 2 + +ResetOverworldDelay: + ld a, [MaxOverworldDelay] + ld [wOverworldDelay], a + ret + +NextOverworldFrame: + ld a, [wOverworldDelay] + and a + ret z + ld c, a + call DelayFrames + ret + +HandleMapTimeAndJoypad: + ld a, [wMapEventStatus] + cp MAPEVENTS_OFF + ret z + + call UpdateTime + call GetJoypad + call TimeOfDayPals + ret + +HandleMapObjects: + farcall HandleNPCStep ; engine/map_objects.asm + farcall _HandlePlayerStep + call _CheckObjectEnteringVisibleRange + ret + +HandleMapBackground: + farcall _UpdateSprites + farcall ScrollScreen + ret + +CheckPlayerState: + ld a, [wPlayerStepFlags] + bit PLAYERSTEP_CONTINUE_F, a + jr z, .events + bit PLAYERSTEP_STOP_F, a + jr z, .noevents + bit PLAYERSTEP_MIDAIR_F, a + jr nz, .noevents + call EnableEvents +.events + ld a, MAPEVENTS_ON + ld [wMapEventStatus], a + ret + +.noevents + ld a, MAPEVENTS_OFF + ld [wMapEventStatus], a + ret + +_CheckObjectEnteringVisibleRange: + ld hl, wPlayerStepFlags + bit PLAYERSTEP_STOP_F, [hl] + ret z + farcall CheckObjectEnteringVisibleRange + ret + +PlayerEvents: + xor a +; If there's already a player event, don't interrupt it. + ld a, [wScriptRunning] + and a + ret nz + + call Dummy_CheckScriptFlags3Bit5 ; This is a waste of time + + call CheckTrainerBattle_GetPlayerEvent + jr c, .ok + + call CheckTileEvent + jr c, .ok + + call RunMemScript + jr c, .ok + + call RunSceneScript + jr c, .ok + + call CheckTimeEvents + jr c, .ok + + call OWPlayerInput + jr c, .ok + + xor a + ret + +.ok + push af + farcall EnableScriptMode + pop af + ld [wScriptRunning], a + call DoPlayerEvent + scf + ret + +CheckTrainerBattle_GetPlayerEvent: + nop + nop + call CheckTrainerBattle + jr nc, .nope + + ld a, PLAYEREVENT_SEENBYTRAINER + scf + ret + +.nope + xor a + ret + +CheckTileEvent: +; Check for warps, coord events, or wild battles. + + call CheckWarpConnxnScriptFlag + jr z, .connections_disabled + + call CheckMovingOffEdgeOfMap + jr c, .map_connection + + call CheckWarpTile + jr c, .warp_tile + +.connections_disabled + call CheckCoordEventScriptFlag + jr z, .coord_events_disabled + + call CheckCurrentMapCoordEvents + jr c, .coord_event + +.coord_events_disabled + call CheckStepCountScriptFlag + jr z, .step_count_disabled + + call CountStep + ret c + +.step_count_disabled + call CheckWildEncountersScriptFlag + jr z, .ok + + call RandomEncounter + ret c + jr .ok ; pointless + +.ok + xor a + ret + +.map_connection + ld a, PLAYEREVENT_CONNECTION + scf + ret + +.warp_tile + ld a, [wPlayerStandingTile] + call CheckPitTile + jr nz, .not_pit + ld a, PLAYEREVENT_FALL + scf + ret + +.not_pit + ld a, PLAYEREVENT_WARP + scf + ret + +.coord_event + ld hl, wCurCoordEventScriptAddr + ld a, [hli] + ld h, [hl] + ld l, a + call GetMapScriptsBank + call CallScript + ret + +CheckWildEncounterCooldown:: + ld hl, wWildEncounterCooldown + ld a, [hl] + and a + ret z + dec [hl] + ret z + scf + ret + +SetUpFiveStepWildEncounterCooldown: + ld a, 5 + ld [wWildEncounterCooldown], a + ret + +ret_96804: + ret + +SetMinTwoStepWildEncounterCooldown: + ld a, [wWildEncounterCooldown] + cp 2 + ret nc + ld a, 2 + ld [wWildEncounterCooldown], a + ret + +Dummy_CheckScriptFlags3Bit5: + call CheckBit5_ScriptFlags3 + ret z + call Function2ffe + ret + +RunSceneScript: + ld a, [wCurMapSceneScriptCount] + and a + jr z, .nope + + ld c, a + call CheckScenes + cp c + jr nc, .nope + + ld e, a + ld d, 0 + ld hl, wCurMapSceneScriptsPointer + ld a, [hli] + ld h, [hl] + ld l, a +rept SCENE_SCRIPT_SIZE + add hl, de +endr + + call GetMapScriptsBank + call GetFarHalfword + call GetMapScriptsBank + call CallScript + + ld hl, wScriptFlags + res 3, [hl] + + farcall EnableScriptMode + farcall ScriptEvents + + ld hl, wScriptFlags + bit 3, [hl] + jr z, .nope + + ld hl, wPriorityScriptAddr + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wPriorityScriptBank] + call CallScript + scf + ret + +.nope + xor a + ret + +CheckTimeEvents: + ld a, [wLinkMode] + and a + jr nz, .nothing + + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + jr z, .do_daily + + farcall CheckBugContestTimer + jr c, .end_bug_contest + xor a + ret + +.do_daily + farcall CheckDailyResetTimer + farcall CheckSwarmFlag + farcall CheckPokerusTick + farcall CheckPhoneCall + ret c + +.nothing + xor a + ret + +.end_bug_contest + ld a, BANK(BugCatchingContestOverScript) + ld hl, BugCatchingContestOverScript + call CallScript + scf + ret + +.unused + ld a, 8 + scf + ret + +OWPlayerInput: + call PlayerMovement + ret c + and a + jr nz, .NoAction + +; Can't perform button actions while sliding on ice. + farcall CheckStandingOnIce + jr c, .NoAction + + call CheckAPressOW + jr c, .Action + + call CheckMenuOW + jr c, .Action + +.NoAction: + xor a + ret + +.Action: + push af + farcall StopPlayerForEvent + pop af + scf + ret + +CheckAPressOW: + ldh a, [hJoyPressed] + and A_BUTTON + ret z + call TryObjectEvent + ret c + call TryBGEvent + ret c + call TryTileCollisionEvent + ret c + xor a + ret + +PlayTalkObject: + push de + ld de, SFX_READ_TEXT_2 + call PlaySFX + pop de + ret + +TryObjectEvent: + farcall CheckFacingObject + jr c, .IsObject + xor a + ret + +.IsObject: + call PlayTalkObject + ldh a, [hObjectStructIndexBuffer] + call GetObjectStruct + ld hl, OBJECT_MAP_OBJECT_INDEX + add hl, bc + ld a, [hl] + ldh [hLastTalked], a + + ldh a, [hLastTalked] + call GetMapObject + ld hl, MAPOBJECT_COLOR + add hl, bc + ld a, [hl] + and %00001111 + +; Bug: If IsInArray returns nc, data at bc will be executed as code. + push bc + ld de, 3 + ld hl, .pointers + call IsInArray + jr nc, .nope + pop bc + + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.nope + ; pop bc + xor a + ret + +.pointers + dbw OBJECTTYPE_SCRIPT, .script + dbw OBJECTTYPE_ITEMBALL, .itemball + dbw OBJECTTYPE_TRAINER, .trainer + ; the remaining four are dummy events + dbw OBJECTTYPE_3, .three + dbw OBJECTTYPE_4, .four + dbw OBJECTTYPE_5, .five + dbw OBJECTTYPE_6, .six + db -1 + +.script + ld hl, MAPOBJECT_SCRIPT_POINTER + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call GetMapScriptsBank + call CallScript + ret + +.itemball + ld hl, MAPOBJECT_SCRIPT_POINTER + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call GetMapScriptsBank + ld de, wItemBallData + ld bc, wItemBallDataEnd - wItemBallData + call FarCopyBytes + ld a, PLAYEREVENT_ITEMBALL + scf + ret + +.trainer + call TalkToTrainer + ld a, PLAYEREVENT_TALKTOTRAINER + scf + ret + +.three + xor a + ret + +.four + xor a + ret + +.five + xor a + ret + +.six + xor a + ret + +TryBGEvent: + call CheckFacingBGEvent + jr c, .is_bg_event + xor a + ret + +.is_bg_event: + ld a, [wCurBGEventType] + ld hl, .bg_events + rst JumpTable + ret + +.bg_events + dw .read + dw .up + dw .down + dw .right + dw .left + dw .ifset + dw .ifnotset + dw .itemifset + dw .copy + +.up + ld b, OW_UP + jr .checkdir +.down + ld b, OW_DOWN + jr .checkdir +.right + ld b, OW_RIGHT + jr .checkdir +.left + ld b, OW_LEFT + jr .checkdir + +.checkdir + ld a, [wPlayerDirection] + and %1100 + cp b + jp nz, .dontread + +.read + call PlayTalkObject + ld hl, wCurBGEventScriptAddr + ld a, [hli] + ld h, [hl] + ld l, a + call GetMapScriptsBank + call CallScript + scf + ret + +.itemifset + call CheckBGEventFlag + jp nz, .dontread + call PlayTalkObject + call GetMapScriptsBank + ld de, wHiddenItemData + ld bc, wHiddenItemDataEnd - wHiddenItemData + call FarCopyBytes + ld a, BANK(HiddenItemScript) + ld hl, HiddenItemScript + call CallScript + scf + ret + +.copy + call CheckBGEventFlag + jr nz, .dontread + call GetMapScriptsBank + ld de, wHiddenItemData + ld bc, wHiddenItemDataEnd - wHiddenItemData + call FarCopyBytes + jr .dontread + +.ifset + call CheckBGEventFlag + jr z, .dontread + jr .thenread + +.ifnotset + call CheckBGEventFlag + jr nz, .dontread + +.thenread + push hl + call PlayTalkObject + pop hl + inc hl + inc hl + call GetMapScriptsBank + call GetFarHalfword + call GetMapScriptsBank + call CallScript + scf + ret + +.dontread + xor a + ret + +CheckBGEventFlag: + ld hl, wCurBGEventScriptAddr + ld a, [hli] + ld h, [hl] + ld l, a + push hl + call GetMapScriptsBank + call GetFarHalfword + ld e, l + ld d, h + ld b, CHECK_FLAG + call EventFlagAction + ld a, c + and a + pop hl + ret + +PlayerMovement: + farcall DoPlayerMovement + ld a, c + ld hl, .pointers + rst JumpTable + ld a, c + ret + +.pointers +; entries correspond to PLAYERMOVEMENT_* constants + dw .normal + dw .warp + dw .turn + dw .force_turn + dw .finish + dw .continue + dw .exit_water + dw .jump + +.normal: +.finish: + xor a + ld c, a + ret + +.jump: + call ret_96804 + xor a + ld c, a + ret + +.warp: + ld a, PLAYEREVENT_WARP + ld c, a + scf + ret + +.turn: + ld a, PLAYEREVENT_JOYCHANGEFACING + ld c, a + scf + ret + +.force_turn: +; force the player to move in some direction + ld a, BANK(Script_ForcedMovement) + ld hl, Script_ForcedMovement + call CallScript +; ld a, -1 + ld c, a + scf + ret + +.continue: +.exit_water: + ld a, -1 + ld c, a + and a + ret + +CheckMenuOW: + xor a + ldh [hMenuReturn], a + ldh [hUnusedFFA3], a + ldh a, [hJoyPressed] + + bit SELECT_F, a + jr nz, .Select + + bit START_F, a + jr z, .NoMenu + + ld a, BANK(StartMenuScript) + ld hl, StartMenuScript + call CallScript + scf + ret + +.NoMenu: + xor a + ret + +.Select: + call PlayTalkObject + ld a, BANK(SelectMenuScript) + ld hl, SelectMenuScript + call CallScript + scf + ret + +StartMenuScript: + callasm StartMenu + sjump StartMenuCallback + +SelectMenuScript: + callasm SelectMenu + sjump SelectMenuCallback + +StartMenuCallback: +SelectMenuCallback: + readmem hMenuReturn + ifequal HMENURETURN_SCRIPT, .Script + ifequal HMENURETURN_ASM, .Asm + end + +.Script: + memjump wQueuedScriptBank + +.Asm: + memcallasm wQueuedScriptBank + end + +CountStep: + ; Don't count steps in link communication rooms. + ld a, [wLinkMode] + and a + jr nz, .done + + ; If there is a special phone call, don't count the step. + farcall CheckSpecialPhoneCall + jr c, .doscript + + ; If Repel wore off, don't count the step. + call DoRepelStep + jr c, .doscript + + ; Count the step for poison and total steps + ld hl, wPoisonStepCount + inc [hl] + ld hl, wStepCount + inc [hl] + ; Every 256 steps, increase the happiness of all your Pokemon. + jr nz, .skip_happiness + + farcall StepHappiness + +.skip_happiness + ; Every 256 steps, offset from the happiness incrementor by 128 steps, + ; decrease the hatch counter of all your eggs until you reach the first + ; one that is ready to hatch. + ld a, [wStepCount] + cp $80 + jr nz, .skip_egg + + farcall DoEggStep + jr nz, .hatch + +.skip_egg + ; Increase the EXP of (both) DayCare Pokemon by 1. + farcall DayCareStep + + ; Every four steps, deal damage to all Poisoned Pokemon + ld hl, wPoisonStepCount + ld a, [hl] + cp 4 + jr c, .skip_poison + ld [hl], 0 + + farcall DoPoisonStep + jr c, .doscript + +.skip_poison + farcall DoBikeStep + +.done + xor a + ret + +.doscript + ld a, -1 + scf + ret + +.hatch + ld a, PLAYEREVENT_HATCH + scf + ret + +; unused +.unreferenced + ld a, PLAYEREVENT_WHITEOUT + scf + ret + +DoRepelStep: + ld a, [wRepelEffect] + and a + ret z + + dec a + ld [wRepelEffect], a + ret nz + + ld a, BANK(RepelWoreOffScript) + ld hl, RepelWoreOffScript + call CallScript + scf + ret + +DoPlayerEvent: + ld a, [wScriptRunning] + and a + ret z + + cp PLAYEREVENT_MAPSCRIPT ; run script + ret z + + cp NUM_PLAYER_EVENTS + ret nc + + ld c, a + ld b, 0 + ld hl, PlayerEventScriptPointers + add hl, bc + add hl, bc + add hl, bc + ld a, [hli] + ld [wScriptBank], a + ld a, [hli] + ld [wScriptPos], a + ld a, [hl] + ld [wScriptPos + 1], a + ret + +PlayerEventScriptPointers: +; entries correspond to PLAYEREVENT_* constants + dba Invalid_0x96b60 ; PLAYEREVENT_NONE + dba SeenByTrainerScript ; PLAYEREVENT_SEENBYTRAINER + dba TalkToTrainerScript ; PLAYEREVENT_TALKTOTRAINER + dba FindItemInBallScript ; PLAYEREVENT_ITEMBALL + dba EdgeWarpScript ; PLAYEREVENT_CONNECTION + dba WarpToNewMapScript ; PLAYEREVENT_WARP + dba FallIntoMapScript ; PLAYEREVENT_FALL + dba Script_OverworldWhiteout ; PLAYEREVENT_WHITEOUT + dba HatchEggScript ; PLAYEREVENT_HATCH + dba ChangeDirectionScript ; PLAYEREVENT_JOYCHANGEFACING + dba Invalid_0x96b60 ; (NUM_PLAYER_EVENTS) + +Invalid_0x96b60: + end + +; unused + end + +HatchEggScript: + callasm OverworldHatchEgg + end + +WarpToNewMapScript: + warpsound + newloadmap MAPSETUP_DOOR + end + +FallIntoMapScript: + newloadmap MAPSETUP_FALL + playsound SFX_KINESIS + applymovement PLAYER, MovementData_0x96c48 + playsound SFX_STRENGTH + scall LandAfterPitfallScript + end + +MovementData_0x96c48: + skyfall + step_end + +LandAfterPitfallScript: + earthquake 16 + end + +EdgeWarpScript: ; 4 + reloadandreturn MAPSETUP_CONNECTION + +ChangeDirectionScript: ; 9 + deactivatefacing 3 + callasm EnableWildEncounters + end + +INCLUDE "engine/overworld/scripting.asm" + +WarpToSpawnPoint:: + ld hl, wStatusFlags2 + res STATUSFLAGS2_SAFARI_GAME_F, [hl] + res STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + ret + +RunMemScript:: +; If there is no script here, we don't need to be here. + ld a, [wMapReentryScriptQueueFlag] + and a + ret z +; Execute the script at (wMapReentryScriptBank):(wMapReentryScriptAddress). + ld hl, wMapReentryScriptAddress + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wMapReentryScriptBank] + call CallScript + scf +; Clear the buffer for the next script. + push af + xor a + ld hl, wMapReentryScriptQueueFlag + ld bc, 8 + call ByteFill + pop af + ret + +LoadScriptBDE:: +; If there's already a script here, don't overwrite. + ld hl, wMapReentryScriptQueueFlag + ld a, [hl] + and a + ret nz +; Set the flag + ld [hl], 1 + inc hl +; Load the script pointer b:de into (wMapReentryScriptBank):(wMapReentryScriptAddress) + ld [hl], b + inc hl + ld [hl], e + inc hl + ld [hl], d + scf + ret + +TryTileCollisionEvent:: + call GetFacingTileCoord + ld [wFacingTileID], a + ld c, a + farcall CheckFacingTileForStdScript + jr c, .done + + call CheckCutTreeTile + jr nz, .whirlpool + farcall TryCutOW + jr .done + +.whirlpool + ld a, [wFacingTileID] + call CheckWhirlpoolTile + jr nz, .waterfall + farcall TryWhirlpoolOW + jr .done + +.waterfall + ld a, [wFacingTileID] + call CheckWaterfallTile + jr nz, .headbutt + farcall TryWaterfallOW + jr .done + +.headbutt + ld a, [wFacingTileID] + call CheckHeadbuttTreeTile + jr nz, .surf + farcall TryHeadbuttOW + jr c, .done + jr .noevent + +.surf + farcall TrySurfOW + jr nc, .noevent + jr .done + +.noevent + xor a + ret + +.done + call PlayClickSFX + ld a, $ff + scf + ret + +RandomEncounter:: +; Random encounter + + call CheckWildEncounterCooldown + jr c, .nope + call CanUseSweetScent + jr nc, .nope + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BUG_CONTEST_TIMER_F, [hl] + jr nz, .bug_contest + farcall TryWildEncounter + jr nz, .nope + jr .ok + +.bug_contest + call _TryWildEncounter_BugContest + jr nc, .nope + jr .ok_bug_contest + +.nope + ld a, 1 + and a + ret + +.ok + ld a, BANK(WildBattleScript) + ld hl, WildBattleScript + jr .done + +.ok_bug_contest + ld a, BANK(BugCatchingContestBattleScript) + ld hl, BugCatchingContestBattleScript + jr .done + +.done + call CallScript + scf + ret + +WildBattleScript: + randomwildmon + startbattle + reloadmapafterbattle + end + +CanUseSweetScent:: + ld hl, wStatusFlags + bit STATUSFLAGS_NO_WILD_ENCOUNTERS_F, [hl] + jr nz, .no + ld a, [wEnvironment] + cp CAVE + jr z, .ice_check + cp DUNGEON + jr z, .ice_check + farcall CheckGrassCollision + jr nc, .no + +.ice_check + ld a, [wPlayerStandingTile] + call CheckIceTile + jr z, .no + scf + ret + +.no + and a + ret + +_TryWildEncounter_BugContest: + call TryWildEncounter_BugContest + ret nc + call ChooseWildEncounter_BugContest + farcall CheckRepelEffect + ret + +ChooseWildEncounter_BugContest:: +; Pick a random mon out of ContestMons. + +.loop + call Random + cp 100 << 1 + jr nc, .loop + srl a + + ld hl, ContestMons + ld de, 4 +.CheckMon: + sub [hl] + jr c, .GotMon + add hl, de + jr .CheckMon + +.GotMon: + inc hl + +; Species + ld a, [hli] + ld [wTempWildMonSpecies], a + +; Min level + ld a, [hli] + ld d, a + +; Max level + ld a, [hl] + + sub d + jr nz, .RandomLevel + +; If min and max are the same. + ld a, d + jr .GotLevel + +.RandomLevel: +; Get a random level between the min and max. + ld c, a + inc c + call Random + ldh a, [hRandomAdd] + call SimpleDivide + add d + +.GotLevel: + ld [wCurPartyLevel], a + + xor a + ret + +TryWildEncounter_BugContest: + ld a, [wPlayerStandingTile] + call CheckSuperTallGrassTile + ld b, 40 percent + jr z, .ok + ld b, 20 percent + +.ok + farcall ApplyMusicEffectOnEncounterRate + farcall ApplyCleanseTagEffectOnEncounterRate + call Random + ldh a, [hRandomAdd] + cp b + ret c + ld a, 1 + and a + ret + +INCLUDE "data/wild/bug_contest_mons.asm" + +DoBikeStep:: + nop + nop + ; If the bike shop owner doesn't have our number, or + ; if we've already gotten the call, we don't have to + ; be here. + ld hl, wStatusFlags2 + bit STATUSFLAGS2_BIKE_SHOP_CALL_F, [hl] + jr z, .NoCall + + ; If we're not on the bike, we don't have to be here. + ld a, [wPlayerState] + cp PLAYER_BIKE + jr nz, .NoCall + + ; If we're not in an area of phone service, we don't + ; have to be here. + call GetMapPhoneService + and a + jr nz, .NoCall + + ; Check the bike step count and check whether we've + ; taken 65536 of them yet. + ld hl, wBikeStep + ld a, [hli] + ld d, a + ld e, [hl] + cp 255 + jr nz, .increment + ld a, e + cp 255 + jr z, .dont_increment + +.increment + inc de + ld [hl], e + dec hl + ld [hl], d + +.dont_increment + ; If we've taken at least 1024 steps, have the bike + ; shop owner try to call us. + ld a, d + cp HIGH(1024) + jr c, .NoCall + + ; If a call has already been queued, don't overwrite + ; that call. + ld a, [wSpecialPhoneCallID] + and a + jr nz, .NoCall + + ; Queue the call. + ld a, SPECIALCALL_BIKESHOP + ld [wSpecialPhoneCallID], a + xor a + ld [wSpecialPhoneCallID + 1], a + ld hl, wStatusFlags2 + res STATUSFLAGS2_BIKE_SHOP_CALL_F, [hl] + scf + ret + +.NoCall: + xor a + ret + +ClearCmdQueue:: + ld hl, wCmdQueue + ld de, CMDQUEUE_ENTRY_SIZE + ld c, CMDQUEUE_CAPACITY + xor a +.loop + ld [hl], a + add hl, de + dec c + jr nz, .loop + ret + +HandleCmdQueue:: + ld hl, wCmdQueue + xor a +.loop + ldh [hMapObjectIndexBuffer], a + ld a, [hl] + and a + jr z, .skip + push hl + ld b, h + ld c, l + call HandleQueuedCommand + pop hl + +.skip + ld de, CMDQUEUE_ENTRY_SIZE + add hl, de + ldh a, [hMapObjectIndexBuffer] + inc a + cp CMDQUEUE_CAPACITY + jr nz, .loop + ret + +Unreferenced_GetNthCmdQueueEntry: + ld hl, wCmdQueue + ld bc, CMDQUEUE_ENTRY_SIZE + call AddNTimes + ld b, h + ld c, l + ret + +WriteCmdQueue:: + push bc + push de + call .GetNextEmptyEntry + ld d, h + ld e, l + pop hl + pop bc + ret c + ld a, b + ld bc, CMDQUEUE_ENTRY_SIZE - 1 + call FarCopyBytes + xor a + ld [hl], a + ret + +.GetNextEmptyEntry: + ld hl, wCmdQueue + ld de, CMDQUEUE_ENTRY_SIZE + ld c, CMDQUEUE_CAPACITY +.loop + ld a, [hl] + and a + jr z, .done + add hl, de + dec c + jr nz, .loop + scf + ret + +.done + ld a, CMDQUEUE_CAPACITY + sub c + and a + ret + +DelCmdQueue:: + ld hl, wCmdQueue + ld de, CMDQUEUE_ENTRY_SIZE + ld c, CMDQUEUE_CAPACITY +.loop + ld a, [hl] + cp b + jr z, .done + add hl, de + dec c + jr nz, .loop + and a + ret + +.done + xor a + ld [hl], a + scf + ret + +_DelCmdQueue: + ld hl, CMDQUEUE_TYPE + add hl, bc + ld [hl], 0 + ret + +HandleQueuedCommand: + ld hl, CMDQUEUE_TYPE + add hl, bc + ld a, [hl] + cp NUM_CMDQUEUE_TYPES + jr c, .okay + xor a + +.okay + ld e, a + ld d, 0 + ld hl, .Jumptable + add hl, de + add hl, de + add hl, de + ld a, [hli] + push af + ld a, [hli] + ld h, [hl] + ld l, a + pop af + rst FarCall + ret + +.Jumptable: + dba CmdQueue_Null + dba CmdQueue_Type2 + dba CmdQueue_StoneTable + dba CmdQueue_Null2 + dba CmdQueue_Type4 + +CmdQueueAnonymousJumptable: + ld hl, CMDQUEUE_05 + add hl, bc + ld a, [hl] + pop hl + rst JumpTable + ret + +CmdQueueAnonJT_Increment: + ld hl, CMDQUEUE_05 + add hl, bc + inc [hl] + ret + +CmdQueueAnonJT_Decrement: + ld hl, CMDQUEUE_05 + add hl, bc + dec [hl] + ret + +CmdQueue_Null: + ret + +CmdQueue_Type2: + call Function2ffe + ret + +CmdQueue_Type4: + call CmdQueueAnonymousJumptable + ; anonymous dw + dw .zero + dw .one + +.zero + ldh a, [hSCY] + ld hl, CMDQUEUE_04 + add hl, bc + ld [hl], a + call CmdQueueAnonJT_Increment +.one + ld hl, CMDQUEUE_ADDR + add hl, bc + ld a, [hl] + dec a + ld [hl], a + jr z, .finish + and 1 + jr z, .add + ld hl, CMDQUEUE_02 + add hl, bc + ldh a, [hSCY] + sub [hl] + ldh [hSCY], a + ret + +.add + ld hl, CMDQUEUE_02 + add hl, bc + ldh a, [hSCY] + add [hl] + ldh [hSCY], a + ret + +.finish + ld hl, CMDQUEUE_04 + add hl, bc + ld a, [hl] + ldh [hSCY], a + call _DelCmdQueue + ret + +CmdQueue_Null2: + ret + +CmdQueue_StoneTable: + ld de, wPlayerStruct + ld a, NUM_OBJECT_STRUCTS +.loop + push af + + ld hl, OBJECT_SPRITE + add hl, de + ld a, [hl] + and a + jr z, .next + + ld hl, OBJECT_MOVEMENTTYPE + add hl, de + ld a, [hl] + cp SPRITEMOVEDATA_STRENGTH_BOULDER + jr nz, .next + + ld hl, OBJECT_NEXT_TILE + add hl, de + ld a, [hl] + call CheckPitTile + jr nz, .next + + ld hl, OBJECT_DIRECTION_WALKING + add hl, de + ld a, [hl] + cp STANDING + jr nz, .next + call HandleStoneQueue + jr c, .fall_down_hole + +.next + ld hl, OBJECT_LENGTH + add hl, de + ld d, h + ld e, l + + pop af + dec a + jr nz, .loop + ret + +.fall_down_hole + pop af + ret + +INCLUDE "engine/events/trainer_scripts.asm" diff --git a/engine/overworld/init_map.asm b/engine/overworld/init_map.asm new file mode 100644 index 00000000..72950ac7 --- /dev/null +++ b/engine/overworld/init_map.asm @@ -0,0 +1,96 @@ +ReanchorBGMap_NoOAMUpdate:: + call DelayFrame + ldh a, [hOAMUpdate] + push af + + ld a, $1 + ldh [hOAMUpdate], a + ldh a, [hBGMapMode] + push af + xor a + ldh [hBGMapMode], a + + call .ReanchorBGMap + + pop af + ldh [hBGMapMode], a + pop af + ldh [hOAMUpdate], a + ret + +.ReanchorBGMap: + xor a + ldh [hLCDCPointer], a + ldh [hBGMapMode], a + ld hl, wEnteredMapFromContinue + set 7, [hl] + res 2, [hl] + ld a, $90 + ldh [hWY], a + call OverworldTextModeSwitch + ld a, HIGH(vBGMap1) + call .LoadBGMapAddrIntoHRAM + call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap + xor a + ldh [hBGMapMode], a + ldh [hWY], a + ld a, HIGH(vBGMap0) + call .LoadBGMapAddrIntoHRAM + call .WaitTransfer + xor a ; LOW(vBGMap0) + ld [wBGMapAnchor], a + ld a, HIGH(vBGMap0) + ld [wBGMapAnchor + 1], a + xor a + ldh [hSCX], a + ldh [hSCY], a + call ApplyBGMapAnchorToObjects + ret + +.LoadBGMapAddrIntoHRAM: + ldh [hBGMapAddress + 1], a + xor a + ldh [hBGMapAddress], a + ret + +.WaitTransfer: + ldh a, [hBGMapMode] + push af + xor a + ldh [hBGMapMode], a + ldh a, [hOAMUpdate] + push af + ld a, 1 + ldh [hOAMUpdate], a + ld a, 3 + ldh [hFF9E], a +.asm_65bc + call DelayFrame + ldh a, [hFF9E] + and a + jr nz, .asm_65bc + pop af + ldh [hOAMUpdate], a + pop af + ldh [hBGMapMode], a + ret + +LoadFonts_NoOAMUpdate:: + ldh a, [hOAMUpdate] + push af + ld a, $1 + ldh [hOAMUpdate], a + + call .LoadGFX + + pop af + ldh [hOAMUpdate], a + ret + +.LoadGFX: + call LoadFontsExtra + ld a, $90 + ldh [hWY], a + call SafeUpdateSprites + call LoadStandardFont + ret diff --git a/engine/overworld/landmarks.asm b/engine/overworld/landmarks.asm new file mode 100644 index 00000000..bee64c75 --- /dev/null +++ b/engine/overworld/landmarks.asm @@ -0,0 +1,82 @@ +GetLandmarkCoords: +; Return coordinates (d, e) of landmark e. + push hl + ld l, e + ld h, 0 + add hl, hl + add hl, hl + ld de, Landmarks + add hl, de + ld a, [hli] + ld e, a + ld d, [hl] + pop hl + ret + +GetLandmarkName:: +; Copy the name of landmark e to wStringBuffer1. + push hl + push de + push bc + + ld l, e + ld h, 0 + add hl, hl + add hl, hl + ld de, Landmarks + 2 + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + ld de, wStringBuffer1 + ld c, 18 +.copy + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .copy + + pop bc + pop de + pop hl + ret + +INCLUDE "data/maps/landmarks.asm" + +RegionCheck: +; Checks if the player is in Kanto or Johto. +; If in Johto, returns 0 in e. +; If in Kanto, returns 1 in e. + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + call GetWorldMapLocation + cp LANDMARK_FAST_SHIP ; S.S. Aqua + jr z, .johto + cp LANDMARK_SPECIAL + jr nz, .checkagain + +; In a special map, get the backup map group / map id + ld a, [wBackupMapGroup] + ld b, a + ld a, [wBackupMapNumber] + ld c, a + call GetWorldMapLocation + +.checkagain + cp KANTO_LANDMARK + jr c, .johto + +; Victory Road area is considered to be Johto. + cp LANDMARK_VICTORY_ROAD + jr c, .kanto + +.johto + ld e, JOHTO_REGION + ret +.kanto + ld e, KANTO_REGION + ret diff --git a/engine/overworld/load_map_part.asm b/engine/overworld/load_map_part.asm new file mode 100644 index 00000000..23758f28 --- /dev/null +++ b/engine/overworld/load_map_part.asm @@ -0,0 +1,155 @@ +_LoadMapPart:: + ld hl, wSurroundingTiles + ld a, [wMetatileStandingY] + and a + jr z, .top_row + ld bc, SURROUNDING_WIDTH * 2 + add hl, bc + +.top_row + ld a, [wMetatileStandingX] + and a + jr z, .left_column + inc hl + inc hl + +.left_column + decoord 0, 0 + ld b, SCREEN_HEIGHT +.loop + ld c, SCREEN_WIDTH +.loop2 + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop2 + ld a, l + add METATILE_WIDTH + ld l, a + jr nc, .carry + inc h + +.carry + dec b + jr nz, .loop + ret + +UnusedFunction153ba: + decoord 2, 2 + ld bc, (SURROUNDING_WIDTH + 1) * 2 + add hl, bc + ld c, SCREEN_HEIGHT - 4 * 1 +.loop: + ld b, SCREEN_WIDTH - SCREEN_META_WIDTH +.loop2: + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop2 + ld a, l + add SCREEN_META_WIDTH + METATILE_WIDTH + ld l, a + jr nc, .carry1 + inc h + +.carry1: + ld a, e + add SCREEN_META_WIDTH + ld e, a + jr nc, .carry2 + inc d + +.carry2: + dec c + jr nz, .loop + ret + +UnusedFunction153dd: + decoord 4, 4 + ld bc, (SURROUNDING_WIDTH + 1) * 4 + add hl, bc + ld c, SCREEN_HEIGHT - 4 * 2 +.loop: + ld b, SCREEN_WIDTH - SCREEN_META_WIDTH - METATILE_WIDTH +.loop2: + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop2 + ld a, l + add SCREEN_META_WIDTH + METATILE_WIDTH * 2 + ld l, a + jr nc, .carry1 + inc h + +.carry1: + ld a, e + add SCREEN_META_WIDTH + METATILE_WIDTH + ld e, a + jr nc, .carry2 + inc d + +.carry2: + dec c + jr nz, .loop + ret + +UnusedFunction15400: + decoord 6, 6 + ld bc, (SURROUNDING_WIDTH + 1) * 6 + add hl, bc + ld c, SCREEN_HEIGHT - 4 * 3 +.loop: + ld b, SCREEN_WIDTH - SCREEN_META_WIDTH - METATILE_WIDTH * 2 +.loop2: + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop2 + ld a, l + add SCREEN_META_WIDTH + METATILE_WIDTH * 3 + ld l, a + jr nc, .carry1 + inc h + +.carry1: + ld a, e + add SCREEN_META_WIDTH + METATILE_WIDTH * 2 + ld e, a + jr nc, .carry2 + inc d + +.carry2: + dec c + jr nz, .loop + ret + +UnusedFunction15423: + decoord 8, 8 + ld bc, (SURROUNDING_WIDTH + 1) * 8 + add hl, bc +.loop + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld bc, SCREEN_WIDTH + 2 + add hl, bc + ld a, e + add SCREEN_META_WIDTH + METATILE_WIDTH * 3 + 1 + ld e, a + jr nc, .carry + inc d + +.carry: + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ret diff --git a/engine/overworld/map_object_action.asm b/engine/overworld/map_object_action.asm index 553243c4..8f749f84 100755 --- a/engine/overworld/map_object_action.asm +++ b/engine/overworld/map_object_action.asm @@ -1,260 +1,264 @@ - ld hl, $b - add hl, bc - ld a, [hl] - ld l, a - ld h, $0 - add hl, hl - add hl, hl - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - call _hl_ - ret +ObjectActionPairPointers: +; entries correspond to OBJECT_ACTION_* constants + dw SetFacingStanding, SetFacingStanding + dw SetFacingStandAction, SetFacingCurrent + dw SetFacingStepAction, SetFacingCurrent + dw SetFacingBumpAction, SetFacingCurrent + dw SetFacingCounterclockwiseSpin, SetFacingCurrent + dw SetFacingCounterclockwiseSpin2, SetFacingStanding + dw SetFacingFish, SetFacingFish + dw SetFacingShadow, SetFacingStanding + dw SetFacingEmote, SetFacingEmote + dw SetFacingBigDollSym, SetFacingBigDollSym + dw SetFacingBounce, SetFacingFreezeBounce + dw SetFacingWeirdTree, SetFacingCurrent + dw SetFacingBigDollAsym, SetFacingBigDollAsym + dw SetFacingBigDoll, SetFacingBigDoll + dw SetFacingBoulderDust, SetFacingStanding + dw SetFacingGrassShake, SetFacingStanding -Pointers4460: - dw Function44a0, Function44a0 - dw Function44b2, Function44a7 - dw Function44be, Function44a7 - dw Function44e1, Function44a7 - dw Function4502, Function44a7 - dw Function4512, Function44a0 - dw Function4547, Function4547 - dw Function4554, Function44a0 - dw Function455b, Function455b - dw Function4562, Function4562 - dw Function4569, Function457d - dw Function4584, Function44a7 - dw Function4597, Function4597 - dw Function459e, Function459e - dw Function45b3, Function44a0 - dw Function45c6, Function44a0 - -Function44a0 - ld hl, $d +SetFacingStanding: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $ff + ld [hl], STANDING ret -Function44a7: ; 44a7 (1:44a7) +SetFacingCurrent: call GetSpriteDirection - or $0 - ld hl, $d + or FACING_STEP_DOWN_0 ; useless + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], a ret -Function44b2: - ld hl, $d +SetFacingStandAction: + ld hl, OBJECT_FACING_STEP add hl, bc ld a, [hl] - and $1 - jr nz, Function44be - jp Function44a7 + and 1 + jr nz, SetFacingStepAction + jp SetFacingCurrent -Function44be: - ld hl, $4 +SetFacingStepAction: + ld hl, OBJECT_FLAGS1 add hl, bc - bit 3, [hl] - jp nz, Function44a7 - ld hl, $c + bit SLIDING_F, [hl] + jp nz, SetFacingCurrent + + ld hl, OBJECT_STEP_FRAME add hl, bc ld a, [hl] inc a - and $f + and %00001111 ld [hl], a + rrca rrca - and $3 + maskbits NUM_DIRECTIONS ld d, a + call GetSpriteDirection - or $0 + or FACING_STEP_DOWN_0 ; useless or d - ld hl, $d + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], a ret -Function44e1: - ld hl, $4 +SetFacingBumpAction: + ld hl, OBJECT_FLAGS1 add hl, bc - bit 3, [hl] - jp nz, Function44a7 - ld hl, $c + bit SLIDING_F, [hl] + jp nz, SetFacingCurrent + + ld hl, OBJECT_STEP_FRAME add hl, bc inc [hl] + ld a, [hl] rrca rrca rrca - and $3 + maskbits NUM_DIRECTIONS ld d, a + call GetSpriteDirection - or $0 + or FACING_STEP_DOWN_0 ; useless or d - ld hl, $d + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], a ret -Function4502: - call Function4518 - ld hl, $8 +SetFacingCounterclockwiseSpin: + call CounterclockwiseSpinAction + ld hl, OBJECT_FACING add hl, bc ld a, [hl] - or $0 - ld hl, $d + or FACING_STEP_DOWN_0 ; useless + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], a ret -Function4512: - call Function4518 - jp Function44a0 +SetFacingCounterclockwiseSpin2: + call CounterclockwiseSpinAction + jp SetFacingStanding -Function4518: ; 4518 (1:4518) - ld hl, $c +CounterclockwiseSpinAction: +; Here, OBJECT_STEP_FRAME consists of two 2-bit components, +; using only bits 0,1 and 4,5. +; bits 0,1 is a timer (4 overworld frames) +; bits 4,5 determines the facing - the direction is counterclockwise. + ld hl, OBJECT_STEP_FRAME add hl, bc ld a, [hl] - and $f0 + and %11110000 ld e, a + ld a, [hl] inc a - and $f + and %00001111 ld d, a - cp $4 - jr c, .asm_4531 - ld d, $0 + cp 4 + jr c, .ok + + ld d, 0 ld a, e add $10 - and $30 + and %00110000 ld e, a -.asm_4531 + +.ok ld a, d or e ld [hl], a + swap e - ld d, $0 - ld hl, .directions + ld d, 0 + ld hl, .Directions add hl, de ld a, [hl] - ld hl, $8 + ld hl, OBJECT_FACING add hl, bc ld [hl], a ret -.directions +.Directions: db OW_DOWN, OW_RIGHT, OW_UP, OW_LEFT -Function4547: +SetFacingFish: call GetSpriteDirection rrca rrca - add $10 - ld hl, $d + add FACING_FISH_DOWN + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], a ret -Function4554: - ld hl, $d +SetFacingShadow: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $15 + ld [hl], FACING_SHADOW ret -Function455b: - ld hl, $d +SetFacingEmote: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $14 + ld [hl], FACING_EMOTE ret -Function4562: - ld hl, $d +SetFacingBigDollSym: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $17 + ld [hl], FACING_BIG_DOLL_SYM ret -Function4569: - ld hl, $c +SetFacingBounce: + ld hl, OBJECT_STEP_FRAME add hl, bc ld a, [hl] inc a - and $f + and %00001111 ld [hl], a - and $8 - jr z, Function457d - ld hl, $d + and %00001000 + jr z, SetFacingFreezeBounce + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $4 + ld [hl], FACING_STEP_UP_0 ret -Function457d: - ld hl, $d +SetFacingFreezeBounce: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $0 + ld [hl], FACING_STEP_DOWN_0 ret -Function4584: - ld hl, $c +SetFacingWeirdTree: + ld hl, OBJECT_STEP_FRAME add hl, bc ld a, [hl] inc a ld [hl], a - and $c + maskbits NUM_DIRECTIONS, 2 rrca rrca - add $18 - ld hl, $d + add FACING_WEIRD_TREE_0 + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], a ret -Function4597: - ld hl, $d +SetFacingBigDollAsym: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $16 + ld [hl], FACING_BIG_DOLL_ASYM ret -Function459e: - ld a, [wd558] - ld d, $17 - cp $33 - jr z, .asm_45ad - cp $47 - jr z, .asm_45ad - ld d, $16 -.asm_45ad - ld hl, $d +SetFacingBigDoll: + ld a, [wVariableSprites + SPRITE_BIG_DOLL - SPRITE_VARS] + ld d, FACING_BIG_DOLL_SYM ; symmetric + cp SPRITE_BIG_SNORLAX + jr z, .ok + cp SPRITE_BIG_LAPRAS + jr z, .ok + ld d, FACING_BIG_DOLL_ASYM ; asymmetric + +.ok + ld hl, OBJECT_FACING_STEP add hl, bc ld [hl], d ret -Function45b3: - ld hl, $c +SetFacingBoulderDust: + ld hl, OBJECT_STEP_FRAME add hl, bc inc [hl] ld a, [hl] - ld hl, $d + + ld hl, OBJECT_FACING_STEP add hl, bc - and $2 - ld a, $1c - jr z, .asm_45c4 - inc a -.asm_45c4 + and 2 + ld a, FACING_BOULDER_DUST_1 + jr z, .ok + inc a ; FACING_BOULDER_DUST_2 +.ok ld [hl], a ret -Function45c6: - ld hl, $c +SetFacingGrassShake: + ld hl, OBJECT_STEP_FRAME add hl, bc inc [hl] ld a, [hl] - ld hl, $d + ld hl, OBJECT_FACING_STEP add hl, bc - and $4 - ld a, $1e - jr z, .asm_45d7 - inc a -.asm_45d7 + and 4 + ld a, FACING_GRASS_1 + jr z, .ok + inc a ; FACING_GRASS_2 + +.ok ld [hl], a ret diff --git a/engine/overworld/map_objects.asm b/engine/overworld/map_objects.asm index 887fb753..62b1df41 100755 --- a/engine/overworld/map_objects.asm +++ b/engine/overworld/map_objects.asm @@ -1,27 +1,28 @@ -INCLUDE "engine/facings.asm" -SpriteMovementData:: INCLUDE "data/map_objects.asm" +INCLUDE "data/sprites/facings.asm" -DeleteMapObject:: ; 4358 (1:4358) +INCLUDE "data/sprites/map_objects.asm" + +DeleteMapObject:: push bc - ld hl, $1 + ld hl, OBJECT_MAP_OBJECT_INDEX add hl, bc ld a, [hl] push af ld h, b ld l, c - ld bc, $28 + ld bc, OBJECT_LENGTH xor a call ByteFill pop af - cp $ff - jr z, .asm_437a + cp -1 + jr z, .ok bit 7, a - jr nz, .asm_437a + jr nz, .ok call GetMapObject - ld hl, $0 + ld hl, OBJECT_SPRITE add hl, bc - ld [hl], $ff -.asm_437a + ld [hl], -1 +.ok pop bc ret @@ -32,306 +33,322 @@ Function437c: call .HandleObjectAction ret -.CheckObjectStillVisible: ; 4387 (1:4387) - ld hl, $5 +.CheckObjectStillVisible: + ld hl, OBJECT_FLAGS2 add hl, bc - res 6, [hl] + res OBJ_FLAGS2_6, [hl] ld a, [wXCoord] ld e, a - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] - add $1 + add 1 sub e - jr c, .asm_43b3 - cp $c - jr nc, .asm_43b3 + jr c, .ok + cp MAPOBJECT_SCREEN_WIDTH + jr nc, .ok ld a, [wYCoord] ld e, a - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, [hl] - add $1 + add 1 sub e - jr c, .asm_43b3 - cp $b - jr nc, .asm_43b3 - jr .asm_43dd + jr c, .ok + cp MAPOBJECT_SCREEN_HEIGHT + jr nc, .ok + jr .yes -.asm_43b3 - ld hl, $5 +.ok + ld hl, OBJECT_FLAGS2 add hl, bc - set 6, [hl] + set OBJ_FLAGS2_6, [hl] ld a, [wXCoord] ld e, a - ld hl, $14 + ld hl, OBJECT_INIT_X add hl, bc ld a, [hl] - add $1 + add 1 sub e - jr c, .asm_43df - cp $c - jr nc, .asm_43df + jr c, .ok2 + cp MAPOBJECT_SCREEN_WIDTH + jr nc, .ok2 ld a, [wYCoord] ld e, a - ld hl, $15 + ld hl, OBJECT_INIT_Y add hl, bc ld a, [hl] - add $1 + add 1 sub e - jr c, .asm_43df - cp $b - jr nc, .asm_43df -.asm_43dd + jr c, .ok2 + cp MAPOBJECT_SCREEN_HEIGHT + jr nc, .ok2 +.yes and a ret -.asm_43df - ld hl, $4 +.ok2 + ld hl, OBJECT_FLAGS1 add hl, bc - bit 1, [hl] - jr nz, .asm_43ec + bit WONT_DELETE_F, [hl] + jr nz, .yes2 call DeleteMapObject scf ret -.asm_43ec - ld hl, $5 +.yes2 + ld hl, OBJECT_FLAGS2 add hl, bc - set 6, [hl] + set OBJ_FLAGS2_6, [hl] and a ret -.HandleStepType: ; 43f4 (1:43f4) - ld hl, $9 +.HandleStepType: + ld hl, OBJECT_STEP_TYPE add hl, bc ld a, [hl] and a - jr z, .asm_440a - ld hl, $5 + jr z, .zero + ld hl, OBJECT_FLAGS2 add hl, bc - bit 5, [hl] - jr nz, .asm_4427 - cp $1 - jr z, .asm_4415 - jr .asm_4422 + bit OBJ_FLAGS2_5, [hl] + jr nz, .bit5 + cp STEP_TYPE_SLEEP + jr z, .one + jr .ok3 -.asm_440a +.zero call ObjectMovementReset - ld hl, $5 + ld hl, OBJECT_FLAGS2 add hl, bc - bit 5, [hl] - jr nz, .asm_4427 -.asm_4415 + bit OBJ_FLAGS2_5, [hl] + jr nz, .bit5 +.one call MapObjectMovementPattern - ld hl, $9 + ld hl, OBJECT_STEP_TYPE add hl, bc ld a, [hl] and a ret z - cp $1 + cp STEP_TYPE_SLEEP ret z -.asm_4422 +.ok3 ld hl, StepTypesJumptable rst JumpTable ret -.asm_4427 +.bit5 ret -.HandleObjectAction: ; 4428 (1:4428) - ld hl, $4 +.HandleObjectAction: + ld hl, OBJECT_FLAGS1 add hl, bc - bit 0, [hl] - jr nz, Function44a0 - ld hl, $5 + bit INVISIBLE_F, [hl] + jr nz, SetFacingStanding + ld hl, OBJECT_FLAGS2 add hl, bc - bit 6, [hl] - jr nz, Function44a0 - bit 5, [hl] + bit OBJ_FLAGS2_6, [hl] + jr nz, SetFacingStanding + bit OBJ_FLAGS2_5, [hl] jr nz, asm_4449 - ld de, Pointers4460 - jr asm_444e + ld de, ObjectActionPairPointers ; use first column + jr _HandleObjectAction Function4441: - ld hl, $4 + ld hl, OBJECT_FLAGS1 add hl, bc - bit 0, [hl] - jr nz, Function44a0 -asm_4449 - ld de, Pointers4460 + 2 - jr asm_444e + bit INVISIBLE_F, [hl] + jr nz, SetFacingStanding +asm_4449: + ld de, ObjectActionPairPointers + 2 ; use second column + jr _HandleObjectAction + +_HandleObjectAction: +; call [4 * wObjectStructs[ObjInd, OBJECT_ACTION] + de] + ld hl, OBJECT_ACTION + add hl, bc + ld a, [hl] + ld l, a + ld h, 0 + add hl, hl + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call _hl_ + ret -asm_444e INCLUDE "engine/overworld/map_object_action.asm" -CopyNextCoordsTileToStandingCoordsTile: ; 45d9 (1:45d9) - ld hl, $10 +CopyNextCoordsTileToStandingCoordsTile: + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] - ld hl, $12 + ld hl, OBJECT_MAP_X add hl, bc ld [hl], a - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, [hl] - ld hl, $13 + ld hl, OBJECT_MAP_Y add hl, bc ld [hl], a - ld hl, $e + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] - ld hl, $f + ld hl, OBJECT_STANDING_TILE add hl, bc ld [hl], a - call SetGrassPriority - ld hl, $e + call SetTallGrassFlags + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] call UselessAndA ret Function4603: - ld hl, $12 + ld hl, OBJECT_MAP_X add hl, bc ld a, [hl] - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld [hl], a - ld hl, $13 + ld hl, OBJECT_MAP_Y add hl, bc ld a, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld [hl], a ret -UpdateGrassPriority: - ld hl, $5 +UpdateTallGrassFlags: + ld hl, OBJECT_FLAGS2 add hl, bc - bit 3, [hl] - jr z, .asm_4628 - ld hl, $e + bit OVERHEAD_F, [hl] + jr z, .ok + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] - call SetGrassPriority -.asm_4628 - ld hl, $e + call SetTallGrassFlags +.ok + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] call UselessAndA - ret c - ld hl, $f + ret c ; never happens + ld hl, OBJECT_STANDING_TILE add hl, bc ld a, [hl] call UselessAndA ret -SetGrassPriority: ; 463a (1:463a) +SetTallGrassFlags: call CheckSuperTallGrassTile - jr z, .asm_4644 + jr z, .set call CheckGrassTile - jr c, .asm_464b -.asm_4644 - ld hl, $5 + jr c, .reset +.set + ld hl, OBJECT_FLAGS2 add hl, bc - set 3, [hl] + set OVERHEAD_F, [hl] ret -.asm_464b - ld hl, $5 +.reset + ld hl, OBJECT_FLAGS2 add hl, bc - res 3, [hl] + res OVERHEAD_F, [hl] ret -UselessAndA: ; 4652 (1:4652) +UselessAndA: and a ret EndSpriteMovement: xor a - ld hl, $c + ld hl, OBJECT_STEP_FRAME add hl, bc ld [hl], a - ld hl, $1b + ld hl, OBJECT_MOVEMENT_BYTE_INDEX add hl, bc ld [hli], a ld [hli], a ld [hli], a - ld [hl], a - ld hl, $7 + ld [hl], a ; OBJECT_1E + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff + ld [hl], STANDING ret InitStep: - ld hl, $7 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld [hl], a - ld hl, $4 + ld hl, OBJECT_FLAGS1 add hl, bc - bit 2, [hl] + bit FIXED_FACING_F, [hl] jr nz, GetNextTile add a add a - and $c - ld hl, $8 + and %00001100 + ld hl, OBJECT_FACING add hl, bc ld [hl], a GetNextTile: call GetStepVector - ld hl, $a + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a ld a, d call GetStepVectorSign - ld hl, $12 + ld hl, OBJECT_MAP_X add hl, bc add [hl] - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld [hl], a ld d, a ld a, e call GetStepVectorSign - ld hl, $13 + ld hl, OBJECT_MAP_Y add hl, bc add [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld [hl], a ld e, a push bc call GetCoordTile pop bc - ld hl, $e + ld hl, OBJECT_NEXT_TILE add hl, bc ld [hl], a ret -AddStepVector: ; 46b0 (1:46b0) +AddStepVector: call GetStepVector - ld hl, $17 + ld hl, OBJECT_SPRITE_X add hl, bc ld a, [hl] add d ld [hl], a - ld hl, $18 + ld hl, OBJECT_SPRITE_Y add hl, bc ld a, [hl] add e ld [hl], a ret -GetStepVector: ; 46c2 (1:46c2) - ld hl, $7 +GetStepVector: +; Return (x, y, duration, speed) in (d, e, a, h). + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] - and $f + and %00001111 add a add a ld l, a - ld h, $0 + ld h, 0 ld de, StepVectors add hl, de ld d, [hl] @@ -342,7 +359,7 @@ GetStepVector: ; 46c2 (1:46c2) ld h, [hl] ret -StepVectors: ; 46d9 +StepVectors: ; x, y, duration, speed ; slow db 0, 1, 16, 1 @@ -360,19 +377,19 @@ StepVectors: ; 46d9 db -4, 0, 4, 4 db 4, 0, 4, 4 -GetStepVectorSign: ; 4709 (1:4709) +GetStepVectorSign: add a - ret z - ld a, $1 - ret nc - ld a, $ff - ret + ret z ; 0 or 128 + ld a, 1 + ret nc ; 1 - 127 + ld a, -1 + ret ; 129 - 255 UpdatePlayerStep: - ld hl, $7 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] - and $3 + and %00000011 ld [wPlayerStepDirection], a call AddStepVector ld a, [wPlayerStepVectorX] @@ -382,14 +399,14 @@ UpdatePlayerStep: add e ld [wPlayerStepVectorY], a ld hl, wPlayerStepFlags - set 5, [hl] + set PLAYERSTEP_CONTINUE_F, [hl] ret -Function4732: +Unreferenced_Function4732: push bc ld e, a - ld d, $0 - ld hl, $1 + ld d, 0 + ld hl, OBJECT_MAP_OBJECT_INDEX add hl, bc ld a, [hl] call GetMapObject @@ -398,40 +415,1480 @@ Function4732: pop bc ret -INCLUDE "engine/movement_pattern.asm" -INCLUDE "engine/step_types.asm" -INCLUDE "engine/overworld/movement.asm" +RestoreDefaultMovement: + ld hl, OBJECT_MAP_OBJECT_INDEX + add hl, bc + ld a, [hl] + cp -1 + jr z, .ok + push bc + call GetMapObject + ld hl, MAPOBJECT_MOVEMENT + add hl, bc + ld a, [hl] + pop bc + ret + +.ok + ld a, SPRITEMOVEDATA_STANDING_DOWN + ret -Function5429: ; 5429 (1:5429) +ClearObjectMovementByteIndex: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + ld [hl], 0 + ret + +IncrementObjectMovementByteIndex: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + inc [hl] + ret + +DecrementObjectMovementByteIndex: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + dec [hl] + ret + +MovementAnonymousJumptable: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + ld a, [hl] + pop hl + rst JumpTable + ret + +ClearObjectStructField1c: + ld hl, OBJECT_1C + add hl, bc + ld [hl], 0 + ret + +IncrementObjectStructField1c: + ld hl, OBJECT_1C + add hl, bc + inc [hl] + ret + +Field1cAnonymousJumptable: + ld hl, OBJECT_1C + add hl, bc + ld a, [hl] + pop hl + rst JumpTable + ret + +GetValueObjectStructField1c: + ld hl, OBJECT_1C + add hl, bc + ld a, [hl] + ret + +SetValueObjectStructField1c: + ld hl, OBJECT_1C + add hl, bc + ld [hl], a + ret + +ObjectMovementReset: + ld hl, OBJECT_NEXT_MAP_X + add hl, bc + ld d, [hl] + ld hl, OBJECT_NEXT_MAP_Y + add hl, bc + ld e, [hl] + push bc + call GetCoordTile + pop bc + ld hl, OBJECT_NEXT_TILE + add hl, bc + ld [hl], a + call CopyNextCoordsTileToStandingCoordsTile + call EndSpriteMovement + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +MapObjectMovementPattern: + call ClearObjectStructField1c + call GetSpriteMovementFunction + ld a, [hl] + ld hl, .Pointers + rst JumpTable + ret + +.Pointers: +; entries correspond to SPRITEMOVEFN_* constants + dw .Null_00 ; 00 + dw .RandomWalkY ; 01 + dw .RandomWalkX ; 02 + dw .RandomWalkXY ; 03 + dw .RandomSpin1 ; 04 + dw .RandomSpin2 ; 05 + dw .Standing ; 06 + dw .ObeyDPad ; 07 + dw .Movement08 ; 08 + dw .Movement09 ; 09 + dw .Movement0a ; 0a + dw .Movement0b ; 0b + dw .Movement0c ; 0c + dw .Movement0d ; 0d + dw .Movement0e ; 0e + dw .Follow ; 0f + dw .Script ; 10 + dw .Strength ; 11 + dw .FollowNotExact ; 12 + dw .MovementShadow ; 13 + dw .MovementEmote ; 14 + dw .MovementBigStanding ; 15 + dw .MovementBouncing ; 16 + dw .MovementScreenShake ; 17 + dw .MovementSpinClockwise ; 18 + dw .MovementSpinCounterclockwise ; 19 + dw .MovementBoulderDust ; 1a + dw .MovementShakingGrass ; 1b + +.Null_00: + ret + +.RandomWalkY: + call Random + ldh a, [hRandomAdd] + and %00000001 + jp .RandomWalkContinue + +.RandomWalkX: + call Random + ldh a, [hRandomAdd] + and %00000001 + or %00000010 + jp .RandomWalkContinue + +.RandomWalkXY: + call Random + ldh a, [hRandomAdd] + and %00000011 + jp .RandomWalkContinue + +.RandomSpin1: + call Random + ldh a, [hRandomAdd] + and %00001100 + ld hl, OBJECT_FACING + add hl, bc + ld [hl], a + jp RandomStepDuration_Slow + +.RandomSpin2: + ld hl, OBJECT_FACING + add hl, bc + ld a, [hl] + and %00001100 + ld d, a + call Random + ldh a, [hRandomAdd] + and %00001100 + cp d + jr nz, .keep + xor %00001100 +.keep + ld [hl], a + jp RandomStepDuration_Fast + +.Standing: + call Function4603 + call EndSpriteMovement + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STAND + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_05 + ret + +.ObeyDPad: + ld hl, Function4fa8 + jp HandleMovementData + +.Movement08: + ld hl, Function4fbd + jp HandleMovementData + +.Movement09: + ld hl, Function4fce + jp HandleMovementData + +.Movement0a: + jp _GetMovementObject + +.Movement0b: + jp _GetMovementObject + +.Movement0c: + jp _GetMovementObject + +.Movement0d: + ld hl, Function4fa8 + jp HandleMovementData + +.Movement0e: + jp _GetMovementObject + +.Follow: + ld hl, GetFollowerNextMovementByte + jp HandleMovementData + +.Script: + ld hl, GetMovementByte + jp HandleMovementData + +.Strength: + call MovementAnonymousJumptable + dw .Strength_Start + dw .Strength_Stop + +.Strength_Start: + ld hl, OBJECT_NEXT_TILE + add hl, bc + ld a, [hl] + call CheckPitTile + jr z, .on_pit + ld hl, OBJECT_FLAGS2 + add hl, bc + bit OBJ_FLAGS2_2, [hl] + res OBJ_FLAGS2_2, [hl] + jr z, .ok + ld hl, OBJECT_RANGE + add hl, bc + ld a, [hl] + and %00000011 + or 0 call InitStep - ld hl, $1f + call CanObjectMoveInDirection + jr c, .ok2 + ld de, SFX_STRENGTH + call PlaySFX + call SpawnStrengthBoulderDust + call UpdateTallGrassFlags + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_0F + ret + +.ok2 + call Function4603 +.ok + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ret + +.on_pit + call IncrementObjectMovementByteIndex +.Strength_Stop: + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ret + +.FollowNotExact: + ld hl, OBJECT_NEXT_MAP_X + add hl, bc + ld d, [hl] + ld hl, OBJECT_NEXT_MAP_Y add hl, bc - ld [hl], $0 - ld hl, $5 + ld e, [hl] + ld hl, OBJECT_RANGE + add hl, bc + ld a, [hl] + push bc + call GetObjectStruct + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - res 3, [hl] - ld hl, $b + ld a, [hl] + cp STANDING + jr z, .standing + ld hl, OBJECT_MAP_X + add hl, bc + ld a, [hl] + cp d + jr z, .equal + jr c, .less + ld a, 3 + jr .done + +.less + ld a, 2 + jr .done + +.equal + ld hl, OBJECT_MAP_Y + add hl, bc + ld a, [hl] + cp e + jr z, .standing + jr c, .less2 + ld a, 0 + jr .done + +.less2 + ld a, 1 +.done + ld d, a + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld a, [hl] + and %00001100 + or d + pop bc + jp NormalStep + +.standing + pop bc + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $2 - call Function54c8 + ld [hl], STANDING + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STAND + ret + +.MovementBigStanding: + call EndSpriteMovement + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_BIG_DOLL_SYM + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_04 + ret + +.MovementBouncing: + call EndSpriteMovement + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_BOUNCE + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_04 + ret + +.MovementSpinCounterclockwise: + call MovementAnonymousJumptable + dw .MovementSpinInit + dw .MovementSpinRepeat + dw .MovementSpinTurnLeft + +.MovementSpinClockwise: + call MovementAnonymousJumptable + dw .MovementSpinInit + dw .MovementSpinRepeat + dw .MovementSpinTurnRight + +.MovementSpinInit: + call EndSpriteMovement + call IncrementObjectMovementByteIndex +.MovementSpinRepeat: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STAND + ld hl, OBJECT_RANGE + add hl, bc + ld a, [hl] + ld a, $10 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_03 + call IncrementObjectMovementByteIndex + ret + +.MovementSpinTurnLeft: + ld de, .DirectionData_Counterclockwise + call .MovementSpinNextFacing + jr .MovementSpinCounterclockwise + +.DirectionData_Counterclockwise: + db OW_RIGHT, OW_LEFT, OW_DOWN, OW_UP + +.MovementSpinTurnRight: + ld de, .DirectionData_Clockwise + call .MovementSpinNextFacing + jr .MovementSpinClockwise + +.DirectionData_Clockwise: + db OW_LEFT, OW_RIGHT, OW_UP, OW_DOWN + +.MovementSpinNextFacing: + ld hl, OBJECT_FACING + add hl, bc + ld a, [hl] + and %00001100 + rrca + rrca + push hl + ld l, a + ld h, 0 + add hl, de + ld a, [hl] + pop hl + ld [hl], a + call DecrementObjectMovementByteIndex + ret + +.MovementShadow: + call ._MovementShadow_Grass_Emote_BoulderDust + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_SHADOW + ld hl, OBJECT_STEP_DURATION + add hl, de + ld a, [hl] + inc a + add a + add 0 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], a + ld hl, OBJECT_DIRECTION_WALKING + add hl, de + ld a, [hl] + maskbits NUM_DIRECTIONS + ld d, 1 * 8 + 6 + cp DOWN + jr z, .ok_13 + cp UP + jr z, .ok_13 + ld d, 1 * 8 + 4 +.ok_13 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], d + ld hl, OBJECT_SPRITE_X_OFFSET + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_TRACKING_OBJECT + ret + +.MovementEmote: + call EndSpriteMovement + call ._MovementShadow_Grass_Emote_BoulderDust + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_EMOTE + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 0 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], -2 * 8 + ld hl, OBJECT_SPRITE_X_OFFSET + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_TRACKING_OBJECT + ret + +.MovementBoulderDust: + call EndSpriteMovement + call ._MovementShadow_Grass_Emote_BoulderDust + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_BOULDER_DUST + ld hl, OBJECT_STEP_DURATION + add hl, de + ld a, [hl] + inc a + add a + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], a + ld hl, OBJECT_DIRECTION_WALKING + add hl, de + ld a, [hl] + and %00000011 + ld e, a + ld d, 0 + ld hl, .data_4a81 + add hl, de + add hl, de + ld d, [hl] + inc hl + ld e, [hl] + ld hl, OBJECT_SPRITE_X_OFFSET + add hl, bc + ld [hl], d + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], e + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_TRACKING_OBJECT + ret + +.data_4a81 + ; x, y + db 0, -4 + db 0, 8 + db 6, 2 + db -6, 2 + +.MovementShakingGrass: + call EndSpriteMovement + call ._MovementShadow_Grass_Emote_BoulderDust + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_GRASS_SHAKE + ld hl, OBJECT_STEP_DURATION + add hl, de + ld a, [hl] + add -1 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_TRACKING_OBJECT + ret + +._MovementShadow_Grass_Emote_BoulderDust: + ld hl, OBJECT_RANGE + add hl, bc + ld a, [hl] + push bc + call GetObjectStruct + ld d, b + ld e, c + pop bc + ld hl, OBJECT_1D + add hl, bc + ld [hl], e + inc hl + ld [hl], d + ret + +.MovementScreenShake: + call EndSpriteMovement + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_00 + ld hl, OBJECT_RANGE + add hl, bc + ld a, [hl] + call ._MovementScreenShake + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], e + ld hl, OBJECT_1E + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_15 + ret + +._MovementScreenShake: + ld d, a + and %00111111 + ld e, a + ld a, d + rlca + rlca + and %00000011 + ld d, a + inc d + ld a, 1 +.loop + dec d + ret z + add a + jr .loop + +.RandomWalkContinue: + call InitStep + call CanObjectMoveInDirection ; check whether the object can move in that direction + jr c, .NewDuration + call UpdateTallGrassFlags + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STEP ld hl, wCenteredObject ldh a, [hMapObjectIndexBuffer] cp [hl] - jr z, .asm_5450 - ld hl, $9 + jr z, .load_6 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_07 + ret + +.load_6 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_PLAYER_WALK + ret + +.NewDuration: + call EndSpriteMovement + call Function4603 +RandomStepDuration_Slow: + call Random + ldh a, [hRandomAdd] + and %01111111 + jr SetRandomStepDuration + +RandomStepDuration_Fast: + call Random + ldh a, [hRandomAdd] + and %00011111 +SetRandomStepDuration: + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], a + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STAND + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_03 + ret + +StepTypesJumptable: +; entries correspond to STEP_TYPE_* constants + dw ObjectMovementReset ; 00 + dw MapObjectMovementPattern ; 01 + dw NPCStep ; 02 + dw StepType03 ; 03 + dw StepType04 ; 04 + dw StepType05 ; 05 + dw PlayerStep ; 06 + dw StepType07 ; 07 + dw NPCJump ; 08 + dw PlayerJump ; 09 + dw PlayerOrNPCTurnStep ; 0a + dw StepTypeBump ; 0b + dw TeleportFrom ; 0c + dw TeleportTo ; 0d + dw Skyfall ; 0e + dw StepType0f ; 0f + dw GotBiteStep ; 10 + dw RockSmashStep ; 11 + dw ReturnDigStep ; 12 + dw StepTypeTrackingObject ; 13 + dw StepType14 ; 14 + dw StepType15 ; 15 + dw StepType16 ; 16 + dw StepType17 ; 17 + dw StepType18 ; 18 + +WaitStep_InPlace: + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +NPCJump: + call Field1cAnonymousJumptable +; anonymous dw + dw .Jump + dw .Land + +.Jump: + call AddStepVector + call UpdateJumpPosition + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call CopyNextCoordsTileToStandingCoordsTile + call GetNextTile + ld hl, OBJECT_FLAGS2 add hl, bc - ld [hl], $8 + res OVERHEAD_F, [hl] + call IncrementObjectStructField1c ret -.asm_5450 - ld hl, $9 +.Land: + call AddStepVector + call UpdateJumpPosition + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call CopyNextCoordsTileToStandingCoordsTile + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $9 + ld [hl], STEP_TYPE_SLEEP ret -Function5457: ; 5457 (1:5457) + +PlayerJump: + call Field1cAnonymousJumptable +; anonymous dw + dw .initjump + dw .stepjump + dw .initland + dw .stepland + +.initjump + ld hl, wPlayerStepFlags + set PLAYERSTEP_START_F, [hl] + call IncrementObjectStructField1c +.stepjump + call UpdateJumpPosition + call UpdatePlayerStep + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call CopyNextCoordsTileToStandingCoordsTile + ld hl, OBJECT_FLAGS2 + add hl, bc + res OVERHEAD_F, [hl] + ld hl, wPlayerStepFlags + set PLAYERSTEP_STOP_F, [hl] + set PLAYERSTEP_MIDAIR_F, [hl] + call IncrementObjectStructField1c + ret + +.initland + call GetNextTile + ld hl, wPlayerStepFlags + set PLAYERSTEP_START_F, [hl] + call IncrementObjectStructField1c +.stepland + call UpdateJumpPosition + call UpdatePlayerStep + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, wPlayerStepFlags + set PLAYERSTEP_STOP_F, [hl] + call CopyNextCoordsTileToStandingCoordsTile + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +TeleportFrom: + call Field1cAnonymousJumptable +; anonymous dw + dw .InitSpin + dw .DoSpin + dw .InitSpinRise + dw .DoSpinRise + +.InitSpin: + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + call IncrementObjectStructField1c +.DoSpin: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_SPIN + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call IncrementObjectStructField1c + ret + +.InitSpinRise: + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_1F + add hl, bc + ld [hl], $10 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + ld hl, OBJECT_FLAGS2 + add hl, bc + res OVERHEAD_F, [hl] + call IncrementObjectStructField1c +.DoSpinRise: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_SPIN + ld hl, OBJECT_1F + add hl, bc + inc [hl] + ld a, [hl] + ld d, $60 + call Sine + ld a, h + sub $60 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +TeleportTo: + call Field1cAnonymousJumptable +; anonymous dw + dw .InitWait + dw .DoWait + dw .InitDescent + dw .DoDescent + dw .InitFinalSpin + dw .DoFinalSpin + dw .FinishStep + +.InitWait: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_00 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + call IncrementObjectStructField1c + ret + +.DoWait: + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call IncrementObjectStructField1c +.InitDescent: + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_1F + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + call IncrementObjectStructField1c + ret + +.DoDescent: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_SPIN + ld hl, OBJECT_1F + add hl, bc + inc [hl] + ld a, [hl] + ld d, $60 + call Sine + ld a, h + sub $60 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call IncrementObjectStructField1c +.InitFinalSpin: + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + call IncrementObjectStructField1c + ret + +.DoFinalSpin: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_SPIN + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz +.FinishStep: + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +Skyfall: + call Field1cAnonymousJumptable +; anonymous dw + dw .Init + dw .Step + dw .Fall + dw .Finish + +.Init: + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_00 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + call IncrementObjectStructField1c +.Step: + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STEP + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_1F + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 16 + call IncrementObjectStructField1c +.Fall: + ld hl, OBJECT_1F + add hl, bc + inc [hl] + ld a, [hl] + ld d, $60 + call Sine + ld a, h + sub $60 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call IncrementObjectStructField1c +.Finish: + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld [hl], 0 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +GotBiteStep: + call Field1cAnonymousJumptable +; anonymous dw + dw .Init + dw .Run + +.Init: + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 8 + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], 0 + call IncrementObjectStructField1c +.Run: + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld a, [hl] + xor 1 + ld [hl], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], 0 + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +RockSmashStep: + call .Step + jp WaitStep_InPlace + +.Step: + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld a, [hl] + and %00000001 + ld a, OBJECT_ACTION_STAND + jr z, .yes + ld a, OBJECT_ACTION_00 +.yes + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], a + ret + +ReturnDigStep: + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld a, [hl] + and %00000001 + ld a, OBJECT_ACTION_SPIN + jr z, .yes + ld a, OBJECT_ACTION_SPIN_FLICKER +.yes + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], a + jp WaitStep_InPlace + +StepType03: + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +StepType18: + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + jp DeleteMapObject + +StepTypeBump: + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +StepType05: + call Field1cAnonymousJumptable +; anonymous dw + dw .Reset + dw StepType04 + +.Reset: + call RestoreDefaultMovement + call GetInitialFacing + ld hl, OBJECT_FACING + add hl, bc + ld [hl], a + call IncrementObjectStructField1c +StepType04: + call Stubbed_Function4f5a + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ret + +NPCStep: + call Stubbed_Function4f5a + call AddStepVector + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call CopyNextCoordsTileToStandingCoordsTile + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +StepType07: + call AddStepVector + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call CopyNextCoordsTileToStandingCoordsTile + jp RandomStepDuration_Slow + +PlayerStep: +; AnimateStep? + call Field1cAnonymousJumptable +; anonymous dw + dw .init + dw .step + +.init + ld hl, wPlayerStepFlags + set PLAYERSTEP_START_F, [hl] + call IncrementObjectStructField1c +.step + call UpdatePlayerStep + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, wPlayerStepFlags + set PLAYERSTEP_STOP_F, [hl] + call CopyNextCoordsTileToStandingCoordsTile + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +PlayerOrNPCTurnStep: + call Field1cAnonymousJumptable +; anonymous dw + dw .init1 + dw .step1 + dw .init2 + dw .step2 + +.init1 + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_STEP_FRAME + add hl, bc + ld a, [hl] + ld [hl], 2 + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 2 + call IncrementObjectStructField1c +.step1 + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + call IncrementObjectStructField1c +.init2 + ld hl, OBJECT_1D ; new facing + add hl, bc + ld a, [hl] + ld hl, OBJECT_FACING + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld [hl], 2 + call IncrementObjectStructField1c +.step2 + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +StepType0f: + call AddStepVector + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + ret nz + push bc + ld hl, OBJECT_NEXT_MAP_X + add hl, bc + ld d, [hl] + ld hl, OBJECT_NEXT_MAP_Y + add hl, bc + ld e, [hl] + ld hl, OBJECT_MAP_OBJECT_INDEX + add hl, bc + ld a, [hl] + ld b, a + farcall CopyDECoordsToMapObject + pop bc + ld hl, OBJECT_FLAGS2 + add hl, bc + res OBJ_FLAGS2_2, [hl] + call CopyNextCoordsTileToStandingCoordsTile + ld hl, OBJECT_DIRECTION_WALKING + add hl, bc + ld [hl], STANDING + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_SLEEP + ret + +StepTypeTrackingObject: + ld hl, OBJECT_1D + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + ld hl, OBJECT_SPRITE + add hl, de + ld a, [hl] + and a + jr z, .nope + ld hl, OBJECT_SPRITE_X + add hl, de + ld a, [hl] + ld hl, OBJECT_SPRITE_X + add hl, bc + ld [hl], a + ld hl, OBJECT_SPRITE_Y + add hl, de + ld a, [hl] + ld hl, OBJECT_SPRITE_Y + add hl, bc + ld [hl], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + ld a, [hl] + and a + ret z + dec [hl] + ret nz +.nope + jp DeleteMapObject + +StepType14: +StepType15: + call Field1cAnonymousJumptable +; anonymous dw + dw .Init + dw .Run + +.Init: + xor a + ld hl, OBJECT_1D + add hl, bc + ld [hl], a + call IncrementObjectStructField1c +.Run: + ld hl, OBJECT_1D + add hl, bc + ld d, [hl] + ld a, [wPlayerStepVectorY] + sub d + ld [wPlayerStepVectorY], a + ld hl, OBJECT_STEP_DURATION + add hl, bc + dec [hl] + jr z, .ok + ld a, [hl] + call .GetSign + ld hl, OBJECT_1D + add hl, bc + ld [hl], a + ld d, a + ld a, [wPlayerStepVectorY] + add d + ld [wPlayerStepVectorY], a + ret + +.ok + call DeleteMapObject + ret + +.GetSign: + ld hl, OBJECT_1E + add hl, bc + and 1 + ld a, [hl] + ret z + cpl + inc a + ret + +StepType16: + call Field1cAnonymousJumptable ; ???? +StepType17: + call Field1cAnonymousJumptable +; anonymous dw + dw .null + dw .null + dw .null +.null + +Stubbed_Function4f5a: + ret + ld hl, OBJECT_1D + add hl, bc + inc [hl] + ld a, [hl] + srl a + srl a + and %00000111 + ld l, a + ld h, 0 + ld de, .y + add hl, de + ld a, [hl] + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], a + ret + +.y + db 0, -1, -2, -3, -4, -3, -2, -1 +UpdateJumpPosition: + call GetStepVector + ld a, h + ld hl, OBJECT_1F + add hl, bc + ld e, [hl] + add e + ld [hl], a + nop + srl e + ld d, 0 + ld hl, .y + add hl, de + ld a, [hl] + ld hl, OBJECT_SPRITE_Y_OFFSET + add hl, bc + ld [hl], a + ret + +.y + db -4, -6, -8, -10, -11, -12, -12, -12 + db -11, -10, -9, -8, -6, -4, 0, 0 + +Function4fa8: ; unscripted? +; copy [wPlayerNextMovement] to [wPlayerMovement] + ld a, [wPlayerNextMovement] + ld hl, wPlayerMovement + ld [hl], a +; load [wPlayerNextMovement] with movement_step_sleep + ld a, movement_step_sleep + ld [wPlayerNextMovement], a +; recover the previous value of [wPlayerNextMovement] + ld a, [hl] + ret + +GetMovementByte: + ld hl, wMovementDataBank + call _GetMovementByte + ret + +Function4fbd: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + ld e, [hl] + inc [hl] + ld d, 0 + ld hl, wMovementObject + ld a, [hli] + ld h, [hl] + ld l, a + add hl, de + ld a, [hl] + ret + +Function4fce: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + ld e, [hl] + inc [hl] + ld d, 0 + ld hl, wce8f + ld a, [hli] + ld h, [hl] + ld l, a + add hl, de + ld a, [hl] + ret + +_GetMovementObject: + ld hl, GetMovementObject + jp HandleMovementData + +GetMovementObject: + ld a, [wMovementObject] + ret + +HandleMovementData: + call .StorePointer +.loop + xor a + ld [wMovementByteWasControlSwitch], a + call JumpMovementPointer + call DoMovementFunction + ld a, [wMovementByteWasControlSwitch] + and a + jr nz, .loop + ret + +.StorePointer: + ld a, l + ld [wMovementPointer], a + ld a, h + ld [wMovementPointer + 1], a + ret + +JumpMovementPointer: + ld hl, wMovementPointer + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +ContinueReadingMovement: + ld a, 1 + ld [wMovementByteWasControlSwitch], a + ret + +DoMovementFunction: + push af + call ApplyMovementToFollower + pop af + ld hl, MovementPointers + rst JumpTable + ret + +INCLUDE "engine/overworld/movement.asm" + +ApplyMovementToFollower: ld e, a ld a, [wObjectFollow_Follower] - cp $ff + cp -1 ret z ld a, [wObjectFollow_Leader] ld d, a @@ -439,21 +1896,21 @@ Function5457: ; 5457 (1:5457) cp d ret nz ld a, e - cp $3e + cp movement_step_sleep ret z - cp $47 + cp movement_step_end ret z - cp $4b + cp movement_step_4b ret z - cp $50 + cp movement_step_bump ret z - cp $8 + cp movement_slow_step ret c push af ld hl, wFollowerMovementQueueLength inc [hl] ld e, [hl] - ld d, $0 + ld d, 0 ld hl, wFollowMovementQueue add hl, de pop af @@ -464,143 +1921,149 @@ GetFollowerNextMovementByte: ld hl, wFollowerMovementQueueLength ld a, [hl] and a - jr z, .asm_54a2 - cp $ff - jr z, .asm_54a2 + jr z, .done + cp -1 + jr z, .done dec [hl] ld e, a - ld d, $0 + ld d, 0 ld hl, wFollowMovementQueue add hl, de inc e - ld a, $ff -.asm_549b + ld a, -1 +.loop ld d, [hl] ld [hld], a ld a, d dec e - jr nz, .asm_549b + jr nz, .loop ret -.asm_54a2 - call Function54a9 +.done + call .CancelFollowIfLeaderMissing ret c - ld a, $3e + ld a, movement_step_sleep ret -Function54a9: ; 54a9 (1:54a9) +.CancelFollowIfLeaderMissing: ld a, [wObjectFollow_Leader] - cp $ff - jr z, .asm_54bf + cp -1 + jr z, .nope push bc call GetObjectStruct - ld hl, $0 + ld hl, OBJECT_SPRITE add hl, bc ld a, [hl] pop bc and a - jr z, .asm_54bf + jr z, .nope and a ret -.asm_54bf - ld a, $ff +.nope + ld a, -1 ld [wObjectFollow_Follower], a - ld a, $47 + ld a, movement_step_end scf ret -Function54c8: ; 54c8 (1:54c8) +SpawnShadow: push bc - ld de, .data - call Function5558 - call Function554b + ld de, .ShadowObject + call CopyTempObjectData + call InitTempObject pop bc ret -.data db $fc, PAL_OW_SILVER, SPRITEMOVEDATA_SHADOW +.ShadowObject: + ; vtile, palette, movement + db $fc, PAL_OW_SILVER, SPRITEMOVEDATA_SHADOW -Function54d7: ; 54d7 (1:54d7) +SpawnStrengthBoulderDust: push bc - ld de, .data - call Function5558 - call Function554b + ld de, .BoulderDustObject + call CopyTempObjectData + call InitTempObject pop bc ret -.data db $fe, PAL_OW_SILVER, SPRITEMOVEDATA_BOULDERDUST +.BoulderDustObject: + db $fe, PAL_OW_SILVER, SPRITEMOVEDATA_BOULDERDUST -Function54e6: ; 54e6 (1:54e6) +SpawnEmote: push bc - ld de, .data - call Function5558 - call Function554b + ld de, .EmoteObject + call CopyTempObjectData + call InitTempObject pop bc ret -.data db $f8, PAL_OW_SILVER, SPRITEMOVEDATA_EMOTE +.EmoteObject: + db $f8, PAL_OW_SILVER, SPRITEMOVEDATA_EMOTE -Function54f5: ; 54f5 (1:54f5) +ShakeGrass: push bc - ld de, .data - call Function5558 - call Function554b + ld de, .GrassObject + call CopyTempObjectData + call InitTempObject pop bc ret -.data db $fe, PAL_OW_TREE, SPRITEMOVEDATA_GRASS +.GrassObject + db $fe, PAL_OW_TREE, SPRITEMOVEDATA_GRASS -Function5504: ; 5504 (1:5504) +ShakeScreen: push bc push af - ld de, .data - call Function5558 + ld de, .ScreenShakeObject + call CopyTempObjectData pop af - ld [wce9e], a - call Function554b + ld [wTempObjectCopyRange], a + call InitTempObject pop bc ret -.data db $00, PAL_OW_SILVER, SPRITEMOVEDATA_SCREENSHAKE +.ScreenShakeObject: + db $00, PAL_OW_SILVER, SPRITEMOVEDATA_SCREENSHAKE -Function5518: ; 5518 (1:5518) +DespawnEmote: push bc ldh a, [hMapObjectIndexBuffer] ld c, a - call Function5521 + call .DeleteEmote pop bc ret -Function5521: ; 5521 (1:5521) - ld de, wPlayerStruct - ld a, $d -.asm_5526 +.DeleteEmote: + ld de, wObjectStructs + ld a, NUM_OBJECT_STRUCTS +.loop push af - ld hl, $4 + ld hl, OBJECT_FLAGS1 add hl, de - bit 7, [hl] - jr z, .asm_5540 - ld hl, $0 + bit EMOTE_OBJECT_F, [hl] + jr z, .next + ld hl, OBJECT_SPRITE add hl, de ld a, [hl] and a - jr z, .asm_5540 + jr z, .next push bc xor a - ld bc, $28 + ld bc, OBJECT_LENGTH call ByteFill pop bc -.asm_5540 - ld hl, $28 +.next + ld hl, OBJECT_LENGTH add hl, de ld d, h ld e, l pop af dec a - jr nz, .asm_5526 + jr nz, .loop ret -Function554b: ; 554b (1:554b) +InitTempObject: call FindFirstEmptyObjectStruct ret nc ld d, h @@ -608,11 +2071,14 @@ Function554b: ; 554b (1:554b) farcall CopyTempObjectToObjectStruct ret -Function5558: ; 5558 (1:5558) - ld hl, wce99 - ld [hl], $ff +CopyTempObjectData: +; load into wTempObjectCopy: +; -1, -1, [de], [de + 1], [de + 2], [hMapObjectIndexBuffer], [NextMapX], [NextMapY], -1 +; This spawns the object at the same place as whichever object is loaded into bc. + ld hl, wTempObjectCopyMapObjectIndex + ld [hl], -1 inc hl - ld [hl], $ff + ld [hl], -1 inc hl ld a, [de] inc de @@ -625,10 +2091,10 @@ Function5558: ; 5558 (1:5558) ldh a, [hMapObjectIndexBuffer] ld [hli], a push hl - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] pop hl @@ -636,56 +2102,57 @@ Function5558: ; 5558 (1:5558) inc hl ld [hl], e inc hl - ld [hl], $ff + ld [hl], -1 ret -Function557f:: ; 557f (1:557f) +Function557f:: ld a, [wVramState] bit 0, a ret z - ld bc, wPlayerStruct + ld bc, wObjectStructs xor a -.asm_5589 - ldh [hConnectionStripLength], a +.loop + ldh [hMapObjectIndexBuffer], a call DoesObjectHaveASprite - jr z, .asm_5593 + jr z, .ok call Function55ef -.asm_5593 - ld hl, $28 +.ok + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l ldh a, [hMapObjectIndexBuffer] inc a - cp $d - jr nz, .asm_5589 + cp NUM_OBJECT_STRUCTS + jr nz, .loop ret -Function55a1 - call Function55d8 - ld a, $0 - call Function55bc - ld a, [wd180] +Function55a1: +; called at battle start + call Function55d8 ; clear sprites + ld a, PLAYER + call Function55bc ; respawn player + ld a, [wBattleScriptFlags] bit 7, a - jr z, .asm_55b8 + jr z, .ok ldh a, [hLastTalked] and a - jr z, .asm_55b8 - call Function55bc -.asm_55b8 + jr z, .ok + call Function55bc ; respawn opponent +.ok call _UpdateSprites ret -Function55bc: ; 55bc (1:55bc) - cp $10 +Function55bc: + cp NUM_OBJECTS ret nc call GetMapObject - ld hl, $0 + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] - cp $ff + cp -1 ret z - cp $d + cp NUM_OBJECT_STRUCTS ret nc call GetObjectStruct call DoesObjectHaveASprite @@ -693,209 +2160,211 @@ Function55bc: ; 55bc (1:55bc) call Function5606 ret -Function55d8: ; 55d8 (1:55d8) +Function55d8: xor a - ld bc, wPlayerStruct -.asm_55dc + ld bc, wObjectStructs +.loop ldh [hMapObjectIndexBuffer], a - call Function5613 - ld hl, $28 + call SetFacing_Standing + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l - ldh a, [hConnectionStripLength] + ldh a, [hMapObjectIndexBuffer] inc a - cp $d - jr nz, .asm_55dc + cp NUM_OBJECT_STRUCTS + jr nz, .loop ret -Function55ef: ; 55ef (1:55ef) +Function55ef: push bc call Function5660 pop bc - jr c, Function5613 + jr c, SetFacing_Standing call Function5636 - jr c, Function5613 + jr c, SetFacing_Standing call Function561b - farcall Function4441 ; same bank + farcall Function4441 xor a ret -Function5606: ; 5606 (1:5606) +Function5606: call Function5636 - jr c, Function5613 - farcall Function4441 ; same bank + jr c, SetFacing_Standing + farcall Function4441 xor a ret -Function5613: ; 5613 (1:5613) - ld hl, $d +SetFacing_Standing: + ld hl, OBJECT_FACING_STEP add hl, bc - ld [hl], $ff + ld [hl], STANDING scf ret -Function561b: ; 561b (1:561b) +Function561b: push bc - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] call GetCoordTile pop bc - ld hl, $e + ld hl, OBJECT_NEXT_TILE add hl, bc ld [hl], a - farcall UpdateGrassPriority ; same bank + farcall UpdateTallGrassFlags ; no need to farcall ret -Function5636: ; 5636 (1:5636) - ld hl, $10 +Function5636: + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] inc d inc e ld a, [wXCoord] cp d - jr z, .asm_564f - jr nc, .asm_565e - add $b + jr z, .equal_x + jr nc, .nope + add MAPOBJECT_SCREEN_WIDTH - 1 cp d - jr c, .asm_565e -.asm_564f + jr c, .nope +.equal_x ld a, [wYCoord] cp e - jr z, .asm_565c - jr nc, .asm_565e - add $a + jr z, .equal_y + jr nc, .nope + add MAPOBJECT_SCREEN_HEIGHT - 1 cp e - jr c, .asm_565e -.asm_565c + jr c, .nope +.equal_y xor a ret -.asm_565e +.nope scf ret -Function5660: ; 5660 (1:5660) - ld a, [wce81] +Function5660: + ld a, [wPlayerBGMapOffsetX] ld d, a - ld hl, $19 + ld hl, OBJECT_SPRITE_X_OFFSET add hl, bc ld a, [hl] - ld hl, $17 + ld hl, OBJECT_SPRITE_X add hl, bc add [hl] add d cp $f0 - jr nc, .asm_5678 + jr nc, .ok1 cp $a0 - jp nc, Function56fb -.asm_5678 - and $7 - ld d, $2 - cp $4 - jr c, .asm_5682 - ld d, $3 -.asm_5682 + jp nc, .nope +.ok1 + and %00000111 + ld d, 2 + cp 4 + jr c, .ok2 + ld d, 3 +.ok2 ld a, [hl] srl a srl a srl a - cp $14 - jr c, .asm_568f - sub $20 -.asm_568f - ldh [hUsedSpriteIndex], a - ld a, [wce82] + cp SCREEN_WIDTH + jr c, .ok3 + sub BG_MAP_WIDTH +.ok3 + ldh [hCurSpriteXCoord], a + ld a, [wPlayerBGMapOffsetY] ld e, a - ld hl, $1a + ld hl, OBJECT_SPRITE_Y_OFFSET add hl, bc ld a, [hl] - ld hl, $18 + ld hl, OBJECT_SPRITE_Y add hl, bc add [hl] add e cp $f0 - jr nc, .asm_56a8 + jr nc, .ok4 cp $90 - jr nc, Function56fb -.asm_56a8 - and $7 - ld e, $2 - cp $4 - jr c, .asm_56b2 - ld e, $3 -.asm_56b2 + jr nc, .nope +.ok4 + and %00000111 + ld e, 2 + cp 4 + jr c, .ok5 + ld e, 3 +.ok5 ld a, [hl] srl a srl a srl a - cp $12 - jr c, .asm_56bf - sub $20 -.asm_56bf - ldh [hUsedSpriteTile], a - ld hl, $6 - add hl, bc - bit 7, [hl] - jr z, .asm_56d1 + cp SCREEN_HEIGHT + jr c, .ok6 + sub BG_MAP_HEIGHT +.ok6 + ldh [hCurSpriteYCoord], a + ld hl, OBJECT_PALETTE + add hl, bc + bit BIG_OBJECT_F, [hl] + jr z, .ok7 ld a, d - add $2 + add 2 ld d, a ld a, e - add $2 + add 2 ld e, a -.asm_56d1 +.ok7 ld a, d - ldh [hFFC1], a -.asm_56d4 - ldh a, [hFFC1] + ldh [hCurSpriteXPixel], a +.loop + ldh a, [hCurSpriteXPixel] ld d, a - ldh a, [hUsedSpriteTile] + ldh a, [hCurSpriteYCoord] add e dec a - cp $12 - jr nc, .asm_56f6 + cp SCREEN_HEIGHT + jr nc, .ok9 ld b, a -.asm_56e0 - ldh a, [hUsedSpriteIndex] +.next + ldh a, [hCurSpriteXCoord] add d dec a - cp $14 - jr nc, .asm_56f3 + cp SCREEN_WIDTH + jr nc, .ok8 ld c, a push bc call Coord2Tile pop bc +; NPCs disappear if standing on tile $60-$7f (or $e0-$ff), +; since those IDs are for text characters and textbox frames. ld a, [hl] - cp $60 - jr nc, Function56fb -.asm_56f3 + cp FIRST_REGULAR_TEXT_CHAR + jr nc, .nope +.ok8 dec d - jr nz, .asm_56e0 -.asm_56f6 + jr nz, .next +.ok9 dec e - jr nz, .asm_56d4 + jr nz, .loop and a ret -Function56fb: ; 56fb (1:56fb) +.nope scf ret HandleNPCStep:: - call Function5704 - call Function5714 + call .ResetStepVector + call .DoStepsForAllObjects ret -Function5704: ; 5704 (1:5704) +.ResetStepVector: xor a ld [wPlayerStepVectorX], a ld [wPlayerStepVectorY], a @@ -904,257 +2373,261 @@ Function5704: ; 5704 (1:5704) ld [wPlayerStepDirection], a ret -Function5714: ; 5714 (1:5714) - ld bc, wPlayerSprite +.DoStepsForAllObjects: + ld bc, wObjectStructs xor a -.asm_5718 +.loop ldh [hMapObjectIndexBuffer], a call DoesObjectHaveASprite - jr z, .asm_5722 + jr z, .next call Function437c -.asm_5722 - ld hl, $28 +.next + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l - ldh a, [hConnectionStripLength] + ldh a, [hMapObjectIndexBuffer] inc a - cp $d - jr nz, .asm_5718 + cp NUM_OBJECT_STRUCTS + jr nz, .loop ret -Function5730:: ; 5730 (1:5730) - ld a, $3e - ld [wce87], a - ld [wce88], a +RefreshPlayerSprite:: + ld a, movement_step_sleep + ld [wPlayerNextMovement], a + ld [wPlayerMovement], a xor a - ld [wcf39], a + ld [wPlayerTurningDirection], a ld [wPlayerObjectStepFrame], a - call Function574f - farcall Function14a44 - call c, Function5770 - call Function5761 + call .TryResetPlayerAction + farcall CheckWarpFacingDown + call c, SpawnInFacingDown + call .SpawnInCustomFacing ret -Function574f: ; 574f (1:574f) - ld hl, wd182 - bit 7, [hl] - jr nz, .asm_575b - bit 6, [hl] - jr nz, .asm_575b +.TryResetPlayerAction: + ld hl, wPlayerSpriteSetupFlags + bit PLAYERSPRITESETUP_RESET_ACTION_F, [hl] + jr nz, .ok + bit PLAYERSPRITESETUP_SKIP_RELOAD_GFX_F, [hl] + jr nz, .ok ret -.asm_575b - ld a, $0 +.ok + ld a, OBJECT_ACTION_00 ld [wPlayerAction], a ret -Function5761: ; 5761 (1:5761) - ld hl, wd182 - bit 5, [hl] +.SpawnInCustomFacing: + ld hl, wPlayerSpriteSetupFlags + bit PLAYERSPRITESETUP_CUSTOM_FACING_F, [hl] ret z - ld a, [wd182] - and $3 + ld a, [wPlayerSpriteSetupFlags] + and PLAYERSPRITESETUP_FACING_MASK add a add a - jr asm_5772 + jr ContinueSpawnFacing -Function5770: ; 5770 (1:5770) - ld a, $0 -asm_5772 - ld bc, wObjectStructs +SpawnInFacingDown: + ld a, DOWN +ContinueSpawnFacing: + ld bc, wPlayerStruct call SetSpriteDirection ret StartFollow:: push bc ld a, b - call Function578b + call SetLeaderIfVisible pop bc ret c ld a, c - call Function57a2 + call SetFollowerIfVisible farcall QueueFollowerFirstStep ret -Function578b: ; 578b (1:578b) +SetLeaderIfVisible: call CheckObjectVisibility ret c ldh a, [hObjectStructIndexBuffer] ld [wObjectFollow_Leader], a ret -StopFollow:: ; 5795 (1:5795) - call Function579c - call Function57bd +StopFollow:: + call ResetLeader + call ResetFollower ret -Function579c: ; 579c (1:579c) - ld a, $ff +ResetLeader: + ld a, -1 ld [wObjectFollow_Leader], a ret -Function57a2: ; 57a2 (1:57a2) +SetFollowerIfVisible: push af - call Function57bd + call ResetFollower pop af call CheckObjectVisibility ret c - ld hl, $3 + ld hl, OBJECT_MOVEMENTTYPE add hl, bc - ld [hl], $13 - ld hl, $9 + ld [hl], SPRITEMOVEDATA_FOLLOWING + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $0 - ldh a, [hConnectedMapWidth] + ld [hl], STEP_TYPE_00 + ldh a, [hObjectStructIndexBuffer] ld [wObjectFollow_Follower], a ret -Function57bd: ; 57bd (1:57bd) +ResetFollower: ld a, [wObjectFollow_Follower] - cp $ff + cp -1 ret z call GetObjectStruct - farcall Function5859 ; same bank - ld a, $ff + farcall Function5859 ; no need to bankswitch + ld a, -1 ld [wObjectFollow_Follower], a ret -Function57d2: +SetFlagsForMovement_1:: ld a, c call CheckObjectVisibility ret c push bc call Function57f0 pop bc - ld hl, $5 + ld hl, OBJECT_FLAGS2 add hl, bc - res 5, [hl] + res OBJ_FLAGS2_5, [hl] xor a ret Function57e4: call CheckObjectVisibility ret c - ld hl, $5 + ld hl, OBJECT_FLAGS2 add hl, bc - set 5, [hl] + set OBJ_FLAGS2_5, [hl] xor a ret -Function57f0: ; 57f0 (1:57f0) - ld bc, wPlayerStruct +Function57f0: + ld bc, wObjectStructs xor a -.asm_57f4 +.loop push af call DoesObjectHaveASprite - jr z, .asm_5800 - ld hl, $5 + jr z, .next + ld hl, OBJECT_FLAGS2 add hl, bc - set 5, [hl] -.asm_5800 - ld hl, $28 + set OBJ_FLAGS2_5, [hl] +.next + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l pop af inc a - cp $d - jr nz, .asm_57f4 + cp NUM_OBJECT_STRUCTS + jr nz, .loop ret -Function580d: +_SetFlagsForMovement_2:: ld a, [wObjectFollow_Leader] - cp $ff + cp -1 ret z push bc call GetObjectStruct - ld hl, $1 + ld hl, OBJECT_MAP_OBJECT_INDEX add hl, bc ld a, [hl] pop bc cp c ret nz ld a, [wObjectFollow_Follower] - cp $ff + cp -1 ret z call GetObjectStruct - ld hl, $5 + ld hl, OBJECT_FLAGS2 add hl, bc - res 5, [hl] + res OBJ_FLAGS2_5, [hl] ret -Function582f: +Function582f:: push bc - ld bc, wPlayerSprite + ld bc, wObjectStructs xor a -.asm_5834 +.loop push af call DoesObjectHaveASprite - jr z, .asm_5840 - ld hl, $5 + jr z, .next + ld hl, OBJECT_FLAGS2 add hl, bc - res 5, [hl] -.asm_5840 - ld hl, $28 + res OBJ_FLAGS2_5, [hl] +.next + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l pop af inc a - cp $d - jr nz, .asm_5834 + cp NUM_OBJECT_STRUCTS + jr nz, .loop pop bc ret Function584e: call CheckObjectVisibility ret c - ld hl, $5 + ld hl, OBJECT_FLAGS2 add hl, bc - res 5, [hl] + res OBJ_FLAGS2_5, [hl] ret -Function5859: - ld hl, $1 +Function5859:: + ld hl, OBJECT_MAP_OBJECT_INDEX add hl, bc ld a, [hl] - cp $ff - jp z, Function5879 + cp -1 + jp z, Function5879 ; a jr would have been appropriate here push bc call GetMapObject - ld hl, $4 + ld hl, MAPOBJECT_MOVEMENT add hl, bc ld a, [hl] pop bc - ld hl, $3 + ld hl, OBJECT_MOVEMENTTYPE add hl, bc ld [hl], a - ld hl, $9 + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $0 + ld [hl], STEP_TYPE_00 ret -Function5879: ; 5879 (1:5879) +Function5879: call GetSpriteDirection rrca rrca ld e, a - ld d, $0 - ld hl, .data + ld d, 0 + ld hl, .standing_movefns add hl, de ld a, [hl] - ld hl, $3 + ld hl, OBJECT_MOVEMENTTYPE add hl, bc ld [hl], a - ld hl, $9 + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $0 + ld [hl], STEP_TYPE_00 ret -.data db 6,7,8,9 +.standing_movefns + db SPRITEMOVEDATA_STANDING_DOWN + db SPRITEMOVEDATA_STANDING_UP + db SPRITEMOVEDATA_STANDING_LEFT + db SPRITEMOVEDATA_STANDING_RIGHT -_UpdateSprites:: ; 5896 (1:5896) +_UpdateSprites:: ld a, [wVramState] bit 0, a ret z @@ -1162,119 +2635,124 @@ _UpdateSprites:: ; 5896 (1:5896) ldh [hUsedSpriteIndex], a ldh a, [hOAMUpdate] push af - ld a, $1 + ld a, 1 ldh [hOAMUpdate], a - call Function58fe - call Function58b0 + call InitSprites + call .fill pop af ldh [hOAMUpdate], a ret -Function58b0: ; 58b0 (1:58b0) - ld b, $a0 +.fill + ld b, OBJECT_LENGTH * SPRITEOAMSTRUCT_LENGTH ldh a, [hUsedSpriteIndex] cp b ret nc ld l, a - ld h, wVirtualOAM / $100 - ld de, $4 + ld h, HIGH(wVirtualOAM) + ld de, SPRITEOAMSTRUCT_LENGTH ld a, b - ld c, $a0 -.asm_58bf - ld [hl], c + ld c, SCREEN_HEIGHT_PX + 2 * TILE_WIDTH +.loop + ld [hl], c ; y add hl, de cp l - jr nz, .asm_58bf + jr nz, .loop ret -ApplyBGMapAnchorToObjects:: ; 58c5 (1:58c5) +ApplyBGMapAnchorToObjects:: push hl push de push bc - ld a, [wce81] + ld a, [wPlayerBGMapOffsetX] ld d, a - ld a, [wce82] + ld a, [wPlayerBGMapOffsetY] ld e, a - ld bc, wPlayerStruct - ld a, $d -.asm_58d5 + ld bc, wObjectStructs + ld a, NUM_OBJECT_STRUCTS +.loop push af call DoesObjectHaveASprite - jr z, .asm_58e9 - ld hl, $17 + jr z, .skip + ld hl, OBJECT_SPRITE_X add hl, bc ld a, [hl] add d ld [hl], a - ld hl, $18 + ld hl, OBJECT_SPRITE_Y add hl, bc ld a, [hl] add e ld [hl], a -.asm_58e9 - ld hl, $28 +.skip + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l pop af dec a - jr nz, .asm_58d5 + jr nz, .loop xor a - ld [wce81], a - ld [wce82], a + ld [wPlayerBGMapOffsetX], a + ld [wPlayerBGMapOffsetY], a pop bc pop de pop hl ret -Function58fe: ; 58fe (1:58fe) - call Function5911 - ld c, $30 - call Function5960 - ld c, $20 - call Function5960 - ld c, $10 - call Function5960 +PRIORITY_LOW EQU $10 +PRIORITY_NORM EQU $20 +PRIORITY_HIGH EQU $30 + +InitSprites: + call .DeterminePriorities + ld c, PRIORITY_HIGH + call .InitSpritesByPriority + ld c, PRIORITY_NORM + call .InitSpritesByPriority + ld c, PRIORITY_LOW + call .InitSpritesByPriority ret -Function5911: ; 5911 (1:5911) +.DeterminePriorities: xor a - ld hl, wce94 - ld bc, $d + ld hl, wMovementPointer + ld bc, NUM_OBJECT_STRUCTS call ByteFill - ld d, $0 + ld d, 0 ld bc, wObjectStructs - ld hl, wce94 -.asm_5923 + ld hl, wMovementPointer +.loop push hl call DoesObjectHaveASprite - jr z, .asm_5946 - ld hl, $d + jr z, .skip + ld hl, OBJECT_FACING_STEP add hl, bc ld a, [hl] - cp $ff - jr z, .asm_5946 - ld e, $10 - ld hl, $5 - add hl, bc - bit 0, [hl] - jr nz, .asm_594f - ld e, $20 - bit 1, [hl] - jr z, .asm_594f - ld e, $30 - jr .asm_594f - -.asm_5946 - ld hl, $28 + cp STANDING + jr z, .skip +; Define the sprite priority. + ld e, PRIORITY_LOW + ld hl, OBJECT_FLAGS2 + add hl, bc + bit LOW_PRIORITY_F, [hl] + jr nz, .add + ld e, PRIORITY_NORM + bit HIGH_PRIORITY_F, [hl] + jr z, .add + ld e, PRIORITY_HIGH + jr .add + +.skip + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l pop hl - jr .asm_5959 + jr .next -.asm_594f - ld hl, $28 +.add + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l @@ -1282,157 +2760,158 @@ Function5911: ; 5911 (1:5911) ld a, d or e ld [hli], a -.asm_5959 +.next inc d ld a, d - cp $d - jr nz, .asm_5923 + cp NUM_OBJECT_STRUCTS + jr nz, .loop ret -Function5960: ; 5960 (1:5960) - ld hl, wce94 -.asm_5963 +.InitSpritesByPriority: + ld hl, wMovementPointer +.next_sprite ld a, [hli] ld d, a and $f0 ret z cp c - jr nz, .asm_5963 + jr nz, .next_sprite push bc push hl ld a, d and $f - call Function5a27 - call Function597a + call .GetObjectStructPointer + call .InitSprite pop hl pop bc - jr .asm_5963 + jr .next_sprite -Function597a: ; 597a (1:597a) +.InitSprite: xor a - ld hl, $5 +.skip1 + ld hl, OBJECT_FLAGS2 add hl, bc ld e, [hl] - bit 7, e - jr z, .asm_5986 - or $80 -.asm_5986 - bit 4, e - jr z, .asm_598c - or $10 -.asm_598c - ld hl, $6 + bit OBJ_FLAGS2_7, e + jr z, .skip2 + or PRIORITY +.skip2 + bit USE_OBP1_F, e + jr z, .skip3 + or OBP_NUM +.skip3 + ld hl, OBJECT_PALETTE add hl, bc ld d, a ld a, [hl] - and $7 + and PALETTE_MASK or d ld d, a xor a - bit 3, e - jr z, .asm_599d - or $80 -.asm_599d - ldh [hFFC4], a - ld hl, $2 + bit OVERHEAD_F, e + jr z, .skip4 + or PRIORITY +.skip4 + ldh [hCurSpriteOAMFlags], a + ld hl, OBJECT_SPRITE_TILE add hl, bc ld a, [hl] - ldh [hFFC3], a - ld hl, $17 + ldh [hCurSpriteTile], a + ld hl, OBJECT_SPRITE_X add hl, bc ld a, [hl] - ld hl, $19 + ld hl, OBJECT_SPRITE_X_OFFSET add hl, bc add [hl] - add $8 + add 8 ld e, a - ld a, [wce81] + ld a, [wPlayerBGMapOffsetX] add e - ldh [hFFC1], a - ld hl, $18 + ldh [hCurSpriteXPixel], a + ld hl, OBJECT_SPRITE_Y add hl, bc ld a, [hl] - ld hl, $1a + ld hl, OBJECT_SPRITE_Y_OFFSET add hl, bc add [hl] - add $c + add 12 ld e, a - ld a, [wce82] + ld a, [wPlayerBGMapOffsetY] add e - ldh [hFFC2], a - ld hl, $d + ldh [hCurSpriteYPixel], a + ld hl, OBJECT_FACING_STEP add hl, bc ld a, [hl] - cp $ff - jp z, .asm_5a23 - cp $20 - jp nc, .asm_5a23 + cp STANDING + jp z, .done + cp NUM_FACINGS + jp nc, .done ld l, a - ld h, $0 + ld h, 0 add hl, hl - ld bc, PushOAMEnd + ld bc, Facings add hl, bc ld a, [hli] ld h, [hl] ld l, a ldh a, [hUsedSpriteIndex] ld c, a - ld b, $c3 + ld b, HIGH(wVirtualOAM) ld a, [hli] ldh [hUsedSpriteTile], a add c - cp $a0 - jr nc, .asm_5a25 -.asm_59f3 - ldh a, [hFFC2] + cp LOW(wVirtualOAMEnd) + jr nc, .full +.addsprite + ldh a, [hCurSpriteYPixel] add [hl] inc hl - ld [bc], a + ld [bc], a ; y inc c - ldh a, [hFFC1] + ldh a, [hCurSpriteXPixel] add [hl] inc hl - ld [bc], a + ld [bc], a ; x inc c ld e, [hl] inc hl - ldh a, [hFFC3] - bit 2, e - jr z, .asm_5a08 + ldh a, [hCurSpriteTile] + bit ABSOLUTE_TILE_ID_F, e + jr z, .nope1 xor a -.asm_5a08 +.nope1 add [hl] inc hl - ld [bc], a + ld [bc], a ; tile id inc c ld a, e - bit 1, a - jr z, .asm_5a14 - ldh a, [hFFC4] + bit RELATIVE_ATTRIBUTES_F, a + jr z, .nope2 + ldh a, [hCurSpriteOAMFlags] or e -.asm_5a14 - and $f0 +.nope2 + and OBP_NUM | X_FLIP | Y_FLIP | PRIORITY or d - ld [bc], a + ld [bc], a ; attributes inc c ldh a, [hUsedSpriteTile] dec a ldh [hUsedSpriteTile], a - jr nz, .asm_59f3 + jr nz, .addsprite ld a, c ldh [hUsedSpriteIndex], a -.asm_5a23 +.done xor a ret -.asm_5a25 +.full scf ret -Function5a27: ; 5a27 (1:5a27) +.GetObjectStructPointer: ld c, a - ld b, $0 - ld hl, ObjectStructPointers + ld b, 0 + ld hl, .Addresses add hl, bc add hl, bc ld c, [hl] @@ -1440,7 +2919,7 @@ Function5a27: ; 5a27 (1:5a27) ld b, [hl] ret -ObjectStructPointers: +.Addresses: dw wPlayerStruct dw wObject1Struct dw wObject2Struct diff --git a/engine/overworld/map_objects_2.asm b/engine/overworld/map_objects_2.asm new file mode 100644 index 00000000..d89d95fc --- /dev/null +++ b/engine/overworld/map_objects_2.asm @@ -0,0 +1,70 @@ +LoadObjectMasks: + ld hl, wObjectMasks + xor a + ld bc, NUM_OBJECTS + call ByteFill + nop + ld bc, wMapObjects + ld de, wObjectMasks + xor a +.loop + push af + push bc + push de + call GetObjectTimeMask + jr c, .next + call CheckObjectFlag +.next + pop de + ld [de], a + inc de + pop bc + ld hl, MAPOBJECT_LENGTH + add hl, bc + ld b, h + ld c, l + pop af + inc a + cp NUM_OBJECTS + jr nz, .loop + ret + +CheckObjectFlag: + ld hl, MAPOBJECT_SPRITE + add hl, bc + ld a, [hl] + and a + jr z, .masked + ld hl, MAPOBJECT_EVENT_FLAG + add hl, bc + ld a, [hli] + ld e, a + ld a, [hl] + ld d, a + cp -1 + jr nz, .check + ld a, e + cp -1 + jr z, .unmasked + jr .masked +.check + ld b, CHECK_FLAG + call EventFlagAction + ld a, c + and a + jr nz, .masked +.unmasked + xor a + ret + +.masked + ld a, -1 + scf + ret + +GetObjectTimeMask: + call CheckObjectTime + ld a, -1 + ret c + xor a + ret diff --git a/engine/overworld/map_setup.asm b/engine/overworld/map_setup.asm new file mode 100644 index 00000000..aec3c949 --- /dev/null +++ b/engine/overworld/map_setup.asm @@ -0,0 +1,256 @@ +RunMapSetupScript:: + ldh a, [hMapEntryMethod] + and $f + dec a + ld c, a + ld b, 0 + ld hl, MapSetupScripts + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call ReadMapSetupScript + ret + +INCLUDE "data/maps/setup_scripts.asm" + +ReadMapSetupScript: +.loop + ld a, [hli] + cp map_end + ret z + + push hl + + ld c, a + ld b, 0 + ld hl, MapSetupCommands + add hl, bc + add hl, bc + add hl, bc + + ; bank + ld b, [hl] + inc hl + + ; address + ld a, [hli] + ld h, [hl] + ld l, a + + ; Bit 7 of the bank indicates a parameter. + ; This is left unused. + bit 7, b + jr z, .go + + pop de + ld a, [de] + ld c, a + inc de + push de + +.go + ld a, b + and $7f + rst FarCall + + pop hl + jr .loop + +MapSetupCommands: +; entries correspond to command indexes in constants/map_setup_constants.asm + dba EnableLCD ; 00 + dba DisableLCD ; 01 + dba InitSound ; 02 + dba PlayMapMusic ; 03 + dba RestartMapMusic ; 04 + dba FadeToMapMusic ; 05 + dba FadeMapMusicAndPalettes ; 06 + dba PlayMapMusicBike ; 07 + dba ForceMapMusic ; 08 + dba FadeInMusic ; 09 + dba LoadBlockData ; 0a (callback 1) + dba LoadConnectionBlockData ; 0b + dba SaveScreen ; 0c + dba BufferScreen ; 0d + dba LoadMapGraphics ; 0e + dba LoadMapTileset ; 0f + dba LoadMapTimeOfDay ; 10 + dba LoadMapPalettes ; 11 + dba LoadWildMonData ; 12 + dba RefreshMapSprites ; 13 + dba HandleNewMap ; 14 + dba HandleContinueMap ; 15 + dba LoadMapObjects ; 16 + dba EnterMapSpawnPoint ; 17 + dba EnterMapConnection ; 18 + dba EnterMapWarp ; 19 + dba LoadMapAttributes ; 1a + dba LoadMapAttributes_SkipObjects ; 1b + dba ClearBGPalettes ; 1c + dba FadeOutPalettes ; 1d + dba FadeInPalettes ; 1e + dba GetMapScreenCoords ; 1f + dba GetWarpDestCoords ; 20 + dba SpawnInFacingDown ; 21 + dba SpawnPlayer ; 22 + dba RefreshPlayerCoords ; 23 + dba ResetPlayerObjectAction ; 24 + dba SkipUpdateMapSprites ; 25 + dba UpdateRoamMons ; 26 + dba JumpRoamMons ; 27 + dba FadeOutMapMusic ; 28 + dba ActivateMapAnims ; 29 + dba SuspendMapAnims ; 2a + dba ApplyMapPalettes ; 2b + dba EnableTextAcceleration ; 2c + +EnableTextAcceleration: + xor a + ld [wDisableTextAcceleration], a + ret + +UnusedActivateMapAnims: + ld a, $1 + ldh [hMapAnims], a + ret + +UnusedSuspendMapAnims: + xor a + ldh [hMapAnims], a + ret + +LoadMapObjects: + ld a, MAPCALLBACK_OBJECTS + call RunMapCallback + farcall LoadObjectMasks + farcall InitializeVisibleSprites + ret + +; unused + ret + +ResetPlayerObjectAction: + ld hl, wPlayerSpriteSetupFlags + set PLAYERSPRITESETUP_RESET_ACTION_F, [hl] + ret + +SkipUpdateMapSprites: + ld hl, wPlayerSpriteSetupFlags + set PLAYERSPRITESETUP_SKIP_RELOAD_GFX_F, [hl] + ret + +CheckReplaceChrisSprite:: + nop + call .CheckBiking + jr c, .ok + call .CheckSurfing + jr c, .ok + call .CheckSurfing2 + jr c, .ok + ret + +.ok + call ReplaceChrisSprite + ret + +.CheckBiking: + and a + ld hl, wBikeFlags + bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl] + ret z + ld a, PLAYER_BIKE + ld [wPlayerState], a + scf + ret + +.CheckSurfing2: + ld a, [wPlayerState] + cp PLAYER_NORMAL + jr z, .nope + cp PLAYER_SKATE + jr z, .nope + cp PLAYER_SURF + jr z, .surfing + cp PLAYER_SURF_PIKA + jr z, .surfing + call GetMapEnvironment + cp INDOOR + jr z, .no_biking + cp ENVIRONMENT_5 + jr z, .no_biking + cp DUNGEON + jr z, .no_biking + jr .nope +.no_biking + ld a, [wPlayerState] + cp PLAYER_BIKE + jr nz, .nope +.surfing + ld a, PLAYER_NORMAL + ld [wPlayerState], a + scf + ret + +.nope + and a + ret + +.CheckSurfing: + call CheckOnWater + jr nz, .nope2 + ld a, [wPlayerState] + cp PLAYER_SURF + jr z, .is_surfing + cp PLAYER_SURF_PIKA + jr z, .is_surfing + ld a, PLAYER_SURF + ld [wPlayerState], a +.is_surfing + scf + ret + +.nope2 + and a + ret + +FadeOutMapMusic: + ld a, 6 + call SkipMusic + ret + +ActivateMapAnims: + ld a, $1 + ldh [hMapAnims], a + ret + +SuspendMapAnims: + xor a + ldh [hMapAnims], a + ret + +ApplyMapPalettes: + farcall _UpdateTimePals + ret + +FadeMapMusicAndPalettes: + ld e, LOW(MUSIC_NONE) + ld a, [wMusicFadeID] + ld d, HIGH(MUSIC_NONE) + ld a, [wMusicFadeID + 1] + ld a, $4 + ld [wMusicFade], a + call RotateThreePalettesRight + ret + +ForceMapMusic: + ld a, [wPlayerState] + cp PLAYER_BIKE + jr nz, .notbiking + call MinVolume + ld a, $88 + ld [wMusicFade], a +.notbiking + call TryRestartMapMusic + ret diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm index d98b47ee..1a819acb 100755 --- a/engine/overworld/movement.asm +++ b/engine/overworld/movement.asm @@ -1,776 +1,767 @@ -GetMovementByte: - ld hl, wMovementDataBank - call _GetMovementByte +MovementPointers: +; 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 + dw Movement_turn_head_right ; 03 + dw Movement_turn_step_down ; 04 + dw Movement_turn_step_up ; 05 + dw Movement_turn_step_left ; 06 + dw Movement_turn_step_right ; 07 + dw Movement_slow_step_down ; 08 + dw Movement_slow_step_up ; 09 + dw Movement_slow_step_left ; 0a + dw Movement_slow_step_right ; 0b + dw Movement_step_down ; 0c + dw Movement_step_up ; 0d + dw Movement_step_left ; 0e + dw Movement_step_right ; 0f + dw Movement_big_step_down ; 10 + dw Movement_big_step_up ; 11 + dw Movement_big_step_left ; 12 + dw Movement_big_step_right ; 13 + dw Movement_slow_slide_step_down ; 14 + dw Movement_slow_slide_step_up ; 15 + dw Movement_slow_slide_step_left ; 16 + dw Movement_slow_slide_step_right ; 17 + dw Movement_slide_step_down ; 18 + dw Movement_slide_step_up ; 19 + dw Movement_slide_step_left ; 1a + dw Movement_slide_step_right ; 1b + dw Movement_fast_slide_step_down ; 1c + dw Movement_fast_slide_step_up ; 1d + dw Movement_fast_slide_step_left ; 1e + dw Movement_fast_slide_step_right ; 1f + dw Movement_turn_away_down ; 20 + dw Movement_turn_away_up ; 21 + dw Movement_turn_away_left ; 22 + dw Movement_turn_away_right ; 23 + dw Movement_turn_in_down ; 24 + dw Movement_turn_in_up ; 25 + dw Movement_turn_in_left ; 26 + dw Movement_turn_in_right ; 27 + dw Movement_turn_waterfall_down ; 28 + dw Movement_turn_waterfall_up ; 29 + dw Movement_turn_waterfall_left ; 2a + dw Movement_turn_waterfall_right ; 2b + dw Movement_slow_jump_step_down ; 2c + dw Movement_slow_jump_step_up ; 2d + dw Movement_slow_jump_step_left ; 2e + dw Movement_slow_jump_step_right ; 2f + dw Movement_jump_step_down ; 30 + dw Movement_jump_step_up ; 31 + dw Movement_jump_step_left ; 32 + dw Movement_jump_step_right ; 33 + dw Movement_fast_jump_step_down ; 34 + dw Movement_fast_jump_step_up ; 35 + dw Movement_fast_jump_step_left ; 36 + dw Movement_fast_jump_step_right ; 37 + dw Movement_remove_sliding ; 38 + dw Movement_set_sliding ; 39 + dw Movement_remove_fixed_facing ; 3a + dw Movement_fix_facing ; 3b + dw Movement_show_object ; 3c + dw Movement_hide_object ; 3d + dw Movement_step_sleep_1 ; 3e + dw Movement_step_sleep_2 ; 3f + dw Movement_step_sleep_3 ; 40 + dw Movement_step_sleep_4 ; 41 + dw Movement_step_sleep_5 ; 42 + dw Movement_step_sleep_6 ; 43 + dw Movement_step_sleep_7 ; 44 + dw Movement_step_sleep_8 ; 45 + dw Movement_step_sleep ; 46 + dw Movement_step_end ; 47 + dw Movement_48 ; 48 + dw Movement_remove_object ; 49 + dw Movement_step_loop ; 4a + dw Movement_4b ; 4b + dw Movement_teleport_from ; 4c + dw Movement_teleport_to ; 4d + dw Movement_skyfall ; 4e + dw Movement_step_dig ; 4f + dw Movement_step_bump ; 50 + dw Movement_fish_got_bite ; 51 + dw Movement_fish_cast_rod ; 52 + dw Movement_hide_emote ; 53 + dw Movement_show_emote ; 54 + dw Movement_step_shake ; 55 + dw Movement_tree_shake ; 56 + dw Movement_rock_smash ; 57 + dw Movement_return_dig ; 58 + +Movement_teleport_from: + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_TELEPORT_FROM ret -Function4fbd: - ld hl, $1b - add hl, bc - ld e, [hl] - inc [hl] - ld d, $0 - ld hl, wMovementObject - ld a, [hli] - ld h, [hl] - ld l, a - add hl, de - ld a, [hl] - ret - -Function4fce: - ld hl, $1b - add hl, bc - ld e, [hl] - inc [hl] - ld d, $0 - ld hl, wce8f - ld a, [hli] - ld h, [hl] - ld l, a - add hl, de - ld a, [hl] - ret - -Function4fdf: ; 4fdf (1:4fdf) - ld hl, GetMovementPerson - jp Function4fe9 - -GetMovementPerson - ld a, [wMovementObject] - ret - -Function4fe9: ; 4fe9 (1:4fe9) - call Function4ffd -.asm_4fec - xor a - ld [wce93], a - call Function5006 - call Function5013 - ld a, [wce93] - and a - jr nz, .asm_4fec - ret - -Function4ffd: ; 4ffd (1:4ffd) - ld a, l - ld [wce94], a - ld a, h - ld [wce95], a - ret - -Function5006: ; 5006 (1:5006) - ld hl, wce94 - ld a, [hli] - ld h, [hl] - ld l, a - jp hl - -Function500d: ; 500d (1:500d) - ld a, $1 - ld [wce93], a - ret - -Function5013: ; 5013 (1:5013) - push af - call Function5457 - pop af - ld hl, MovementPointers - rst JumpTable - ret - -MovementPointers: ; 501d - dw Function527d - dw Function5281 - dw Function5285 - dw Function5289 - dw Function538f - dw Function5393 - dw Function5397 - dw Function539b - dw Function529f - dw Function52a4 - dw Function52a9 - dw Function52ae - dw Function52b3 - dw Function52b8 - dw Function52bd - dw Function52c2 - dw Function52c7 - dw Function52cc - dw Function52d1 - dw Function52d6 - dw Function5317 - dw Function531c - dw Function5321 - dw Function5326 - dw Function532b - dw Function5330 - dw Function5335 - dw Function533a - dw Function533f - dw Function5344 - dw Function5349 - dw Function534e - dw Function52db - dw Function52e0 - dw Function52e5 - dw Function52ea - dw Function52ef - dw Function52f4 - dw Function52f9 - dw Function52fe - dw Function5303 - dw Function5308 - dw Function530d - dw Function5312 - dw Function5353 - dw Function5358 - dw Function535d - dw Function5362 - dw Function5367 - dw Function536c - dw Function5371 - dw Function5376 - dw Function537b - dw Function5380 - dw Function5385 - dw Function538a - dw Function5232 - dw Function523b - dw Function5244 - dw Function524d - dw Function5256 - dw Function525f - dw Function51c1 - dw Function51c5 - dw Function51c9 - dw Function51cd - dw Function51d1 - dw Function51d5 - dw Function51d9 - dw Function51dd - dw Function51e1 - dw Function5160 - dw Function517a - dw Function519c - dw Function5157 - dw Function51af - dw Function50cf - dw Function50d6 - dw Function50dd - dw Function50e4 - dw Function51fe - dw Function5128 - dw Function514a - dw Function5268 - dw Function526e - dw Function5274 - dw Function5218 - dw Function5135 - dw Function5109 - -Function50cf: ; 50cf (1:50cf) - ld hl, $9 - add hl, bc - ld [hl], $c - ret - -Function50d6: ; 50d6 (1:50d6) - ld hl, $9 +Movement_teleport_to: + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $d + ld [hl], STEP_TYPE_TELEPORT_TO ret -Function50dd: ; 50dd (1:50dd) - ld hl, $9 +Movement_skyfall: + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $e + ld [hl], STEP_TYPE_SKYFALL ret -Function50e4: ; 50e4 (1:50e4) +Movement_step_dig: call GetSpriteDirection rlca rlca - ld hl, $c + ld hl, OBJECT_STEP_FRAME add hl, bc ld [hl], a - ld hl, $b + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $4 - call Function5006 - ld hl, $a + ld [hl], OBJECT_ACTION_SPIN + call JumpMovementPointer + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $9 + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $3 - ld hl, $7 + ld [hl], STEP_TYPE_03 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff + ld [hl], STANDING ret -Function5109: ; 5109 (1:5109) +Movement_return_dig: call GetSpriteDirection rlca rlca - ld hl, $c + ld hl, OBJECT_STEP_FRAME add hl, bc ld [hl], a - call Function5006 - ld hl, $a + call JumpMovementPointer + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $7 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff - ld hl, $9 + ld [hl], STANDING + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $12 + ld [hl], STEP_TYPE_RETURN_DIG ret -Function5128: ; 5128 (1:5128) - ld hl, $b +Movement_fish_got_bite: + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $6 - ld hl, $9 + ld [hl], OBJECT_ACTION_FISHING + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $10 + ld [hl], STEP_TYPE_GOT_BITE ret -Function5135: ; 5135 (1:5135) - call Function5006 - ld hl, $a +Movement_rock_smash: + call JumpMovementPointer + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $b + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $1 - ld hl, $9 + ld [hl], OBJECT_ACTION_STAND + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $11 + ld [hl], STEP_TYPE_ROCK_SMASH ret -Function514a: ; 514a (1:514a) - ld hl, $b +Movement_fish_cast_rod: + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $6 - ld hl, $9 + ld [hl], OBJECT_ACTION_FISHING + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $1 + ld [hl], STEP_TYPE_SLEEP ret -Function5157: ; 5157 (1:5157) - ld hl, $1b +Movement_step_loop: + ld hl, OBJECT_MOVEMENT_BYTE_INDEX add hl, bc ld [hl], $0 - jp Function500d + jp ContinueReadingMovement -Function5160: ; 5160 (1:5160) +Movement_step_end: call RestoreDefaultMovement - ld hl, $3 + ld hl, OBJECT_MOVEMENTTYPE add hl, bc ld [hl], a - ld hl, $1b + + ld hl, OBJECT_MOVEMENT_BYTE_INDEX add hl, bc ld [hl], $0 + ld hl, wVramState res 7, [hl] - ld hl, $9 + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $1 + ld [hl], STEP_TYPE_SLEEP ret -Function517a: ; 517a (1:517a) +Movement_48: call RestoreDefaultMovement - ld hl, $3 + ld hl, OBJECT_MOVEMENTTYPE add hl, bc ld [hl], a - ld hl, $1b + + ld hl, OBJECT_MOVEMENT_BYTE_INDEX add hl, bc ld [hl], $0 - call Function5006 - ld hl, $a + + call JumpMovementPointer + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $9 + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $3 + ld [hl], STEP_TYPE_03 + ld hl, wVramState res 7, [hl] ret -Function519c: ; 519c (1:519c) +Movement_remove_object: call DeleteMapObject ld hl, wObjectFollow_Leader ldh a, [hMapObjectIndexBuffer] cp [hl] - jr nz, .asm_51a9 - ld [hl], $ff -.asm_51a9 + jr nz, .not_leading + ld [hl], -1 + +.not_leading ld hl, wVramState res 7, [hl] ret -Function51af: ; 51af (1:51af) - ld hl, $b +Movement_4b: + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $1 - ld hl, $9 + ld [hl], OBJECT_ACTION_STAND + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $4 + ld [hl], STEP_TYPE_04 + ld hl, wVramState res 7, [hl] ret -Function51c1: ; 51c1 (1:51c1) - ld a, $1 - jr asm_51e6 +Movement_step_sleep_1: + ld a, 1 + jr Movement_step_sleep_common + +Movement_step_sleep_2: + ld a, 2 + jr Movement_step_sleep_common -Function51c5: ; 51c5 (1:51c5) - ld a, $2 - jr asm_51e6 +Movement_step_sleep_3: + ld a, 3 + jr Movement_step_sleep_common -Function51c9: ; 51c9 (1:51c9) - ld a, $3 - jr asm_51e6 +Movement_step_sleep_4: + ld a, 4 + jr Movement_step_sleep_common -Function51cd: ; 51cd (1:51cd) - ld a, $4 - jr asm_51e6 +Movement_step_sleep_5: + ld a, 5 + jr Movement_step_sleep_common -Function51d1: ; 51d1 (1:51d1) - ld a, $5 - jr asm_51e6 +Movement_step_sleep_6: + ld a, 6 + jr Movement_step_sleep_common -Function51d5: ; 51d5 (1:51d5) - ld a, $6 - jr asm_51e6 +Movement_step_sleep_7: + ld a, 7 + jr Movement_step_sleep_common -Function51d9: ; 51d9 (1:51d9) - ld a, $7 - jr asm_51e6 +Movement_step_sleep_8: + ld a, 8 + jr Movement_step_sleep_common -Function51dd: ; 51dd (1:51dd) - ld a, $8 - jr asm_51e6 +Movement_step_sleep: +; parameters: +; duration (DecimalParam) -Function51e1: ; 51e1 (1:51e1) - call Function5006 - jr asm_51e6 + call JumpMovementPointer + jr Movement_step_sleep_common -asm_51e6 - ld hl, $a +Movement_step_sleep_common: + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $9 + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $3 - ld hl, $b + ld [hl], STEP_TYPE_03 + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $1 - ld hl, $7 + ld [hl], OBJECT_ACTION_STAND + + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff + ld [hl], STANDING ret -Function51fe: ; 51fe (1:51fe) - ld a, $1 - ld hl, $a +Movement_step_bump: + ld a, 1 + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $9 + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $b - ld hl, $b + ld [hl], STEP_TYPE_BUMP + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $3 - ld hl, $7 + ld [hl], OBJECT_ACTION_BUMP + + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff + ld [hl], STANDING ret -Function5218: ; 5218 (1:5218) - ld a, $18 - ld hl, $a +Movement_tree_shake: + ld a, 24 + ld hl, OBJECT_STEP_DURATION add hl, bc ld [hl], a - ld hl, $9 + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $3 - ld hl, $b + ld [hl], STEP_TYPE_03 + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $b - ld hl, $7 + ld [hl], OBJECT_ACTION_WEIRD_TREE + + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff + ld [hl], STANDING ret -Function5232: ; 5232 (1:5232) - ld hl, $4 +Movement_remove_sliding: + ld hl, OBJECT_FLAGS1 add hl, bc - res 3, [hl] - jp Function500d + res SLIDING_F, [hl] + jp ContinueReadingMovement -Function523b: ; 523b (1:523b) - ld hl, $4 +Movement_set_sliding: + ld hl, OBJECT_FLAGS1 add hl, bc - set 3, [hl] - jp Function500d + set SLIDING_F, [hl] + jp ContinueReadingMovement -Function5244: ; 5244 (1:5244) - ld hl, $4 +Movement_remove_fixed_facing: + ld hl, OBJECT_FLAGS1 add hl, bc - res 2, [hl] - jp Function500d + res FIXED_FACING_F, [hl] + jp ContinueReadingMovement -Function524d: ; 524d (1:524d) - ld hl, $4 +Movement_fix_facing: + ld hl, OBJECT_FLAGS1 add hl, bc - set 2, [hl] - jp Function500d + set FIXED_FACING_F, [hl] + jp ContinueReadingMovement -Function5256: ; 5256 (1:5256) - ld hl, $4 +Movement_show_object: + ld hl, OBJECT_FLAGS1 add hl, bc - res 0, [hl] - jp Function500d + res INVISIBLE_F, [hl] + jp ContinueReadingMovement -Function525f: ; 525f (1:525f) - ld hl, $4 +Movement_hide_object: + ld hl, OBJECT_FLAGS1 add hl, bc - set 0, [hl] - jp Function500d + set INVISIBLE_F, [hl] + jp ContinueReadingMovement + +Movement_hide_emote: + call DespawnEmote + jp ContinueReadingMovement -Function5268: ; 5268 (1:5268) - call Function5518 - jp Function500d +Movement_show_emote: + call SpawnEmote + jp ContinueReadingMovement -Function526e: ; 526e (1:526e) - call Function54e6 - jp Function500d +Movement_step_shake: +; parameters: +; displacement (DecimalParam) -Function5274: ; 5274 (1:5274) - call Function5006 - call Function5504 - jp Function500d + call JumpMovementPointer + call ShakeScreen + jp ContinueReadingMovement -Function527d: ; 527d (1:527d) - ld a, $0 - jr asm_528d +Movement_turn_head_down: + ld a, OW_DOWN + jr TurnHead -Function5281: ; 5281 (1:5281) - ld a, $4 - jr asm_528d +Movement_turn_head_up: + ld a, OW_UP + jr TurnHead -Function5285: ; 5285 (1:5285) - ld a, $8 - jr asm_528d +Movement_turn_head_left: + ld a, OW_LEFT + jr TurnHead -Function5289: ; 5289 (1:5289) - ld a, $c - jr asm_528d +Movement_turn_head_right: + ld a, OW_RIGHT + jr TurnHead -asm_528d - ld hl, $8 +TurnHead: + ld hl, OBJECT_FACING add hl, bc ld [hl], a - ld hl, $b + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $1 - ld hl, $7 + ld [hl], OBJECT_ACTION_STAND + + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - ld [hl], $ff + ld [hl], STANDING ret -Function529f: ; 529f (1:529f) - ld a, $0 - jp Function53b1 +Movement_slow_step_down: + ld a, STEP_SLOW << 2 | DOWN + jp NormalStep -Function52a4: ; 52a4 (1:52a4) - ld a, $1 - jp Function53b1 +Movement_slow_step_up: + ld a, STEP_SLOW << 2 | UP + jp NormalStep -Function52a9: ; 52a9 (1:52a9) - ld a, $2 - jp Function53b1 +Movement_slow_step_left: + ld a, STEP_SLOW << 2 | LEFT + jp NormalStep -Function52ae: ; 52ae (1:52ae) - ld a, $3 - jp Function53b1 +Movement_slow_step_right: + ld a, STEP_SLOW << 2 | RIGHT + jp NormalStep -Function52b3: ; 52b3 (1:52b3) - ld a, $4 - jp Function53b1 +Movement_step_down: + ld a, STEP_WALK << 2 | DOWN + jp NormalStep -Function52b8: ; 52b8 (1:52b8) - ld a, $5 - jp Function53b1 +Movement_step_up: + ld a, STEP_WALK << 2 | UP + jp NormalStep -Function52bd: ; 52bd (1:52bd) - ld a, $6 - jp Function53b1 +Movement_step_left: + ld a, STEP_WALK << 2 | LEFT + jp NormalStep -Function52c2: ; 52c2 (1:52c2) - ld a, $7 - jp Function53b1 +Movement_step_right: + ld a, STEP_WALK << 2 | RIGHT + jp NormalStep -Function52c7: ; 52c7 (1:52c7) - ld a, $8 - jp Function53b1 +Movement_big_step_down: + ld a, STEP_BIKE << 2 | DOWN + jp NormalStep -Function52cc: ; 52cc (1:52cc) - ld a, $9 - jp Function53b1 +Movement_big_step_up: + ld a, STEP_BIKE << 2 | UP + jp NormalStep -Function52d1: ; 52d1 (1:52d1) - ld a, $a - jp Function53b1 +Movement_big_step_left: + ld a, STEP_BIKE << 2 | LEFT + jp NormalStep -Function52d6: ; 52d6 (1:52d6) - ld a, $b - jp Function53b1 +Movement_big_step_right: + ld a, STEP_BIKE << 2 | RIGHT + jp NormalStep -Function52db: ; 52db (1:52db) - ld a, $0 - jp Function53e5 +Movement_turn_away_down: + ld a, STEP_SLOW << 2 | DOWN + jp TurningStep -Function52e0: ; 52e0 (1:52e0) - ld a, $1 - jp Function53e5 +Movement_turn_away_up: + ld a, STEP_SLOW << 2 | UP + jp TurningStep -Function52e5: ; 52e5 (1:52e5) - ld a, $2 - jp Function53e5 +Movement_turn_away_left: + ld a, STEP_SLOW << 2 | LEFT + jp TurningStep -Function52ea: ; 52ea (1:52ea) - ld a, $3 - jp Function53e5 +Movement_turn_away_right: + ld a, STEP_SLOW << 2 | RIGHT + jp TurningStep -Function52ef: ; 52ef (1:52ef) - ld a, $4 - jp Function53e5 +Movement_turn_in_down: + ld a, STEP_WALK << 2 | DOWN + jp TurningStep -Function52f4: ; 52f4 (1:52f4) - ld a, $5 - jp Function53e5 +Movement_turn_in_up: + ld a, STEP_WALK << 2 | UP + jp TurningStep -Function52f9: ; 52f9 (1:52f9) - ld a, $6 - jp Function53e5 +Movement_turn_in_left: + ld a, STEP_WALK << 2 | LEFT + jp TurningStep -Function52fe: ; 52fe (1:52fe) - ld a, $7 - jp Function53e5 +Movement_turn_in_right: + ld a, STEP_WALK << 2 | RIGHT + jp TurningStep -Function5303: ; 5303 (1:5303) - ld a, $8 - jp Function53e5 +Movement_turn_waterfall_down: + ld a, STEP_BIKE << 2 | DOWN + jp TurningStep -Function5308: ; 5308 (1:5308) - ld a, $9 - jp Function53e5 +Movement_turn_waterfall_up: + ld a, STEP_BIKE << 2 | UP + jp TurningStep -Function530d: ; 530d (1:530d) - ld a, $a - jp Function53e5 +Movement_turn_waterfall_left: + ld a, STEP_BIKE << 2 | LEFT + jp TurningStep -Function5312: ; 5312 (1:5312) - ld a, $b - jp Function53e5 +Movement_turn_waterfall_right: + ld a, STEP_BIKE << 2 | RIGHT + jp TurningStep -Function5317: ; 5317 (1:5317) - ld a, $0 - jp Function5407 +Movement_slow_slide_step_down: + ld a, STEP_SLOW << 2 | DOWN + jp SlideStep -Function531c: ; 531c (1:531c) - ld a, $1 - jp Function5407 +Movement_slow_slide_step_up: + ld a, STEP_SLOW << 2 | UP + jp SlideStep -Function5321: ; 5321 (1:5321) - ld a, $2 - jp Function5407 +Movement_slow_slide_step_left: + ld a, STEP_SLOW << 2 | LEFT + jp SlideStep -Function5326: ; 5326 (1:5326) - ld a, $3 - jp Function5407 +Movement_slow_slide_step_right: + ld a, STEP_SLOW << 2 | RIGHT + jp SlideStep -Function532b: ; 532b (1:532b) - ld a, $4 - jp Function5407 +Movement_slide_step_down: + ld a, STEP_WALK << 2 | DOWN + jp SlideStep -Function5330: ; 5330 (1:5330) - ld a, $5 - jp Function5407 +Movement_slide_step_up: + ld a, STEP_WALK << 2 | UP + jp SlideStep -Function5335: ; 5335 (1:5335) - ld a, $6 - jp Function5407 +Movement_slide_step_left: + ld a, STEP_WALK << 2 | LEFT + jp SlideStep -Function533a: ; 533a (1:533a) - ld a, $7 - jp Function5407 +Movement_slide_step_right: + ld a, STEP_WALK << 2 | RIGHT + jp SlideStep -Function533f: ; 533f (1:533f) - ld a, $8 - jp Function5407 +Movement_fast_slide_step_down: + ld a, STEP_BIKE << 2 | DOWN + jp SlideStep -Function5344: ; 5344 (1:5344) - ld a, $9 - jp Function5407 +Movement_fast_slide_step_up: + ld a, STEP_BIKE << 2 | UP + jp SlideStep -Function5349: ; 5349 (1:5349) - ld a, $a - jp Function5407 +Movement_fast_slide_step_left: + ld a, STEP_BIKE << 2 | LEFT + jp SlideStep -Function534e: ; 534e (1:534e) - ld a, $b - jp Function5407 +Movement_fast_slide_step_right: + ld a, STEP_BIKE << 2 | RIGHT + jp SlideStep -Function5353: ; 5353 (1:5353) - ld a, $0 - jp Function5429 +Movement_slow_jump_step_down: + ld a, STEP_SLOW << 2 | DOWN + jp JumpStep -Function5358: ; 5358 (1:5358) - ld a, $1 - jp Function5429 +Movement_slow_jump_step_up: + ld a, STEP_SLOW << 2 | UP + jp JumpStep -Function535d: ; 535d (1:535d) - ld a, $2 - jp Function5429 +Movement_slow_jump_step_left: + ld a, STEP_SLOW << 2 | LEFT + jp JumpStep -Function5362: ; 5362 (1:5362) - ld a, $3 - jp Function5429 +Movement_slow_jump_step_right: + ld a, STEP_SLOW << 2 | RIGHT + jp JumpStep -Function5367: ; 5367 (1:5367) - ld a, $4 - jp Function5429 +Movement_jump_step_down: + ld a, STEP_WALK << 2 | DOWN + jp JumpStep -Function536c: ; 536c (1:536c) - ld a, $5 - jp Function5429 +Movement_jump_step_up: + ld a, STEP_WALK << 2 | UP + jp JumpStep -Function5371: ; 5371 (1:5371) - ld a, $6 - jp Function5429 +Movement_jump_step_left: + ld a, STEP_WALK << 2 | LEFT + jp JumpStep -Function5376: ; 5376 (1:5376) - ld a, $7 - jp Function5429 +Movement_jump_step_right: + ld a, STEP_WALK << 2 | RIGHT + jp JumpStep -Function537b: ; 537b (1:537b) - ld a, $8 - jp Function5429 +Movement_fast_jump_step_down: + ld a, STEP_BIKE << 2 | DOWN + jp JumpStep -Function5380: ; 5380 (1:5380) - ld a, $9 - jp Function5429 +Movement_fast_jump_step_up: + ld a, STEP_BIKE << 2 | UP + jp JumpStep -Function5385: ; 5385 (1:5385) - ld a, $a - jp Function5429 +Movement_fast_jump_step_left: + ld a, STEP_BIKE << 2 | LEFT + jp JumpStep -Function538a: ; 538a (1:538a) - ld a, $b - jp Function5429 +Movement_fast_jump_step_right: + ld a, STEP_BIKE << 2 | RIGHT + jp JumpStep -Function538f: ; 538f (1:538f) - ld a, $0 - jr asm_539f +Movement_turn_step_down: + ld a, OW_DOWN + jr TurnStep -Function5393: ; 5393 (1:5393) - ld a, $4 - jr asm_539f +Movement_turn_step_up: + ld a, OW_UP + jr TurnStep -Function5397: ; 5397 (1:5397) - ld a, $8 - jr asm_539f +Movement_turn_step_left: + ld a, OW_LEFT + jr TurnStep -Function539b: ; 539b (1:539b) - ld a, $c - jr asm_539f +Movement_turn_step_right: + ld a, OW_RIGHT + jr TurnStep -asm_539f - ld hl, $1d +TurnStep: + ld hl, OBJECT_1D ; new facing add hl, bc ld [hl], a - ld hl, $b + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $2 - ld hl, $9 + ld [hl], OBJECT_ACTION_STEP + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $a + ld [hl], STEP_TYPE_HALF_STEP ret -Function53b1: ; 53b1 (1:53b1) +NormalStep: call InitStep - call UpdateGrassPriority - ld hl, $b + call UpdateTallGrassFlags + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $2 - ld hl, $e + ld [hl], OBJECT_ACTION_STEP + + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] call CheckSuperTallGrassTile - jr z, .asm_53cc + jr z, .shake_grass + call CheckGrassTile - jr c, .asm_53cf -.asm_53cc - call Function54f5 -.asm_53cf + jr c, .skip_grass + +.shake_grass + call ShakeGrass + +.skip_grass ld hl, wCenteredObject - ldh a, [hConnectionStripLength] + ldh a, [hMapObjectIndexBuffer] cp [hl] - jr z, .asm_53de - ld hl, $9 + jr z, .player + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $2 + ld [hl], STEP_TYPE_NPC_WALK ret -.asm_53de - ld hl, $9 +.player + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $6 + ld [hl], STEP_TYPE_PLAYER_WALK ret -Function53e5: ; 53e5 (1:53e5) +TurningStep: call InitStep - call UpdateGrassPriority - ld hl, $b + call UpdateTallGrassFlags + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $4 + ld [hl], OBJECT_ACTION_SPIN + ld hl, wCenteredObject ldh a, [hMapObjectIndexBuffer] cp [hl] - jr z, .asm_5400 - ld hl, $9 + jr z, .player + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $2 + ld [hl], STEP_TYPE_NPC_WALK ret -.asm_5400 - ld hl, $9 +.player + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $6 + ld [hl], STEP_TYPE_PLAYER_WALK ret -Function5407: ; 5407 (1:5407) +SlideStep: call InitStep - call UpdateGrassPriority - ld hl, $b + call UpdateTallGrassFlags + + ld hl, OBJECT_ACTION add hl, bc - ld [hl], $1 + ld [hl], OBJECT_ACTION_STAND + ld hl, wCenteredObject - ldh a, [hConnectionStripLength] + ldh a, [hMapObjectIndexBuffer] cp [hl] - jr z, .asm_5422 - ld hl, $9 + jr z, .player + + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_NPC_WALK + ret + +.player + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_PLAYER_WALK + ret + +JumpStep: + call InitStep + ld hl, OBJECT_1F + add hl, bc + ld [hl], $0 + + ld hl, OBJECT_FLAGS2 + add hl, bc + res OVERHEAD_F, [hl] + + ld hl, OBJECT_ACTION + add hl, bc + ld [hl], OBJECT_ACTION_STEP + call SpawnShadow + ld hl, wCenteredObject + ldh a, [hMapObjectIndexBuffer] + cp [hl] + jr z, .player + + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $2 + ld [hl], STEP_TYPE_NPC_JUMP ret -.asm_5422 - ld hl, $9 +.player + ld hl, OBJECT_STEP_TYPE add hl, bc - ld [hl], $6 + ld [hl], STEP_TYPE_PLAYER_JUMP ret diff --git a/engine/overworld/npc_movement.asm b/engine/overworld/npc_movement.asm index 84235570..01d49d21 100755 --- a/engine/overworld/npc_movement.asm +++ b/engine/overworld/npc_movement.asm @@ -1,102 +1,110 @@ -CheckNPCMovementPermissions: ; 6fa0 (1:6fa0) - ld hl, $6 +CanObjectMoveInDirection: + ld hl, OBJECT_PALETTE add hl, bc - bit 5, [hl] - jr z, .asm_6fb8 - ld hl, $4 + bit SWIMMING_F, [hl] + jr z, .not_swimming + + ld hl, OBJECT_FLAGS1 add hl, bc - bit 4, [hl] + bit NOCLIP_TILES_F, [hl] ; lost, uncomment next line to fix + ; jr nz, .noclip_tiles push hl push bc - call Function700b + call WillObjectBumpIntoLand pop bc pop hl ret c - jr .asm_6fc8 + jr .continue -.asm_6fb8 - ld hl, $4 +.not_swimming + ld hl, OBJECT_FLAGS1 add hl, bc - bit 4, [hl] - jr nz, .asm_6fc8 + bit NOCLIP_TILES_F, [hl] + jr nz, .noclip_tiles push hl push bc - call Function6fe6 + call WillObjectBumpIntoWater pop bc pop hl ret c -.asm_6fc8 - bit 6, [hl] - jr nz, .asm_6fd4 + +.noclip_tiles +.continue + bit NOCLIP_OBJS_F, [hl] + jr nz, .noclip_objs + push hl push bc - call WillPersonBumpIntoSomeoneElse + call WillObjectBumpIntoSomeoneElse pop bc pop hl ret c -.asm_6fd4 - bit 5, [hl] - jr nz, .asm_6fe4 + +.noclip_objs + bit MOVE_ANYWHERE_F, [hl] + jr nz, .move_anywhere push hl - call HasPersonReachedMovementLimit + call HasObjectReachedMovementLimit pop hl ret c + push hl - call IsPersonMovingOffEdgeOfScreen + call IsObjectMovingOffEdgeOfScreen pop hl ret c -.asm_6fe4 + +.move_anywhere and a ret -Function6fe6: ; 6fe6 (1:6fe6) +WillObjectBumpIntoWater: call Function703e ret c - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] - ld hl, $6 + ld hl, OBJECT_PALETTE add hl, bc - bit 7, [hl] + bit OAM_PRIORITY, [hl] jp nz, Function7080 - ld hl, $e + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] ld d, a call GetTileCollision - and a - jr z, Function701d + and a ; LAND_TILE + jr z, WillObjectBumpIntoTile scf ret -Function700b: ; 700b (1:700b) +WillObjectBumpIntoLand: call Function703e ret c - ld hl, $e + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] call GetTileCollision - cp $1 - jr z, Function701d + cp WATER_TILE + jr z, WillObjectBumpIntoTile scf ret -Function701d - ld hl, $e +WillObjectBumpIntoTile: + ld hl, OBJECT_NEXT_TILE add hl, bc ld a, [hl] call Function705e ret nc push af - ld hl, $7 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] - and $3 + maskbits NUM_DIRECTIONS ld e, a - ld d, $0 + ld d, 0 ld hl, .data_703a add hl, de pop af @@ -106,20 +114,23 @@ Function701d ret .data_703a - db 1 << DOWN, 1 << UP, 1 << RIGHT, 1 << LEFT + db DOWN_MASK ; DOWN + db UP_MASK ; UP + db RIGHT_MASK ; LEFT + db LEFT_MASK ; RIGHT -Function703e: ; 703e (1:703e) - ld hl, $f +Function703e: + ld hl, OBJECT_STANDING_TILE add hl, bc ld a, [hl] call Function705e ret nc push af - ld hl, $7 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc - and $3 + maskbits NUM_DIRECTIONS ld e, a - ld d, $0 + ld d, 0 ld hl, .data_705a add hl, de pop af @@ -129,23 +140,26 @@ Function703e: ; 703e (1:703e) ret .data_705a - db 1 << UP, 1 << DOWN, 1 << LEFT, 1 << RIGHT + db UP_MASK ; DOWN + db DOWN_MASK ; UP + db LEFT_MASK ; LEFT + db RIGHT_MASK ; RIGHT -Function705e: ; 705e (1:705e) +Function705e: ld d, a and $f0 - cp $b0 - jr z, .asm_706b - cp $c0 - jr z, .asm_706b + cp HI_NYBBLE_SIDE_WALLS + jr z, .continue + cp HI_NYBBLE_SIDE_BUOYS + jr z, .continue xor a ret -.asm_706b +.continue ld a, d - and $7 + and 7 ld e, a - ld d, $0 + ld d, 0 ld hl, .data_7078 add hl, de ld a, [hl] @@ -153,216 +167,234 @@ Function705e: ; 705e (1:705e) ret .data_7078 - db 8, 4, 1, 2 - db 10, 6, 9, 5 - -Function7080: ; 7080 (1:7080) - ld hl, $7 + db RIGHT_MASK ; COLL_RIGHT_WALL/BUOY + db LEFT_MASK ; COLL_LEFT_WALL/BUOY + db DOWN_MASK ; COLL_UP_WALL/BUOY + db UP_MASK ; COLL_DOWN_WALL/BUOY + db UP_MASK | RIGHT_MASK ; COLL_DOWN_RIGHT_WALL/BUOY + db UP_MASK | LEFT_MASK ; COLL_DOWN_LEFT_WALL/BUOY + db DOWN_MASK | RIGHT_MASK ; COLL_UP_RIGHT_WALL/BUOY + db DOWN_MASK | LEFT_MASK ; COLL_UP_LEFT_WALL/BUOY + +Function7080: + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] - and $3 - jr z, .asm_7091 + maskbits NUM_DIRECTIONS + jr z, .down dec a - jr z, .asm_7096 + jr z, .up dec a - jr z, .asm_709a - jr .asm_709e + jr z, .left + jr .right -.asm_7091 +.down inc e push de inc d - jr .asm_70a1 + jr .continue -.asm_7096 +.up push de inc d - jr .asm_70a1 + jr .continue -.asm_709a +.left push de inc e - jr .asm_70a1 + jr .continue -.asm_709e +.right inc d push de inc e -.asm_70a1 + +.continue call GetCoordTile call GetTileCollision pop de - and a - jr nz, .asm_70b6 + and a ; LAND_TILE + jr nz, .not_land call GetCoordTile call GetTileCollision - and a - jr nz, .asm_70b6 + and a ; LAND_TILE + jr nz, .not_land xor a ret -.asm_70b6 +.not_land scf ret -CheckFacingObject: +CheckFacingObject:: call GetFacingTileCoord + +; Double the distance for counter tiles. call CheckCounterTile jr nz, .asm_70d0 + ld a, [wPlayerStandingMapX] sub d cpl inc a add d ld d, a + ld a, [wPlayerStandingMapY] sub e cpl inc a add e ld e, a + .asm_70d0 - ld bc, wObjectStructs - ld a, $0 + ld bc, wObjectStructs ; redundant + ld a, 0 ldh [hMapObjectIndexBuffer], a - call Function7120 + call IsNPCAtCoord ret nc - ld hl, $7 + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] - cp $ff - jr z, .asm_70e6 + cp STANDING + jr z, .standing xor a ret -.asm_70e6 +.standing scf ret -WillPersonBumpIntoSomeoneElse: ; 70e8 (1:70e8) - ld hl, $10 +WillObjectBumpIntoSomeoneElse: + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] - jr Function7120 + jr IsNPCAtCoord -Function70f4: +Unreferenced_Function70f4: ldh a, [hMapObjectIndexBuffer] call GetObjectStruct - call Function7100 - call Function7120 + call .CheckWillBeFacingNPC + call IsNPCAtCoord ret -Function7100: ; 7100 (1:7100) - ld hl, $10 +.CheckWillBeFacingNPC: + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] call GetSpriteDirection and a - jr z, .asm_711a - cp $4 - jr z, .asm_711c - cp $8 - jr z, .asm_711e + jr z, .down + cp OW_UP + jr z, .up + cp OW_LEFT + jr z, .left inc d ret -.asm_711a +.down inc e ret -.asm_711c +.up dec e ret -.asm_711e +.left dec d ret -Function7120: ; 7120 (1:7120) - ld bc, wPlayerStruct +IsNPCAtCoord: + ld bc, wObjectStructs xor a -.asm_7124 +.loop ldh [hObjectStructIndexBuffer], a call DoesObjectHaveASprite - jr z, .asm_7172 - ld hl, $4 + jr z, .next + + ld hl, OBJECT_FLAGS1 add hl, bc bit 7, [hl] - jr nz, .asm_7172 - ld hl, $6 + jr nz, .next + + ld hl, OBJECT_PALETTE add hl, bc - bit 7, [hl] - jr z, .asm_7142 + bit BIG_OBJECT_F, [hl] + jr z, .got + call Function7250 - jr nc, .asm_715a - jr .asm_7152 + jr nc, .ok + jr .ok2 -.asm_7142 - ld hl, $10 +.got + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] cp d - jr nz, .asm_715a - ld hl, $11 + jr nz, .ok + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, [hl] cp e - jr nz, .asm_715a -.asm_7152 + jr nz, .ok + +.ok2 ldh a, [hMapObjectIndexBuffer] ld l, a - ldh a, [hConnectedMapWidth] + ldh a, [hObjectStructIndexBuffer] cp l - jr nz, .asm_7181 -.asm_715a - ld hl, $12 + jr nz, .setcarry + +.ok + ld hl, OBJECT_MAP_X add hl, bc ld a, [hl] cp d - jr nz, .asm_7172 - ld hl, $13 + jr nz, .next + ld hl, OBJECT_MAP_Y add hl, bc ld a, [hl] cp e - jr nz, .asm_7172 - ldh a, [hConnectionStripLength] + jr nz, .next + ldh a, [hMapObjectIndexBuffer] ld l, a ldh a, [hObjectStructIndexBuffer] cp l - jr nz, .asm_7181 -.asm_7172 - ld hl, $28 + jr nz, .setcarry + +.next + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l - ldh a, [hConnectedMapWidth] + ldh a, [hObjectStructIndexBuffer] inc a - cp $d - jr nz, .asm_7124 + cp NUM_OBJECT_STRUCTS + jr nz, .loop and a ret -.asm_7181 +.setcarry scf ret -HasPersonReachedMovementLimit: ; 7183 (1:7183) - ld hl, $16 +HasObjectReachedMovementLimit: + ld hl, OBJECT_RADIUS add hl, bc ld a, [hl] and a - jr z, .asm_71c8 + jr z, .nope and $f - jr z, .asm_71a6 + jr z, .check_y ld e, a ld d, a - ld hl, $14 + ld hl, OBJECT_INIT_X add hl, bc ld a, [hl] sub d @@ -370,23 +402,24 @@ HasPersonReachedMovementLimit: ; 7183 (1:7183) ld a, [hl] add e ld e, a - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] cp d - jr z, .asm_71ca + jr z, .yes cp e - jr z, .asm_71ca -.asm_71a6 - ld hl, $16 + jr z, .yes + +.check_y + ld hl, OBJECT_RADIUS add hl, bc ld a, [hl] swap a and $f - jr z, .asm_71c8 + jr z, .nope ld e, a ld d, a - ld hl, $15 + ld hl, OBJECT_INIT_Y add hl, bc ld a, [hl] sub d @@ -394,132 +427,135 @@ HasPersonReachedMovementLimit: ; 7183 (1:7183) ld a, [hl] add e ld e, a - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, [hl] cp d - jr z, .asm_71ca + jr z, .yes cp e - jr z, .asm_71ca -.asm_71c8 + jr z, .yes + +.nope xor a ret -.asm_71ca +.yes scf ret -IsPersonMovingOffEdgeOfScreen: ; 71cc (1:71cc) - ld hl, $10 +IsObjectMovingOffEdgeOfScreen: + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [wXCoord] cp [hl] - jr z, .asm_71dd - jr nc, .asm_71f0 + jr z, .check_y + jr nc, .yes add $9 cp [hl] - jr c, .asm_71f0 -.asm_71dd - ld hl, $11 + jr c, .yes + +.check_y + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, [wYCoord] cp [hl] - jr z, .asm_71ee - jr nc, .asm_71f0 + jr z, .nope + jr nc, .yes add $8 cp [hl] - jr c, .asm_71f0 -.asm_71ee + jr c, .yes + +.nope and a ret -.asm_71f0 +.yes scf ret -Function71f2 +Unreferenced_Function71f2: ld a, [wPlayerStandingMapX] ld d, a ld a, [wPlayerStandingMapY] ld e, a ld bc, wObjectStructs xor a -.asm_71fe - ldh [hConnectedMapWidth], a +.loop + ldh [hObjectStructIndexBuffer], a call DoesObjectHaveASprite - jr z, .asm_723f - ld hl, $3 + jr z, .next + ld hl, OBJECT_MOVEMENTTYPE add hl, bc ld a, [hl] - cp $15 - jr nz, .asm_7215 + cp SPRITEMOVEDATA_BIGDOLLSYM + jr nz, .not_snorlax call Function7250 - jr c, .asm_724e - jr .asm_723f + jr c, .yes + jr .next -.asm_7215 - ld hl, $11 +.not_snorlax + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, [hl] cp e - jr nz, .asm_722d - ld hl, $10 + jr nz, .check_current_coords + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] cp d - jr nz, .asm_722d + jr nz, .check_current_coords ldh a, [hObjectStructIndexBuffer] - cp $0 - jr z, .asm_723f - jr .asm_724e + cp PLAYER_OBJECT + jr z, .next + jr .yes -.asm_722d - ld hl, $13 +.check_current_coords + ld hl, OBJECT_MAP_Y add hl, bc ld a, [hl] cp e - jr nz, .asm_723f - ld hl, $12 + jr nz, .next + ld hl, OBJECT_MAP_X add hl, bc ld a, [hl] cp d - jr nz, .asm_723f - jr .asm_724e + jr nz, .next + jr .yes -.asm_723f - ld hl, $28 +.next + ld hl, OBJECT_LENGTH add hl, bc ld b, h ld c, l - ldh a, [hConnectedMapWidth] + ldh a, [hObjectStructIndexBuffer] inc a - cp $d - jr nz, .asm_71fe + cp NUM_OBJECT_STRUCTS + jr nz, .loop xor a ret -.asm_724e +.yes scf ret -Function7250: ; 7250 (1:7250) - ld hl, $10 +Function7250: + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, d sub [hl] - jr c, .asm_726a + jr c, .nope cp $2 - jr nc, .asm_726a - ld hl, $11 + jr nc, .nope + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, e sub [hl] - jr c, .asm_726a + jr c, .nope cp $2 - jr nc, .asm_726a + jr nc, .nope scf ret -.asm_726a +.nope and a ret diff --git a/engine/overworld/overworld.asm b/engine/overworld/overworld.asm new file mode 100644 index 00000000..05b15ea9 --- /dev/null +++ b/engine/overworld/overworld.asm @@ -0,0 +1,494 @@ +_ReplaceChrisSprite:: + call GetChrisSprite + ld a, [wUsedSprites] + ld c, a + ld a, [wUsedSprites + 1] + ld b, a + call GetUsedSprite + ret + +_RefreshSprites:: + ld hl, wSpriteFlags + ld a, [hl] + push af + res 7, [hl] + set 6, [hl] + call LoadUsedSpritesGFX + pop af + ld [wSpriteFlags], a + ret + +_ClearSprites:: + ld hl, wSpriteFlags + ld a, [hl] + push af + set 7, [hl] + res 6, [hl] + call LoadUsedSpritesGFX + pop af + ld [wSpriteFlags], a + ret + +RefreshSprites:: + call .Refresh + call LoadUsedSpritesGFX + ret + +.Refresh: + xor a + ld bc, SPRITE_GFX_LIST_CAPACITY * 2 + ld hl, wUsedSprites + call ByteFill + call GetChrisSprite + call AddMapSprites + ret + +GetChrisSprite: + ld a, [wPlayerState] + ld c, a +; Get Chris's sprite. + ld hl, ChrisStateSprites +.loop + ld a, [hli] + cp c + jr z, .good + inc hl + cp -1 + jr nz, .loop + +; Any player state not in the array defaults to Chris's sprite. + xor a ; ld a, PLAYER_NORMAL + ld [wPlayerState], a + ld a, SPRITE_CHRIS + jr .finish + +.good + ld a, [hl] + +.finish + ld [wUsedSprites + 0], a + ld [wPlayerSprite], a + ld [wPlayerObjectSprite], a + ret + +INCLUDE "data/sprites/player_sprites.asm" + +AddMapSprites: + call GetMapEnvironment + call CheckOutdoorMap + jr z, .outdoor + call AddIndoorSprites + ret + +.outdoor + call AddOutdoorSprites + ret + +AddIndoorSprites: + ld hl, wMap2ObjectSprite + ld a, 2 +.loop + push af + ld a, [hl] + call AddSpriteGFX + ld de, MAPOBJECT_LENGTH + add hl, de + pop af + inc a + cp NUM_OBJECTS + jr nz, .loop + ret + +AddOutdoorSprites: + ld a, [wMapGroup] + dec a + ld c, a + ld b, 0 + ld hl, OutdoorSprites + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld c, MAX_OUTDOOR_SPRITES +.loop + push bc + ld a, [hli] + call AddSpriteGFX + pop bc + dec c + jr nz, .loop + + ld a, [wUnusedD05A] + ld c, a + ret + +AddSpriteGFX: + and a + ret z + ld c, a + call _DoesSpriteHaveFacings + jr nc, .nope + ld de, wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 2) * 2 + ld b, 2 + call .Loop + jr nc, .ok +.nope + ld de, wUsedSprites + 2 + ld b, SPRITE_GFX_LIST_CAPACITY - 3 + call .Loop + jr .ok +.ok: + ret + +.Loop: + ld a, [de] + and a + jr z, .new + cp c + jr z, .exists + inc de + inc de + dec b + jr nz, .Loop + scf + ret +.new: + ld a, c + ld [de], a + xor a + ret +.exists: + xor a + ret + +LoadUsedSpritesGFX: + ld a, MAPCALLBACK_SPRITES + call RunMapCallback + call GetUsedSprites + ret c + + call _LoadMiscTiles + call LoadMiscTiles + ret + +GetUsedSprites: + xor a + ldh [hUsedSpriteTile], a + ld hl, wUsedSprites + ld a, SPRITE_GFX_LIST_CAPACITY - 2 + +.loop + push af + ld a, [hli] + ldh [hUsedSpriteIndex], a + and a + jr z, .dont_set + + call GetSprite + push hl + push bc + ldh a, [hUsedSpriteTile] + call CopyToVram + pop bc + pop hl + ldh a, [hUsedSpriteTile] + ld [hl], a + add c + ldh [hUsedSpriteTile], a + cp $80 + jr nc, .done + +.dont_set + inc hl + pop af + dec a + jr nz, .loop + + xor a + ret + +.done + pop af + scf + ret + +_LoadMiscTiles: + ld a, [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 2) * 2] + and a + jr z, .asm_14274 + + call GetSprite + ld hl, vTiles0 tile $78 + call Get2bpp + +.asm_14274 + ld a, $78 + ld [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 2) * 2 + 1], a + ld a, [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 1) * 2] + and a + jr z, .asm_14288 + + call GetSprite + ld hl, vTiles0 tile $7c + call Get2bpp + +.asm_14288 + ld a, $7c + ld [wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 1) * 2 + 1], a + ret + +LoadMiscTiles: + ld a, [wSpriteFlags] + bit 6, a + ret nz + + ld c, EMOTE_SHADOW + farcall LoadEmote + call GetMapEnvironment + call CheckOutdoorMap + ld c, EMOTE_GRASS_RUSTLE + jr z, .outdoor + ld c, EMOTE_BOULDER_DUST +.outdoor + farcall LoadEmote + ret + +GetSprite: + call GetMonSprite + ret c + + push hl + ld hl, OverworldSprites + SPRITEDATA_ADDR + dec a + ld c, a + ld b, 0 + ld a, NUM_SPRITEDATA_FIELDS + call AddNTimes + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + swap a + ld c, a + ld b, [hl] + pop hl + ret + +GetMonSprite: +; Return carry if a monster sprite was loaded. + + cp SPRITE_POKEMON + jr c, .Normal + cp SPRITE_DAY_CARE_MON_1 + jr z, .BreedMon1 + cp SPRITE_DAY_CARE_MON_2 + jr z, .BreedMon2 + cp SPRITE_VARS + jr nc, .Variable + jr .Icon + +.Normal: + and a + ret + +.Icon: + push hl + sub SPRITE_POKEMON + ld e, a + ld d, 0 + ld hl, SpriteMons + add hl, de + ld a, [hl] + pop hl + jr .Mon + +.BreedMon1 + ld a, [wBreedMon1Species] + jr .Mon + +.BreedMon2 + ld a, [wBreedMon2Species] + +.Mon: + ld e, a + and a + jr z, .NoBreedmon + + push hl + farcall LoadOverworldMonIcon + pop hl + + scf + ret + +.Variable: + push hl + sub SPRITE_VARS + ld e, a + ld d, 0 + ld hl, wVariableSprites + add hl, de + ld a, [hl] + pop hl + and a + jp nz, GetMonSprite + +.NoBreedmon: + ld a, 1 + and a + ret + +_DoesSpriteHaveFacings:: +; Checks to see whether we can apply a facing to a sprite. +; Returns carry unless the sprite is a Pokemon or a Still Sprite. + cp SPRITE_POKEMON + jr nc, .only_down + + push hl + push bc + ld hl, OverworldSprites + SPRITEDATA_TYPE + dec a + ld c, a + ld b, 0 + ld a, NUM_SPRITEDATA_FIELDS + call AddNTimes + ld a, [hl] + pop bc + pop hl + cp STILL_SPRITE + jr nz, .only_down + scf + ret + +.only_down + and a + ret + +_GetSpritePalette:: + ld a, c + call GetMonSprite + jr c, .is_pokemon + + ld hl, OverworldSprites + SPRITEDATA_PALETTE + dec a + ld c, a + ld b, 0 + ld a, NUM_SPRITEDATA_FIELDS + call AddNTimes + ld c, [hl] + ret + +.is_pokemon + xor a + ld c, a + ret + +CopyToVram: + ld l, a + ld h, 0 +rept 4 + add hl, hl +endr + ld a, l + add LOW(vTiles0) + ld l, a + ld a, h + adc HIGH(vTiles0) + ld h, a + push hl + push de + push bc + ld a, [wSpriteFlags] + bit 7, a + jr nz, .skip + call Get2bpp + +.skip: + pop bc + ld l, c + ld h, 0 +rept 4 + add hl, hl +endr + pop de + add hl, de + ld e, l + ld d, h + pop hl + ld a, h + add HIGH(vTiles1 - vTiles0) + ld h, a + ldh a, [hUsedSpriteIndex] + call _DoesSpriteHaveFacings + jr c, .done + + ld a, [wSpriteFlags] + bit 6, a + jr nz, .done + + call Get2bpp + +.done: + ret + +Unreferenced_Function1438a: + ld a, c + jr GetUsedSprite + + ld a, c + ld b, 0 + jr GetUsedSprite + + ld a, c + ld b, SPRITE_GFX_LIST_CAPACITY + jr GetUsedSprite + +GetUsedSprite: + push bc + ld a, c + ldh [hUsedSpriteIndex], a + call GetSprite + pop af + call CopyToVram + ret + +LoadEmote:: +; Get the address of the pointer to emote c. + ld a, c + ld bc, 6 ; sizeof(emote) + ld hl, Emotes + call AddNTimes +; Load the emote address into de + ld e, [hl] + inc hl + ld d, [hl] +; load the length of the emote (in tiles) into c + inc hl + ld c, [hl] + swap c +; load the emote pointer bank into b + inc hl + ld b, [hl] +; load the VRAM destination into hl + inc hl + ld a, [hli] + ld h, [hl] + ld l, a +; if the emote has a length of 0, do not proceed (error handling) + ld a, c + and a + ret z + call Get2bpp + ret + +INCLUDE "data/sprites/emotes.asm" + +INCLUDE "gfx/emotes.asm" + +INCLUDE "data/sprites/sprite_mons.asm" + +INCLUDE "data/maps/outdoor_sprites.asm" + +INCLUDE "data/sprites/sprites.asm" diff --git a/engine/overworld/player_movement.asm b/engine/overworld/player_movement.asm index 3fa38cc0..bdf23ec4 100755 --- a/engine/overworld/player_movement.asm +++ b/engine/overworld/player_movement.asm @@ -1,421 +1,475 @@ -DoPlayerMovement:: ; 10000 (4:4000) - call Function10017 +DoPlayerMovement:: + + call .GetDPad ld a, movement_step_sleep - ld [wcf2d], a + ld [wMovementAnimation], a xor a - ld [wcf2c], a - call Function1002d + ld [wWalkingIntoEdgeWarp], a + call .TranslateIntoMovement ld c, a - ld a, [wcf2d] - ld [wce87], a + ld a, [wMovementAnimation] + ld [wPlayerNextMovement], a ret -Function10017: ; 10017 (4:4017) +.GetDPad: + ldh a, [hJoyDown] - ld [wcf29], a - CheckFlagHL ENGINE_DOWNHILL + ld [wCurInput], a + +; Standing downhill instead moves down. + + ld hl, wBikeFlags + bit BIKEFLAGS_DOWNHILL_F, [hl] ret z + ld c, a - and $f0 + and D_PAD ret nz + ld a, c - or $80 - ld [wcf29], a + or D_DOWN + ld [wCurInput], a ret -Function1002d: ; 1002d (4:402d) +.TranslateIntoMovement: ld a, [wPlayerState] cp PLAYER_NORMAL - jr z, .asm_10044 + jr z, .Normal cp PLAYER_SURF - jr z, .asm_10060 + jr z, .Surf cp PLAYER_SURF_PIKA - jr z, .asm_10060 + jr z, .Surf cp PLAYER_BIKE - jr z, .asm_10044 - cp PLAYER_SLIP - jr z, .asm_10074 -.asm_10044 - call Function102cb - call Function102ec - call Function100b7 + jr z, .Normal + cp PLAYER_SKATE + jr z, .Ice + +.Normal: + call .CheckForced + call .GetAction + call .CheckTile ret c - call Function10147 + call .CheckTurning ret c - call Function1016b + call .TryStep ret c - call Function101f3 + call .TryJump ret c - call Function10226 + call .CheckWarp ret c - jr .asm_1009d + jr .NotMoving -.asm_10060 - call Function102cb - call Function102ec - call Function100b7 +.Surf: + call .CheckForced + call .GetAction + call .CheckTile ret c - call Function10147 + call .CheckTurning ret c - call Function101c0 + call .TrySurf ret c - jr .asm_1009d + jr .NotMoving -.asm_10074 - call Function102cb - call Function102ec - call Function100b7 +.Ice: + call .CheckForced + call .GetAction + call .CheckTile ret c - call Function10147 + call .CheckTurning ret c - call Function1016b + call .TryStep ret c - call Function101f3 + call .TryJump ret c - call Function10226 + call .CheckWarp ret c - ld a, [wcf2e] - cp $ff - jr z, .asm_10098 - call Function103ee -.asm_10098 - call Function102b3 + ld a, [wWalkingDirection] + cp STANDING + jr z, .HitWall + call .BumpSound +.HitWall: + call .StandInPlace xor a ret -.asm_1009d - ld a, [wcf2e] - cp $ff - jr z, .asm_100b2 - ld a, [wTempTrainer] +.NotMoving: + ld a, [wWalkingDirection] + cp STANDING + jr z, .Standing + +; Walking into an edge warp won't bump. + ld a, [wWalkingIntoEdgeWarp] and a - jr nz, .asm_100ad - call Function103ee -.asm_100ad - call Function102bf + jr nz, .CantMove + call .BumpSound +.CantMove: + call ._WalkInPlace xor a ret -.asm_100b2 - call Function102b3 +.Standing: + call .StandInPlace xor a ret -Function100b7: ; 100b7 (4:40b7) +.CheckTile: +; Tiles such as waterfalls and warps move the player +; in a given direction, overriding input. + ld a, [wPlayerStandingTile] ld c, a call CheckWhirlpoolTile - jr c, .asm_100c4 - ld a, $3 + jr c, .not_whirlpool + ld a, PLAYERMOVEMENT_FORCE_TURN scf ret -.asm_100c4 +.not_whirlpool and $f0 - cp $30 - jr z, .asm_100d8 - cp $40 - jr z, .asm_100ec - cp $50 - jr z, .asm_10108 - cp $70 - jr z, .asm_10124 - jr .asm_1013c - -.asm_100d8 + cp HI_NYBBLE_CURRENT + jr z, .water + cp HI_NYBBLE_WALK + jr z, .land1 + cp HI_NYBBLE_WALK_ALT + jr z, .land2 + cp HI_NYBBLE_WARPS + jr z, .warps + jr .no_walk + +.water ld a, c - and $3 + maskbits NUM_DIRECTIONS ld c, a - ld b, $0 + ld b, 0 ld hl, .water_table add hl, bc ld a, [hl] - ld [wcf2e], a - jr .asm_1013e + ld [wWalkingDirection], a + jr .continue_walk .water_table - db RIGHT - db LEFT - db UP - db DOWN + db RIGHT ; COLL_WATERFALL_RIGHT + db LEFT ; COLL_WATERFALL_LEFT + db UP ; COLL_WATERFALL_UP + db DOWN ; COLL_WATERFALL -.asm_100ec +.land1 ld a, c - and $7 + and 7 ld c, a - ld b, $0 + ld b, 0 ld hl, .land1_table add hl, bc ld a, [hl] - cp $ff - jr z, .asm_1013c - ld [wcf2e], a - jr .asm_1013e + cp STANDING + jr z, .no_walk + ld [wWalkingDirection], a + jr .continue_walk .land1_table - db STANDING - db RIGHT - db LEFT - db UP - db DOWN - db STANDING - db STANDING - db STANDING - -.asm_10108 + db STANDING ; COLL_BRAKE + db RIGHT ; COLL_WALK_RIGHT + db LEFT ; COLL_WALK_LEFT + db UP ; COLL_WALK_UP + db DOWN ; COLL_WALK_DOWN + db STANDING ; COLL_BRAKE_45 + db STANDING ; COLL_BRAKE_46 + db STANDING ; COLL_BRAKE_47 + +.land2 ld a, c - and $7 + and 7 ld c, a - ld b, $0 + ld b, 0 ld hl, .land2_table add hl, bc ld a, [hl] - cp $ff - jr z, .asm_1013c - ld [wcf2e], a - jr .asm_1013e + cp STANDING + jr z, .no_walk + ld [wWalkingDirection], a + jr .continue_walk .land2_table - db RIGHT - db LEFT - db UP - db DOWN - db STANDING - db STANDING - db STANDING - db STANDING - -.asm_10124 + db RIGHT ; COLL_WALK_RIGHT_ALT + db LEFT ; COLL_WALK_LEFT_ALT + db UP ; COLL_WALK_UP_ALT + db DOWN ; COLL_WALK_DOWN_ALT + db STANDING ; COLL_BRAKE_ALT + db STANDING ; COLL_BRAKE_55 + db STANDING ; COLL_BRAKE_56 + db STANDING ; COLL_BRAKE_57 + +.warps ld a, c - cp $71 - jr z, .asm_10135 - cp $79 - jr z, .asm_10135 - cp $7a - jr z, .asm_10135 - cp $7b - jr nz, .asm_1013c -.asm_10135 - ld a, $0 - ld [wcf2e], a - jr .asm_1013e - -.asm_1013c + cp COLL_DOOR + jr z, .down + cp COLL_DOOR_79 + jr z, .down + cp COLL_STAIRCASE + jr z, .down + cp COLL_CAVE + jr nz, .no_walk + +.down + ld a, DOWN + ld [wWalkingDirection], a + jr .continue_walk + +.no_walk xor a ret -.asm_1013e - ld a, $1 - call Function1025f - ld a, $5 +.continue_walk + ld a, STEP_WALK + call .DoStep + ld a, PLAYERMOVEMENT_CONTINUE scf ret -Function10147: ; 10147 (4:4147) - ld a, [wcf39] - cp $0 - jr nz, .asm_10169 - ld a, [wcf2e] - cp $ff - jr z, .asm_10169 +.CheckTurning: +; If the player is turning, change direction first. This also lets +; the player change facing without moving by tapping a direction. + + ld a, [wPlayerTurningDirection] + cp 0 + jr nz, .not_turning + ld a, [wWalkingDirection] + cp STANDING + jr z, .not_turning + ld e, a ld a, [wPlayerDirection] rrca rrca - and $3 + maskbits NUM_DIRECTIONS cp e - jr z, .asm_10169 - ld a, $5 - call Function1025f - ld a, $2 + jr z, .not_turning + + ld a, STEP_TURN + call .DoStep + ld a, PLAYERMOVEMENT_TURN scf ret -.asm_10169 +.not_turning xor a ret -Function1016b: ; 1016b (4:416b) +.TryStep: +; Surfing actually calls .TrySurf directly instead of passing through here. ld a, [wPlayerState] - cp $4 - jr z, Function101c0 - cp $8 - jr z, Function101c0 - call Function1039e - jr c, .asm_101be - call Function10341 + cp PLAYER_SURF + jr z, .TrySurf + cp PLAYER_SURF_PIKA + jr z, .TrySurf + + call .CheckLandPerms + jr c, .bump + + call .CheckNPC and a - jr z, .asm_101be - cp $2 - jr z, .asm_101be + jr z, .bump + cp 2 + jr z, .bump + ld a, [wPlayerStandingTile] call CheckIceTile - jr nc, .asm_101b5 - call Function103ca - jr nz, .asm_101ae + jr nc, .ice + +; Downhill riding is slower when not moving down. + call .BikeCheck + jr nz, .walk + ld hl, wBikeFlags - bit 2, [hl] - jr z, .asm_101a7 - ld a, [wcf2e] - cp $0 - jr z, .asm_101a7 - ld a, $1 - call Function1025f + bit BIKEFLAGS_DOWNHILL_F, [hl] + jr z, .fast + + ld a, [wWalkingDirection] + cp DOWN + jr z, .fast + + ld a, STEP_WALK + call .DoStep scf ret -.asm_101a7 - ld a, $2 - call Function1025f +.fast + ld a, STEP_BIKE + call .DoStep scf ret -.asm_101ae - ld a, $1 - call Function1025f +.walk + ld a, STEP_WALK + call .DoStep scf ret -.asm_101b5 - ld a, $4 - call Function1025f +.ice + ld a, STEP_ICE + call .DoStep scf ret +; unused xor a ret -.asm_101be +.bump xor a ret -Function101c0: ; 101c0 (4:41c0) - call Function103b4 - ld [wcf2b], a - jr c, .asm_101f1 - call Function10341 - ld [wcf2a], a +.TrySurf: + call .CheckSurfPerms + ld [wWalkingIntoLand], a + jr c, .surf_bump + + call .CheckNPC + ld [wWalkingIntoNPC], a and a - jr z, .asm_101f1 - cp $2 - jr z, .asm_101f1 - ld a, [wcf2b] + jr z, .surf_bump + cp 2 + jr z, .surf_bump + + ld a, [wWalkingIntoLand] and a - jr nz, .asm_101e2 - ld a, $1 - call Function1025f + jr nz, .ExitWater + + ld a, STEP_WALK + call .DoStep scf ret -.asm_101e2 - call Function103f9 +.ExitWater: + call .GetOutOfWater call PlayMapMusic - ld a, $1 - call Function1025f - ld a, $6 + ld a, STEP_WALK + call .DoStep + ld a, PLAYERMOVEMENT_EXIT_WATER scf ret -.asm_101f1 +.surf_bump xor a ret -Function101f3: ; 101f3 (4:41f3) +.TryJump: ld a, [wPlayerStandingTile] ld e, a and $f0 - cp $a0 - jr nz, .asm_1021c + cp HI_NYBBLE_LEDGES + jr nz, .DontJump + ld a, e - and $7 + and 7 ld e, a - ld d, $0 + ld d, 0 ld hl, .data_1021e add hl, de - ld a, [wcf2f] + ld a, [wFacingDirection] and [hl] - jr z, .asm_1021c - ld de, $16 + jr z, .DontJump + + ld de, SFX_JUMP_OVER_LEDGE call PlaySFX - ld a, $3 - call Function1025f - ld a, $7 + ld a, STEP_LEDGE + call .DoStep + ld a, PLAYERMOVEMENT_JUMP scf ret -.asm_1021c +.DontJump: xor a ret .data_1021e - db FACE_RIGHT - db FACE_LEFT - db FACE_UP - db FACE_DOWN - db FACE_RIGHT | FACE_DOWN - db FACE_DOWN | FACE_LEFT - db FACE_UP | FACE_RIGHT - db FACE_UP | FACE_LEFT - -Function10226: ; 10226 (4:4226) - ld a, [wcf2e] + db FACE_RIGHT ; COLL_HOP_RIGHT + db FACE_LEFT ; COLL_HOP_LEFT + db FACE_UP ; COLL_HOP_UP + db FACE_DOWN ; COLL_HOP_DOWN + db FACE_RIGHT | FACE_DOWN ; COLL_HOP_DOWN_RIGHT + db FACE_DOWN | FACE_LEFT ; COLL_HOP_DOWN_LEFT + db FACE_UP | FACE_RIGHT ; COLL_HOP_UP_RIGHT + db FACE_UP | FACE_LEFT ; COLL_HOP_UP_LEFT + +.CheckWarp: +; Bug: Since no case is made for STANDING here, it will check +; [.edgewarps + $ff]. This resolves to $3e at $8035a. +; This causes wWalkingIntoEdgeWarp to be nonzero when standing on tile $3e, +; making bumps silent. + + ld a, [wWalkingDirection] + ; cp STANDING + ; jr z, .not_warp ld e, a - ld d, $0 - ld hl, .edge_warps + ld d, 0 + ld hl, .EdgeWarps add hl, de ld a, [wPlayerStandingTile] cp [hl] - jr nz, .asm_10259 - ld a, $1 - ld [wTempTrainer], a - ld a, [wcf2e] - cp $ff - jr z, .asm_10259 + jr nz, .not_warp + + ld a, TRUE + ld [wWalkingIntoEdgeWarp], a + ld a, [wWalkingDirection] + ; This is in the wrong place. + cp STANDING + jr z, .not_warp + ld e, a ld a, [wPlayerDirection] rrca rrca - and $3 + maskbits NUM_DIRECTIONS cp e - jr nz, .asm_10259 - call Function22a5 - jr nc, .asm_10259 - call Function102b3 + jr nz, .not_warp + call WarpCheck + jr nc, .not_warp + + call .StandInPlace scf - ld a, $1 + ld a, PLAYERMOVEMENT_WARP ret -.asm_10259 - xor a +.not_warp + xor a ; PLAYERMOVEMENT_NORMAL ret -.edge_warps - db $70, $78, $76, $7e +.EdgeWarps: + db COLL_WARP_CARPET_DOWN + db COLL_WARP_CARPET_UP + db COLL_WARP_CARPET_LEFT + db COLL_WARP_CARPET_RIGHT -Function1025f: ; 1025f (4:425f) +.DoStep: ld e, a - ld d, $0 + ld d, 0 ld hl, .Steps add hl, de add hl, de ld a, [hli] ld h, [hl] ld l, a - ld a, [wcf2e] + + ld a, [wWalkingDirection] ld e, a - cp $ff - jp z, Function102b3 + cp STANDING + jp z, .StandInPlace + add hl, de ld a, [hl] - ld [wcf2d], a - ld hl, $42af + ld [wMovementAnimation], a + + ld hl, .FinishFacing add hl, de ld a, [hl] - ld [wcf39], a - ld a, $4 + ld [wPlayerTurningDirection], a + + ld a, PLAYERMOVEMENT_FINISH ret .Steps: +; entries correspond to STEP_* constants dw .SlowStep dw .NormalStep dw .FastStep @@ -461,275 +515,307 @@ Function1025f: ; 1025f (4:425f) turn_step LEFT turn_step RIGHT .FinishFacing: - db $80 + DOWN - db $80 + UP - db $80 + LEFT - db $80 + RIGHT - -Function102b3: ; 102b3 (4:42b3) - ld a, $0 - ld [wcf39], a - ld a, $3e - ld [wcf2d], a + db $80 | DOWN + db $80 | UP + db $80 | LEFT + db $80 | RIGHT + +.StandInPlace: + ld a, 0 + ld [wPlayerTurningDirection], a + ld a, movement_step_sleep + ld [wMovementAnimation], a xor a ret -Function102bf: ; 102bf (4:42bf) - ld a, $0 - ld [wTempTrainerEnd], a - ld a, $50 - ld [wcf2d], a +._WalkInPlace: + ld a, 0 + ld [wPlayerTurningDirection], a + ld a, movement_step_bump + ld [wMovementAnimation], a xor a ret -Function102cb: ; 102cb (4:42cb) - call Function10404 +.CheckForced: +; When sliding on ice, input is forced to remain in the same direction. + + call CheckStandingOnIce ret nc - ld a, [wTempTrainerEnd] -.asm_102d2 - cp $0 + + ld a, [wPlayerTurningDirection] + cp 0 ret z - and $3 + + maskbits NUM_DIRECTIONS ld e, a - ld d, $0 + ld d, 0 ld hl, .forced_dpad add hl, de - ld a, [wcf29] - and $f + ld a, [wCurInput] + and BUTTONS or [hl] - ld [wcf29], a + ld [wCurInput], a ret .forced_dpad db D_DOWN, D_UP, D_LEFT, D_RIGHT -Function102ec: ; 102ec (4:42ec) - ld hl, .table - ld de, .table2 - .table1 - ld a, [wcf29] - bit 7, a - jr nz, .asm_10307 - bit 6, a - jr nz, .asm_10308 -.asm_102fc - bit 5, a - jr nz, .asm_10309 - bit 4, a - jr nz, .asm_1030a - jr .asm_1030b - -.asm_10307 +.GetAction: +; Poll player input and update movement info. + + ld hl, .action_table + ld de, .action_table_1_end - .action_table_1 + ld a, [wCurInput] + bit D_DOWN_F, a + jr nz, .d_down + bit D_UP_F, a + jr nz, .d_up + bit D_LEFT_F, a + jr nz, .d_left + bit D_RIGHT_F, a + jr nz, .d_right +; Standing + jr .update + +.d_down add hl, de -.asm_10308 +.d_up add hl, de -.asm_10309 +.d_left add hl, de -.asm_1030a +.d_right add hl, de -.asm_1030b +.update ld a, [hli] - ld [wcf2e], a + ld [wWalkingDirection], a ld a, [hli] - ld [wcf2f], a + ld [wFacingDirection], a ld a, [hli] - ld [wcf30], a + ld [wWalkingX], a ld a, [hli] - ld [wcf31], a + ld [wWalkingY], a ld a, [hli] ld h, [hl] ld l, a ld a, [hl] - ld [wWinTextPointer], a - ret - -.table -; struct: -; walk direction -; facing -; x movement -; y movement -; tile collision pointer -.table1 - db STANDING, FACE_CURRENT, 0, 0 - dw wPlayerStandingTile -.table2 - db RIGHT, FACE_RIGHT, 1, 0 - dw wTileRight - db LEFT, FACE_LEFT, -1, 0 - dw wTileLeft - db UP, FACE_UP, 0, -1 - dw wTileUp - db DOWN, FACE_DOWN, 0, 1 - dw wTileDown - -Function10341: ; 10341 (4:4341) + ld [wWalkingTile], a + ret + +player_action: MACRO +; walk direction, facing, x movement, y movement, tile collision pointer + db \1, \2, \3, \4 + dw \5 +ENDM + +.action_table: +.action_table_1 + player_action STANDING, FACE_CURRENT, 0, 0, wPlayerStandingTile +.action_table_1_end + player_action RIGHT, FACE_RIGHT, 1, 0, wTileRight + player_action LEFT, FACE_LEFT, -1, 0, wTileLeft + player_action UP, FACE_UP, 0, -1, wTileUp + player_action DOWN, FACE_DOWN, 0, 1, wTileDown + +.CheckNPC: +; Returns 0 if there is an NPC in front that you can't move +; Returns 1 if there is no NPC in front +; Returns 2 if there is a movable NPC in front ld a, 0 ldh [hMapObjectIndexBuffer], a +; Load the next X coordinate into d ld a, [wPlayerStandingMapX] ld d, a - ld a, [wcf30] + ld a, [wWalkingX] add d ld d, a +; Load the next Y coordinate into e ld a, [wPlayerStandingMapY] ld e, a - ld a, [wcf31] + ld a, [wWalkingY] add e ld e, a - ld bc, wPlayerSprite - farcall Function7120 - jr nc, .asm_10369 - call Function1036f - jr c, .asm_1036c +; Find an object struct with coordinates equal to d,e + ld bc, wObjectStructs ; redundant + farcall IsNPCAtCoord + jr nc, .is_npc + call .CheckStrengthBoulder + jr c, .no_bump + xor a ret -.asm_10369 - ld a, $1 +.is_npc + ld a, 1 ret -.asm_1036c - ld a, $2 +.no_bump + ld a, 2 ret -Function1036f: ; 1036f (4:436f) +.CheckStrengthBoulder: ld hl, wBikeFlags - bit 0, [hl] - jr z, .asm_1039c - ld hl, $7 + bit BIKEFLAGS_STRENGTH_ACTIVE_F, [hl] + jr z, .not_boulder + + ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] - cp $ff - jr nz, .asm_1039c - ld hl, $6 + cp STANDING + jr nz, .not_boulder + + ld hl, OBJECT_PALETTE add hl, bc - bit 6, [hl] - jr z, .asm_1039c - ld hl, $5 + bit STRENGTH_BOULDER_F, [hl] + jr z, .not_boulder + + ld hl, OBJECT_FLAGS2 add hl, bc set 2, [hl] - ld a, [wcf2e] + + ld a, [wWalkingDirection] ld d, a - ld hl, $20 + ld hl, OBJECT_RANGE add hl, bc ld a, [hl] - and $fc + and %11111100 or d ld [hl], a + scf ret -.asm_1039c +.not_boulder xor a ret -Function1039e: ; 1039e (4:439e) +.CheckLandPerms: +; Return 0 if walking onto land and tile permissions allow it. +; Otherwise, return carry. + ld a, [wTilePermissions] ld d, a - ld a, [wcf2f] + ld a, [wFacingDirection] and d - jr nz, .asm_103b2 - ld a, [wWinTextPointer] - call Function103d3 - jr c, .asm_103b2 + jr nz, .NotWalkable + + ld a, [wWalkingTile] + call .CheckWalkable + jr c, .NotWalkable + xor a ret -.asm_103b2 +.NotWalkable: scf ret -Function103b4: ; 103b4 (4:43b4) +.CheckSurfPerms: +; Return 0 if moving in water, or 1 if moving onto land. +; Otherwise, return carry. + ld a, [wTilePermissions] ld d, a - ld a, [wcf2f] + ld a, [wFacingDirection] and d - jr nz, .asm_103c8 - ld a, [wWinTextPointer] - call Function103da - jr c, .asm_103c8 + jr nz, .NotSurfable + + ld a, [wWalkingTile] + call .CheckSurfable + jr c, .NotSurfable + and a ret -.asm_103c8 +.NotSurfable: scf ret -Function103ca: ; 103ca (4:43ca) +.BikeCheck: ld a, [wPlayerState] - cp $1 + cp PLAYER_BIKE ret z - cp $2 + cp PLAYER_SKATE ret -Function103d3: ; 103d3 (4:43d3) +.CheckWalkable: +; Return 0 if tile a is land. Otherwise, return carry. + call GetTileCollision - and a + and a ; LAND_TILE ret z scf ret -Function103da: ; 103da (4:43da) +.CheckSurfable: +; Return 0 if tile a is water, or 1 if land. +; Otherwise, return carry. + call GetTileCollision - cp $1 - jr z, .asm_103e6 - and a - jr z, .asm_103e8 - jr .asm_103ec + cp WATER_TILE + jr z, .Water + +; Can walk back onto land from water. + and a ; LAND_TILE + jr z, .Land + + jr .Neither -.asm_103e6 +.Water: xor a ret -.asm_103e8 - ld a, $1 +.Land: + ld a, 1 and a ret -.asm_103ec +.Neither: scf ret -Function103ee: ; 103ee (4:43ee) +.BumpSound: call CheckSFX ret c - ld de, $24 + ld de, SFX_BUMP call PlaySFX ret -Function103f9: ; 103f9 (4:43f9) +.GetOutOfWater: push bc - ld a, $0 + ld a, PLAYER_NORMAL ld [wPlayerState], a - call ReplacePlayerSprite + call ReplaceChrisSprite ; UpdateSprites pop bc ret -Function10404: ; 10404 (4:4404) - ld a, [wTempTrainerEnd] - cp $0 - jr z, .asm_10420 +CheckStandingOnIce:: + ld a, [wPlayerTurningDirection] + cp 0 + jr z, .not_ice cp $f0 - jr z, .asm_10420 + jr z, .not_ice ld a, [wPlayerStandingTile] call CheckIceTile - jr nc, .asm_1041e + jr nc, .yep ld a, [wPlayerState] - cp $2 - jr nz, .asm_10420 -.asm_1041e + cp PLAYER_SKATE + jr nz, .not_ice + +.yep scf ret -.asm_10420 +.not_ice and a ret StopPlayerForEvent:: - ld hl, wce87 - ld a, $3e + ld hl, wPlayerNextMovement + ld a, movement_step_sleep cp [hl] ret z + ld [hl], a - ld a, $0 - ld [wcf39], a + ld a, 0 + ld [wPlayerTurningDirection], a ret diff --git a/engine/overworld/player_object.asm b/engine/overworld/player_object.asm index 0865dbf8..cd886bc3 100755 --- a/engine/overworld/player_object.asm +++ b/engine/overworld/player_object.asm @@ -4,80 +4,81 @@ BlankScreen: ldh [hBGMapMode], a call ClearBGPalettes call ClearSprites - ld hl, wTilemap - ld bc, SCREEN_HEIGHT * SCREEN_WIDTH + hlcoord 0, 0 + ld bc, wTilemapEnd - wTilemap ld a, " " call ByteFill - ld hl, wAttrmap - ld bc, SCREEN_HEIGHT * SCREEN_WIDTH + hlcoord 0, 0, wAttrmap + ld bc, wAttrmapEnd - wAttrmap ld a, $7 call ByteFill call WaitBGMap2 call SetPalettes ret -SpawnPlayer: ; 861a (2:461a) - ld a, $ff +SpawnPlayer: + ld a, -1 ld [wObjectFollow_Leader], a ld [wObjectFollow_Follower], a - ld a, $0 - ld hl, .PlayerObjectTemplate + ld a, PLAYER + ld hl, PlayerObjectTemplate call CopyPlayerObjectTemplate - ld b, $0 + ld b, PLAYER call PlayerSpawn_ConvertCoords - ld a, $0 + ld a, PLAYER_OBJECT ldh [hObjectStructIndexBuffer], a ld de, wObjectStructs - ld a, $0 + ld a, PLAYER_OBJECT ldh [hMapObjectIndexBuffer], a ld bc, wMapObjects call CopyMapObjectToObjectStruct - ld a, $0 + ld a, PLAYER ld [wCenteredObject], a ret -.PlayerObjectTemplate +PlayerObjectTemplate: ; A dummy map object used to initialize the player object. ; Shorter than the actual amount copied by two bytes. ; Said bytes seem to be unused. object_event -4, -4, SPRITE_CHRIS, SPRITEMOVEDATA_PLAYER, 15, 15, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, 0, -1 -CopyDECoordsToMapObject: ; 8653 (2:4653) +CopyDECoordsToMapObject:: push de ld a, b call GetMapObject pop de - ld hl, $3 + ld hl, MAPOBJECT_X_COORD add hl, bc ld [hl], d - ld hl, $2 + ld hl, MAPOBJECT_Y_COORD add hl, bc ld [hl], e ret -PlayerSpawn_ConvertCoords: ; 8664 (2:4664) +PlayerSpawn_ConvertCoords: push bc ld a, [wXCoord] - add $4 + add 4 ld d, a ld a, [wYCoord] - add $4 + add 4 ld e, a pop bc call CopyDECoordsToMapObject ret -WritePersonXY: +WriteObjectXY:: ld a, b call CheckObjectVisibility ret c - ld hl, $10 + + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] - ldh a, [hConnectionStripLength] + ldh a, [hMapObjectIndexBuffer] ld b, a call CopyDECoordsToMapObject and a @@ -85,381 +86,417 @@ WritePersonXY: RefreshPlayerCoords: ld a, [wXCoord] - add $4 + add 4 ld d, a ld hl, wPlayerStandingMapX sub [hl] ld [hl], d - ld hl, wPlayerObjectXCoord + ld hl, wMapObjects + MAPOBJECT_X_COORD ld [hl], d ld hl, wPlayerLastMapX ld [hl], d ld d, a ld a, [wYCoord] - add $4 + add 4 ld e, a ld hl, wPlayerStandingMapY sub [hl] ld [hl], e - ld hl, wPlayerObjectYCoord + ld hl, wMapObjects + MAPOBJECT_Y_COORD ld [hl], e ld hl, wPlayerLastMapY ld [hl], e ld e, a +; the next three lines are useless ld a, [wObjectFollow_Leader] - cp $0 + cp PLAYER ret nz ret SpawnPlayer2: - ld a, $1 + ld a, 1 ld hl, .PlayerObjectTemplate call CopyPlayerObjectTemplate - ld b, $1 + ld b, 1 call PlayerSpawn_ConvertCoords ret .PlayerObjectTemplate: object_event -4, -4, SPRITE_CHRIS, SPRITEMOVEDATA_12, 15, 15, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, 0, -1 -CopyObjectStruct:: ; 86d7 (2:46d7) +CopyObjectStruct:: call CheckObjectMask and a - ret nz - ld hl, wPlayerStructEnd - ld a, $1 - ld de, $28 -.asm_86e4 + ret nz ; masked + + ld hl, wObjectStructs + OBJECT_LENGTH * 1 + ld a, 1 + ld de, OBJECT_LENGTH +.loop ldh [hObjectStructIndexBuffer], a ld a, [hl] and a - jr z, .asm_86f4 + jr z, .done add hl, de - ldh a, [hConnectedMapWidth] + ldh a, [hObjectStructIndexBuffer] inc a - cp $d - jr nz, .asm_86e4 + cp NUM_OBJECT_STRUCTS + jr nz, .loop scf - ret + ret ; overflow -.asm_86f4 +.done ld d, h ld e, l call CopyMapObjectToObjectStruct ld a, [wVramState] bit 7, a ret z - ld hl, $5 + + ld hl, OBJECT_FLAGS2 add hl, de set 5, [hl] ret -CopyMapObjectToObjectStruct: ; 8706 (2:4706) - call CopyMapObjectToTempObject +CopyMapObjectToObjectStruct: + call .CopyMapObjectToTempObject call CopyTempObjectToObjectStruct ret -CopyMapObjectToTempObject: ; 870d (2:470d) - ldh a, [hConnectedMapWidth] - ld hl, $0 +.CopyMapObjectToTempObject: + ldh a, [hObjectStructIndexBuffer] + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld [hl], a + ldh a, [hMapObjectIndexBuffer] - ld [wce99], a - ld hl, $1 + ld [wTempObjectCopyMapObjectIndex], a + + ld hl, MAPOBJECT_SPRITE add hl, bc ld a, [hl] - ld [wce9a], a + ld [wTempObjectCopySprite], a + call GetSpriteVTile - ld [wce9b], a + ld [wTempObjectCopySpriteVTile], a + ld a, [hl] call GetSpritePalette - ld [wce9c], a - ld hl, $8 + ld [wTempObjectCopyPalette], a + + ld hl, MAPOBJECT_COLOR add hl, bc ld a, [hl] and $f0 - jr z, .asm_873e + jr z, .skip_color_override swap a - and $7 - ld [wce9c], a -.asm_873e - ld hl, $4 + and PALETTE_MASK + ld [wTempObjectCopyPalette], a + +.skip_color_override + ld hl, MAPOBJECT_MOVEMENT add hl, bc ld a, [hl] - ld [wce9d], a - ld hl, $9 + ld [wTempObjectCopyMovement], a + + ld hl, MAPOBJECT_RANGE add hl, bc ld a, [hl] - ld [wce9e], a - ld hl, $3 + ld [wTempObjectCopyRange], a + + ld hl, MAPOBJECT_X_COORD add hl, bc ld a, [hl] - ld [wce9f], a - ld hl, $2 + ld [wTempObjectCopyX], a + + ld hl, MAPOBJECT_Y_COORD add hl, bc ld a, [hl] - ld [wcea0], a - ld hl, $5 + ld [wTempObjectCopyY], a + + ld hl, MAPOBJECT_RADIUS add hl, bc ld a, [hl] - ld [wcea1], a + ld [wTempObjectCopyRadius], a ret -InitializeVariableSprites: +InitializeVisibleSprites: ld bc, wMap2Object - ld a, $2 -.asm_876c - ldh [hConnectionStripLength], a - ld hl, $1 + ld a, 2 +.loop + ldh [hMapObjectIndexBuffer], a + ld hl, MAPOBJECT_SPRITE add hl, bc ld a, [hl] and a - jr z, .asm_87ab - ld hl, $0 + jr z, .next + + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] - cp $ff - jr nz, .asm_87ab + cp -1 + jr nz, .next + ld a, [wXCoord] ld d, a ld a, [wYCoord] ld e, a - ld hl, $3 + + ld hl, MAPOBJECT_X_COORD add hl, bc ld a, [hl] - add $1 + add 1 sub d - jr c, .asm_87ab - cp $c - jr nc, .asm_87ab - ld hl, $2 + jr c, .next + + cp MAPOBJECT_SCREEN_WIDTH + jr nc, .next + + ld hl, MAPOBJECT_Y_COORD add hl, bc ld a, [hl] - add $1 + add 1 sub e - jr c, .asm_87ab - cp $b - jr nc, .asm_87ab + jr c, .next + + cp MAPOBJECT_SCREEN_HEIGHT + jr nc, .next + push bc call CopyObjectStruct pop bc - jp c, Function87b9 -.asm_87ab - ld hl, $10 + jp c, .ret + +.next + ld hl, MAPOBJECT_LENGTH add hl, bc ld b, h ld c, l ldh a, [hMapObjectIndexBuffer] inc a - cp $10 - jr nz, .asm_876c + cp NUM_OBJECTS + jr nz, .loop ret -Function87b9: ; 87b9 (2:47b9) +.ret ret -CheckObjectEnteringVisibleRange: +CheckObjectEnteringVisibleRange:: nop ld a, [wPlayerStepDirection] - cp $ff + cp STANDING ret z - ld hl, .Jumptable + ld hl, .dw rst JumpTable ret -.Jumptable: - dw Function87d5 - dw Function87ce - dw Function8822 - dw Function8829 +.dw + dw .Down + dw .Up + dw .Left + dw .Right -Function87ce: +.Up: ld a, [wYCoord] - sub $1 - jr asm_87da + sub 1 + jr .Vertical -Function87d5: +.Down: ld a, [wYCoord] - add $9 -asm_87da + add 9 +.Vertical: ld d, a ld a, [wXCoord] ld e, a ld bc, wMap2Object - ld a, $2 -.asm_87e4 - ldh [hConnectionStripLength], a - ld hl, $1 + ld a, 2 +.loop_v + ldh [hMapObjectIndexBuffer], a + ld hl, MAPOBJECT_SPRITE add hl, bc ld a, [hl] and a - jr z, .asm_8814 - ld hl, $2 + jr z, .next_v + ld hl, MAPOBJECT_Y_COORD add hl, bc ld a, d cp [hl] - jr nz, .asm_8814 - ld hl, $0 + jr nz, .next_v + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] - cp $ff - jr nz, .asm_8814 - ld hl, $3 + cp -1 + jr nz, .next_v + ld hl, MAPOBJECT_X_COORD add hl, bc ld a, [hl] - add $1 + add 1 sub e - jr c, .asm_8814 - cp $c - jr nc, .asm_8814 + jr c, .next_v + cp MAPOBJECT_SCREEN_WIDTH + jr nc, .next_v push de push bc call CopyObjectStruct pop bc pop de -.asm_8814 - ld hl, $10 + +.next_v + ld hl, MAPOBJECT_LENGTH add hl, bc ld b, h ld c, l ldh a, [hMapObjectIndexBuffer] inc a - cp $10 - jr nz, .asm_87e4 + cp NUM_OBJECTS + jr nz, .loop_v ret -Function8822: +.Left: ld a, [wXCoord] - sub $1 - jr asm_882e + sub 1 + jr .Horizontal -Function8829: +.Right: ld a, [wXCoord] - add $a -asm_882e + add 10 +.Horizontal: ld e, a ld a, [wYCoord] ld d, a ld bc, wMap2Object - ld a, $2 -.asm_8838 - ldh [hConnectionStripLength], a - ld hl, $1 + ld a, 2 +.loop_h + ldh [hMapObjectIndexBuffer], a + ld hl, MAPOBJECT_SPRITE add hl, bc ld a, [hl] and a - jr z, .asm_8868 - ld hl, $3 + jr z, .next_h + ld hl, MAPOBJECT_X_COORD add hl, bc ld a, e cp [hl] - jr nz, .asm_8868 - ld hl, $0 + jr nz, .next_h + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] - cp $ff - jr nz, .asm_8868 - ld hl, $2 + cp -1 + jr nz, .next_h + ld hl, MAPOBJECT_Y_COORD add hl, bc ld a, [hl] - add $1 + add 1 sub d - jr c, .asm_8868 - cp $b - jr nc, .asm_8868 + jr c, .next_h + cp MAPOBJECT_SCREEN_HEIGHT + jr nc, .next_h push de push bc call CopyObjectStruct pop bc pop de -.asm_8868 - ld hl, $10 + +.next_h + ld hl, MAPOBJECT_LENGTH add hl, bc ld b, h ld c, l - ldh a, [hConnectionStripLength] + ldh a, [hMapObjectIndexBuffer] inc a - cp $10 - jr nz, .asm_8838 + cp NUM_OBJECTS + jr nz, .loop_h ret -CopyTempObjectToObjectStruct: ; 8876 (2:4876) - ld a, [wce99] - ld hl, $1 +CopyTempObjectToObjectStruct: + ld a, [wTempObjectCopyMapObjectIndex] + ld hl, OBJECT_MAP_OBJECT_INDEX add hl, de ld [hl], a - ld a, [wce9d] + + ld a, [wTempObjectCopyMovement] call CopySpriteMovementData - ld a, [wce9c] - ld hl, $6 + + ld a, [wTempObjectCopyPalette] + ld hl, OBJECT_PALETTE add hl, de or [hl] ld [hl], a - ld a, [wcea0] - call InitTempObjectYCoord - ld a, [wce9f] - call InitTempObjectXCoord - ld a, [wce9a] - ld hl, $0 + + ld a, [wTempObjectCopyY] + call .InitYCoord + + ld a, [wTempObjectCopyX] + call .InitXCoord + + ld a, [wTempObjectCopySprite] + ld hl, OBJECT_SPRITE add hl, de ld [hl], a - ld a, [wce9b] - ld hl, $2 + + ld a, [wTempObjectCopySpriteVTile] + ld hl, OBJECT_SPRITE_TILE add hl, de ld [hl], a - ld hl, $9 + + ld hl, OBJECT_STEP_TYPE add hl, de - ld [hl], $0 - ld hl, $d + ld [hl], STEP_TYPE_00 + + ld hl, OBJECT_FACING_STEP add hl, de - ld [hl], $ff - ld a, [wcea1] - call InitTempObjectRadius - ld a, [wce9e] - ld hl, $20 + ld [hl], STANDING + + ld a, [wTempObjectCopyRadius] + call .InitRadius + + ld a, [wTempObjectCopyRange] + ld hl, OBJECT_RANGE add hl, de ld [hl], a + and a ret -InitTempObjectYCoord: ; 88c5 (2:48c5) - ld hl, $15 +.InitYCoord: + ld hl, OBJECT_INIT_Y add hl, de ld [hl], a - ld hl, $11 + + ld hl, OBJECT_NEXT_MAP_Y add hl, de ld [hl], a + ld hl, wYCoord sub [hl] and $f swap a - ld hl, wce82 + ld hl, wPlayerBGMapOffsetY sub [hl] - ld hl, $18 + ld hl, OBJECT_SPRITE_Y add hl, de ld [hl], a ret -InitTempObjectXCoord: ; 88e1 (2:48e1) - ld hl, $14 +.InitXCoord: + ld hl, OBJECT_INIT_X add hl, de ld [hl], a - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, de ld [hl], a ld hl, wXCoord sub [hl] and $f swap a - ld hl, wce81 + ld hl, wPlayerBGMapOffsetX sub [hl] - ld hl, $17 + ld hl, OBJECT_SPRITE_X add hl, de ld [hl], a ret -InitTempObjectRadius: ; 88fd (2:48fd) +.InitRadius: ld h, a inc a and $f @@ -468,93 +505,102 @@ InitTempObjectRadius: ; 88fd (2:48fd) add $10 and $f0 or l - ld hl, $16 + ld hl, OBJECT_RADIUS add hl, de ld [hl], a ret -TrainerWalkToPlayer: +TrainerWalkToPlayer:: ldh a, [hLastTalked] call InitMovementBuffer ld a, movement_step_sleep call AppendToMovementBuffer - ld a, [wcf2a] + ld a, [wWalkingIntoNPC] dec a - jr z, .asm_892b + jr z, .TerminateStep ldh a, [hLastTalked] ld b, a ld c, PLAYER - ld d, $1 - call GetTrainerPathToPlayer + ld d, 1 + call .GetPathToPlayer call DecrementMovementBufferCount -.asm_892b + +.TerminateStep: ld a, movement_step_end call AppendToMovementBuffer ret -GetTrainerPathToPlayer: ; 8931 (2:4931) +.GetPathToPlayer: push de push bc +; get player object struct, load to de ld a, c call GetMapObject - ld hl, $0 + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] call GetObjectStruct ld d, b ld e, c + +; get last talked object struct, load to bc pop bc ld a, b call GetMapObject - ld hl, $0 + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] call GetObjectStruct - ld hl, $10 + +; get last talked coords, load to bc + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld c, [hl] ld b, a - ld hl, $10 + +; get player coords, load to de + ld hl, OBJECT_NEXT_MAP_X add hl, de ld a, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, de ld e, [hl] ld d, a + pop af call ComputePathToWalkToPlayer ret -SurfStartStep: ; 8969 (2:4969) +SurfStartStep: call InitMovementBuffer - call GetInitialSurfStep + call .GetMovementData call AppendToMovementBuffer ld a, movement_step_end call AppendToMovementBuffer ret -GetInitialSurfStep: ; 8978 (2:4978) +.GetMovementData: ld a, [wPlayerDirection] srl a srl a - and $3 + maskbits NUM_DIRECTIONS ld e, a - ld d, $0 - ld hl, .Data ; $498a + ld d, 0 + ld hl, .movement_data add hl, de ld a, [hl] ret -.Data +.movement_data slow_step DOWN slow_step UP slow_step LEFT slow_step RIGHT -FollowNotExact: +FollowNotExact:: push bc ld a, c call CheckObjectVisibility @@ -562,43 +608,48 @@ FollowNotExact: ld e, c pop bc ret c + ld a, b call CheckObjectVisibility ret c - ld hl, $10 + +; object 2 is now in bc, object 1 is now in de + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld c, [hl] ld b, a - ld hl, $10 + + ld hl, OBJECT_NEXT_MAP_X add hl, de ld a, [hl] cp b - jr z, .asm_89b7 - jr c, .asm_89b4 + jr z, .same_x + jr c, .to_the_left inc b - jr .asm_89c5 + jr .continue -.asm_89b4 +.to_the_left dec b - jr .asm_89c5 + jr .continue -.asm_89b7 - ld hl, $11 +.same_x + ld hl, OBJECT_NEXT_MAP_Y add hl, de ld a, [hl] cp c - jr z, .asm_89c5 - jr c, .asm_89c4 + jr z, .continue + jr c, .below inc c - jr .asm_89c5 + jr .continue -.asm_89c4 +.below dec c -.asm_89c5 - ld hl, $10 + +.continue + ld hl, OBJECT_NEXT_MAP_X add hl, de ld [hl], b ld a, b @@ -606,12 +657,12 @@ FollowNotExact: sub [hl] and $f swap a - ld hl, wce81 + ld hl, wPlayerBGMapOffsetX sub [hl] - ld hl, $17 + ld hl, OBJECT_SPRITE_X add hl, de ld [hl], a - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, de ld [hl], c ld a, c @@ -619,171 +670,184 @@ FollowNotExact: sub [hl] and $f swap a - ld hl, wce82 + ld hl, wPlayerBGMapOffsetY sub [hl] - ld hl, $18 + ld hl, OBJECT_SPRITE_Y add hl, de ld [hl], a ldh a, [hObjectStructIndexBuffer] - ld hl, $20 + ld hl, OBJECT_RANGE add hl, de ld [hl], a - ld hl, $3 + ld hl, OBJECT_MOVEMENTTYPE add hl, de - ld [hl], $1a - ld hl, $9 + ld [hl], SPRITEMOVEDATA_FOLLOWNOTEXACT + ld hl, OBJECT_STEP_TYPE add hl, de - ld [hl], $0 + ld [hl], STEP_TYPE_00 ret -GetRelativeFacing: +GetRelativeFacing:: +; Determines which way map object e would have to turn to face map object d. Returns carry if it's impossible for whatever reason. ld a, d call GetMapObject - ld hl, $0 + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] - cp $d - jr nc, .asm_8a27 + cp NUM_OBJECT_STRUCTS + jr nc, .carry ld d, a ld a, e call GetMapObject - ld hl, $0 + ld hl, MAPOBJECT_OBJECT_STRUCT_ID add hl, bc ld a, [hl] - cp $d - jr nc, .asm_8a27 + cp NUM_OBJECT_STRUCTS + jr nc, .carry ld e, a - call GetFacing_e_relativeto_d + call .GetFacing_e_relativeto_d ret -.asm_8a27 +.carry scf ret -GetFacing_e_relativeto_d: ; 8a29 (2:4a29) +.GetFacing_e_relativeto_d: +; Determines which way object e would have to turn to face object d. Returns carry if it's impossible. +; load the coordinates of object d into bc ld a, d call GetObjectStruct - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld c, [hl] ld b, a push bc +; load the coordinates of object e into de ld a, e call GetObjectStruct - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] pop bc +; |x1 - x2| ld a, b sub d - jr z, .asm_8a5c - jr nc, .asm_8a50 + jr z, .same_x_1 + jr nc, .b_right_of_d_1 cpl inc a -.asm_8a50 + +.b_right_of_d_1 +; |y1 - y2| ld h, a ld a, c sub e - jr z, .asm_8a6a - jr nc, .asm_8a59 + jr z, .same_y_1 + jr nc, .c_below_e_1 cpl inc a -.asm_8a59 + +.c_below_e_1 +; |y1 - y2| - |x1 - x2| sub h - jr c, .asm_8a6a -.asm_8a5c + jr c, .same_y_1 + +.same_x_1 +; compare the y coordinates ld a, c cp e - jr z, .asm_8a78 - jr c, .asm_8a66 - ld d, $0 + jr z, .same_x_and_y + jr c, .c_directly_below_e +; c directly above e + ld d, DOWN and a ret -.asm_8a66 - ld d, $1 +.c_directly_below_e + ld d, UP and a ret -.asm_8a6a +.same_y_1 ld a, b cp d - jr z, .asm_8a78 - jr c, .asm_8a74 - ld d, $3 + jr z, .same_x_and_y + jr c, .b_directly_right_of_d +; b directly left of d + ld d, RIGHT and a ret -.asm_8a74 - ld d, $2 +.b_directly_right_of_d + ld d, LEFT and a ret -.asm_8a78 +.same_x_and_y scf ret -QueueFollowerFirstStep: ; 8a7a (2:4a7a) - call Function8a8d - jr c, .asm_8a87 +QueueFollowerFirstStep: + call .QueueFirstStep + jr c, .same ld [wFollowMovementQueue], a xor a ld [wFollowerMovementQueueLength], a ret -.asm_8a87 - ld a, $ff +.same + ld a, -1 ld [wFollowerMovementQueueLength], a ret -Function8a8d: ; 8a8d (2:4a8d) +.QueueFirstStep: ld a, [wObjectFollow_Leader] call GetObjectStruct - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld d, [hl] - ld hl, $11 + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld e, [hl] ld a, [wObjectFollow_Follower] call GetObjectStruct - ld hl, $10 + ld hl, OBJECT_NEXT_MAP_X add hl, bc ld a, d cp [hl] - jr z, .asm_8ab5 - jr c, .asm_8ab1 + jr z, .check_y + jr c, .left and a - ld a, $f + ld a, movement_step + RIGHT ret -.asm_8ab1 +.left and a - ld a, $e + ld a, movement_step + LEFT ret -.asm_8ab5 - ld hl, $11 +.check_y + ld hl, OBJECT_NEXT_MAP_Y add hl, bc ld a, e cp [hl] - jr z, .asm_8ac7 - jr c, .asm_8ac3 + jr z, .same_xy + jr c, .up and a - ld a, $c + ld a, movement_step + DOWN ret -.asm_8ac3 +.up and a - ld a, $d + ld a, movement_step + UP ret -.asm_8ac7 +.same_xy scf ret diff --git a/engine/overworld/player_step.asm b/engine/overworld/player_step.asm index 36698ed8..a290730c 100755 --- a/engine/overworld/player_step.asm +++ b/engine/overworld/player_step.asm @@ -1,37 +1,37 @@ -HandlePlayerStep_:: +_HandlePlayerStep:: ld a, [wPlayerStepFlags] and a ret z - bit 7, a - jr nz, .asm_d4b6 - bit 6, a - jr nz, .asm_d4c0 - bit 5, a - jr nz, .asm_d4c5 + bit PLAYERSTEP_START_F, a + jr nz, .update_overworld_map + bit PLAYERSTEP_STOP_F, a + jr nz, .update_player_coords + bit PLAYERSTEP_CONTINUE_F, a + jr nz, .finish ret -.asm_d4b6 - ld a, $4 +.update_overworld_map + ld a, 4 ld [wHandlePlayerStep], a - call Functiond53c - jr .asm_d4c5 + call UpdateOverworldMap + jr .finish -.asm_d4c0 - call Functiond517 - jr .asm_d4c5 +.update_player_coords + call UpdatePlayerCoords + jr .finish -.asm_d4c5 - call Functiond4f2 +.finish + call HandlePlayerStep ld a, [wPlayerStepVectorX] ld d, a ld a, [wPlayerStepVectorY] ld e, a - ld a, [wce81] + ld a, [wPlayerBGMapOffsetX] sub d - ld [wce81], a - ld a, [wce82] + ld [wPlayerBGMapOffsetX], a + ld a, [wPlayerBGMapOffsetY] sub e - ld [wce82], a + ld [wPlayerBGMapOffsetY], a ret ScrollScreen:: @@ -47,7 +47,7 @@ ScrollScreen:: ldh [hSCY], a ret -Functiond4f2: ; d4f2 (3:54f2) +HandlePlayerStep: ld hl, wHandlePlayerStep ld a, [hl] and a @@ -58,146 +58,147 @@ Functiond4f2: ; d4f2 (3:54f2) rst JumpTable ret -.Jumptable +.Jumptable: dw GetMovementPermissions dw BufferScreen - dw Functiond515 - dw Functiond516 - dw Functiond515 - dw Functiond515 - dw Functiond515 - dw Functiond515 - dw Functiond515 - dw Functiond515 - dw Functiond515 + dw .fail1 + dw .fail2 +; The rest are never used. Ever. + dw .fail1 + dw .fail1 + dw .fail1 + dw .fail1 + dw .fail1 + dw .fail1 + dw .fail1 -Functiond515: +.fail1 ret -Functiond516: +.fail2 ret -Functiond517: ; d517 (3:5517) +UpdatePlayerCoords: ld a, [wPlayerStepDirection] and a - jr nz, .asm_d522 + jr nz, .check_step_down ld hl, wYCoord inc [hl] ret -.asm_d522 - cp $1 - jr nz, .asm_d52b +.check_step_down + cp UP + jr nz, .check_step_left ld hl, wYCoord dec [hl] ret -.asm_d52b - cp $2 - jr nz, .asm_d534 +.check_step_left + cp LEFT + jr nz, .check_step_right ld hl, wXCoord dec [hl] ret -.asm_d534 - cp $3 +.check_step_right + cp RIGHT ret nz ld hl, wXCoord inc [hl] ret -Functiond53c: ; d53c (3:553c) +UpdateOverworldMap: ld a, [wPlayerStepDirection] and a - jr z, .asm_d54f - cp $1 - jr z, .asm_d559 - cp $2 - jr z, .asm_d563 - cp $3 - jr z, .asm_d56d + jr z, .step_down + cp UP + jr z, .step_up + cp LEFT + jr z, .step_left + cp RIGHT + jr z, .step_right ret -.asm_d54f - call Functiond577 +.step_down + call .ScrollOverworldMapDown call LoadMapPart - call ScrollMapUp + call ScrollMapDown ret -.asm_d559 - call Functiond5a8 +.step_up + call .ScrollOverworldMapUp call LoadMapPart - call ScrollMapDown + call ScrollMapUp ret -.asm_d563 - call Functiond5db +.step_left + call .ScrollOverworldMapLeft call LoadMapPart - call ScrollMapRight + call ScrollMapLeft ret -.asm_d56d - call Functiond604 +.step_right + call .ScrollOverworldMapRight call LoadMapPart - call ScrollMapLeft + call ScrollMapRight ret -Functiond577: ; d577 (3:5577) - ld a, [wd05b] - add $40 - ld [wd05b], a - jr nc, .asm_d58c - ld a, [wd05c] +.ScrollOverworldMapDown: + ld a, [wBGMapAnchor] + add 2 * BG_MAP_WIDTH + ld [wBGMapAnchor], a + jr nc, .not_overflowed + ld a, [wBGMapAnchor + 1] inc a - and $3 - or $98 - ld [wd05c], a -.asm_d58c - ld hl, wd07f + and %11 + or HIGH(vBGMap0) + ld [wBGMapAnchor + 1], a +.not_overflowed + ld hl, wMetatileStandingY inc [hl] ld a, [hl] - cp $2 - jr nz, .asm_d59a - ld [hl], $0 - call Functiond59b -.asm_d59a + cp 2 ; was 1 + jr nz, .done_down + ld [hl], 0 + call .ScrollMapDataDown +.done_down ret -Functiond59b: ; d59b (3:559b) +.ScrollMapDataDown: ld hl, wOverworldMapAnchor ld a, [wMapWidth] - add $6 + add 3 * 2 ; surrounding tiles add [hl] ld [hli], a ret nc inc [hl] ret -Functiond5a8: ; d5a8 (3:55a8) - ld a, [wd05b] - sub $40 - ld [wd05b], a - jr nc, .asm_d5bd - ld a, [wd05c] +.ScrollOverworldMapUp: + ld a, [wBGMapAnchor] + sub 2 * BG_MAP_WIDTH + ld [wBGMapAnchor], a + jr nc, .not_underflowed + ld a, [wBGMapAnchor + 1] dec a - and $3 - or $98 - ld [wd05c], a -.asm_d5bd - ld hl, wd07f + and %11 + or HIGH(vBGMap0) + ld [wBGMapAnchor + 1], a +.not_underflowed + ld hl, wMetatileStandingY dec [hl] ld a, [hl] - cp $ff - jr nz, .asm_d5cb + cp -1 ; was 0 + jr nz, .done_up ld [hl], $1 - call Functiond5cc -.asm_d5cb + call .ScrollMapDataUp +.done_up ret -Functiond5cc: ; d5cc (3:55cc) +.ScrollMapDataUp: ld hl, wOverworldMapAnchor ld a, [wMapWidth] - add $6 + add 3 * 2 ; surrounding tiles ld b, a ld a, [hl] sub b @@ -206,8 +207,8 @@ Functiond5cc: ; d5cc (3:55cc) dec [hl] ret -Functiond5db: ; d5db (3:55db) - ld a, [wd05b] +.ScrollOverworldMapLeft: + ld a, [wBGMapAnchor] ld e, a and $e0 ld d, a @@ -215,28 +216,28 @@ Functiond5db: ; d5db (3:55db) sub $2 and $1f or d - ld [wd05b], a - ld hl, wd080 + ld [wBGMapAnchor], a + ld hl, wMetatileStandingX dec [hl] ld a, [hl] - cp $ff - jr nz, .asm_d5f9 - ld [hl], $1 - call Functiond5fa -.asm_d5f9 + cp -1 + jr nz, .done_left + ld [hl], 1 + call .ScrollMapDataLeft +.done_left ret -Functiond5fa: ; d5fa (3:55fa) +.ScrollMapDataLeft: ld hl, wOverworldMapAnchor ld a, [hl] - sub $1 + sub 1 ld [hli], a ret nc dec [hl] ret -Functiond604: ; d604 (3:5604) - ld a, [wd05b] +.ScrollOverworldMapRight: + ld a, [wBGMapAnchor] ld e, a and $e0 ld d, a @@ -244,21 +245,21 @@ Functiond604: ; d604 (3:5604) add $2 and $1f or d - ld [wd05b], a - ld hl, wd080 + ld [wBGMapAnchor], a + ld hl, wMetatileStandingX inc [hl] ld a, [hl] - cp $2 - jr nz, .asm_d622 - ld [hl], $0 - call Functiond623 -.asm_d622 + cp 2 + jr nz, .done_right + ld [hl], 0 + call .ScrollMapDataRight +.done_right ret -Functiond623: ; d623 (3:5623) +.ScrollMapDataRight: ld hl, wOverworldMapAnchor ld a, [hl] - add $1 + add 1 ld [hli], a ret nc inc [hl] diff --git a/engine/overworld/scripting.asm b/engine/overworld/scripting.asm new file mode 100644 index 00000000..7659c42d --- /dev/null +++ b/engine/overworld/scripting.asm @@ -0,0 +1,2673 @@ +; Event scripting commands. + +EnableScriptMode:: + push af + ld a, SCRIPT_READ + ld [wScriptMode], a + pop af + ret + +ScriptEvents:: + call StartScript +.loop + ld a, [wScriptMode] + ld hl, .modes + rst JumpTable + call CheckScript + jr nz, .loop + ret + +.modes + dw EndScript + dw RunScriptCommand + dw WaitScriptMovement + dw WaitScript + +EndScript: + call StopScript + ret + +WaitScript: + call StopScript + + ld hl, wScriptDelay + dec [hl] + ret nz + + farcall Function582f + + ld a, SCRIPT_READ + ld [wScriptMode], a + call StartScript + ret + +WaitScriptMovement: + call StopScript + + ld hl, wVramState + bit 7, [hl] + ret nz + + farcall Function582f + + ld a, SCRIPT_READ + ld [wScriptMode], a + call StartScript + ret + +RunScriptCommand: + call GetScriptByte + ld hl, ScriptCommandTable + rst JumpTable + ret + +ScriptCommandTable: +; entries correspond to macros/scripts/events.asm enumeration + dw Script_scall ; 00 + dw Script_farscall ; 01 + dw Script_memcall ; 02 + dw Script_sjump ; 03 + dw Script_farsjump ; 04 + dw Script_memjump ; 05 + dw Script_ifequal ; 06 + dw Script_ifnotequal ; 07 + dw Script_iffalse ; 08 + dw Script_iftrue ; 09 + dw Script_ifgreater ; 0a + dw Script_ifless ; 0b + dw Script_jumpstd ; 0c + dw Script_callstd ; 0d + dw Script_callasm ; 0e + dw Script_special ; 0f + dw Script_memcallasm ; 10 + dw Script_checkmapscene ; 11 + dw Script_setmapscene ; 12 + dw Script_checkscene ; 13 + dw Script_setscene ; 14 + dw Script_setval ; 15 + dw Script_addval ; 16 + dw Script_random ; 17 + dw Script_checkver ; 18 + dw Script_readmem ; 19 + dw Script_writemem ; 1a + dw Script_loadmem ; 1b + dw Script_readvar ; 1c + dw Script_writevar ; 1d + dw Script_loadvar ; 1e + dw Script_giveitem ; 1f + dw Script_takeitem ; 20 + dw Script_checkitem ; 21 + dw Script_givemoney ; 22 + dw Script_takemoney ; 23 + dw Script_checkmoney ; 24 + dw Script_givecoins ; 25 + dw Script_takecoins ; 26 + dw Script_checkcoins ; 27 + dw Script_addcellnum ; 28 + dw Script_delcellnum ; 29 + dw Script_checkcellnum ; 2a + dw Script_checktime ; 2b + dw Script_checkpoke ; 2c + dw Script_givepoke ; 2d + dw Script_giveegg ; 2e + dw Script_givepokemail ; 2f + dw Script_checkpokemail ; 30 + dw Script_checkevent ; 31 + dw Script_clearevent ; 32 + dw Script_setevent ; 33 + dw Script_checkflag ; 34 + dw Script_clearflag ; 35 + dw Script_setflag ; 36 + dw Script_wildon ; 37 + dw Script_wildoff ; 38 + dw Script_xycompare ; 39 + dw Script_warpmod ; 3a + dw Script_blackoutmod ; 3b + dw Script_warp ; 3c + dw Script_getmoney ; 3d + dw Script_getcoins ; 3e + dw Script_getnum ; 3f + dw Script_getmonname ; 40 + dw Script_getitemname ; 41 + dw Script_getcurlandmarkname ; 42 + dw Script_gettrainername ; 43 + dw Script_getstring ; 44 + dw Script_itemnotify ; 45 + dw Script_pocketisfull ; 46 + dw Script_opentext ; 47 + dw Script_refreshscreen ; 48 + dw Script_closetext ; 49 + dw Script_writeunusedbytebuffer ; 4a + dw Script_farwritetext ; 4b + dw Script_writetext ; 4c + dw Script_repeattext ; 4d + dw Script_yesorno ; 4e + dw Script_loadmenu ; 4f + dw Script_closewindow ; 50 + dw Script_jumptextfaceplayer ; 51 + dw Script_jumptext ; 52 + dw Script_waitbutton ; 53 + dw Script_promptbutton ; 54 + dw Script_pokepic ; 55 + dw Script_closepokepic ; 56 + dw Script__2dmenu ; 57 + dw Script_verticalmenu ; 58 + dw Script_loadpikachudata ; 59 + dw Script_randomwildmon ; 5a + dw Script_loadtemptrainer ; 5b + dw Script_loadwildmon ; 5c + dw Script_loadtrainer ; 5d + dw Script_startbattle ; 5e + dw Script_reloadmapafterbattle ; 5f + dw Script_catchtutorial ; 60 + dw Script_trainertext ; 61 + dw Script_trainerflagaction ; 62 + dw Script_winlosstext ; 63 + dw Script_scripttalkafter ; 64 + dw Script_endifjustbattled ; 65 + dw Script_checkjustbattled ; 66 + dw Script_setlasttalked ; 67 + dw Script_applymovement ; 68 + dw Script_applymovementlasttalked ; 69 + dw Script_faceplayer ; 6a + dw Script_faceobject ; 6b + dw Script_variablesprite ; 6c + dw Script_disappear ; 6d + dw Script_appear ; 6e + dw Script_follow ; 6f + dw Script_stopfollow ; 70 + dw Script_moveobject ; 71 + dw Script_writeobjectxy ; 72 + dw Script_loademote ; 73 + dw Script_showemote ; 74 + dw Script_turnobject ; 75 + dw Script_follownotexact ; 76 + dw Script_earthquake ; 77 + dw Script_changemapblocks ; 78 + dw Script_changeblock ; 79 + dw Script_reloadmap ; 7a + dw Script_reloadmappart ; 7b + dw Script_writecmdqueue ; 7c + dw Script_delcmdqueue ; 7d + dw Script_playmusic ; 7e + dw Script_encountermusic ; 7f + dw Script_musicfadeout ; 80 + dw Script_playmapmusic ; 81 + dw Script_dontrestartmapmusic ; 82 + dw Script_cry ; 83 + dw Script_playsound ; 84 + dw Script_waitsfx ; 85 + dw Script_warpsound ; 86 + dw Script_specialsound ; 87 + dw Script_autoinput ; 88 + dw Script_newloadmap ; 89 + dw Script_pause ; 8a + dw Script_deactivatefacing ; 8b + dw Script_prioritysjump ; 8c + dw Script_warpcheck ; 8d + dw Script_stopandsjump ; 8e + dw Script_return ; 8f + dw Script_end ; 90 + dw Script_reloadandreturn ; 91 + dw Script_endall ; 92 + dw Script_pokemart ; 93 + dw Script_elevator ; 94 + dw Script_trade ; 95 + dw Script_askforphonenumber ; 96 + dw Script_phonecall ; 97 + dw Script_hangup ; 98 + dw Script_describedecoration ; 99 + dw Script_fruittree ; 9a + dw Script_specialphonecall ; 9b + dw Script_checkphonecall ; 9c + dw Script_verbosegiveitem ; 9d + dw Script_swarm ; 9e + dw Script_halloffame ; 9f + dw Script_credits ; a0 + dw Script_warpfacing ; a1 + +StartScript: + ld hl, wScriptFlags + set SCRIPT_RUNNING, [hl] + ret + +CheckScript: + ld hl, wScriptFlags + bit SCRIPT_RUNNING, [hl] + ret + +StopScript: + ld hl, wScriptFlags + res SCRIPT_RUNNING, [hl] + ret + +Script_callasm: +; script command 0xe +; parameters: asm + + call GetScriptByte + ld b, a + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, b + rst FarCall + ret + +Script_special: +; script command 0xf +; parameters: predefined_script + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + farcall Special + ret + +Script_memcallasm: +; script command 0x10 +; parameters: asm + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld b, [hl] + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + ld a, b + rst FarCall + ret + +Script_jumptextfaceplayer: +; script command 0x51 +; parameters: text_pointer + + ld a, [wScriptBank] + ld [wScriptTextBank], a + call GetScriptByte + ld [wScriptTextAddr], a + call GetScriptByte + ld [wScriptTextAddr + 1], a + ld b, BANK(JumpTextFacePlayerScript) + ld hl, JumpTextFacePlayerScript + jp ScriptJump + +Script_jumptext: +; script command 0x52 +; parameters: text_pointer + + ld a, [wScriptBank] + ld [wScriptTextBank], a + call GetScriptByte + ld [wScriptTextAddr], a + call GetScriptByte + ld [wScriptTextAddr + 1], a + ld b, BANK(JumpTextScript) + ld hl, JumpTextScript + jp ScriptJump + +JumpTextFacePlayerScript: + faceplayer +JumpTextScript: + opentext + repeattext -1, -1 + waitbutton + closetext + end + +Script_writetext: +; script command 0x4c +; parameters: text_pointer + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, [wScriptBank] + ld b, a + call MapTextbox + ret + +Script_farwritetext: +; script command 0x4b +; parameters: text_pointer + + call GetScriptByte + ld b, a + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + call MapTextbox + ret + +Script_repeattext: +; script command 0x4d +; parameters: byte, byte + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + cp -1 + jr nz, .done + ld a, l + cp -1 + jr nz, .done + ld hl, wScriptTextBank + ld a, [hli] + ld b, a + ld a, [hli] + ld h, [hl] + ld l, a + call MapTextbox + ret + +.done + ret + +Script_waitbutton: +; script command 0x53 + + jp WaitButton + +Script_promptbutton: +; script command 0x54 + + ldh a, [hOAMUpdate] + push af + ld a, $1 + ldh [hOAMUpdate], a + call WaitBGMap + call PromptButton + pop af + ldh [hOAMUpdate], a + ret + +Script_yesorno: +; script command 0x4e + + call YesNoBox + ld a, FALSE + jr c, .no + ld a, TRUE +.no + ld [wScriptVar], a + ret + +Script_loadmenu: +; script command 0x4f +; parameters: menu_header + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld de, LoadMenuHeader + ld a, [wScriptBank] + call Call_a_de + call UpdateSprites + ret + +Script_closewindow: +; script command 0x50 + + call CloseWindow + call UpdateSprites + ret + +Script_pokepic: +; script command 0x55 +; parameters: pokemon + + call GetScriptByte + and a + jr nz, .ok + ld a, [wScriptVar] +.ok + ld [wCurPartySpecies], a + farcall Pokepic + ret + +Script_closepokepic: +; script command 0x56 + + farcall ClosePokepic + ret + +Script_verticalmenu: +; script command 0x58 + + ld a, [wScriptBank] + ld hl, VerticalMenu + rst FarCall + ld a, [wMenuCursorY] + jr nc, .ok + xor a +.ok + ld [wScriptVar], a + ret + +Script__2dmenu: +; script command 0x57 + + ld a, [wScriptBank] + ld hl, _2DMenu + rst FarCall + ld a, [wMenuCursorBuffer] + jr nc, .ok + xor a +.ok + ld [wScriptVar], a + ret + +Script_verbosegiveitem: +; script command 0x9d +; parameters: item, quantity + + call Script_giveitem + call CurItemName + ld de, wStringBuffer1 + ld a, STRING_BUFFER_4 + call CopyConvertedText + ld b, BANK(GiveItemScript) + ld de, GiveItemScript + jp ScriptCall + +ret_96e71: + ret + +GiveItemScript: + callasm ret_96e71 + writetext ReceivedItemText + iffalse .Full + waitsfx + specialsound + waitbutton + itemnotify + end + +.Full: + promptbutton + pocketisfull + end + +ReceivedItemText: + text_far _ReceivedItemText + text_end + +Script_itemnotify: +; script command 0x45 + + call GetPocketName + call CurItemName + ld b, BANK(PutItemInPocketText) + ld hl, PutItemInPocketText + call MapTextbox + ret + +Script_pocketisfull: +; script command 0x46 + + call GetPocketName + call CurItemName + ld b, BANK(PocketIsFullText) + ld hl, PocketIsFullText + call MapTextbox + ret + +Script_specialsound: +; script command 0x87 + + farcall CheckItemPocket + ld a, [wItemAttributeParamBuffer] + cp TM_HM + ld de, SFX_GET_TM + jr z, .play + ld de, SFX_ITEM +.play + call PlaySFX + call WaitSFX + ret + +GetPocketName: + farcall CheckItemPocket + ld a, [wItemAttributeParamBuffer] + dec a + ld hl, ItemPocketNames + maskbits NUM_POCKETS + add a + ld e, a + ld d, 0 + add hl, de + ld a, [hli] + ld d, [hl] + ld e, a + ld hl, wStringBuffer3 + call CopyName2 + ret + +INCLUDE "data/items/pocket_names.asm" + +CurItemName: + ld a, [wCurItem] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ret + +PutItemInPocketText: + text_far _PutItemInPocketText + text_end + +PocketIsFullText: + text_far _PocketIsFullText + text_end + +Script_pokemart: +; script command 0x93 +; parameters: mart_type, mart_id + + call GetScriptByte + ld c, a + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld a, [wScriptBank] + ld b, a + farcall OpenMartDialog + ret + +Script_elevator: +; script command 0x94 +; parameters: floor_list_pointer + + xor a + ld [wScriptVar], a + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld a, [wScriptBank] + ld b, a + farcall Elevator + ret c + ld a, TRUE + ld [wScriptVar], a + ret + +Script_trade: +; script command 0x95 +; parameters: trade_id + + call GetScriptByte + ld e, a + farcall NPCTrade + ret + +Script_phonecall: +; script command 0x97 +; parameters: caller_name + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld a, [wScriptBank] + ld b, a + farcall PhoneCall + ret + +Script_hangup: +; script command 0x98 + + farcall HangUp + ret + +Script_askforphonenumber: +; script command 0x96 +; parameters: number + + call YesNoBox + jr c, .refused + call GetScriptByte + ld c, a + farcall AddPhoneNumber + jr c, .phonefull + xor a ; PHONE_CONTACT_GOT + jr .done +.phonefull + ld a, PHONE_CONTACTS_FULL + jr .done +.refused + call GetScriptByte + ld a, PHONE_CONTACT_REFUSED +.done + ld [wScriptVar], a + ret + +Script_describedecoration: +; script command 0x99 +; parameters: byte + + call GetScriptByte + ld b, a + farcall DescribeDecoration + ld h, d + ld l, e + jp ScriptJump + +Script_fruittree: +; script command 0x9a +; parameters: tree_id + + call GetScriptByte + ld [wCurFruitTree], a + ld b, BANK(FruitTreeScript) + ld hl, FruitTreeScript + jp ScriptJump + +Script_swarm: +; script command 0x9e +; parameters: map_group, map_id + + call GetScriptByte + ld d, a + call GetScriptByte + ld e, a + farcall StoreSwarmMapIndices + ret + +Script_trainertext: +; script command 0x61 +; parameters: text_id + + call GetScriptByte + ld c, a + ld b, 0 + ld hl, wSeenTextPointer + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wSeenTrainerBank] + ld b, a + call MapTextbox + ret + +Script_scripttalkafter: +; script command 0x64 + + ld hl, wScriptAfterPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wSeenTrainerBank] + ld b, a + jp ScriptJump + +Script_trainerflagaction: +; script command 0x62 +; parameters: action + + xor a + ld [wScriptVar], a + ld hl, wTempTrainerEventFlag + ld e, [hl] + inc hl + ld d, [hl] + call GetScriptByte + ld b, a + call EventFlagAction + ld a, c + and a + ret z + ld a, TRUE + ld [wScriptVar], a + ret + +Script_winlosstext: +; script command 0x63 +; parameters: win_text_pointer, loss_text_pointer + + ld hl, wWinTextPointer + call GetScriptByte + ld [hli], a + call GetScriptByte + ld [hli], a + ld hl, wLossTextPointer + call GetScriptByte + ld [hli], a + call GetScriptByte + ld [hli], a + ret + +Script_endifjustbattled: +; script command 0x65 + + ld a, [wRunningTrainerBattleScript] + and a + ret z + jp Script_end + +Script_checkjustbattled: +; script command 0x66 + + ld a, TRUE + ld [wScriptVar], a + ld a, [wRunningTrainerBattleScript] + and a + ret nz + xor a + ld [wScriptVar], a + ret + +Script_encountermusic: +; script command 0x7f + + ld a, [wOtherTrainerClass] + ld e, a + farcall PlayTrainerEncounterMusic + ret + +Script_playmapmusic: +; script command 0x81 + + call PlayMapMusic + ret + +Script_playmusic: +; script command 0x7e +; parameters: music_pointer + + ld de, MUSIC_NONE + call PlayMusic + xor a + ld [wMusicFade], a + call MaxVolume + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + call PlayMusic + ret + +Script_musicfadeout: +; script command 0x80 +; parameters: music, fadetime + + call GetScriptByte + ld [wMusicFadeID], a + call GetScriptByte + ld [wMusicFadeID + 1], a + call GetScriptByte + and $ff ^ (1 << MUSIC_FADE_IN_F) + ld [wMusicFade], a + ret + +Script_playsound: +; script command 0x84 +; parameters: sound_pointer + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + call PlaySFX + ret + +Script_waitsfx: +; script command 0x85 + + call WaitSFX + ret + +Script_warpsound: +; script command 0x86 + + farcall GetWarpSFX + call PlaySFX + ret + +Script_cry: +; script command 0x83 +; parameters: cry_id + + call GetScriptByte + push af + call GetScriptByte + pop af + and a + jr nz, .ok + ld a, [wScriptVar] +.ok + call PlayMonCry + ret + +Script_setlasttalked: +; script command 0x67 +; parameters: object_id + + call GetScriptByte + ldh [hLastTalked], a + ret + +Script_applymovement: +; script command 0x68 +; parameters: object_id, data + + call GetScriptByte + ld c, a + +ApplyMovement: + push bc + ld a, c + farcall SetFlagsForMovement_1 + pop bc + + push bc + call SetFlagsForMovement_2 + pop bc + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, [wScriptBank] + ld b, a + call GetMovementData + ret c + + ld a, SCRIPT_WAIT_MOVEMENT + ld [wScriptMode], a + call StopScript + ret + +SetFlagsForMovement_2: + farcall _SetFlagsForMovement_2 + ret + +Script_applymovementlasttalked: +; script command 0x69 +; parameters: data +; apply movement to last talked + + ldh a, [hLastTalked] + ld c, a + jp ApplyMovement + +Script_faceplayer: +; script command 0x6a + + ldh a, [hLastTalked] + and a + ret z + ld d, $0 + ldh a, [hLastTalked] + ld e, a + farcall GetRelativeFacing + ld a, d + add a + add a + ld e, a + ldh a, [hLastTalked] + ld d, a + call ApplyObjectFacing + ret + +Script_faceobject: +; script command 0x6b +; parameters: object1, object2 + + call GetScriptByte + cp LAST_TALKED + jr c, .ok + ldh a, [hLastTalked] +.ok + ld e, a + call GetScriptByte + cp LAST_TALKED + jr nz, .ok2 + ldh a, [hLastTalked] +.ok2 + ld d, a + push de + farcall GetRelativeFacing + pop bc + ret c + ld a, d + add a + add a + ld e, a + ld d, c + call ApplyObjectFacing + ret + +Script_turnobject: +; script command 0x75 +; parameters: object_id, facing + + call GetScriptByte + cp LAST_TALKED + jr nz, .ok + ldh a, [hLastTalked] +.ok + ld d, a + call GetScriptByte + add a + add a + ld e, a + call ApplyObjectFacing + ret + +ApplyObjectFacing: + ld a, d + push de + call CheckObjectVisibility + jr c, .not_visible + ld hl, OBJECT_SPRITE + add hl, bc + ld a, [hl] + push bc + call DoesSpriteHaveFacings + pop bc + jr c, .not_visible ; STILL_SPRITE + ld hl, OBJECT_FLAGS1 + add hl, bc + bit FIXED_FACING_F, [hl] + jr nz, .not_visible + pop de + ld a, e + call SetSpriteDirection + call UpdateSprites + ret + +.not_visible + pop de + scf + ret + +Script_variablesprite: +; script command 0x6c +; parameters: byte, sprite + + call GetScriptByte + ld e, a + ld d, $0 + ld hl, wVariableSprites + add hl, de + call GetScriptByte + ld [hl], a + ret + +Script_appear: +; script command 0x6e +; parameters: object_id + + call GetScriptByte + call _CopyObjectStruct + ldh a, [hMapObjectIndexBuffer] + ld b, 0 ; clear + call ApplyEventActionAppearDisappear + ret + +Script_disappear: +; script command 0x6d +; parameters: object_id + + call GetScriptByte + cp LAST_TALKED + jr nz, .ok + ldh a, [hLastTalked] +.ok + call DeleteObjectStruct + ldh a, [hMapObjectIndexBuffer] + ld b, 1 ; set + call ApplyEventActionAppearDisappear + farcall _UpdateSprites + ret + +ApplyEventActionAppearDisappear: + push bc + call GetMapObject + ld hl, MAPOBJECT_EVENT_FLAG + add hl, bc + pop bc + ld e, [hl] + inc hl + ld d, [hl] + ld a, -1 + cp e + jr nz, .okay + cp d + jr nz, .okay + xor a + ret +.okay + call EventFlagAction + ret + +Script_follow: +; script command 0x6f +; parameters: object2, object1 + + call GetScriptByte + ld b, a + call GetScriptByte + ld c, a + farcall StartFollow + ret + +Script_stopfollow: +; script command 0x70 + + farcall StopFollow + ret + +Script_moveobject: +; script command 0x71 +; parameters: object id, x, y + + call GetScriptByte + ld b, a + call GetScriptByte + add 4 + ld d, a + call GetScriptByte + add 4 + ld e, a + farcall CopyDECoordsToMapObject + ret + +Script_writeobjectxy: +; script command 0x72 +; parameters: object_id + + call GetScriptByte + cp LAST_TALKED + jr nz, .ok + ldh a, [hLastTalked] +.ok + ld b, a + farcall WriteObjectXY + ret + +Script_follownotexact: +; script command 0x76 +; parameters: object2, object1 + + call GetScriptByte + ld b, a + call GetScriptByte + ld c, a + farcall FollowNotExact + ret + +Script_loademote: +; script command 0x73 +; parameters: bubble + + call GetScriptByte + cp EMOTE_FROM_MEM + jr nz, .not_var_emote + ld a, [wScriptVar] +.not_var_emote + ld c, a + farcall LoadEmote + ret + +Script_showemote: +; script command 0x74 +; parameters: bubble, object_id, time + + call GetScriptByte + ld [wScriptVar], a + call GetScriptByte + cp LAST_TALKED + jr z, .ok + ldh [hLastTalked], a +.ok + call GetScriptByte + ld [wScriptDelay], a + ld b, BANK(ShowEmoteScript) + ld de, ShowEmoteScript + jp ScriptCall + +ShowEmoteScript: + loademote EMOTE_FROM_MEM + applymovementlasttalked .Show + pause 0 + applymovementlasttalked .Hide + end + +.Show: + show_emote + step_sleep 1 + step_end + +.Hide: + hide_emote + step_sleep 1 + step_end + +Script_earthquake: +; script command 0x77 +; parameters: param + + ld hl, EarthquakeMovement + ld de, wEarthquakeMovementDataBuffer + ld bc, EarthquakeMovement.End - EarthquakeMovement + call CopyBytes + call GetScriptByte + ld [wEarthquakeMovementDataBuffer + 1], a + and %00111111 + ld [wEarthquakeMovementDataBuffer + 3], a + ld b, BANK(.script) + ld de, .script + jp ScriptCall + +.script + applymovement PLAYER, wEarthquakeMovementDataBuffer + end + +EarthquakeMovement: + step_shake 16 ; the 16 gets overwritten with the script byte + step_sleep 16 ; the 16 gets overwritten with the lower 6 bits of the script byte + step_end +.End + +Script_loadpikachudata: +; script command 0x59 + + ld a, PIKACHU + ld [wTempWildMonSpecies], a + ld a, 5 + ld [wCurPartyLevel], a + ret + +Script_randomwildmon: +; script command 0x5a + + xor a + ld [wBattleScriptFlags], a + ret + +Script_loadtemptrainer: +; script command 0x5b + + ld a, (1 << 7) | 1 + ld [wBattleScriptFlags], a + ld a, [wTempTrainerClass] + ld [wOtherTrainerClass], a + ld a, [wTempTrainerID] + ld [wOtherTrainerID], a + ret + +Script_loadwildmon: +; script command 0x5c +; parameters: pokemon, level + + ld a, (1 << 7) + ld [wBattleScriptFlags], a + call GetScriptByte + ld [wTempWildMonSpecies], a + call GetScriptByte + ld [wCurPartyLevel], a + ret + +Script_loadtrainer: +; script command 0x5d +; parameters: trainer_group, trainer_id + + ld a, (1 << 7) | 1 + ld [wBattleScriptFlags], a + call GetScriptByte + ld [wOtherTrainerClass], a + call GetScriptByte + ld [wOtherTrainerID], a + ret + +Script_startbattle: +; script command 0x5e + + call BufferScreen + predef StartBattle + ld a, [wBattleResult] + and $ff ^ BATTLERESULT_BITMASK + ld [wScriptVar], a + ret + +Script_catchtutorial: +; script command 0x60 +; parameters: byte + + call GetScriptByte + ld [wBattleType], a + call BufferScreen + farcall CatchTutorial + jp Script_reloadmap + +Script_reloadmapafterbattle: +; script command 0x5f + + ld hl, wBattleScriptFlags + ld d, [hl] + ld [hl], 0 + ld a, [wBattleResult] + and $ff ^ BATTLERESULT_BITMASK + cp LOSE + jr nz, .notblackedout + ld b, BANK(Script_BattleWhiteout) + ld hl, Script_BattleWhiteout + jp ScriptJump + +.notblackedout + bit 0, d + jr z, .was_wild + farcall MomTriesToBuySomething + jr .done + +.was_wild + ld a, [wBattleResult] + bit BATTLERESULT_BOX_FULL, a + jr z, .done + ld b, BANK(Script_SpecialBillCall) + ld de, Script_SpecialBillCall + farcall LoadScriptBDE +.done + jp Script_reloadmap + +Script_reloadmap: +; script command 0x7a + + xor a + ld [wBattleScriptFlags], a + ld a, MAPSETUP_RELOADMAP + ldh [hMapEntryMethod], a + ld a, MAPSTATUS_ENTER + call LoadMapStatus + call StopScript + ret + +Script_scall: +; script command 0x0 +; parameters: pointer + + ld a, [wScriptBank] + ld b, a + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + jr ScriptCall + +Script_farscall: +; script command 0x1 +; parameters: pointer + + call GetScriptByte + ld b, a + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + jr ScriptCall + +Script_memcall: +; script command 0x2 +; parameters: pointer + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld b, [hl] + inc hl + ld e, [hl] + inc hl + ld d, [hl] + ; fallthrough + +ScriptCall: +; Bug: The script stack has a capacity of 5 scripts, yet there is +; nothing to stop you from pushing a sixth script. The high part +; of the script address can then be overwritten by modifications +; to wScriptDelay, causing the script to return to the rst/interrupt +; space. + + push de + ld hl, wScriptStackSize + ld e, [hl] + inc [hl] + ld d, 0 + ld hl, wScriptStack + add hl, de + add hl, de + add hl, de + pop de + ld a, [wScriptBank] + ld [hli], a + ld a, [wScriptPos] + ld [hli], a + ld a, [wScriptPos + 1] + ld [hl], a + ld a, b + ld [wScriptBank], a + ld a, e + ld [wScriptPos], a + ld a, d + ld [wScriptPos + 1], a + ret + +CallCallback:: + ld a, [wScriptBank] + or $80 + ld [wScriptBank], a + jp ScriptCall + +Script_sjump: +; script command 0x3 +; parameters: pointer + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, [wScriptBank] + ld b, a + jp ScriptJump + +Script_farsjump: +; script command 0x4 +; parameters: pointer + + call GetScriptByte + ld b, a + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + jp ScriptJump + +Script_memjump: +; script command 0x5 +; parameters: pointer + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld b, [hl] + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + jp ScriptJump + +Script_iffalse: +; script command 0x8 +; parameters: pointer + + ld a, [wScriptVar] + and a + jp nz, SkipTwoScriptBytes + jp Script_sjump + +Script_iftrue: +; script command 0x9 +; parameters: pointer + + ld a, [wScriptVar] + and a + jp nz, Script_sjump + jp SkipTwoScriptBytes + +Script_ifequal: +; script command 0x6 +; parameters: byte, pointer + + call GetScriptByte + ld hl, wScriptVar + cp [hl] + jr z, Script_sjump + jr SkipTwoScriptBytes + +Script_ifnotequal: +; script command 0x7 +; parameters: byte, pointer + + call GetScriptByte + ld hl, wScriptVar + cp [hl] + jr nz, Script_sjump + jr SkipTwoScriptBytes + +Script_ifgreater: +; script command 0xa +; parameters: byte, pointer + + ld a, [wScriptVar] + ld b, a + call GetScriptByte + cp b + jr c, Script_sjump + jr SkipTwoScriptBytes + +Script_ifless: +; script command 0xb +; parameters: byte, pointer + + call GetScriptByte + ld b, a + ld a, [wScriptVar] + cp b + jr c, Script_sjump + jr SkipTwoScriptBytes + +Script_jumpstd: +; script command 0xc +; parameters: predefined_script + + call StdScript + jr ScriptJump + +Script_callstd: +; script command 0xd +; parameters: predefined_script + + call StdScript + ld d, h + ld e, l + jp ScriptCall + +StdScript: + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld hl, StdScripts + add hl, de + add hl, de + add hl, de + ld a, BANK(StdScripts) + call GetFarByte + ld b, a + inc hl + ld a, BANK(StdScripts) + call GetFarHalfword + ret + +SkipTwoScriptBytes: + call GetScriptByte + call GetScriptByte + ret + +ScriptJump: + ld a, b + ld [wScriptBank], a + ld a, l + ld [wScriptPos], a + ld a, h + ld [wScriptPos + 1], a + ret + +Script_prioritysjump: +; script command 0x8c +; parameters: pointer + + ld a, [wScriptBank] + ld [wPriorityScriptBank], a + call GetScriptByte + ld [wPriorityScriptAddr], a + call GetScriptByte + ld [wPriorityScriptAddr + 1], a + ld hl, wScriptFlags + set 3, [hl] + ret + +Script_checkscene: +; script command 0x13 + + call CheckScenes + jr z, .no_scene + ld [wScriptVar], a + ret + +.no_scene + ld a, $ff + ld [wScriptVar], a + ret + +Script_checkmapscene: +; script command 0x11 +; parameters: map_group, map_id + + call GetScriptByte + ld b, a + call GetScriptByte + ld c, a + call GetMapSceneID + ld a, d + or e + jr z, .no_scene + ld a, [de] + ld [wScriptVar], a + ret + +.no_scene + ld a, $ff + ld [wScriptVar], a + ret + +Script_setscene: +; script command 0x14 +; parameters: scene_id + + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + jr DoScene + +Script_setmapscene: +; script command 0x12 +; parameters: map_group, map_id, scene_id + + call GetScriptByte + ld b, a + call GetScriptByte + ld c, a +DoScene: + call GetMapSceneID + ld a, d + or e + jr z, .no_scene + call GetScriptByte + ld [de], a +.no_scene + ret + +Script_readmem: +; script command 0x19 +; parameters: address + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, [hl] + ld [wScriptVar], a + ret + +Script_writemem: +; script command 0x1a +; parameters: address + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, [wScriptVar] + ld [hl], a + ret + +Script_loadmem: +; script command 0x1b +; parameters: address, value + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + call GetScriptByte + ld [hl], a + ret + +Script_setval: +; script command 0x15 +; parameters: value + + call GetScriptByte + ld [wScriptVar], a + ret + +Script_addval: +; script command 0x16 +; parameters: value + + call GetScriptByte + ld hl, wScriptVar + add [hl] + ld [hl], a + ret + +Script_random: +; script command 0x17 +; parameters: input + + call GetScriptByte + ld [wScriptVar], a + and a + ret z + + ld c, a + call .Divide256byC + and a + jr z, .no_restriction ; 256 % b == 0 + ld b, a + xor a + sub b + ld b, a +.loop + push bc + call Random + pop bc + ldh a, [hRandomAdd] + cp b + jr nc, .loop + jr .finish + +.no_restriction + push bc + call Random + pop bc + ldh a, [hRandomAdd] + +.finish + push af + ld a, [wScriptVar] + ld c, a + pop af + call SimpleDivide + ld [wScriptVar], a + ret + +.Divide256byC: + xor a + ld b, a + sub c +.mod_loop + inc b + sub c + jr nc, .mod_loop + dec b + add c + ret + +Script_readvar: +; script command 0x1c +; parameters: variable_id + + call GetScriptByte + call GetVarAction + ld a, [de] + ld [wScriptVar], a + ret + +Script_writevar: +; script command 0x1d +; parameters: variable_id + + call GetScriptByte + call GetVarAction + ld a, [wScriptVar] + ld [de], a + ret + +Script_loadvar: +; script command 0x1e +; parameters: variable_id, value + + call GetScriptByte + call GetVarAction + call GetScriptByte + ld [de], a + ret + +GetVarAction: + ld c, a + farcall _GetVarAction + ret + +Script_checkver: +; script command 0x18 + + ld a, [.gs_version] + ld [wScriptVar], a + ret + +.gs_version: + db GS_VERSION + +Script_getmonname: +; script command 0x40 +; parameters: string_buffer, mon_id (0 aka USE_SCRIPT_VAR to use wScriptVar) + + call GetScriptByte + and a + jr nz, .gotit + ld a, [wScriptVar] +.gotit + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld de, wStringBuffer1 + +GetStringBuffer: + call GetScriptByte + cp NUM_STRING_BUFFERS + jr c, .ok + xor a +.ok + +CopyConvertedText: + ld hl, wStringBuffer3 + ld bc, wStringBuffer4 - wStringBuffer3 + call AddNTimes + call CopyName2 + ret + +Script_getitemname: +; script command 0x41 +; parameters: string_buffer, item_id (0 aka USE_SCRIPT_VAR to use wScriptVar) + + call GetScriptByte + and a ; USE_SCRIPT_VAR + jr nz, .ok + ld a, [wScriptVar] +.ok + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld de, wStringBuffer1 + jr GetStringBuffer + +Script_getcurlandmarkname: +; script command 0x42 +; parameters: string_buffer + + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + call GetWorldMapLocation + +ConvertLandmarkToText: + ld e, a + farcall GetLandmarkName + ld de, wStringBuffer1 + jp GetStringBuffer + +Script_gettrainername: +; script command 0x43 +; parameters: string_buffer, trainer_group, trainer_id + + call GetScriptByte + ld c, a + call GetScriptByte + ld b, a + farcall GetTrainerName + jr GetStringBuffer + +Script_getmoney: +; script command 0x3d +; parameters: string_buffer, account + + call ResetStringBuffer1 + call GetMoneyAccount + ld hl, wStringBuffer1 + lb bc, PRINTNUM_LEFTALIGN | 3, 6 + call PrintNum + ld de, wStringBuffer1 + jp GetStringBuffer + +Script_getcoins: +; script command 0x3e +; parameters: string_buffer + + call ResetStringBuffer1 + ld hl, wStringBuffer1 + ld de, wCoins + lb bc, PRINTNUM_LEFTALIGN | 2, 6 + call PrintNum + ld de, wStringBuffer1 + jp GetStringBuffer + +Script_getnum: +; script command 0x3f +; parameters: string_buffer + + call ResetStringBuffer1 + ld de, wScriptVar + ld hl, wStringBuffer1 + lb bc, PRINTNUM_LEFTALIGN | 1, 3 + call PrintNum + ld de, wStringBuffer1 + jp GetStringBuffer + +ResetStringBuffer1: + ld hl, wStringBuffer1 + ld bc, NAME_LENGTH + 2 + ld a, "@" + call ByteFill + ret + +Script_getstring: +; script command 0x44 +; parameters: string_buffer, text_pointer + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld a, [wScriptBank] + ld hl, CopyName1 + rst FarCall + ld de, wStringBuffer2 + jp GetStringBuffer + +Script_givepokemail: +; script command 0x2f +; parameters: pointer + + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + ld a, [wScriptBank] + call GetFarByte + ld b, a + push bc + inc hl + ld bc, MAIL_MSG_LENGTH + ld de, wceed + ld a, [wScriptBank] + call FarCopyBytes + pop bc + farcall GivePokeMail + ret + +Script_checkpokemail: +; script command 0x30 +; parameters: pointer + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld a, [wScriptBank] + ld b, a + farcall CheckPokeMail + ret + +Script_giveitem: +; script command 0x1f +; parameters: item, quantity + + call GetScriptByte + cp ITEM_FROM_MEM + jr nz, .ok + ld a, [wScriptVar] +.ok + ld [wCurItem], a + call GetScriptByte + ld [wItemQuantityChangeBuffer], a + ld hl, wNumItems + call ReceiveItem + jr nc, .full + ld a, TRUE + ld [wScriptVar], a + ret +.full + xor a + ld [wScriptVar], a + ret + +Script_takeitem: +; script command 0x20 +; parameters: item, quantity + + xor a + ld [wScriptVar], a + call GetScriptByte + ld [wCurItem], a + call GetScriptByte + ld [wItemQuantityChangeBuffer], a + ld a, -1 + ld [wCurItemQuantity], a + ld hl, wNumItems + call TossItem + ret nc + ld a, TRUE + ld [wScriptVar], a + ret + +Script_checkitem: +; script command 0x21 +; parameters: item + + xor a + ld [wScriptVar], a + call GetScriptByte + ld [wCurItem], a + ld hl, wNumItems + call CheckItem + ret nc + ld a, TRUE + ld [wScriptVar], a + ret + +Script_givemoney: +; script command 0x22 +; parameters: account, money + + call GetMoneyAccount + call LoadMoneyAmountToMem + farcall GiveMoney + ret + +Script_takemoney: +; script command 0x23 +; parameters: account, money + + call GetMoneyAccount + call LoadMoneyAmountToMem + farcall TakeMoney + ret + +Script_checkmoney: +; script command 0x24 +; parameters: account, money + + call GetMoneyAccount + call LoadMoneyAmountToMem + farcall CompareMoney + +CompareMoneyAction: + jr c, .less + jr z, .exact + ld a, HAVE_MORE + jr .done +.exact + ld a, HAVE_AMOUNT + jr .done +.less + ld a, HAVE_LESS +.done + ld [wScriptVar], a + ret + +GetMoneyAccount: + call GetScriptByte + and a + ld de, wMoney ; YOUR_MONEY + ret z + ld de, wMomsMoney ; MOMS_MONEY + ret + +LoadMoneyAmountToMem: + ld bc, hMoneyTemp + push bc + call GetScriptByte + ld [bc], a + inc bc + call GetScriptByte + ld [bc], a + inc bc + call GetScriptByte + ld [bc], a + pop bc + ret + +Script_givecoins: +; script command 0x25 +; parameters: coins + + call LoadCoinAmountToMem + farcall GiveCoins + ret + +Script_takecoins: +; script command 0x26 +; parameters: coins + + call LoadCoinAmountToMem + farcall TakeCoins + ret + +Script_checkcoins: +; script command 0x27 +; parameters: coins + + call LoadCoinAmountToMem + farcall CheckCoins + jr CompareMoneyAction + +LoadCoinAmountToMem: + call GetScriptByte + ldh [hMoneyTemp + 1], a + call GetScriptByte + ldh [hMoneyTemp], a + ld bc, hMoneyTemp + ret + +Script_checktime: +; script command 0x2b +; parameters: time + + xor a + ld [wScriptVar], a + farcall CheckTime + call GetScriptByte + and c + ret z + ld a, TRUE + ld [wScriptVar], a + ret + +Script_checkpoke: +; script command 0x2c +; parameters: pokemon + + xor a + ld [wScriptVar], a + call GetScriptByte + ld hl, wPartySpecies + ld de, 1 + call IsInArray + ret nc + ld a, TRUE + ld [wScriptVar], a + ret + +Script_addcellnum: +; script command 0x28 +; parameters: person + + xor a + ld [wScriptVar], a + call GetScriptByte + ld c, a + farcall AddPhoneNumber + ret nc + ld a, TRUE + ld [wScriptVar], a + ret + +Script_delcellnum: +; script command 0x29 +; parameters: person + + xor a + ld [wScriptVar], a + call GetScriptByte + ld c, a + farcall DelCellNum + ret nc + ld a, TRUE + ld [wScriptVar], a + ret + +Script_checkcellnum: +; script command 0x2a +; parameters: person +; returns false if the cell number is not in your phone + + xor a + ld [wScriptVar], a + call GetScriptByte + ld c, a + farcall CheckCellNum + ret nc + ld a, TRUE + ld [wScriptVar], a + ret + +Script_specialphonecall: +; script command 0x9b +; parameters: call_id + + call GetScriptByte + ld [wSpecialPhoneCallID], a + call GetScriptByte + ld [wSpecialPhoneCallID + 1], a + ret + +Script_checkphonecall: +; script command 0x9c +; returns false if no special phone call is stored + + ld a, [wSpecialPhoneCallID] + and a + jr z, .ok + ld a, TRUE +.ok + ld [wScriptVar], a + ret + +Script_givepoke: +; script command 0x2d +; parameters: pokemon, level, item, trainer, trainer_name_pointer, pkmn_nickname + + call GetScriptByte + ld [wCurPartySpecies], a + call GetScriptByte + ld [wCurPartyLevel], a + call GetScriptByte + ld [wCurItem], a + call GetScriptByte + and a + ld b, a + jr z, .ok + ld hl, wScriptPos + ld e, [hl] + inc hl + ld d, [hl] + call GetScriptByte + call GetScriptByte + call GetScriptByte + call GetScriptByte +.ok + farcall GivePoke + ld a, b + ld [wScriptVar], a + ret + +Script_giveegg: +; script command 0x2e +; parameters: pokemon, level +; if no room in the party, return 0 in wScriptVar; else, return 2 + + xor a ; PARTYMON + ld [wScriptVar], a + ld [wMonType], a + call GetScriptByte + ld [wCurPartySpecies], a + call GetScriptByte + ld [wCurPartyLevel], a + farcall GiveEgg + ret nc + ld a, 2 + ld [wScriptVar], a + ret + +Script_setevent: +; script command 0x33 +; parameters: bit_number + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld b, SET_FLAG + call EventFlagAction + ret + +Script_clearevent: +; script command 0x32 +; parameters: bit_number + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld b, RESET_FLAG + call EventFlagAction + ret + +Script_checkevent: +; script command 0x31 +; parameters: bit_number + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld b, CHECK_FLAG + call EventFlagAction + ld a, c + and a + jr z, .false + ld a, TRUE +.false + ld [wScriptVar], a + ret + +Script_setflag: +; script command 0x36 +; parameters: bit_number + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld b, SET_FLAG + call _EngineFlagAction + ret + +Script_clearflag: +; script command 0x35 +; parameters: bit_number + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld b, RESET_FLAG + call _EngineFlagAction + ret + +Script_checkflag: +; script command 0x34 +; parameters: bit_number + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld b, CHECK_FLAG + call _EngineFlagAction + ld a, c + and a + jr z, .false + ld a, TRUE +.false + ld [wScriptVar], a + ret + +_EngineFlagAction: + farcall EngineFlagAction + ret + +Script_wildoff: +; script command 0x38 + + ld hl, wStatusFlags + set STATUSFLAGS_NO_WILD_ENCOUNTERS_F, [hl] + ret + +Script_wildon: +; script command 0x37 + + ld hl, wStatusFlags + res STATUSFLAGS_NO_WILD_ENCOUNTERS_F, [hl] + ret + +Script_xycompare: +; script command 0x39 +; parameters: pointer + + call GetScriptByte + ld [wXYComparePointer], a + call GetScriptByte + ld [wXYComparePointer + 1], a + ret + +Script_warpfacing: +; script command 0xa1 +; parameters: facing, map_group, map_id, x, y + + call GetScriptByte + maskbits NUM_DIRECTIONS + ld c, a + ld a, [wPlayerSpriteSetupFlags] + set PLAYERSPRITESETUP_CUSTOM_FACING_F, a + or c + ld [wPlayerSpriteSetupFlags], a +; fall through + +Script_warp: +; script command 0x3c +; parameters: map_group, map_id, x, y + +; This seems to be some sort of error handling case. + call GetScriptByte + and a + jr z, .not_ok + ld [wMapGroup], a + call GetScriptByte + ld [wMapNumber], a + call GetScriptByte + ld [wXCoord], a + call GetScriptByte + ld [wYCoord], a + ld a, SPAWN_N_A + ld [wDefaultSpawnpoint], a + ld a, MAPSETUP_WARP + ldh [hMapEntryMethod], a + ld a, MAPSTATUS_ENTER + call LoadMapStatus + call StopScript + ret + +.not_ok + call GetScriptByte + call GetScriptByte + call GetScriptByte + ld a, SPAWN_N_A + ld [wDefaultSpawnpoint], a + ld a, MAPSETUP_BADWARP + ldh [hMapEntryMethod], a + ld a, MAPSTATUS_ENTER + call LoadMapStatus + call StopScript + ret + +Script_warpmod: +; script command 0x3a +; parameters: warp_id, map_group, map_id + + call GetScriptByte + ld [wBackupWarpNumber], a + call GetScriptByte + ld [wBackupMapGroup], a + call GetScriptByte + ld [wBackupMapNumber], a + ret + +Script_blackoutmod: +; script command 0x3b +; parameters: map_group, map_id + + call GetScriptByte + ld [wLastSpawnMapGroup], a + call GetScriptByte + ld [wLastSpawnMapNumber], a + ret + +Script_dontrestartmapmusic: +; script command 0x82 + + ld a, TRUE + ld [wDontPlayMapMusicOnReload], a + ret + +Script_writecmdqueue: +; script command 0x7c +; parameters: queue_pointer + + call GetScriptByte + ld e, a + call GetScriptByte + ld d, a + ld a, [wScriptBank] + ld b, a + farcall WriteCmdQueue ; no need to farcall + ret + +Script_delcmdqueue: +; script command 0x7d +; parameters: byte + + xor a + ld [wScriptVar], a + call GetScriptByte + ld b, a + farcall DelCmdQueue ; no need to farcall + ret c + ld a, TRUE + ld [wScriptVar], a + ret + +Script_changemapblocks: +; script command 0x78 +; parameters: map_data_pointer + + call GetScriptByte + ld [wMapBlocksBank], a + call GetScriptByte + ld [wMapBlocksPointer], a + call GetScriptByte + ld [wMapBlocksPointer + 1], a + call ChangeMap + call BufferScreen + ret + +Script_changeblock: +; script command 0x79 +; parameters: x, y, block + + call GetScriptByte + add 4 + ld d, a + call GetScriptByte + add 4 + ld e, a + call GetBlockLocation + call GetScriptByte + ld [hl], a + call BufferScreen + ret + +Script_reloadmappart:: +; script command 0x7b + + xor a + ldh [hBGMapMode], a + call OverworldTextModeSwitch + call GetMovementPermissions + call ApplyTilemap + call UpdateSprites + ret + +Script_warpcheck: +; script command 0x8d + + call WarpCheck + ret nc + farcall EnableEvents + ret + +Script_enableevents: +; unused + farcall EnableEvents + ret + +Script_newloadmap: +; script command 0x89 +; parameters: which_method + + call GetScriptByte + ldh [hMapEntryMethod], a + ld a, MAPSTATUS_ENTER + call LoadMapStatus + call StopScript + ret + +Script_reloadandreturn: +; script command 0x91 + + call Script_newloadmap + jp Script_end + +Script_opentext: +; script command 0x47 + + call OpenText + ret + +Script_refreshscreen: +; script command 0x48 +; parameters: dummy + + call RefreshScreen + call GetScriptByte + ret + +Script_writeunusedbytebuffer: +; script command 0x4a +; parameters: byte + + call GetScriptByte + ld [wUnusedScriptByteBuffer], a + ret + + db closetext_command ; unused + +Script_closetext: +; script command 0x49 + + ldh a, [hOAMUpdate] + push af + ld a, $01 + ldh [hOAMUpdate], a + call WaitBGMap + pop af + ldh [hOAMUpdate], a + call CloseText + ret + +Script_autoinput: +; script command 0x88 +; parameters: input_pointer + + call GetScriptByte + push af + call GetScriptByte + ld l, a + call GetScriptByte + ld h, a + pop af + call StartAutoInput + ret + +Script_pause: +; script command 0x8a +; parameters: length + + call GetScriptByte + and a + jr z, .loop + ld [wScriptDelay], a +.loop + ld c, 2 + call DelayFrames + ld hl, wScriptDelay + dec [hl] + jr nz, .loop + ret + +Script_deactivatefacing: +; script command 0x8b +; parameters: time + + call GetScriptByte + and a + jr z, .no_time + ld [wScriptDelay], a +.no_time + ld a, SCRIPT_WAIT + ld [wScriptMode], a + call StopScript + ret + +Script_stopandsjump: +; script command 0x8e +; parameters: pointer + + call StopScript + jp Script_sjump + +Script_end: +; script command 0x90 + + call ExitScriptSubroutine + jr c, .resume + ret + +.resume + xor a + ld [wScriptRunning], a + ld a, SCRIPT_OFF + ld [wScriptMode], a + ld hl, wScriptFlags + res 0, [hl] + call StopScript + ret + +Script_return: +; script command 0x8f + + call ExitScriptSubroutine + jr c, .dummy +.dummy + ld hl, wScriptFlags + res 0, [hl] + call StopScript + ret + +ExitScriptSubroutine: +; Return carry if there's no parent to return to. + + ld hl, wScriptStackSize + ld a, [hl] + and a + jr z, .done + dec [hl] + ld e, [hl] + ld d, $0 + ld hl, wScriptStack + add hl, de + add hl, de + add hl, de + ld a, [hli] + ld b, a + and " " + ld [wScriptBank], a + ld a, [hli] + ld e, a + ld [wScriptPos], a + ld a, [hl] + ld d, a + ld [wScriptPos + 1], a + and a + ret +.done + scf + ret + +Script_endall: +; script command 0x92 + + xor a + ld [wScriptStackSize], a + ld [wScriptRunning], a + ld a, SCRIPT_OFF + ld [wScriptMode], a + ld hl, wScriptFlags + res 0, [hl] + call StopScript + ret + +Script_halloffame: +; script command 0x9f + + ld hl, wGameTimerPause + res GAMETIMERPAUSE_TIMER_PAUSED_F, [hl] + farcall HallOfFame + ld hl, wGameTimerPause + set GAMETIMERPAUSE_TIMER_PAUSED_F, [hl] + jr ReturnFromCredits + +Script_credits: +; script command 0xa0 + + farcall RedCredits +ReturnFromCredits: + call Script_endall + ld a, MAPSTATUS_DONE + call LoadMapStatus + call StopScript + ret + +; unused + ld a, [.gs_version] + ld [wScriptVar], a + ret + +.gs_version: + db GS_VERSION diff --git a/engine/overworld/select_menu.asm b/engine/overworld/select_menu.asm new file mode 100644 index 00000000..18532eda --- /dev/null +++ b/engine/overworld/select_menu.asm @@ -0,0 +1,172 @@ +SelectMenu:: + call CheckRegisteredItem + jr c, .NotRegistered + jp UseRegisteredItem + +.NotRegistered: + call OpenText + ld b, BANK(MayRegisterItemText) + ld hl, MayRegisterItemText + call MapTextbox + call WaitButton + jp CloseText + +MayRegisterItemText: + text_far _MayRegisterItemText + text_end + +CheckRegisteredItem: + ld a, [wWhichRegisteredItem] + and a + jr z, .NoRegisteredItem + and REGISTERED_POCKET + rlca + rlca + ld hl, .Pockets + rst JumpTable + ret + +.Pockets: +; entries correspond to *_POCKET constants + dw .CheckItem + dw .CheckBall + dw .CheckKeyItem + dw .CheckTMHM + +.CheckItem: + ld hl, wNumItems + call .CheckRegisteredNo + jr c, .NoRegisteredItem + inc hl + ld e, a + ld d, 0 + add hl, de + add hl, de + call .IsSameItem + jr c, .NoRegisteredItem + and a + ret + +.CheckKeyItem: + ld a, [wRegisteredItem] + ld hl, wKeyItems + ld de, 1 + call IsInArray + jr nc, .NoRegisteredItem + ld a, [wRegisteredItem] + ld [wCurItem], a + and a + ret + +.CheckBall: + ld hl, wNumBalls + call .CheckRegisteredNo + jr nc, .NoRegisteredItem + inc hl + ld e, a + ld d, 0 + add hl, de + add hl, de + call .IsSameItem + jr c, .NoRegisteredItem + ret + +.CheckTMHM: + jr .NoRegisteredItem + +.NoRegisteredItem: + xor a + ld [wWhichRegisteredItem], a + ld [wRegisteredItem], a + scf + ret + +.CheckRegisteredNo: + ld a, [wWhichRegisteredItem] + and REGISTERED_NUMBER + dec a + cp [hl] + jr nc, .NotEnoughItems + ld [wCurItemQuantity], a + and a + ret + +.NotEnoughItems: + scf + ret + +.IsSameItem: + ld a, [wRegisteredItem] + cp [hl] + jr nz, .NotSameItem + ld [wCurItem], a + and a + ret + +.NotSameItem: + scf + ret + +UseRegisteredItem: + farcall CheckItemMenu + ld a, [wItemAttributeParamBuffer] + ld hl, .SwitchTo + rst JumpTable + ret + +.SwitchTo: +; entries correspond to ITEMMENU_* constants + dw .CantUse + dw .NoFunction + dw .NoFunction + dw .NoFunction + dw .Current + dw .Party + dw .Overworld + +.NoFunction: + call OpenText + call CantUseItem + call CloseText + and a + ret + +.Current: + call OpenText + call DoItemEffect + call CloseText + and a + ret + +.Party: + call RefreshScreen + call FadeToMenu + call DoItemEffect + call CloseSubmenu + call CloseText + and a + ret + +.Overworld: + call RefreshScreen + ld a, 1 + ld [wUsingItemWithSelect], a + call DoItemEffect + xor a + ld [wUsingItemWithSelect], a + ld a, [wItemEffectSucceeded] + cp 1 + jr nz, ._cantuse + scf + ld a, HMENURETURN_SCRIPT + ldh [hMenuReturn], a + ret + +.CantUse: + call RefreshScreen + +._cantuse + call CantUseItem + call CloseText + and a + ret diff --git a/engine/overworld/spawn_points.asm b/engine/overworld/spawn_points.asm new file mode 100644 index 00000000..1b92b1e0 --- /dev/null +++ b/engine/overworld/spawn_points.asm @@ -0,0 +1,56 @@ +EnterMapSpawnPoint: + ; loads the spawn point in wDefaultSpawnpoint + push hl + push de + ld a, [wDefaultSpawnpoint] + cp SPAWN_N_A + jr z, .spawn_n_a + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, SpawnPoints + add hl, de + ld a, [hli] + ld [wMapGroup], a + ld a, [hli] + ld [wMapNumber], a + ld a, [hli] + ld [wXCoord], a + ld a, [hli] + ld [wYCoord], a +.spawn_n_a + pop de + pop hl + ret + +IsSpawnPoint: +; Checks if the map loaded in de is a spawn point. Returns carry if it's a spawn point. + ld hl, SpawnPoints + ld c, 0 +.loop + ld a, [hl] + cp SPAWN_N_A + jr z, .nope + cp d + jr nz, .next + inc hl + ld a, [hld] + cp e + jr z, .yes + +.next + push bc + ld bc, 4 ; length of a spawn table entry + add hl, bc + pop bc + inc c + jr .loop + +.nope + and a + ret + +.yes + scf + ret diff --git a/engine/overworld/tile_events.asm b/engine/overworld/tile_events.asm new file mode 100644 index 00000000..bb566c99 --- /dev/null +++ b/engine/overworld/tile_events.asm @@ -0,0 +1,101 @@ +CheckWarpCollision:: +; Is this tile a warp? + ld a, [wPlayerStandingTile] + cp COLL_PIT + jr z, .warp + cp COLL_PIT_68 + jr z, .warp + and $f0 + cp HI_NYBBLE_WARPS + jr z, .warp + and a + ret + +.warp + scf + ret + +CheckDirectionalWarp:: +; If this is a directional warp, clear carry (press the designated button to warp). +; Else, set carry (immediate warp). + ld a, [wPlayerStandingTile] + cp COLL_WARP_CARPET_DOWN + jr z, .directional + cp COLL_WARP_CARPET_LEFT + jr z, .directional + cp COLL_WARP_CARPET_UP + jr z, .directional + cp COLL_WARP_CARPET_RIGHT + jr z, .directional + scf + ret + +.directional + xor a + ret + +CheckWarpFacingDown: + ld de, 1 + ld hl, .blocks + ld a, [wPlayerStandingTile] + call IsInArray + ret + +.blocks + db COLL_DOOR + db COLL_DOOR_79 + db COLL_STAIRCASE + db COLL_STAIRCASE_73 + db COLL_CAVE + db COLL_CAVE_74 + db COLL_WARP_PANEL + db COLL_DOOR_75 + db COLL_DOOR_7D + db -1 + +CheckGrassCollision:: + ld a, [wPlayerStandingTile] + ld hl, .blocks + ld de, 1 + call IsInArray + ret + +.blocks + db COLL_CUT_08 + db COLL_TALL_GRASS + db COLL_LONG_GRASS + db COLL_CUT_28 + db COLL_WATER + db COLL_GRASS_48 + db COLL_GRASS_49 + db COLL_GRASS_4A + db COLL_GRASS_4B + db COLL_GRASS_4C + db -1 + +CheckCutCollision: + ld a, c + ld hl, .blocks + ld de, 1 + call IsInArray + ret + +.blocks + db COLL_CUT_TREE + db COLL_CUT_TREE_1A + db COLL_TALL_GRASS_10 + db COLL_TALL_GRASS + db COLL_LONG_GRASS + db COLL_LONG_GRASS_1C + db -1 + +GetWarpSFX:: + ld a, [wPlayerStandingTile] + ld de, SFX_ENTER_DOOR + cp COLL_DOOR + ret z + ld de, SFX_WARP_TO + cp COLL_WARP_PANEL + ret z + ld de, SFX_EXIT_BUILDING + ret diff --git a/engine/overworld/time.asm b/engine/overworld/time.asm index 01273a75..a829cd4f 100755 --- a/engine/overworld/time.asm +++ b/engine/overworld/time.asm @@ -1,5 +1,5 @@ -InitializeStartDay_: ; 117f1 (4:57f1) - call Function118c9 +_InitializeStartDay: + call InitializeStartDay ret ClearDailyTimers: @@ -9,41 +9,45 @@ ClearDailyTimers: ld [wDailyResetTimer], a ret -InitCallReceiveDelay: +InitCallReceiveDelay:: xor a ld [wTimeCyclesSinceLastCall], a -Function11804: ; 11804 (4:5804) + +NextCallReceiveDelay: ld a, [wTimeCyclesSinceLastCall] - cp $3 - jr c, .asm_1180d - ld a, $3 -.asm_1180d + cp 3 + jr c, .okay + ld a, 3 + +.okay ld e, a - ld d, $0 + ld d, 0 ld hl, .ReceiveCallDelays add hl, de ld a, [hl] - jp Function11849 + jp RestartReceiveCallDelay .ReceiveCallDelays: db 20, 10, 5, 3 CheckReceiveCallTimer: - call Function11857 + call CheckReceiveCallDelay ; check timer ret nc ld hl, wTimeCyclesSinceLastCall ld a, [hl] - cp $3 - jr nc, .asm_11829 + cp 3 + jr nc, .ok inc [hl] -.asm_11829 - call Function11804 + +.ok + call NextCallReceiveDelay ; restart timer scf ret -Function1182e: ; 1182e (4:582e) - ld a, $1 -Function11830: +InitOneDayCountdown: + ld a, 1 + +InitNDaysCountdown: ld [hl], a push hl call UpdateTime @@ -52,17 +56,17 @@ Function11830: call CopyDayToHL ret -Function1183b: ; 1183b (4:583b) +CheckDayDependentEventHL: inc hl push hl call CalcDaysSince - call Function119b4 + call GetDaysSince pop hl dec hl - call Function11972 + call UpdateTimeRemaining ret -Function11849: ; 11849 (4:5849) +RestartReceiveCallDelay: ld hl, wReceiveCallDelay_MinsRemaining ld [hl], a call UpdateTime @@ -70,91 +74,92 @@ Function11849: ; 11849 (4:5849) call CopyDayHourMinToHL ret -Function11857: ; 11857 (4:5857) +CheckReceiveCallDelay: ld hl, wReceiveCallDelay_StartTime call CalcMinsHoursDaysSince - call Function1199a + call GetMinutesSinceIfLessThan60 ld hl, wReceiveCallDelay_MinsRemaining - call Function11972 + call UpdateTimeRemaining ret -asm_11867 +RestartDailyResetTimer: ld hl, wDailyResetTimer - jp Function1182e + jp InitOneDayCountdown -CheckDailyResetTimer: +CheckDailyResetTimer:: ld hl, wDailyResetTimer - call Function1183b + call CheckDayDependentEventHL ret nc xor a - ld hl, wDailyFlags - ld [hli], a - ld [hl], a - jr asm_11867 + ld hl, wDailyFlags1 + ld [hli], a ; wDailyFlags1 + ld [hl], a ; wDailyFlags2 + jr RestartDailyResetTimer StartBugContestTimer: - ld a, 20 + ld a, BUG_CONTEST_MINUTES ld [wBugContestMinsRemaining], a - ld a, 0 + ld a, BUG_CONTEST_SECONDS ld [wBugContestSecsRemaining], a call UpdateTime ld hl, wBugContestStartTime call CopyDayHourMinSecToHL ret -CheckBugContestTimer: +CheckBugContestTimer:: ld hl, wBugContestStartTime call CalcSecsMinsHoursDaysSince ld a, [wDaysSince] and a - jr nz, .asm_118c0 + jr nz, .timed_out ld a, [wHoursSince] and a - jr nz, .asm_118c0 - ld a, [wSecsSince] + jr nz, .timed_out + ld a, [wSecondsSince] ld b, a ld a, [wBugContestSecsRemaining] sub b - jr nc, .asm_118ae + jr nc, .okay add 60 -.asm_118ae + +.okay ld [wBugContestSecsRemaining], a - ld a, [wMinsSince] + ld a, [wMinutesSince] ld b, a ld a, [wBugContestMinsRemaining] sbc b ld [wBugContestMinsRemaining], a - jr c, .asm_118c0 + jr c, .timed_out and a ret -.asm_118c0 +.timed_out xor a ld [wBugContestMinsRemaining], a ld [wBugContestSecsRemaining], a scf ret -Function118c9: ; 118c9 (4:58c9) +InitializeStartDay: call UpdateTime - ld hl, wStartDay + ld hl, wTimerEventStartDay call CopyDayToHL ret -CheckPokerusTick: - ld hl, wStartDay +CheckPokerusTick:: + ld hl, wTimerEventStartDay call CalcDaysSince - call Function119b4 + call GetDaysSince and a - jr z, .asm_118e6 + jr z, .done ; not even a day has passed since game start ld b, a - farcall ApplyPokerusTick ; same bank -.asm_118e6 + farcall ApplyPokerusTick +.done xor a ret SetUnusedTwoDayTimer: - ld a, $2 + ld a, 2 ld hl, wUnusedTwoDayTimer ld [hl], a call UpdateTime @@ -162,63 +167,69 @@ SetUnusedTwoDayTimer: call CopyDayToHL ret -Function118f8: ; 118f8 (4:58f8) +CheckUnusedTwoDayTimer: ld hl, wUnusedTwoDayTimerStartDate call CalcDaysSince - call Function119b4 + call GetDaysSince ld hl, wUnusedTwoDayTimer - call Function11972 + call UpdateTimeRemaining ret - ld hl, wDailyFlags - set 2, [hl] +; unused + ld hl, wDailyFlags1 + set DAILYFLAGS1_SWARM_F, [hl] ret +; unused and a - ld hl, wDailyFlags - bit 2, [hl] + ld hl, wDailyFlags1 + bit DAILYFLAGS1_SWARM_F, [hl] ret nz scf ret -Function11917: ; 11917 (4:5917) - call Function11920 +RestartLuckyNumberCountdown: + call .GetDaysUntilNextFriday ld hl, wLuckyNumberDayBuffer - jp Function11830 + jp InitNDaysCountdown -Function11920: ; 11920 (4:5920) +.GetDaysUntilNextFriday: call GetWeekday ld c, a - ld a, $5 + ld a, FRIDAY sub c - jr z, .asm_1192b - jr nc, .asm_1192d -.asm_1192b - add $7 -.asm_1192d + jr z, .friday_saturday + jr nc, .earlier ; could have done "ret nc" + +.friday_saturday + add 7 + +.earlier ret -Function1192e: ; 1192e (4:592e) +_CheckLuckyNumberShowFlag: ld hl, wLuckyNumberDayBuffer - jp Function1183b + jp CheckDayDependentEventHL -Function11934: ; 11934 (4:5934) +DoMysteryGiftIfDayHasPassed: ld a, BANK(sMysteryGiftTimer) call OpenSRAM ld hl, sMysteryGiftTimer ld a, [hli] - ld [wCurHPAnimMaxHP], a + ld [wBuffer1], a ld a, [hl] ld [wBuffer2], a call CloseSRAM - ld hl, wCurHPAnimMaxHP - call Function1183b - jr nc, .asm_1195e - ld hl, wCurHPAnimMaxHP - call Function1182e + + ld hl, wBuffer1 + call CheckDayDependentEventHL + jr nc, .not_timed_out + ld hl, wBuffer1 + call InitOneDayCountdown call CloseSRAM farcall Function2a4f6 -.asm_1195e + +.not_timed_out ld a, BANK(sMysteryGiftTimer) call OpenSRAM ld hl, wBuffer1 @@ -229,21 +240,24 @@ Function11934: ; 11934 (4:5934) call CloseSRAM ret -Function11972: ; 11972 (4:5972) - cp $ff - jr z, .asm_11981 +UpdateTimeRemaining: +; If the amount of time elapsed exceeds the capacity of its +; unit, skip this part. + cp -1 + jr z, .set_carry ld c, a - ld a, [hl] + ld a, [hl] ; time remaining sub c - jr nc, .asm_1197c + jr nc, .ok xor a -.asm_1197c + +.ok ld [hl], a - jr z, .asm_11981 + jr z, .set_carry xor a ret -.asm_11981 +.set_carry xor a ld [hl], a scf @@ -252,100 +266,103 @@ Function11972: ; 11972 (4:5972) GetSecondsSinceIfLessThan60: ld a, [wDaysSince] and a - jr nz, asm_119b8 + jr nz, GetTimeElapsed_ExceedsUnitLimit ld a, [wHoursSince] and a - jr nz, asm_119b8 - ld a, [wMinsSince] - jr nz, asm_119b8 - ld a, [wSecsSince] + jr nz, GetTimeElapsed_ExceedsUnitLimit + ld a, [wMinutesSince] + jr nz, GetTimeElapsed_ExceedsUnitLimit + ld a, [wSecondsSince] ret -Function1199a: ; 1199a (4:599a) +GetMinutesSinceIfLessThan60: ld a, [wDaysSince] and a - jr nz, asm_119b8 + jr nz, GetTimeElapsed_ExceedsUnitLimit ld a, [wHoursSince] and a - jr nz, asm_119b8 - ld a, [wMinsSince] + jr nz, GetTimeElapsed_ExceedsUnitLimit + ld a, [wMinutesSince] ret GetHoursSinceIfLessThan24: ld a, [wDaysSince] and a - jr nz, asm_119b8 + jr nz, GetTimeElapsed_ExceedsUnitLimit ld a, [wHoursSince] ret -Function119b4: ; 119b4 (4:59b4) +GetDaysSince: ld a, [wDaysSince] ret -asm_119b8 - ld a, $ff +GetTimeElapsed_ExceedsUnitLimit: + ld a, -1 ret -CalcDaysSince: ; 119bb (4:59bb) +CalcDaysSince: xor a - jr CalcDaysSince_ + jr _CalcDaysSince CalcHoursDaysSince: inc hl xor a - jr CalcHoursDaysSince_ + jr _CalcHoursDaysSince -CalcMinsHoursDaysSince: ; 119c2 (4:59c2) +CalcMinsHoursDaysSince: inc hl inc hl xor a - jr CalcMinsHoursDaysSince_ + jr _CalcMinsHoursDaysSince -CalcSecsMinsHoursDaysSince: ; 119c7 (4:59c7) +CalcSecsMinsHoursDaysSince: inc hl inc hl inc hl ldh a, [hSeconds] ld c, a sub [hl] - jr nc, .asm_119d2 + jr nc, .skip add 60 -.asm_119d2 - ld [hl], c +.skip + ld [hl], c ; current seconds dec hl - ld [wSecsSince], a -CalcMinsHoursDaysSince_ + ld [wSecondsSince], a ; seconds since + +_CalcMinsHoursDaysSince: ldh a, [hMinutes] ld c, a sbc [hl] - jr nc, .asm_119df + jr nc, .skip add 60 -.asm_119df - ld [hl], c +.skip + ld [hl], c ; current minutes dec hl - ld [wMinsSince], a -CalcHoursDaysSince_ + ld [wMinutesSince], a ; minutes since + +_CalcHoursDaysSince: ldh a, [hHours] ld c, a sbc [hl] - jr nc, .asm_119ec + jr nc, .skip add 24 -.asm_119ec - ld [hl], c +.skip + ld [hl], c ; current hours dec hl - ld [wHoursSince], a -CalcDaysSince_: + ld [wHoursSince], a ; hours since + +_CalcDaysSince: ld a, [wCurDay] ld c, a sbc [hl] - jr nc, .asm_119fa + jr nc, .skip add 20 * 7 -.asm_119fa - ld [hl], c - ld [wDaysSince], a +.skip + ld [hl], c ; current days + ld [wDaysSince], a ; days since ret -CopyDayHourMinSecToHL: ; 119ff (4:59ff) +CopyDayHourMinSecToHL: ld a, [wCurDay] ld [hli], a ldh a, [hHours] @@ -356,7 +373,7 @@ CopyDayHourMinSecToHL: ; 119ff (4:59ff) ld [hli], a ret -CopyDayToHL: ; 11a0d (4:5a0d) +CopyDayToHL: ld a, [wCurDay] ld [hl], a ret @@ -368,7 +385,7 @@ CopyDayHourToHL: ld [hli], a ret -CopyDayHourMinToHL: ; 11a1a (4:5a1a) +CopyDayHourMinToHL: ld a, [wCurDay] ld [hli], a ldh a, [hHours] diff --git a/engine/overworld/variables.asm b/engine/overworld/variables.asm new file mode 100755 index 00000000..406cf715 --- /dev/null +++ b/engine/overworld/variables.asm @@ -0,0 +1,122 @@ +_GetVarAction:: + ld a, c + cp NUM_VARS + jr c, .valid + xor a +.valid + ld c, a + ld b, 0 + ld hl, .VarActionTable + add hl, bc + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld b, [hl] + ld a, b + and RETVAR_EXECUTE + jr nz, .call + ld a, b + and RETVAR_ADDR_DE + ret nz + ld a, [de] + jr .loadstringbuffer2 + +.call + call _de_ + ret + +.loadstringbuffer2 + ld de, wStringBuffer2 + ld [de], a + ret + +.VarActionTable: +; entries correspond to VAR_* constants + ; RETVAR_STRBUF2: copy [de] to wStringBuffer2 + ; RETVAR_ADDR_DE: return address in de + ; RETVAR_EXECUTE: call function + dwb wStringBuffer2, RETVAR_STRBUF2 + dwb wPartyCount, RETVAR_STRBUF2 + dwb .BattleResult, RETVAR_EXECUTE + dwb wBattleType, RETVAR_ADDR_DE + dwb wTimeOfDay, RETVAR_STRBUF2 + dwb .CountCaughtMons, RETVAR_EXECUTE + dwb .CountSeenMons, RETVAR_EXECUTE + dwb .CountBadges, RETVAR_EXECUTE + dwb wPlayerState, RETVAR_ADDR_DE + dwb .PlayerFacing, RETVAR_EXECUTE + dwb hHours, RETVAR_STRBUF2 + dwb .DayOfWeek, RETVAR_EXECUTE + dwb wMapGroup, RETVAR_STRBUF2 + dwb wMapNumber, RETVAR_STRBUF2 + dwb .UnownCaught, RETVAR_EXECUTE + dwb wEnvironment, RETVAR_STRBUF2 + dwb .BoxFreeSpace, RETVAR_EXECUTE + dwb wBugContestMinsRemaining, RETVAR_STRBUF2 + dwb wXCoord, RETVAR_STRBUF2 + dwb wYCoord, RETVAR_STRBUF2 + dwb wSpecialPhoneCallID, RETVAR_STRBUF2 + dwb NULL, RETVAR_STRBUF2 + +.CountCaughtMons: +; Caught mons. + ld hl, wPokedexCaught + ld b, wEndPokedexCaught - wPokedexCaught + call CountSetBits + ld a, [wNumSetBits] + jp .loadstringbuffer2 + +.CountSeenMons: +; Seen mons. + ld hl, wPokedexSeen + ld b, wEndPokedexSeen - wPokedexSeen + call CountSetBits + ld a, [wNumSetBits] + jp .loadstringbuffer2 + +.CountBadges: +; Number of owned badges. + ld hl, wBadges + ld b, 2 + call CountSetBits + ld a, [wNumSetBits] + jp .loadstringbuffer2 + +.PlayerFacing: +; The direction the player is facing. + ld a, [wPlayerDirection] + and $c + rrca + rrca + jp .loadstringbuffer2 + +.DayOfWeek: +; The day of the week. + call GetWeekday + jp .loadstringbuffer2 + +.UnownCaught: +; Number of unique Unown caught. + call CountUnown + ld a, b + jp .loadstringbuffer2 + +.BoxFreeSpace: +; Remaining slots in the current box. + ld a, BANK(sBoxCount) + call OpenSRAM + ld hl, sBoxCount + ld a, MONS_PER_BOX + sub [hl] + ld b, a + call CloseSRAM + ld a, b + jp .loadstringbuffer2 + +.BattleResult: + ld a, [wBattleResult] + and $ff ^ BATTLERESULT_BITMASK + jp .loadstringbuffer2 diff --git a/engine/overworld/wildmons.asm b/engine/overworld/wildmons.asm new file mode 100644 index 00000000..c06020e1 --- /dev/null +++ b/engine/overworld/wildmons.asm @@ -0,0 +1,971 @@ +LoadWildMonData: + call _GrassWildmonLookup + jr c, .copy + ld hl, wMornEncounterRate + xor a + ld [hli], a + ld [hli], a + ld [hl], a + jr .done_copy + +.copy + inc hl + inc hl + ld de, wMornEncounterRate + ld bc, 3 + call CopyBytes +.done_copy + call _WaterWildmonLookup + ld a, 0 + jr nc, .no_copy + inc hl + inc hl + ld a, [hl] +.no_copy + ld [wWaterEncounterRate], a + ret + +FindNest: +; Parameters: +; e: 0 = Johto, 1 = Kanto +; wNamedObjectIndexBuffer: species + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + xor a + call ByteFill + ld a, e + and a + jr nz, .kanto + decoord 0, 0 + ld hl, JohtoGrassWildMons + call .FindGrass + ld hl, JohtoWaterWildMons + call .FindWater + call .RoamMon1 + call .RoamMon2 + call .RoamMon3 + ret + +.kanto + decoord 0, 0 + ld hl, KantoGrassWildMons + call .FindGrass + ld hl, KantoWaterWildMons + jp .FindWater + +.FindGrass: + ld a, [hl] + cp -1 + ret z + push hl + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + inc hl + inc hl + inc hl + ld a, NUM_GRASSMON * 3 + call .SearchMapForMon + jr nc, .next_grass + ld [de], a + inc de + +.next_grass + pop hl + ld bc, GRASS_WILDDATA_LENGTH + add hl, bc + jr .FindGrass + +.FindWater: + ld a, [hl] + cp -1 + ret z + push hl + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + inc hl + ld a, NUM_WATERMON + call .SearchMapForMon + jr nc, .next_water + ld [de], a + inc de + +.next_water + pop hl + ld bc, WATER_WILDDATA_LENGTH + add hl, bc + jr .FindWater + +.SearchMapForMon: + inc hl +.ScanMapLoop: + push af + ld a, [wNamedObjectIndexBuffer] + cp [hl] + jr z, .found + inc hl + inc hl + pop af + dec a + jr nz, .ScanMapLoop + and a + ret + +.found + pop af + jp .AppendNest + +.AppendNest: + push de + call GetWorldMapLocation + ld c, a + hlcoord 0, 0 + ld de, SCREEN_WIDTH * SCREEN_HEIGHT +.AppendNestLoop: + ld a, [hli] + cp c + jr z, .found_nest + dec de + ld a, e + or d + jr nz, .AppendNestLoop + ld a, c + pop de + scf + ret + +.found_nest + pop de + and a + ret + +.RoamMon1: + ld a, [wRoamMon1Species] + ld b, a + ld a, [wNamedObjectIndexBuffer] + cp b + ret nz + ld a, [wRoamMon1MapGroup] + ld b, a + ld a, [wRoamMon1MapNumber] + ld c, a + call .AppendNest + ret nc + ld [de], a + inc de + ret + +.RoamMon2: + ld a, [wRoamMon2Species] + ld b, a + ld a, [wNamedObjectIndexBuffer] + cp b + ret nz + ld a, [wRoamMon2MapGroup] + ld b, a + ld a, [wRoamMon2MapNumber] + ld c, a + call .AppendNest + ret nc + ld [de], a + inc de + ret + +.RoamMon3: + ld a, [wRoamMon3Species] + ld b, a + ld a, [wNamedObjectIndexBuffer] + cp b + ret nz + ld a, [wRoamMon3MapGroup] + ld b, a + ld a, [wRoamMon3MapNumber] + ld c, a + call .AppendNest + ret nc + ld [de], a + inc de + ret + +TryWildEncounter:: +; Try to trigger a wild encounter. + call .EncounterRate + jr nc, .no_battle + call ChooseWildEncounter + jr nz, .no_battle + call CheckRepelEffect + jr nc, .no_battle + xor a + ret + +.no_battle + xor a ; BATTLETYPE_NORMAL + ld [wTempWildMonSpecies], a + ld [wBattleType], a + ld a, 1 + and a + ret + +.EncounterRate: + call GetMapEncounterRate + call ApplyMusicEffectOnEncounterRate + call ApplyCleanseTagEffectOnEncounterRate + call Random + cp b + ret + +GetMapEncounterRate: + ld hl, wMornEncounterRate + call CheckOnWater + ld a, wWaterEncounterRate - wMornEncounterRate + jr z, .ok + ld a, [wTimeOfDay] +.ok + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + ret + +ApplyMusicEffectOnEncounterRate:: +; Pokemon March and Ruins of Alph signal double encounter rate. +; Pokemon Lullaby halves encounter rate. + ld a, [wMapMusic] + cp MUSIC_POKEMON_MARCH + jr z, .double + cp MUSIC_RUINS_OF_ALPH_RADIO + jr z, .double + cp MUSIC_POKEMON_LULLABY + ret nz + srl b + ret + +.double + sla b + ret + +ApplyCleanseTagEffectOnEncounterRate:: +; Cleanse Tag halves encounter rate. + ld hl, wPartyMon1Item + ld de, PARTYMON_STRUCT_LENGTH + ld a, [wPartyCount] + ld c, a +.loop + ld a, [hl] + cp CLEANSE_TAG + jr z, .cleansetag + add hl, de + dec c + jr nz, .loop + ret + +.cleansetag + srl b + ret + +ChooseWildEncounter: + call LoadWildMonDataPointer + jp nc, .nowildbattle + call CheckEncounterRoamMon + jp c, .startwildbattle + + inc hl + inc hl + inc hl + call CheckOnWater + ld de, WaterMonProbTable + jr z, .watermon + inc hl + inc hl + ld a, [wTimeOfDay] + ld bc, NUM_GRASSMON * 2 + call AddNTimes + ld de, GrassMonProbTable + +.watermon +; hl contains the pointer to the wild mon data, let's save that to the stack + push hl +.randomloop + call Random + cp 100 + jr nc, .randomloop + inc a ; 1 <= a <= 100 + ld b, a + ld h, d + ld l, e +; This next loop chooses which mon to load up. +.prob_bracket_loop + ld a, [hli] + cp b + jr nc, .got_it + inc hl + jr .prob_bracket_loop + +.got_it + ld c, [hl] + ld b, 0 + pop hl + add hl, bc ; this selects our mon + ld a, [hli] + ld b, a +; If the Pokemon is encountered by surfing, we need to give the levels some variety. + call CheckOnWater + jr nz, .ok +; Check if we buff the wild mon, and by how much. + call Random + cp 35 percent + jr c, .ok + inc b + cp 65 percent + jr c, .ok + inc b + cp 85 percent + jr c, .ok + inc b + cp 95 percent + jr c, .ok + inc b +; Store the level +.ok + ld a, b + ld [wCurPartyLevel], a + ld b, [hl] + ; ld a, b + call ValidateTempWildMonSpecies + jr c, .nowildbattle + + ld a, b ; This is in the wrong place. + cp UNOWN + jr nz, .done + + ld a, [wUnlockedUnowns] + and a + jr z, .nowildbattle + +.done + jr .loadwildmon + +.nowildbattle + ld a, 1 + and a + ret + +.loadwildmon + ld a, b + ld [wTempWildMonSpecies], a + +.startwildbattle + xor a + ret + +INCLUDE "data/wild/probabilities.asm" + +CheckRepelEffect:: +; If there is no active Repel, there's no need to be here. + ld a, [wRepelEffect] + and a + jr z, .encounter +; Get the first Pokemon in your party that isn't fainted. + ld hl, wPartyMon1HP + ld bc, PARTYMON_STRUCT_LENGTH - 1 +.loop + ld a, [hli] + or [hl] + jr nz, .ok + add hl, bc + jr .loop + +.ok +; to PartyMonLevel +rept 4 + dec hl +endr + + ld a, [wCurPartyLevel] + cp [hl] + jr nc, .encounter + and a + ret + +.encounter + scf + ret + +LoadWildMonDataPointer: + call CheckOnWater + jr z, _WaterWildmonLookup + +_GrassWildmonLookup: + ld hl, SwarmGrassWildMons + ld bc, GRASS_WILDDATA_LENGTH + call _SwarmWildmonCheck + ret c + ld hl, JohtoGrassWildMons + ld de, KantoGrassWildMons + call _JohtoWildmonCheck + ld bc, GRASS_WILDDATA_LENGTH + jr _NormalWildmonOK + +_WaterWildmonLookup: + ld hl, SwarmWaterWildMons + ld bc, WATER_WILDDATA_LENGTH + call _SwarmWildmonCheck + ret c + ld hl, JohtoWaterWildMons + ld de, KantoWaterWildMons + call _JohtoWildmonCheck + ld bc, WATER_WILDDATA_LENGTH + jr _NormalWildmonOK + +_JohtoWildmonCheck: + call IsInJohto + and a + ret z + ld h, d + ld l, e + ret + +_SwarmWildmonCheck: + call CopyCurrMapDE + ld a, [wSwarmMapGroup] + cp d + jr nz, _NoSwarmWildmon + ld a, [wSwarmMapNumber] + cp e + jr nz, _NoSwarmWildmon + call LookUpWildmonsForMapDE + jr nc, _NoSwarmWildmon + scf + ret + +_NoSwarmWildmon: + and a + ret + +_NormalWildmonOK: + call CopyCurrMapDE + jr LookUpWildmonsForMapDE + +CopyCurrMapDE: + ld a, [wMapGroup] + ld d, a + ld a, [wMapNumber] + ld e, a + ret + +LookUpWildmonsForMapDE: +.loop + push hl + ld a, [hl] + inc a + jr z, .nope + ld a, d + cp [hl] + jr nz, .next + inc hl + ld a, e + cp [hl] + jr z, .yup + +.next + pop hl + add hl, bc + jr .loop + +.nope + pop hl + and a + ret + +.yup + pop hl + scf + ret + +InitRoamMons: +; initialize wRoamMon structs + +; species + ld a, RAIKOU + ld [wRoamMon1Species], a + ld a, ENTEI + ld [wRoamMon2Species], a + ld a, SUICUNE + ld [wRoamMon3Species], a + +; level + ld a, 40 + ld [wRoamMon1Level], a + ld [wRoamMon2Level], a + ld [wRoamMon3Level], a + +; raikou starting map + ld a, GROUP_ROUTE_42 + ld [wRoamMon1MapGroup], a + ld a, MAP_ROUTE_42 + ld [wRoamMon1MapNumber], a + +; entei starting map + ld a, GROUP_ROUTE_37 + ld [wRoamMon2MapGroup], a + ld a, MAP_ROUTE_37 + ld [wRoamMon2MapNumber], a + +; suicune starting map + ld a, GROUP_ROUTE_38 + ld [wRoamMon3MapGroup], a + ld a, MAP_ROUTE_38 + ld [wRoamMon3MapNumber], a + +; hp + xor a ; generate new stats + ld [wRoamMon1HP], a + ld [wRoamMon2HP], a + ld [wRoamMon3HP], a + + ret + +CheckEncounterRoamMon: + push hl +; Don't trigger an encounter if we're on water. + call CheckOnWater + jr z, .DontEncounterRoamMon +; Load the current map group and number to de + call CopyCurrMapDE +; Randomly select a beast. + call Random + cp 100 ; 25/64 chance + jr nc, .DontEncounterRoamMon + and %00000011 ; Of that, a 3/4 chance. Running total: 75/256, or around 29.3%. + jr z, .DontEncounterRoamMon + dec a ; 1/3 chance that it's Entei, 1/3 chance that it's Raikou, 1/3 chance that it's Suicune +; Compare its current location with yours + ld hl, wRoamMon1MapGroup + ld c, a + ld b, 0 + ld a, 7 ; length of the roam_struct + call AddNTimes + ld a, d + cp [hl] + jr nz, .DontEncounterRoamMon + inc hl + ld a, e + cp [hl] + jr nz, .DontEncounterRoamMon +; We've decided to take on a beast, so stage its information for battle. + dec hl + dec hl + dec hl + ld a, [hli] + ld [wTempWildMonSpecies], a + ld a, [hl] + ld [wCurPartyLevel], a + ld a, BATTLETYPE_ROAMING + ld [wBattleType], a + + pop hl + scf + ret + +.DontEncounterRoamMon: + pop hl + and a + ret + +UpdateRoamMons: + ld a, [wRoamMon1MapGroup] + cp GROUP_N_A + jr z, .SkipRaikou + ld b, a + ld a, [wRoamMon1MapNumber] + ld c, a + call .Update + ld a, b + ld [wRoamMon1MapGroup], a + ld a, c + ld [wRoamMon1MapNumber], a + +.SkipRaikou: + ld a, [wRoamMon2MapGroup] + cp GROUP_N_A + jr z, .SkipEntei + ld b, a + ld a, [wRoamMon2MapNumber] + ld c, a + call .Update + ld a, b + ld [wRoamMon2MapGroup], a + ld a, c + ld [wRoamMon2MapNumber], a + +.SkipEntei: + ld a, [wRoamMon3MapGroup] + cp GROUP_N_A + jr z, .Finished + ld b, a + ld a, [wRoamMon3MapNumber] + ld c, a + call .Update + ld a, b + ld [wRoamMon3MapGroup], a + ld a, c + ld [wRoamMon3MapNumber], a + +.Finished: + jp _BackUpMapIndices + +.Update: + ld hl, RoamMaps +.loop +; Are we at the end of the table? + ld a, [hl] + cp -1 + ret z +; Is this the correct entry? + ld a, b + cp [hl] + jr nz, .next + inc hl + ld a, c + cp [hl] + jr z, .yes +; We don't have the correct entry yet, so let's continue. A 0 terminates each entry. +.next + ld a, [hli] + and a + jr nz, .next + jr .loop + +; We have the correct entry now, so let's choose a random map from it. +.yes + inc hl + ld d, h + ld e, l +.update_loop + ld h, d + ld l, e +; Choose which map to warp to. + call Random + and %00011111 ; 1/8n chance it moves to a completely random map, where n is the number of roaming connections from the current map. + jr z, JumpRoamMon + and %11 + cp [hl] + jr nc, .update_loop ; invalid index, try again + inc hl + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [wRoamMons_LastMapGroup] + cp [hl] + jr nz, .done + inc hl + ld a, [wRoamMons_LastMapNumber] + cp [hl] + jr z, .update_loop + dec hl + +.done + ld a, [hli] + ld b, a + ld c, [hl] + ret + +JumpRoamMons: + ld a, [wRoamMon1MapGroup] + cp GROUP_N_A + jr z, .SkipRaikou + call JumpRoamMon + ld a, b + ld [wRoamMon1MapGroup], a + ld a, c + ld [wRoamMon1MapNumber], a + +.SkipRaikou: + ld a, [wRoamMon2MapGroup] + cp GROUP_N_A + jr z, .SkipEntei + call JumpRoamMon + ld a, b + ld [wRoamMon2MapGroup], a + ld a, c + ld [wRoamMon2MapNumber], a + +.SkipEntei: + ld a, [wRoamMon3MapGroup] + cp GROUP_N_A + jr z, .Finished + call JumpRoamMon + ld a, b + ld [wRoamMon3MapGroup], a + ld a, c + ld [wRoamMon3MapNumber], a + +.Finished: + jp _BackUpMapIndices + +JumpRoamMon: +.loop + ld hl, RoamMaps +.innerloop1 ; This loop happens to be unnecessary. + call Random ; Choose a random number. + maskbits NUM_ROAMMON_MAPS ; Mask the number to limit it between 0 and 15. + cp NUM_ROAMMON_MAPS ; If the number is not less than 16, try again. + jr nc, .innerloop1 ; I'm sure you can guess why this check is bogus. + inc a + ld b, a +.innerloop2 ; Loop to get hl to the address of the chosen roam map. + dec b + jr z, .ok +.innerloop3 ; Loop to skip the current roam map, which is terminated by a 0. + ld a, [hli] + and a + jr nz, .innerloop3 + jr .innerloop2 +; Check to see if the selected map is the one the player is currently in. If so, try again. +.ok + ld a, [wMapGroup] + cp [hl] + jr nz, .done + inc hl + ld a, [wMapNumber] + cp [hl] + jr z, .loop + dec hl +; Return the map group and number in bc. +.done + ld a, [hli] + ld b, a + ld c, [hl] + ret + +_BackUpMapIndices: + ld a, [wRoamMons_CurMapNumber] + ld [wRoamMons_LastMapNumber], a + ld a, [wRoamMons_CurMapGroup] + ld [wRoamMons_LastMapGroup], a + ld a, [wMapNumber] + ld [wRoamMons_CurMapNumber], a + ld a, [wMapGroup] + ld [wRoamMons_CurMapGroup], a + ret + +INCLUDE "data/wild/roammon_maps.asm" + +ValidateTempWildMonSpecies: +; Due to a development oversight, this function is called with the wild Pokemon's level, not its species, in a. + and a + jr z, .nowildmon ; = 0 + cp NUM_POKEMON + 1 ; 252 + jr nc, .nowildmon ; >= 252 + and a ; 1 <= Species <= 251 + ret + +.nowildmon + scf + ret + +; Finds a rare wild Pokemon in the route of the trainer calling, then checks if it's been Seen already. +; The trainer will then tell you about the Pokemon if you haven't seen it. +RandomUnseenWildMon: + farcall GetCallerLocation + ld d, b + ld e, c + ld hl, JohtoGrassWildMons + ld bc, GRASS_WILDDATA_LENGTH + call LookUpWildmonsForMapDE + jr c, .GetGrassmon + ld hl, KantoGrassWildMons + call LookUpWildmonsForMapDE + jr nc, .done + +.GetGrassmon: + push hl + ld bc, 5 + 4 * 2 ; Location of the level of the 5th wild Pokemon in that map + add hl, bc + ld a, [wTimeOfDay] + ld bc, NUM_GRASSMON * 2 + call AddNTimes +.randloop1 + call Random + and %11 + jr z, .randloop1 + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc +; We now have the pointer to one of the last (rarest) three wild Pokemon found in that area. + inc hl + ld c, [hl] ; Contains the species index of this rare Pokemon + pop hl + ld de, 5 + 0 * 2 + add hl, de + inc hl ; Species index of the most common Pokemon on that route + ld b, 4 +.loop2 + ld a, [hli] + cp c ; Compare this most common Pokemon with the rare one stored in c. + jr z, .done + inc hl + dec b + jr nz, .loop2 +; This Pokemon truly is rare. + push bc + dec c + ld a, c + call CheckSeenMon + pop bc + jr nz, .done +; Since we haven't seen it, have the caller tell us about it. + ld de, wStringBuffer1 + call CopyName1 + ld a, c + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, .JustSawSomeRareMonText + call PrintText + xor a + ld [wScriptVar], a + ret + +.done + ld a, $1 + ld [wScriptVar], a + ret + +.JustSawSomeRareMonText: + text_far _JustSawSomeRareMonText + text_end + +RandomPhoneWildMon: + farcall GetCallerLocation + ld d, b + ld e, c + ld hl, JohtoGrassWildMons + ld bc, GRASS_WILDDATA_LENGTH + call LookUpWildmonsForMapDE + jr c, .ok + ld hl, KantoGrassWildMons + call LookUpWildmonsForMapDE + +.ok + ld bc, 5 + 0 * 2 + add hl, bc + ld a, [wTimeOfDay] + inc a + ld bc, NUM_GRASSMON * 2 +.loop + dec a + jr z, .done + add hl, bc + jr .loop + +.done + call Random + and %11 + ld c, a + ld b, 0 + add hl, bc + add hl, bc + inc hl + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, wStringBuffer1 + ld de, wStringBuffer4 + ld bc, MON_NAME_LENGTH + jp CopyBytes + +RandomPhoneMon: +; Get a random monster owned by the trainer who's calling. + farcall GetCallerLocation + ld hl, TrainerGroups + ld a, d + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, BANK(TrainerGroups) + call GetFarHalfword + +.skip_trainer + dec e + jr z, .skipped +.skip + ld a, BANK(Trainers) + call GetFarByte + inc hl + cp -1 + jr nz, .skip + jr .skip_trainer +.skipped + +.skip_name + ld a, BANK(Trainers) + call GetFarByte + inc hl + cp "@" + jr nz, .skip_name + + ld a, BANK(Trainers) + call GetFarByte + inc hl + ld bc, 2 ; level, species + cp TRAINERTYPE_NORMAL + jr z, .got_mon_length + ld bc, 2 + NUM_MOVES ; level, species, moves + cp TRAINERTYPE_MOVES + jr z, .got_mon_length + ld bc, 2 + 1 ; level, species, item + cp TRAINERTYPE_ITEM + jr z, .got_mon_length + ; TRAINERTYPE_ITEM_MOVES + ld bc, 2 + 1 + NUM_MOVES ; level, species, item, moves +.got_mon_length + + ld e, 0 + push hl +.count_mon + inc e + add hl, bc + ld a, BANK(Trainers) + call GetFarByte + cp -1 + jr nz, .count_mon + pop hl + +.rand + call Random + maskbits PARTY_LENGTH + cp e + jr nc, .rand + + inc a +.get_mon + dec a + jr z, .got_mon + add hl, bc + jr .get_mon +.got_mon + + inc hl ; species + ld a, BANK(Trainers) + call GetFarByte + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, wStringBuffer1 + ld de, wStringBuffer4 + ld bc, MON_NAME_LENGTH + jp CopyBytes + +INCLUDE "data/wild/johto_grass.asm" +INCLUDE "data/wild/johto_water.asm" +INCLUDE "data/wild/kanto_grass.asm" +INCLUDE "data/wild/kanto_water.asm" +INCLUDE "data/wild/swarm_grass.asm" +INCLUDE "data/wild/swarm_water.asm" diff --git a/engine/pack.asm b/engine/pack.asm deleted file mode 100755 index 620976a9..00000000 --- a/engine/pack.asm +++ /dev/null @@ -1,1572 +0,0 @@ -Function10430: - ld hl, wOptions - set NO_TEXT_SCROLL, [hl] - call Function10aba -.asm_10438 - call JoyTextDelay - ld a, [wce63] - bit 7, a - jr nz, .asm_1044a - call Function10456 - call DelayFrame - jr .asm_10438 - -.asm_1044a - ld a, [wce65] - ld [wcfc8], a - ld hl, wOptions - res NO_TEXT_SCROLL, [hl] - ret - -Function10456: ; 10456 (4:4456) - ld a, [wce63] - ld hl, .Jumptable ; $4460 - call Function10c9b - jp hl - -.Jumptable - dw Pack_InitGFX - dw Pack_InitItemsPocket - dw Pack_ItemsPocketMenu - dw Pack_InitBallsPocket - dw Pack_BallsPocketMenu - dw Pack_InitKeyItemsPocket - dw Pack_KeyItemsPocketMenu - dw Pack_InitTMHMPocket - dw Pack_TMHMPocketMenu - dw Pack_ExitNoScript - dw Pack_ExitRunScript - -Pack_InitGFX: - xor a - ldh [hBGMapMode], a - call Function10d70 - ld a, [wce64] - ld [wce63], a - call Function10e5b - ret - -Pack_InitItemsPocket: - xor a - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - call Function10c96 - ret - -Pack_ItemsPocketMenu: - ld hl, ItemsPocketMenuDataHeader - call CopyMenuHeader - ld a, [wcfca] - ld [wMenuCursorBuffer], a - ld a, [wcfcf] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfcf], a - ld a, [wMenuCursorY] - ld [wcfca], a -.asm_104b7 - ld b, $7 - ld c, $3 - call Function10cef - ret c - call Function105f5 - ret - -Pack_InitKeyItemsPocket: - ld a, $2 - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - call Function10c96 - ret - -Pack_KeyItemsPocketMenu: - ld hl, KeyItemsPocketMenuDataHeader ; $4e9a - call CopyMenuHeader - ld a, [wcfcb] - ld [wMenuCursorBuffer], a - ld a, [wcfd0] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfd0], a - ld a, [wMenuCursorY] - ld [wcfcb], a - ld b, $3 - ld c, $7 - call Function10cef - ret c - call Function105f5 - ret - -Pack_InitTMHMPocket: - ld a, $3 - ld [wce65], a - call Function10e51 - call Function10dd6 - xor a - ldh [hBGMapMode], a - call Function10cca - call Function10c96 - ret - -Pack_TMHMPocketMenu: - farcall Pack_TMHMPocketMenu_ - ld b, $5 - ld c, $1 - call Function10cef - ret c - farcall _CheckTossableItem - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_1053a - ld hl, TMHMPocketSubmenuDataHeader_Give ; $456b - ld de, TMHMPocketSubmenuJumptable_Give ; $4583 - jr .asm_10540 - -.asm_1053a - ld hl, TMHMPocketSubmenuDataHeader_NoGive ; $4554 - ld de, TMHMPocketSubmenuJumptable_NoGive ; $4567 -.asm_10540 - push de - call LoadMenuHeader - call VerticalMenu - call ExitMenu - pop hl - ret c - ld a, [wMenuCursorY] - dec a - call Function10c9b - jp hl - -TMHMPocketSubmenuDataHeader_NoGive: - db $40 - db 07, 00 - db 11, 06 - dw .MenuData2 - db 1 - -.MenuData2: - db $c0 - db 2 - db "USE@" - db "QUIT@" - -TMHMPocketSubmenuJumptable_NoGive: - dw UseTMorHM - dw QuitItemSubmenu - -TMHMPocketSubmenuDataHeader_Give: - db $40 - db 05, 00 - db 11, 06 - dw .MenuData2 - db 1 - -.MenuData2: - db $c0 - db 3 - db "USE@" - db "GIVE@" - db "QUIT@" - -TMHMPocketSubmenuJumptable_Give: - dw UseTMorHM - dw GiveItem - dw QuitItemSubmenu - -UseTMorHM: - farcall AskTeachTMHM - ret c - farcall ChooseMonToLearnTMHM - jr c, .asm_105a9 - ld hl, wOptions - ld a, [hl] - push af - res 4, [hl] - farcall TeachTMHM - pop af - ld [wOptions], a -.asm_105a9 - xor a - ldh [hBGMapMode], a - call Function10d70 - call Function10cca - call Function10e5b - ret - -Pack_InitBallsPocket: - ld a, $1 - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - call Function10c96 - ret - -Pack_BallsPocketMenu: - ld hl, BallsPocketMenuDataHeader ; $4eca - call CopyMenuHeader - ld a, [wcfcc] - ld [wMenuCursorBuffer], a - ld a, [wcfd1] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfd1], a - ld a, [wMenuCursorY] - ld [wcfcc], a - ld b, $1 - ld c, $5 - call Function10cef - ret c - call Function105f5 - ret - -Function105f5: ; 105f5 (4:45f5) - farcall _CheckTossableItem - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_10629 - farcall CheckSelectableItem - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_1061b - farcall CheckItemMenu - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_10637 - jr .asm_10657 - -.asm_1061b - farcall CheckItemMenu - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_1063f - jr .asm_1065f - -.asm_10629 - farcall CheckSelectableItem - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_10647 - jr .asm_1064f - -.asm_10637 - ld hl, ItemSubmenuDataHeader_UseGiveTossSelQuit ; $4679 - ld de, ItemSubmenuJumptable_UseGiveTossSelQuit ; $469a - jr .asm_10665 - -.asm_1063f - ld hl, ItemSubmenuDataHeader_UseGiveTossQuit ; $46a4 - ld de, ItemSubmenuJumptable_UseGiveTossQuit ; $46c1 - jr .asm_10665 - -.asm_10647 - ld hl, ItemSubmenuDataHeader_UseQuit ; $46c9 - ld de, ItemSubmenuJumptable_UseQuit ; $46dc - jr .asm_10665 - -.asm_1064f - ld hl, ItemSubmenuDataHeader_UseSelQuit ; $46e0 - ld de, ItemSubmenuJumptable_UseSelQuit ; $46f7 - jr .asm_10665 - -.asm_10657 - ld hl, ItemSubmenuDataHeader_GiveTossSelQuit ; $46fd - ld de, ItemSubmenuJumptable_GiveTossSelQuit ; $471a - jr .asm_10665 - -.asm_1065f - ld hl, ItemSubmenuDataHeader_GiveTossQuit ; $4722 - ld de, ItemSubmenuJumptable_GiveTossQuit ; $473b -.asm_10665 - push de - call LoadMenuHeader - call VerticalMenu - call ExitMenu - pop hl - ret c - ld a, [wMenuCursorY] - dec a - call Function10c9b - jp hl - -ItemSubmenuDataHeader_UseGiveTossSelQuit: - db $40 ; flags - db 02, 00 ; start coords - db 12, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 5 ; items - db "USE@" - db "GIVE@" - db "TOSS@" - db "SEL@" - db "QUIT@" - -ItemSubmenuJumptable_UseGiveTossSelQuit: - dw UseItem - dw GiveItem - dw TossMenu - dw RegisterItem - dw QuitItemSubmenu - -ItemSubmenuDataHeader_UseGiveTossQuit: - db $40 ; flags - db 03, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 4 ; items - db "USE@" - db "GIVE@" - db "TOSS@" - db "QUIT@" - -ItemSubmenuJumptable_UseGiveTossQuit: - dw UseItem - dw GiveItem - dw TossMenu - dw QuitItemSubmenu - -ItemSubmenuDataHeader_UseQuit: - db %01000000 ; flags - db 07, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 2 ; items - db "USE@" - db "QUIT@" - -ItemSubmenuJumptable_UseQuit: - dw UseItem - dw QuitItemSubmenu - -ItemSubmenuDataHeader_UseSelQuit: - db %01000000 ; flags - db 05, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 3 ; items - db "USE@" - db "SEL@" - db "QUIT@" - -ItemSubmenuJumptable_UseSelQuit: - dw UseItem - dw RegisterItem - dw QuitItemSubmenu - -ItemSubmenuDataHeader_GiveTossSelQuit: - db $40 ; flags - db 03, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 4 ; items - db "GIVE@" - db "TOSS@" - db "SEL@" - db "QUIT@" - -ItemSubmenuJumptable_GiveTossSelQuit: - dw GiveItem - dw TossMenu - dw RegisterItem - dw QuitItemSubmenu - -ItemSubmenuDataHeader_GiveTossQuit: - db $40 ; flags - db 05, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 3 ; items - db "GIVE@" - db "TOSS@" - db "QUIT@" - -ItemSubmenuJumptable_GiveTossQuit: - dw GiveItem - dw TossMenu - dw QuitItemSubmenu - -UseItem: - farcall CheckItemMenu - ld a, [wItemAttributeParamBuffer] - ld hl, .Jumptable - rst JumpTable - ret - -.Jumptable - dw .NotTheTime - dw .NotTheTime - dw .NotTheTime - dw .NotTheTime - dw .Current - dw .Party - dw .Field - -.NotTheTime - ld hl, Text_ThisIsntTheTime - call Function10cb9 - ret - -.Current - call DoItemEffect - ret - -.Party - ld a, [wPartyCount] - and a - jr z, .no_pokemon - call DoItemEffect - xor a - ldh [hBGMapMode], a - call Function10d70 - call Function10cca - call Function10e5b - ret - -.no_pokemon - ld hl, Text_YouDontHaveAPokemon - call Function10cb9 - ret - -.Field - call DoItemEffect - ld a, [wFieldMoveSucceeded] - and a - jr z, .NotTheTime - ld a, $a - ld [wce63], a - ret - -TossMenu: - ld hl, Text_ThrowAwayHowMany - call Function10cb9 - farcall SelectQuantityToToss ; 9:4f20 - push af - call ExitMenu - pop af - jr c, .asm_107cc - call Function10e38 - ld hl, Text_ConfirmThrowAway - call MenuTextbox - call YesNoBox - push af - call ExitMenu - pop af - jr c, .asm_107cc - ld hl, wTMsHMsEnd - ld a, [wd003] - call TossItem - call Function10e38 - ld hl, Text_ThrewAway - call Function10cb9 -.asm_107cc - ret - -Function107cd: - ld a, [wce65] - and a - jr z, .asm_107e2 - dec a - jr z, .asm_107da - dec a - jr z, .asm_107ea - ret - -.asm_107da - xor a - ld [wcfcc], a - ld [wcfd1], a - ret - -.asm_107e2 - xor a - ld [wcfca], a - ld [wcfcf], a - ret - -.asm_107ea - xor a - ld [wcfcb], a - ld [wcfd0], a - ret - -RegisterItem: - farcall CheckSelectableItem - ld a, [wItemAttributeParamBuffer] - and a - jr nz, .asm_10826 - ld a, [wce65] - rrca - rrca - and $c0 - ld b, a - ld a, [wd003] - inc a - and $3f - or b - ld [wWhichRegisteredItem], a - ld a, [wd002] - ld [wRegisteredItem], a - call Function10e38 - ld de, SFX_FULL_HEAL - call WaitPlaySFX - ld hl, Text_RegisteredTheItem - call Function10cb9 - ret - -.asm_10826 - ld hl, Text_CantRegisterThatItem - call Function10cb9 - ret - -GiveItem: - ld a, [wPartyCount] - and a - jp z, Function108b6 - ld a, [wOptions] - push af - res 4, a - ld [wOptions], a - ld a, $8 - ld [wPartyMenuActionText], a - call ClearBGPalettes - farcall LoadPartyMenuGFX - farcall InitPartyMenuWithCancel - farcall InitPartyMenuGFX -.asm_10857 - farcall WritePartyMenuTilemap - farcall PrintPartyMenuText - call WaitBGMap - call SetPalettes - call DelayFrame - farcall PartyMenuSelect - jr c, .asm_108a5 - ld a, [wCurPartySpecies] - cp EGG - jr nz, .asm_10883 - ld hl, Text_AnEggCantHoldAnItem - call PrintText - jr .asm_10857 - -.asm_10883 - ld a, [wce63] - push af - ld a, [wce64] - push af - call GetCurNick - ld hl, wStringBuffer1 - ld de, wMonOrItemNameBuffer - ld bc, $b - call CopyBytes - call Function12fa0 - pop af - ld [wce64], a - pop af - ld [wce63], a -.asm_108a5 - pop af - ld [wOptions], a - xor a - ldh [hBGMapMode], a - call Function10d70 - call Function10cca - call Function10e5b - ret - -Function108b6: ; 108b6 (4:48b6) - ld hl, Text_YouDontHaveAPokemon ; $4f13 - call Function10cb9 - ret - -Text_AnEggCantHoldAnItem: - text_far Text_AnEGGCantHoldAnItem - db "@" - -QuitItemSubmenu: - ret - -BattlePack: - ld hl, wOptions - set 4, [hl] - call Function10aba -.asm_108cb - call JoyTextDelay - ld a, [wce63] - bit 7, a - jr nz, .asm_108dd - call Function108e9 - call DelayFrame - jr .asm_108cb - -.asm_108dd - ld a, [wce65] - ld [wcfc8], a - ld hl, wOptions - res 4, [hl] - ret - -Function108e9: ; 108e9 (4:48e9) - ld a, [wce63] - ld hl, .Jumptable - call Function10c9b - jp hl - -.Jumptable - dw BattlePack_InitGFX - dw BattlePack_InitItemsPocket - dw BattlePack_ItemsPocketMenu - dw BattlePack_InitBallsPocket - dw BattlePack_BallsPocketMenu - dw BattlePack_InitKeyItemsPocket - dw BattlePack_KeyItemsPocketMenu - dw BattlePack_InitTMHMPocket - dw BattlePack_TMHMPocketMenu - dw Pack_ExitNoScript - dw Pack_ExitRunScript - -BattlePack_InitGFX: - xor a - ldh [hBGMapMode], a - call Function10d70 - ld a, [wce64] - ld [wce63], a - call Function10e5b - ret - -BattlePack_InitItemsPocket: - xor a - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - call Function10c96 - ret - -BattlePack_ItemsPocketMenu: - ld hl, $4e6a - call CopyMenuHeader - ld a, [wcfca] - ld [wMenuCursorBuffer], a - ld a, [wcfcf] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfcf], a - ld a, [wMenuCursorY] - ld [wcfca], a - ld b, $7 - ld c, $3 - call Function10cef - ret c - call Function10a03 - ret - -BattlePack_InitKeyItemsPocket: - ld a, $2 - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - call Function10c96 - ret - -BattlePack_KeyItemsPocketMenu: - ld hl, $4e9a - call CopyMenuHeader - ld a, [wcfcb] - ld [wMenuCursorBuffer], a - ld a, [wcfd0] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfd0], a - ld a, [wMenuCursorY] - ld [wcfcb], a - ld b, $3 - ld c, $7 - call Function10cef - ret c - call Function10a03 - ret - -BattlePack_InitTMHMPocket: - ld a, $3 - ld [wce65], a - call Function10e51 - call Function10dd6 - xor a - ldh [hBGMapMode], a - call Function10cca - ld hl, Text_PackEmptyString - call Function10cb9 - call Function10c96 - ret - -BattlePack_TMHMPocketMenu: - farcall Pack_TMHMPocketMenu_ ; b:457a - ld b, $5 - ld c, $1 - call Function10cef - ret c - xor a - call Function10a0c - ret - -BattlePack_InitBallsPocket: - ld a, $1 - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - call Function10c96 - ret - -BattlePack_BallsPocketMenu: - ld hl, $4eca - call CopyMenuHeader - ld a, [wcfcc] - ld [wMenuCursorBuffer], a - ld a, [wcfd1] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfd1], a - ld a, [wMenuCursorY] - ld [wcfcc], a - ld b, $1 - ld c, $5 - call Function10cef - ret c - call Function10a03 - ret - -Function10a03: ; 10a03 (4:4a03) - farcall CheckItemContext - ld a, [wItemAttributeParamBuffer] -Function10a0c: ; 10a0c (4:4a0c) - and a - jr z, .asm_10a17 - ld hl, BattlePackUseQuitMenuDataHeader - ld de, BattlePackUseQuitJumptable - jr .asm_10a1d - -.asm_10a17 - ld hl, BattlePackQuitMenuDataHeader - ld de, BattlePackQuitJumptable -.asm_10a1d - push de - call LoadMenuHeader - call VerticalMenu - call ExitMenu - pop hl - ret c - ld a, [wMenuCursorY] - dec a - call Function10c9b - jp hl - -BattlePackUseQuitMenuDataHeader: - db $40 ; flags - db 07, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 2 ; items - db "USE@" - db "QUIT@" - -BattlePackUseQuitJumptable: - dw BattlePack_UseItem - dw BattlePack_QuitSubmenu - -BattlePackQuitMenuDataHeader: - db $40 ; flags - db 09, 00 ; start coords - db 11, 06 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $c0 ; flags - db 1 ; items - db "QUIT@" - -BattlePackQuitJumptable: - dw BattlePack_QuitSubmenu - -BattlePack_UseItem: - farcall CheckItemContext - ld a, [wItemAttributeParamBuffer] - ld hl, $4a67 - rst JumpTable - ret - - dw Function10a75 - dw Function10a75 - dw Function10a75 - dw Function10a75 - dw Function10a7c - dw Function10a86 - dw Function10aa1 - -Function10a75: - ld hl, Text_ThisIsntTheTime - call Function10cb9 - ret - -Function10a7c: - call DoItemEffect - ld a, [wFieldMoveSucceeded] - and a - jr nz, asm_10a9c - ret - -Function10a86: - call DoItemEffect - ld a, [wFieldMoveSucceeded] - and a - jr nz, asm_10aae - xor a - ldh [hBGMapMode], a - call Function10d70 - call Function10cca - call Function10e5b - ret - -asm_10a9c - call ClearBGPalettes - jr asm_10aae - -Function10aa1 - call DoItemEffect - ld a, [wFieldMoveSucceeded] - and a - jr z, Function10a75 - cp $2 - jr z, asm_10ab4 -asm_10aae - ld a, $a - ld [wce63], a - ret - -asm_10ab4 - xor a - ld [wFieldMoveSucceeded], a - ret - -BattlePack_QuitSubmenu: - ret - -Function10aba: ; 10aba (4:4aba) - xor a - ld [wce63], a - ld a, [wcfc8] - and $3 - ld [wce65], a - inc a - add a - dec a - ld [wce64], a - xor a - ld [wce66], a - xor a - ld [wcfd3], a - ret - -Function10ad5: ; 10ad5 (4:4ad5) - xor a - ldh [hBGMapMode], a - ld [wce63], a - ld [wce64], a - ld [wce65], a - ld [wce66], a - ld [wcfd3], a - call Function10d70 - call Function10e5b - ret - -.asm_10aee - call Function10af7 - call Function10b9f - jr c, .asm_10aee - ret - -Function10af7: ; 10af7 (4:4af7) - ld a, [wce63] - ld hl, .Jumptable - call Function10c9b - jp hl - -.Jumptable - dw DepositOrSell_ItemPocket - dw DepositOrSell_BallsPocket - dw DepositOrSell_KeyItemsPocket - dw DepositOrSell_TMHMPocket - -DepositOrSell_ItemPocket: - xor a - call Function10b92 - ld hl, PC_Mart_ItemsPocketMenuDataHeader ; $4e82 - call CopyMenuHeader - ld a, [wcfca] - ld [wMenuCursorBuffer], a - ld a, [wcfcf] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfcf], a - ld a, [wMenuCursorY] - ld [wcfca], a - ret - -DepositOrSell_KeyItemsPocket: - ld a, $2 - call Function10b92 - ld hl, PC_Mart_KeyItemsPocketMenuDataHeader ; $4eb2 - call CopyMenuHeader - ld a, [wcfcb] - ld [wMenuCursorBuffer], a - ld a, [wcfd0] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfd0], a - ld a, [wMenuCursorY] - ld [wcfcb], a - ret - -DepositOrSell_TMHMPocket: - ld a, $3 - call Function10b92 - call Function10cca - farcall Pack_TMHMPocketMenu_ ; b:457a - ld a, [wd002] - ld [wd002], a - ret - -DepositOrSell_BallsPocket: - ld a, $1 - call Function10b92 - ld hl, PC_Mart_BallsPocketMenuDataHeader ; $4ee2 - call CopyMenuHeader - ld a, [wcfcc] - ld [wMenuCursorBuffer], a - ld a, [wcfd1] - ld [wcfd4], a - call ScrollingMenu - ld a, [wcfd4] - ld [wcfd1], a - ld a, [wMenuCursorY] - ld [wcfcc], a - ret - -Function10b92: ; 10b92 (4:4b92) - ld [wce65], a - call Function10e51 - call Function10dd6 - call Function10cca - ret - -Function10b9f: ; 10b9f (4:4b9f) - ld hl, wMenuJoypad - ld a, [hl] - and $1 - jr nz, .asm_10bb8 - ld a, [hl] - and $2 - jr nz, .asm_10bbf - ld a, [hl] - and $20 - jr nz, .asm_10bc5 - ld a, [hl] - and $10 - jr nz, .asm_10bd8 - scf - ret - -.asm_10bb8 - ld a, $1 - ld [wce66], a - and a - ret - -.asm_10bbf - xor a - ld [wce66], a - and a - ret - -.asm_10bc5 - ld a, [wce63] - dec a - and $3 - ld [wce63], a - push de - ld de, $62 - call PlaySFX - pop de - scf - ret - -.asm_10bd8 - ld a, [wce63] - inc a - and $3 - ld [wce63], a - push de - ld de, $62 - call PlaySFX - pop de - scf - ret - -TutorialPack: - call Function10ad5 - ld a, [wInputType] - or a - jr z, .asm_10bfa - farcall DudeAutoInput_RightA ; 70:4dee -.asm_10bfa - call Function10c07 - call Function10b9f - jr c, .asm_10bfa - xor a - ld [wce66], a - ret - -Function10c07: ; 10c07 (4:4c07) - ld a, [wce63] - ld hl, $4c11 - call Function10c9b - jp hl - -.Jumptable - dw TutorialItems - dw TutorialBalls - dw TutorialKeyItems - dw TutorialTMHM - -TutorialItems: - xor a - ld hl, TutorialItemsMenuDataHeader - jr asm_10c8a - -TutorialItemsMenuDataHeader: - db $40 ; flags - db 01, 07 ; start coords - db 11, 19 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $ae ; flags - db 5, 8 ; rows, columns - db 2 ; horizontal spacing - dbw 0, wDudeNumItems - dba PlaceMenuItemName - dba PlaceMenuItemQuantity - dba UpdateItemDescription - -TutorialKeyItems: - ld a, $2 - ld hl, TutorialKeyItemsMenuDataHeader - jr asm_10c8a - -TutorialKeyItemsMenuDataHeader: - db $40 ; flags - db 01, 07 ; start coords - db 11, 19 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $ae ; flags - db 5, 8 ; rows, columns - db 1 ; horizontal spacing - dbw 0, wDudeNumKeyItems - dba PlaceMenuItemName - dba PlaceMenuItemQuantity - dba UpdateItemDescription - -TutorialTMHM: - ld a, $3 - call Function10b92 - call Function10cca - farcall Pack_TMHMPocketMenu_ - ld a, [wd002] - ld [wd002], a - ret - -TutorialBalls: - ld a, $1 - ld hl, TutorialBallsMenuDataHeader - jr asm_10c8a - -TutorialBallsMenuDataHeader: - db $40 ; flags - db 01, 07 ; start coords - db 11, 19 ; end coords - dw .MenuData2 - db 1 ; default option - -.MenuData2: - db $ae ; flags - db 5, 8 ; rows, columns - db 2 ; horizontal spacing - dbw 0, wDudeNumBalls - dba PlaceMenuItemName - dba PlaceMenuItemQuantity - dba UpdateItemDescription - -asm_10c8a - push hl - call Function10b92 - pop hl - call CopyMenuHeader - call ScrollingMenu - ret - -Function10c96: ; 10c96 (4:4c96) - ld hl, wce63 - inc [hl] - ret - -Function10c9b: ; 10c9b (4:4c9b) - ld e, a - ld d, $0 - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ret - -Pack_ExitNoScript: - ld hl, wce63 - set 7, [hl] - xor a - ld [wce66], a - ret - -Pack_ExitRunScript: - ld hl, wce63 - set 7, [hl] - ld a, $1 - ld [wce66], a - ret - -Function10cb9: ; 10cb9 (4:4cb9) - ld a, [wOptions] - push af - set 4, a - ld [wOptions], a - call PrintText - pop af - ld [wOptions], a - ret - -Function10cca: ; 10cca (4:4cca) - call WaitBGMap -Function10ccd: ; 10ccd (4:4ccd) - ld a, [wce65] - and $3 - ld e, a - ld d, $0 - ld hl, PackGFXPointers - add hl, de - add hl, de - ld a, [hli] - ld e, a - ld d, [hl] - ld hl, $9500 - lb bc, BANK(PackGFX), 15 - call Request2bpp - ret - -PackGFXPointers: - dw PackGFX + $f0 * 1 - dw PackGFX + $f0 * 3 - dw PackGFX + $f0 * 0 - dw PackGFX + $f0 * 2 - -Function10cef: ; 10cef (4:4cef) - ld hl, wMenuJoypad - ld a, [wcfd3] - and a - jr nz, .asm_10d4c - ld a, [hl] - and $1 - jr nz, .asm_10d13 - ld a, [hl] - and $2 - jr nz, .asm_10d15 - ld a, [hl] - and $20 - jr nz, .asm_10d1c - ld a, [hl] - and $10 - jr nz, .asm_10d2d - ld a, [hl] - and $4 - jr nz, .asm_10d3e - scf - ret - -.asm_10d13 - and a - ret - -.asm_10d15 - ld a, $9 - ld [wce63], a - scf - ret - -.asm_10d1c - ld a, b - ld [wce63], a - ld [wce64], a - push de - ld de, SFX_SWITCH_POCKETS - call PlaySFX - pop de - scf - ret - -.asm_10d2d - ld a, c - ld [wce63], a - ld [wce64], a - push de - ld de, SFX_SWITCH_POCKETS - call PlaySFX - pop de - scf - ret - -.asm_10d3e - farcall SwitchItemsInBag ; 9:4834 - ld hl, Text_MoveItemWhere - call Function10cb9 - scf - ret - -.asm_10d4c - ld a, [hl] - and $5 - jr nz, .asm_10d58 - ld a, [hl] - and $2 - jr nz, .asm_10d6a - scf - ret - -.asm_10d58 - farcall SwitchItemsInBag ; 9:4834 - ld de, SFX_SWITCH_POKEMON - call WaitPlaySFX - ld de, SFX_SWITCH_POKEMON - call WaitPlaySFX -.asm_10d6a - xor a - ld [wcfd3], a - scf - ret - -Function10d70: ; 10d70 (4:4d70) - call ClearBGPalettes - call ClearTilemap - call ClearSprites - call DisableLCD - ld hl, PackMenuGFX - ld de, $9000 - ld bc, $600 - ld a, BANK(PackMenuGFX) - call FarCopyBytes ; same bank - hlcoord 0, 1 - ld bc, 11 * SCREEN_WIDTH - ld a, $24 - call ByteFill - hlcoord 5, 1 - lb bc, 11, 15 - call ClearBox - hlcoord 0, 0 - ld a, $28 - ld c, $14 -.asm_10da5 - ld [hli], a - inc a - dec c - jr nz, .asm_10da5 - call Function10dd6 - call Function10dc0 - hlcoord 0, 12 - ld bc, IncGradGBPalTable_13 - call Textbox - call EnableLCD - call Function10ccd - ret - -Function10dc0: ; 10dc0 (4:4dc0) - hlcoord 0, 3 - ld a, $50 - ld de, $f - ld b, $3 -.asm_10dca - ld c, $5 -.asm_10dcc - ld [hli], a - inc a - dec c - jr nz, .asm_10dcc - add hl, de - dec b - jr nz, .asm_10dca - ret - -Function10dd6: ; 10dd6 (4:4dd6) - ld a, [wce65] - ld d, a - swap a - sub d - ld d, $0 - ld e, a - ld hl, .tilemap - add hl, de - ld d, h - ld e, l - hlcoord 0, 7 - ld c, $3 -.asm_10deb - ld b, $5 -.asm_10ded - ld a, [de] - inc de - ld [hli], a - dec b - jr nz, .asm_10ded - ld a, c - ld c, $f - add hl, bc - ld c, a - dec c - jr nz, .asm_10deb - ret - -.tilemap - db $00, $04, $04, $04, $01 ; top border - db $06, $07, $08, $09, $0a ; Items - db $02, $05, $05, $05, $03 ; bottom border - db $00, $04, $04, $04, $01 ; top border - db $15, $16, $17, $18, $19 ; Balls - db $02, $05, $05, $05, $03 ; bottom border - db $00, $04, $04, $04, $01 ; top border - db $0b, $0c, $0d, $0e, $0f ; Key Items - db $02, $05, $05, $05, $03 ; bottom border - db $00, $04, $04, $04, $01 ; top border - db $10, $11, $12, $13, $14 ; TM/HM - db $02, $05, $05, $05, $03 ; bottom border - -Function10e38: ; 10e38 (4:4e38) - ld a, [wd002] - ld [wd151], a - call GetItemName - call CopyName1 - ret - -Pack_ClearTilemap: - hlcoord 0, 0 - ld bc, SCREEN_WIDTH * SCREEN_HEIGHT - ld a, " " - call ByteFill - ret - -Function10e51: ; 10e51 (4:4e51) - hlcoord 5, 2 - lb bc, 10, 15 - call ClearBox - ret - -Function10e5b: ; 10e5b (4:4e5b) - call WaitBGMap - ld b, $14 - call GetSGBLayout - call SetPalettes - call DelayFrame - ret - -ItemsPocketMenuDataHeader: - db $40 - db 01, 07 - db 11, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $ae - db 5, 8 - db 2 - dbw 0, wNumItems - dba PlaceMenuItemName ; 9:49dc - dba PlaceMenuItemQuantity ; 9:49eb - dba UpdateItemDescription ; 9:43eb - -PC_Mart_ItemsPocketMenuDataHeader: - db $40 - db 01, 07 - db 11, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $2e - db 5, 8 - db 2 - dbw 0, wNumItems - dba PlaceMenuItemName ; 9:49dc - dba PlaceMenuItemQuantity ; 9:49eb - dba UpdateItemDescription ; 9:43eb - -KeyItemsPocketMenuDataHeader: - db $40 - db 01, 07 - db 11, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $ae - db 5, 8 - db 1 - dbw 0, wNumKeyItems - dba PlaceMenuItemName ; 9:49dc - dba PlaceMenuItemQuantity ; 9:49eb - dba UpdateItemDescription ; 9:43eb - -PC_Mart_KeyItemsPocketMenuDataHeader: - db $40 - db 01, 07 - db 11, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $2e - db 5, 8 - db 1 - dbw 0, wNumKeyItems - dba PlaceMenuItemName ; 9:49dc - dba PlaceMenuItemQuantity ; 9:49eb - dba UpdateItemDescription ; 9:43eb - -BallsPocketMenuDataHeader: - db $40 - db 01, 07 - db 11, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $ae - db 5, 8 - db 2 - dbw 0, wNumBalls - dba PlaceMenuItemName ; 9:49dc - dba PlaceMenuItemQuantity ; 9:49eb - dba UpdateItemDescription ; 9:43eb - -PC_Mart_BallsPocketMenuDataHeader: - db $40 - db 01, 07 - db 11, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $2e - db 5, 8 - db 2 - dbw 0, wNumBalls - dba PlaceMenuItemName ; 9:49dc - dba PlaceMenuItemQuantity ; 9:49eb - dba UpdateItemDescription ; 9:43eb - -Text_PackNoItems: - text_far Text_PackNoItems_ - db "@" - -Text_ThrowAwayHowMany: - text_far Text_ThrowAwayHowMany_ - db "@" - -Text_ConfirmThrowAway: - text_far Text_ConfirmThrowAway_ - db "@" - -Text_ThrewAway: - text_far Text_ThrewAway_ - db "@" - -Text_ThisIsntTheTime: - text_far Text_ThisIsntTheTime_ - db "@" - -Text_YouDontHaveAPokemon: - text_far Text_YouDontHaveAMon - db "@" - -Text_RegisteredTheItem: - text_far Text_RegisteredTheItem_ - db "@" - -Text_CantRegisterThatItem: - text_far Text_CantRegisterThatItem_ - db "@" - -Text_MoveItemWhere: - text_far Text_MoveItemWhere_ - db "@" - -Text_PackEmptyString: - text_far Text_PackEmptyString_ - db "@" - -Text_CantUseItInABattle: - text_far Text_YouCantUseItInABattle - db "@" - -PackMenuGFX: INCBIN "gfx/misc/pack_menu.2bpp" -PackGFX: INCBIN "gfx/misc/pack.2bpp" diff --git a/engine/phone/phone.asm b/engine/phone/phone.asm new file mode 100644 index 00000000..7ee9d0f0 --- /dev/null +++ b/engine/phone/phone.asm @@ -0,0 +1,732 @@ +AddPhoneNumber:: + call _CheckCellNum + jr c, .cant_add + call Phone_FindOpenSlot + jr nc, .cant_add + ld [hl], c + xor a + ret + +.cant_add + scf + ret + +DelCellNum:: + call _CheckCellNum + jr nc, .not_in_list + xor a + ld [hl], a + ret + +.not_in_list + scf + ret + +CheckCellNum:: + jp _CheckCellNum ; useless + +_CheckCellNum: + ld hl, wPhoneList + ld b, CONTACT_LIST_SIZE +.loop + ld a, [hli] + cp c + jr z, .got_it + dec b + jr nz, .loop + xor a + ret + +.got_it + dec hl + scf + ret + +Phone_FindOpenSlot: + call GetRemainingSpaceInPhoneList + ld b, a + ld hl, wPhoneList +.loop + ld a, [hli] + and a + jr z, .FoundOpenSpace + dec b + jr nz, .loop + xor a + ret + +.FoundOpenSpace: + dec hl + scf + ret + +GetRemainingSpaceInPhoneList: + xor a + ld [wBuffer1], a + ld hl, PermanentNumbers +.loop + ld a, [hli] + cp -1 + jr z, .done + cp c + jr z, .continue + + push bc + push hl + ld c, a + call _CheckCellNum + jr c, .permanent + ld hl, wBuffer1 + inc [hl] +.permanent + pop hl + pop bc + +.continue + jr .loop + +.done + ld a, CONTACT_LIST_SIZE + ld hl, wBuffer1 + sub [hl] + ret + +INCLUDE "data/phone/permanent_numbers.asm" + +FarPlaceString: + ldh a, [hROMBank] + push af + ld a, b + rst Bankswitch + + call PlaceString + + pop af + rst Bankswitch + ret + +CheckPhoneCall:: +; Check if the phone is ringing in the overworld. + + call CheckStandingOnEntrance + jr z, .no_call + + call .timecheck + nop + jr nc, .no_call + + call Random + ld b, a + and 50 percent + cp b + jr nz, .no_call + + call GetMapPhoneService + and a + jr nz, .no_call + + call GetAvailableCallers + call ChooseRandomCaller + jr nc, .no_call + + ld e, a + call LoadCallerScript + ld a, BANK(Script_ReceivePhoneCall) + ld hl, Script_ReceivePhoneCall + call CallScript + scf + ret + +.no_call + xor a + ret + +.timecheck + farcall CheckReceiveCallTimer + ret + +; unused + ret + +UnusedInitCallReceiveDelay: + farcall InitCallReceiveDelay + ret + +CheckPhoneContactTimeOfDay: + push hl + push bc + push de + push af + + farcall CheckTime + pop af + and ANYTIME + and c + + pop de + pop bc + pop hl + ret + +ChooseRandomCaller: +; If no one is available to call, don't return anything. + ld a, [wNumAvailableCallers] + and a + jr z, .NothingToSample + +; Store the number of available callers in c. + ld c, a +; Sample a random number between 0 and 31. + call Random + ldh a, [hRandomAdd] + swap a + and $1f +; Compute that number modulo the number of available callers. + call SimpleDivide +; Return the caller ID you just sampled. + ld c, a + ld b, 0 + ld hl, wAvailableCallers + add hl, bc + ld a, [hl] + scf + ret + +.NothingToSample: + xor a + ret + +GetAvailableCallers: + farcall CheckTime + ld a, c + ld [wCheckedTime], a + ld hl, wNumAvailableCallers + ld bc, CONTACT_LIST_SIZE + 1 + xor a + call ByteFill + ld de, wPhoneList + ld a, CONTACT_LIST_SIZE + +.loop + ld [wPhoneListIndex], a + ld a, [de] + and a + jr z, .not_good_for_call + ld hl, PhoneContacts + PHONE_CONTACT_SCRIPT2_TIME + ld bc, PHONE_CONTACT_SIZE + call AddNTimes + ld a, [wCheckedTime] + and [hl] + jr z, .not_good_for_call + ld bc, PHONE_CONTACT_MAP_GROUP - PHONE_CONTACT_SCRIPT2_TIME + add hl, bc + ld a, [wMapGroup] + cp [hl] + jr nz, .different_map + inc hl + ld a, [wMapNumber] + cp [hl] + jr z, .not_good_for_call +.different_map + ld a, [wNumAvailableCallers] + ld c, a + ld b, $0 + inc a + ld [wNumAvailableCallers], a + ld hl, wAvailableCallers + add hl, bc + ld a, [de] + ld [hl], a +.not_good_for_call + inc de + ld a, [wPhoneListIndex] + dec a + jr nz, .loop + ret + +CheckSpecialPhoneCall:: + ld a, [wSpecialPhoneCallID] + and a + jr z, .NoPhoneCall + + dec a + ld c, a + ld b, 0 + ld hl, SpecialPhoneCallList + ld a, 6 + call AddNTimes + ld a, [hli] + ld h, [hl] + ld l, a + call _hl_ + jr nc, .NoPhoneCall + + call .DoSpecialPhoneCall + inc hl + inc hl + ld a, [hli] + ld e, a + push hl + call LoadCallerScript + pop hl + ld de, wCallerContact + PHONE_CONTACT_SCRIPT2_BANK + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld a, BANK(.script) + ld hl, .script + call CallScript + scf + ret +.NoPhoneCall: + xor a + ret + +.script + pause 30 + sjump Script_ReceivePhoneCall + +.DoSpecialPhoneCall: + ld a, [wSpecialPhoneCallID] + dec a + ld c, a + ld b, 0 + ld hl, SpecialPhoneCallList + ld a, 6 + call AddNTimes + ret + +SpecialCallOnlyWhenOutside: + ld a, [wEnvironment] + cp TOWN + jr z, .outside + cp ROUTE + jr z, .outside + xor a + ret + +.outside + scf + ret + +SpecialCallWhereverYouAre: + scf + ret + +Function901a1: + ; Don't do the call if you're in a link communication + ld a, [wLinkMode] + and a + jr nz, .OutOfArea + ; If you're in an area without phone service, don't do the call + call GetMapPhoneService + and a + jr nz, .OutOfArea + ; If the person can't take a call at that time, don't do the call + ld a, b + ld [wCurCaller], a + ld hl, PhoneContacts + ld bc, PHONE_CONTACT_SIZE + call AddNTimes + ld d, h + ld e, l + ld hl, PHONE_CONTACT_SCRIPT1_TIME + add hl, de + ld a, [hl] + call CheckPhoneContactTimeOfDay + jr z, .OutOfArea + ; If we're in the same map as the person we're calling, + ; use the "Just talk to that person" script. + ld hl, PHONE_CONTACT_MAP_GROUP + add hl, de + ld a, [wMapGroup] + cp [hl] + jr nz, .GetPhoneScript + ld hl, PHONE_CONTACT_MAP_NUMBER + add hl, de + ld a, [wMapNumber] + cp [hl] + jr nz, .GetPhoneScript + ld b, BANK(PhoneScript_JustTalkToThem) + ld hl, PhoneScript_JustTalkToThem + jr .DoPhoneCall + +.GetPhoneScript: + ld hl, PHONE_CONTACT_SCRIPT1_BANK + add hl, de + ld b, [hl] + ld hl, PHONE_CONTACT_SCRIPT1_ADDR_LO + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jr .DoPhoneCall + +.OutOfArea: + ld b, BANK(LoadOutOfAreaScript) + ld de, LoadOutOfAreaScript + call ExecuteCallbackScript + ret + +.DoPhoneCall: + ld a, b + ld [wPhoneScriptBank], a + ld a, l + ld [wPhoneCaller], a + ld a, h + ld [wPhoneCaller + 1], a + ld b, BANK(LoadPhoneScriptBank) + ld de, LoadPhoneScriptBank + call ExecuteCallbackScript + ret + +LoadPhoneScriptBank: + memcall wPhoneScriptBank + return + +LoadOutOfAreaScript: + scall PhoneOutOfAreaScript + return + +LoadCallerScript: + nop + nop + ld a, e + ld [wCurCaller], a + and a + jr nz, .actualcaller + ld hl, WrongNumber + ld a, BANK(WrongNumber) + jr .proceed + +.actualcaller + ld hl, PhoneContacts + ld bc, PHONE_CONTACT_SIZE + ld a, e + call AddNTimes + ld a, BANK(PhoneContacts) +.proceed + ld de, wCallerContact + ld bc, PHONE_CONTACT_SIZE + call FarCopyBytes + ret + +WrongNumber: + db TRAINER_NONE, PHONE_00 + dba .script +.script + writetext .PhoneWrongNumberText + end +.PhoneWrongNumberText: + text_far _PhoneWrongNumberText + text_end + +Script_ReceivePhoneCall: + refreshscreen + callasm RingTwice_StartCall + memcall wCallerContact + PHONE_CONTACT_SCRIPT2_BANK + waitbutton + callasm HangUp + closetext + callasm InitCallReceiveDelay + end + +Script_SpecialBillCall:: + callasm .LoadBillScript + sjump Script_ReceivePhoneCall + +.LoadBillScript: + ld e, PHONE_BILL + jp LoadCallerScript + +LoadElmCallScript: + callasm .LoadElmScript + pause 30 + sjump Script_ReceivePhoneCall + +.LoadElmScript: + ld e, PHONE_ELM + jp LoadCallerScript + +RingTwice_StartCall: + call .Ring +; fall through (rings a second time) +.Ring: + call Phone_StartRinging + call Phone_Wait20Frames + call Phone_CallerTextboxWithName + call Phone_Wait20Frames + call Phone_CallerTextbox + call Phone_Wait20Frames + call Phone_CallerTextboxWithName + ret + +Phone_CallerTextboxWithName: + ld a, [wCurCaller] + ld b, a + call Function90357 + ret + +PhoneCall:: + ld a, b + ld [wPhoneScriptBank], a + ld a, e + ld [wPhoneCaller], a + ld a, d + ld [wPhoneCaller + 1], a + call Phone_Ring +; fall through (rings a second time) +Phone_Ring: + call Phone_StartRinging + call Phone_Wait20Frames + call Phone_CallerTextboxWithName2 + call Phone_Wait20Frames + call Phone_CallerTextbox + call Phone_Wait20Frames + call Phone_CallerTextboxWithName2 + ret + +Phone_CallerTextboxWithName2: + call Phone_CallerTextbox + hlcoord 1, 2 + ld [hl], "☎" + inc hl + inc hl + ld a, [wPhoneScriptBank] + ld b, a + ld a, [wPhoneCaller] + ld e, a + ld a, [wPhoneCaller + 1] + ld d, a + call FarPlaceString + ret + +Phone_NoSignal: + ld de, SFX_NO_SIGNAL + call PlaySFX + jr Phone_CallEnd + +HangUp:: + call HangUp_Beep + call HangUp_Wait20Frames +Phone_CallEnd: + call HangUp_BoopOn + call HangUp_Wait20Frames + call HangUp_BoopOff + call HangUp_Wait20Frames + call HangUp_BoopOn + call HangUp_Wait20Frames + call HangUp_BoopOff + call HangUp_Wait20Frames + call HangUp_BoopOn + call HangUp_Wait20Frames + call HangUp_BoopOff + call HangUp_Wait20Frames + ret + +Function9030a: + ld de, SFX_SHUT_DOWN_PC + call PlaySFX + ret + +HangUp_Beep: + ld hl, PhoneClickText + call PrintText + ld de, SFX_HANG_UP + call PlaySFX + ret + +PhoneClickText: + text_far _PhoneClickText + text_end + +HangUp_BoopOn: + ld hl, PhoneEllipseText + call PrintText + ret + +PhoneEllipseText: + text_far _PhoneEllipseText + text_end + +HangUp_BoopOff: + call SpeechTextbox + ret + +Phone_StartRinging: + call WaitSFX + ld de, SFX_CALL + call PlaySFX + call Phone_CallerTextbox + call UpdateSprites + farcall PhoneRing_CopyTilemapAtOnce + ret + +HangUp_Wait20Frames: + jr Phone_Wait20Frames + +Phone_Wait20Frames: + ld c, 20 + call DelayFrames + farcall PhoneRing_CopyTilemapAtOnce + ret + +Function90357: + push bc + call Phone_CallerTextbox + hlcoord 1, 1 + ld [hl], "☎" + inc hl + inc hl + ld d, h + ld e, l + pop bc + call Function90374 + ret + +Phone_CallerTextbox: + hlcoord 0, 0 + ld b, 2 + ld c, SCREEN_WIDTH - 2 + call Textbox + ret + +Function90374: + ld h, d + ld l, e + ld a, b + call GetCallerTrainerClass + call GetCallerName + ret + +CheckCanDeletePhoneNumber: + ld a, c + call GetCallerTrainerClass + ld a, c + ; and a + ret nz + ld a, b + cp PHONECONTACT_MOM + ret z + cp PHONECONTACT_ELM + ret z + ld c, $1 + ret + +GetCallerTrainerClass: + push hl + ld hl, PhoneContacts + PHONE_CONTACT_TRAINER_CLASS + ld bc, PHONE_CONTACT_SIZE + call AddNTimes + ld a, [hli] + ld b, [hl] + ld c, a + pop hl + ret + +GetCallerName: + ld a, c + and a + jr z, .NotTrainer + + call Phone_GetTrainerName + push hl + push bc + call PlaceString + ld a, ":" + ld [bc], a + pop bc + pop hl + ld de, SCREEN_WIDTH + 3 + add hl, de + call Phone_GetTrainerClassName + call PlaceString + ret + +.NotTrainer: + push hl + ld c, b + ld b, 0 + ld hl, NonTrainerCallerNames + add hl, bc + add hl, bc + ld a, [hli] + ld e, a + ld d, [hl] + pop hl + call PlaceString + ld a, ":" + ld [bc], a + ret + +INCLUDE "data/phone/non_trainer_names.asm" + +Phone_GetTrainerName: + push hl + push bc + farcall GetTrainerName + pop bc + pop hl + ret + +Phone_GetTrainerClassName: + push hl + push bc + farcall GetTrainerClassName + pop bc + pop hl + ret + +GetCallerLocation: + ld a, [wCurCaller] + call GetCallerTrainerClass + ld d, c + ld e, b + push de + ld a, [wCurCaller] + ld hl, PhoneContacts + PHONE_CONTACT_MAP_GROUP + ld bc, PHONE_CONTACT_SIZE + call AddNTimes + ld b, [hl] + inc hl + ld c, [hl] + push bc + call GetWorldMapLocation + ld e, a + farcall GetLandmarkName + pop bc + pop de + ret + +INCLUDE "data/phone/phone_contacts.asm" + +INCLUDE "data/phone/special_calls.asm" + +PhoneOutOfAreaScript: + writetext PhoneOutOfAreaText + end + +PhoneOutOfAreaText: + text_far _PhoneOutOfAreaText + text_end + +PhoneScript_JustTalkToThem: + writetext PhoneJustTalkToThemText + end + +PhoneJustTalkToThemText: + text_far _PhoneJustTalkToThemText + text_end + +PhoneThankYouTextScript: + writetext PhoneThankYouText + end + +PhoneThankYouText: + text_far _PhoneThankYouText + text_end diff --git a/engine/pokedex/pokedex_2.asm b/engine/pokedex/pokedex_2.asm new file mode 100644 index 00000000..3d5f51b7 --- /dev/null +++ b/engine/pokedex/pokedex_2.asm @@ -0,0 +1,275 @@ +AnimateDexSearchSlowpoke: + ld hl, .FrameIDs + ld b, 25 +.loop + ld a, [hli] + + ; Wrap around + cp $fe + jr nz, .ok + ld hl, .FrameIDs + ld a, [hli] +.ok + + ld [wDexSearchSlowpokeFrame], a + ld a, [hli] + ld c, a + push bc + push hl + call DoDexSearchSlowpokeFrame + pop hl + pop bc + call DelayFrames + dec b + jr nz, .loop + xor a + ld [wDexSearchSlowpokeFrame], a + call DoDexSearchSlowpokeFrame + ld c, 32 + call DelayFrames + ret + +.FrameIDs: + ; frame ID, duration + db 0, 7 + db 1, 7 + db 2, 7 + db 3, 7 + db 4, 7 + db -2 + +DoDexSearchSlowpokeFrame: + ld a, [wDexSearchSlowpokeFrame] + ld hl, .SlowpokeSpriteData + ld de, wVirtualOAMSprite00 +.loop + ld a, [hli] + cp -1 + ret z + ld [de], a ; y + inc de + ld a, [hli] + ld [de], a ; x + inc de + ld a, [wDexSearchSlowpokeFrame] + ld b, a + add a + add b + add [hl] + inc hl + ld [de], a ; tile id + inc de + ld a, [hli] + ld [de], a ; attributes + inc de + jr .loop + +.SlowpokeSpriteData: + dbsprite 9, 11, 0, 0, $00, 0 + dbsprite 10, 11, 0, 0, $01, 0 + dbsprite 11, 11, 0, 0, $02, 0 + dbsprite 9, 12, 0, 0, $10, 0 + dbsprite 10, 12, 0, 0, $11, 0 + dbsprite 11, 12, 0, 0, $12, 0 + dbsprite 9, 13, 0, 0, $20, 0 + dbsprite 10, 13, 0, 0, $21, 0 + dbsprite 11, 13, 0, 0, $22, 0 + db -1 + +DisplayDexEntry: + call GetPokemonName + hlcoord 9, 3 + call PlaceString ; mon species + ld a, [wTempSpecies] + ld b, a + call GetDexEntryPointer + ld a, b + push af + hlcoord 9, 5 + call FarString ; dex species + ld h, b + ld l, c + push de +; Print dex number + hlcoord 2, 8 + ld a, $5c ; No + ld [hli], a + ld a, $5d ; . + ld [hli], a + ld de, wTempSpecies + lb bc, PRINTNUM_LEADINGZEROS | 1, 3 + call PrintNum +; Check to see if we caught it. Get out of here if we haven't. + ld a, [wTempSpecies] + dec a + call CheckCaughtMon + pop hl + pop bc + ret z +; Get the height of the Pokemon. + ld a, [wCurPartySpecies] + ld [wCurSpecies], a + inc hl + ld a, b + push af + push hl + call GetFarHalfword + ld d, l + ld e, h + pop hl + inc hl + inc hl + ld a, d + or e + jr z, .skip_height + push hl + push de +; Print the height, with two of the four digits in front of the decimal point + ld hl, sp+$0 + ld d, h + ld e, l + hlcoord 12, 7 + lb bc, 2, (2 << 4) | 4 + call PrintNum +; Replace the decimal point with a ft symbol + hlcoord 14, 7 + ld [hl], $5e + pop af + pop hl + +.skip_height + pop af + push af + inc hl + push hl + dec hl + call GetFarHalfword + ld d, l + ld e, h + ld a, e + or d + jr z, .skip_weight + push de +; Print the weight, with four of the five digits in front of the decimal point + ld hl, sp+$0 + ld d, h + ld e, l + hlcoord 11, 9 + lb bc, 2, (4 << 4) | 5 + call PrintNum + pop de + +.skip_weight +; Page 1 + lb bc, 5, SCREEN_WIDTH - 2 + hlcoord 2, 11 + call ClearBox + hlcoord 1, 10 + ld bc, SCREEN_WIDTH - 1 + ld a, $61 ; horizontal divider + call ByteFill + ; page number + hlcoord 1, 9 + ld [hl], $55 + inc hl + ld [hl], $55 + hlcoord 1, 10 + ld [hl], $56 ; P. + inc hl + ld [hl], $57 ; 1 + pop de + inc de + pop af + hlcoord 2, 11 + push af + call FarString + pop bc + ld a, [wPokedexStatus] + or a ; check for page 2 + ret z + +; Page 2 + push bc + push de + lb bc, 5, SCREEN_WIDTH - 2 + hlcoord 2, 11 + call ClearBox + hlcoord 1, 10 + ld bc, SCREEN_WIDTH - 1 + ld a, $61 + call ByteFill + ; page number + hlcoord 1, 9 + ld [hl], $55 + inc hl + ld [hl], $55 + hlcoord 1, 10 + ld [hl], $56 ; P. + inc hl + ld [hl], $58 ; 2 + pop de + inc de + pop af + hlcoord 2, 11 + call FarString + ret + +UnreferencedPOKeString: +; unused + db "#@" + +GetDexEntryPointer: +; return dex entry pointer b:de + push hl + ld hl, PokedexDataPointerTable + ld a, b + dec a + ld d, 0 + ld e, a + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + rlca + rlca + and %11 + add BANK("Pokedex Entries 001-064") + ld b, a + pop hl + ret + +GetDexEntryPagePointer: + call GetDexEntryPointer ; b:de + push hl + ld h, d + ld l, e +; skip species name +.loop1 + ld a, b + call GetFarByte + inc hl + cp "@" + jr nz, .loop1 +; skip height and weight +rept 4 + inc hl +endr +; if c != 1: skip entry + dec c + jr z, .done +; skip entry +.loop2 + ld a, b + call GetFarByte + inc hl + cp "@" + jr nz, .loop2 + +.done + ld d, h + ld e, l + pop hl + ret + +INCLUDE "data/pokemon/dex_entry_pointers.asm" diff --git a/engine/pokegear/pokegear.asm b/engine/pokegear/pokegear.asm new file mode 100644 index 00000000..5443889a --- /dev/null +++ b/engine/pokegear/pokegear.asm @@ -0,0 +1,2878 @@ +; Pokégear cards + const_def + const POKEGEARCARD_CLOCK ; 0 + const POKEGEARCARD_MAP ; 1 + const POKEGEARCARD_PHONE ; 2 + const POKEGEARCARD_RADIO ; 3 +NUM_POKEGEAR_CARDS EQU const_value + +PHONE_DISPLAY_HEIGHT EQU 4 + +; PokegearJumptable.Jumptable indexes + const_def + const POKEGEARSTATE_CLOCKINIT ; 0 + const POKEGEARSTATE_CLOCKJOYPAD ; 1 + const POKEGEARSTATE_MAPCHECKREGION ; 2 + const POKEGEARSTATE_JOHTOMAPINIT ; 3 + const POKEGEARSTATE_JOHTOMAPJOYPAD ; 4 + const POKEGEARSTATE_KANTOMAPINIT ; 5 + const POKEGEARSTATE_KANTOMAPJOYPAD ; 6 + const POKEGEARSTATE_PHONEINIT ; 7 + const POKEGEARSTATE_PHONEJOYPAD ; 8 + const POKEGEARSTATE_MAKEPHONECALL ; 9 + const POKEGEARSTATE_FINISHPHONECALL ; a + const POKEGEARSTATE_RADIOINIT ; b + const POKEGEARSTATE_RADIOJOYPAD ; c + +PokeGear: + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + ld a, [wVramState] + push af + xor a + ld [wVramState], a + call .InitTilemap + call DelayFrame +.loop + call UpdateTime + call JoyTextDelay + ld a, [wJumptableIndex] + bit 7, a + jr nz, .done + call PokegearJumptable + farcall PlaySpriteAnimations + call DelayFrame + jr .loop + +.done + ld de, SFX_READ_TEXT_2 + call PlaySFX + call WaitSFX + pop af + ld [wVramState], a + pop af + ldh [hInMenu], a + pop af + ld [wOptions], a + call ClearBGPalettes + xor a ; LOW(vBGMap0) + ldh [hBGMapAddress], a + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + ld a, $90 + ldh [hWY], a + call ExitPokegearRadio_HandleMusic + ret + +.InitTilemap: + call ClearBGPalettes + call ClearTilemap + call ClearSprites + call DisableLCD + xor a + ldh [hSCY], a + ldh [hSCX], a + ld a, $7 + ldh [hWX], a + call Pokegear_LoadGFX + farcall ClearSpriteAnims + call InitPokegearModeIndicatorArrow + ld a, 8 + call SkipMusic + ld a, LCDC_DEFAULT + ldh [rLCDC], a + call TownMap_InitCursorAndPlayerIconPositions + xor a + ld [wJumptableIndex], a ; POKEGEARSTATE_CLOCKINIT + ld [wPokegearCard], a ; POKEGEARCARD_CLOCK + ld [wPokegearMapRegion], a ; JOHTO_REGION + ld [wPokegearCE66], a + ld [wPokegearPhoneScrollPosition], a + ld [wPokegearPhoneCursorPosition], a + ld [wPokegearPhoneSelectedPerson], a + ld [wPokegearRadioChannelBank], a + ld [wPokegearRadioChannelAddr], a + ld [wPokegearRadioChannelAddr + 1], a + call Pokegear_InitJumptableIndices + call InitPokegearTilemap + ld b, SCGB_POKEGEAR_PALS + call GetSGBLayout + call SetPalettes + ldh a, [hCGB] + and a + ret z + ld a, %11100100 + call DmgToCgbObjPal0 + ret + +Pokegear_LoadGFX: + call ClearVBank1 + ld hl, TownMapGFX + ld de, vTiles2 + ld a, BANK(TownMapGFX) + call FarDecompress + ld hl, PokegearGFX + ld de, vTiles2 tile $30 + ld a, BANK(PokegearGFX) + call FarDecompress + ld hl, PokegearSpritesGFX + ld de, vTiles0 + ld a, BANK(PokegearSpritesGFX) + call Decompress + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + call GetWorldMapLocation + cp LANDMARK_FAST_SHIP + jr z, .ssaqua + ld hl, ChrisSpriteGFX + ld de, vTiles0 tile $10 + ld bc, 4 tiles + ld a, BANK(ChrisSpriteGFX) + call FarCopyBytes + ld hl, ChrisSpriteGFX + 12 tiles + ld de, vTiles0 tile $14 + ld bc, 4 tiles + ld a, BANK(ChrisSpriteGFX) + call FarCopyBytes + ret + +.ssaqua + ld hl, FastShipGFX + ld de, vTiles0 tile $10 + ld bc, 8 tiles + call CopyBytes + ret + +FastShipGFX: +INCBIN "gfx/pokegear/fast_ship.2bpp" + +InitPokegearModeIndicatorArrow: + depixel 4, 2, 4, 0 + ld a, SPRITE_ANIM_INDEX_POKEGEAR_ARROW + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $0 + ret + +AnimatePokegearModeIndicatorArrow: + ld hl, wPokegearCard + ld e, [hl] + ld d, 0 + ld hl, .XCoords + add hl, de + ld a, [hl] + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.XCoords: + db $00 ; POKEGEARCARD_CLOCK + db $10 ; POKEGEARCARD_MAP + db $20 ; POKEGEARCARD_PHONE + db $30 ; POKEGEARCARD_RADIO + +TownMap_GetCurrentLandmark: + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + call GetWorldMapLocation + cp LANDMARK_SPECIAL + ret nz + ld a, [wBackupMapGroup] + ld b, a + ld a, [wBackupMapNumber] + ld c, a + call GetWorldMapLocation + ret + +TownMap_InitCursorAndPlayerIconPositions: + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + call GetWorldMapLocation + cp LANDMARK_FAST_SHIP + jr z, .FastShip + cp LANDMARK_SPECIAL + jr nz, .LoadLandmark + ld a, [wBackupMapGroup] + ld b, a + ld a, [wBackupMapNumber] + ld c, a + call GetWorldMapLocation +.LoadLandmark: + ld [wPokegearMapPlayerIconLandmark], a + ld [wPokegearMapCursorLandmark], a + ret + +.FastShip: + ld [wPokegearMapPlayerIconLandmark], a + ld a, LANDMARK_NEW_BARK_TOWN + ld [wPokegearMapCursorLandmark], a + ret + +Pokegear_InitJumptableIndices: + ld a, POKEGEARSTATE_CLOCKINIT + ld [wJumptableIndex], a + xor a ; POKEGEARCARD_CLOCK + ld [wPokegearCard], a + ret + +InitPokegearTilemap: + xor a + ldh [hBGMapMode], a + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, $4f + call ByteFill + ld a, [wPokegearCard] + maskbits NUM_POKEGEAR_CARDS + add a + ld e, a + ld d, 0 + ld hl, .Jumptable + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .return_from_jumptable + push de + jp hl + +.return_from_jumptable + call Pokegear_FinishTilemap + farcall TownMapPals + ld a, [wPokegearMapRegion] + and a + jr nz, .kanto_0 + xor a ; LOW(vBGMap0) + ldh [hBGMapAddress], a + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + call .UpdateBGMap + ld a, $90 + jr .finish + +.kanto_0 + xor a ; LOW(vBGMap1) + ldh [hBGMapAddress], a + ld a, HIGH(vBGMap1) + ldh [hBGMapAddress + 1], a + call .UpdateBGMap + xor a +.finish + ldh [hWY], a + ; swap region maps + ld a, [wPokegearMapRegion] + maskbits NUM_REGIONS + xor 1 + ld [wPokegearMapRegion], a + ret + +.UpdateBGMap: + ldh a, [hCGB] + and a + jr z, .dmg + ld a, $2 + ldh [hBGMapMode], a + ld c, 3 + call DelayFrames +.dmg + call WaitBGMap + ret + +.Jumptable: +; entries correspond to POKEGEARCARD_* constants + dw .Clock + dw .Map + dw .Phone + dw .Radio + +.Clock: + ld de, ClockTilemapRLE + call Pokegear_LoadTilemapRLE + hlcoord 13, 1 + ld de, .switch + call PlaceString + hlcoord 0, 12 + lb bc, 4, 18 + call Textbox + call Pokegear_UpdateClock + ret + +.switch + db "SWITCH▶@" + +.Map: + ld a, [wPokegearMapPlayerIconLandmark] + cp LANDMARK_FAST_SHIP + jr z, .johto + cp KANTO_LANDMARK + jr nc, .kanto +.johto + ld e, 0 + jr .ok + +.kanto + ld e, 1 +.ok + farcall PokegearMap + ld a, $07 + ld bc, SCREEN_WIDTH - 2 + hlcoord 1, 2 + call ByteFill + hlcoord 0, 2 + ld [hl], $06 + hlcoord 19, 2 + ld [hl], $17 + ld a, [wPokegearMapCursorLandmark] + call PokegearMap_UpdateLandmarkName + ret + +.Radio: + ld de, RadioTilemapRLE + call Pokegear_LoadTilemapRLE + hlcoord 0, 12 + lb bc, 4, 18 + call Textbox + ret + +.Phone: + ld de, PhoneTilemapRLE + call Pokegear_LoadTilemapRLE + hlcoord 0, 12 + lb bc, 4, 18 + call Textbox + call .PlacePhoneBars + call PokegearPhone_UpdateDisplayList + ret + +.PlacePhoneBars: + hlcoord 17, 1 + ld a, $3c + ld [hli], a + inc a + ld [hl], a + hlcoord 17, 2 + inc a + ld [hli], a + call GetMapPhoneService + and a + ret nz + hlcoord 18, 2 + ld [hl], $3f + ret + +Pokegear_FinishTilemap: + hlcoord 0, 0 + ld bc, $8 + ld a, $4f + call ByteFill + hlcoord 0, 1 + ld bc, $8 + ld a, $4f + call ByteFill + ld de, wPokegearFlags + ld a, [de] + bit POKEGEAR_MAP_CARD_F, a + call nz, .PlaceMapIcon + ld a, [de] + bit POKEGEAR_PHONE_CARD_F, a + call nz, .PlacePhoneIcon + ld a, [de] + bit POKEGEAR_RADIO_CARD_F, a + call nz, .PlaceRadioIcon + hlcoord 0, 0 + ld a, $46 + call .PlacePokegearCardIcon + ret + +.PlaceMapIcon: + hlcoord 2, 0 + ld a, $40 + jr .PlacePokegearCardIcon + +.PlacePhoneIcon: + hlcoord 4, 0 + ld a, $44 + jr .PlacePokegearCardIcon + +.PlaceRadioIcon: + hlcoord 6, 0 + ld a, $42 +.PlacePokegearCardIcon: + ld [hli], a + inc a + ld [hld], a + ld bc, $14 + add hl, bc + add $f + ld [hli], a + inc a + ld [hld], a + ret + +PokegearJumptable: + 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 + +.Jumptable: +; entries correspond to POKEGEARSTATE_* constants + dw PokegearClock_Init + dw PokegearClock_Joypad + dw PokegearMap_CheckRegion + dw PokegearMap_Init + dw PokegearMap_JohtoMap + dw PokegearMap_Init + dw PokegearMap_KantoMap + dw PokegearPhone_Init + dw PokegearPhone_Joypad + dw PokegearPhone_MakePhoneCall + dw PokegearPhone_FinishPhoneCall + dw PokegearRadio_Init + dw PokegearRadio_Joypad + +PokegearClock_Init: + call InitPokegearTilemap + ld hl, PokegearPressButtonText + call PrintText + ld hl, wJumptableIndex + inc [hl] + call ExitPokegearRadio_HandleMusic + ret + +PokegearClock_Joypad: + call .UpdateClock + ld hl, hJoyLast + ld a, [hl] + and A_BUTTON | B_BUTTON | START | SELECT + jr nz, .quit + ld a, [hl] + and D_RIGHT + ret z + ld a, [wPokegearFlags] + bit POKEGEAR_MAP_CARD_F, a + jr z, .no_map_card + ld c, POKEGEARSTATE_MAPCHECKREGION + ld b, POKEGEARCARD_MAP + jr .done + +.no_map_card + ld a, [wPokegearFlags] + bit POKEGEAR_PHONE_CARD_F, a + jr z, .no_phone_card + ld c, POKEGEARSTATE_PHONEINIT + ld b, POKEGEARCARD_PHONE + jr .done + +.no_phone_card + ld a, [wPokegearFlags] + bit POKEGEAR_RADIO_CARD_F, a + ret z + ld c, POKEGEARSTATE_RADIOINIT + ld b, POKEGEARCARD_RADIO +.done + call Pokegear_SwitchPage + ret + +.quit + ld hl, wJumptableIndex + set 7, [hl] + ret + +.UpdateClock: + xor a + ldh [hBGMapMode], a + call Pokegear_UpdateClock + ld a, $1 + ldh [hBGMapMode], a + ret + +Pokegear_UpdateClock: + hlcoord 3, 5 + lb bc, 5, 14 + call ClearBox + ldh a, [hHours] + ld b, a + ldh a, [hMinutes] + ld c, a + decoord 6, 8 + farcall PrintHoursMins + ld hl, .GearTodayText + bccoord 6, 6 + call PlaceHLTextAtBC + ret + + db "ごぜん@" + db "ごご@" + +.GearTodayText: + text_far _GearTodayText + text_end + +PokegearMap_CheckRegion: + ld a, [wPokegearMapPlayerIconLandmark] + cp LANDMARK_FAST_SHIP + jr z, .johto + cp KANTO_LANDMARK + jr nc, .kanto +.johto + ld a, POKEGEARSTATE_JOHTOMAPINIT + jr .done + ret + +.kanto + ld a, POKEGEARSTATE_KANTOMAPINIT +.done + ld [wJumptableIndex], a + call ExitPokegearRadio_HandleMusic + ret + +PokegearMap_Init: + call InitPokegearTilemap + ld a, [wPokegearMapPlayerIconLandmark] + call PokegearMap_InitPlayerIcon + ld a, [wPokegearMapCursorLandmark] + call PokegearMap_InitCursor + ld a, c + ld [wPokegearMapCursorObjectPointer], a + ld a, b + ld [wPokegearMapCursorObjectPointer + 1], a + ld hl, wJumptableIndex + inc [hl] + ret + +PokegearMap_KantoMap: + call TownMap_GetKantoLandmarkLimits + jr PokegearMap_ContinueMap + +PokegearMap_JohtoMap: + ld d, LANDMARK_SILVER_CAVE + ld e, LANDMARK_NEW_BARK_TOWN +PokegearMap_ContinueMap: + ld hl, hJoyLast + ld a, [hl] + and B_BUTTON + jr nz, .cancel + ld a, [hl] + and D_RIGHT + jr nz, .right + ld a, [hl] + and D_LEFT + jr nz, .left + call .DPad + ret + +.right + ld a, [wPokegearFlags] + bit POKEGEAR_PHONE_CARD_F, a + jr z, .no_phone + ld c, POKEGEARSTATE_PHONEINIT + ld b, POKEGEARCARD_PHONE + jr .done + +.no_phone + ld a, [wPokegearFlags] + bit POKEGEAR_RADIO_CARD_F, a + ret z + ld c, POKEGEARSTATE_RADIOINIT + ld b, POKEGEARCARD_RADIO + jr .done + +.left + ld c, POKEGEARSTATE_CLOCKINIT + ld b, POKEGEARCARD_CLOCK +.done + call Pokegear_SwitchPage + ret + +.cancel + ld hl, wJumptableIndex + set 7, [hl] + ret + +.DPad: + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .up + ld a, [hl] + and D_DOWN + jr nz, .down + ret + +.up + ld hl, wPokegearMapCursorLandmark + ld a, [hl] + cp d + jr c, .wrap_around_up + ld a, e + dec a + ld [hl], a +.wrap_around_up + inc [hl] + jr .done_dpad + +.down + ld hl, wPokegearMapCursorLandmark + ld a, [hl] + cp e + jr nz, .wrap_around_down + ld a, d + inc a + ld [hl], a +.wrap_around_down + dec [hl] +.done_dpad + ld a, [wPokegearMapCursorLandmark] + call PokegearMap_UpdateLandmarkName + ld a, [wPokegearMapCursorObjectPointer] + ld c, a + ld a, [wPokegearMapCursorObjectPointer + 1] + ld b, a + ld a, [wPokegearMapCursorLandmark] + call PokegearMap_UpdateCursorPosition + ret + +PokegearMap_InitPlayerIcon: + push af + depixel 0, 0 + ld a, SPRITE_ANIM_INDEX_RED_WALK + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $10 + pop af + ld e, a + push bc + farcall GetLandmarkCoords + pop bc + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], e + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ret + +PokegearMap_InitCursor: + push af + depixel 0, 0 + ld a, SPRITE_ANIM_INDEX_POKEGEAR_ARROW + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $04 + ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID + add hl, bc + ld [hl], SPRITE_ANIM_SEQ_NULL + pop af + push bc + call PokegearMap_UpdateCursorPosition + pop bc + ret + +PokegearMap_UpdateLandmarkName: + push af + hlcoord 8, 0 + lb bc, 2, 12 + call ClearBox + pop af + ld e, a + push de + farcall GetLandmarkName + pop de + farcall TownMap_ConvertLineBreakCharacters + hlcoord 8, 0 + ld [hl], $34 + ret + +PokegearMap_UpdateCursorPosition: + push bc + ld e, a + farcall GetLandmarkCoords + pop bc + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], e + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ret + +TownMap_GetKantoLandmarkLimits: + ld a, [wStatusFlags] + bit STATUSFLAGS_HALL_OF_FAME_F, a + jr z, .not_hof + ld d, LANDMARK_ROUTE_28 + ld e, LANDMARK_PALLET_TOWN + ret + +.not_hof + ld d, LANDMARK_ROUTE_28 + ld e, LANDMARK_VICTORY_ROAD + ret + +PokegearRadio_Init: + call InitPokegearTilemap + depixel 4, 10, 4, 4 + ld a, SPRITE_ANIM_INDEX_RADIO_TUNING_KNOB + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $08 + call _UpdateRadioStation + ld hl, wJumptableIndex + inc [hl] + ret + +PokegearRadio_Joypad: + ld hl, hJoyLast + ld a, [hl] + and B_BUTTON + jr nz, .cancel + ld a, [hl] + and D_LEFT + jr nz, .left + ld a, [wPokegearRadioChannelAddr] + ld l, a + ld a, [wPokegearRadioChannelAddr + 1] + ld h, a + ld a, [wPokegearRadioChannelBank] + and a + ret z + rst FarCall + ret + +.left + ld a, [wPokegearFlags] + bit POKEGEAR_PHONE_CARD_F, a + jr z, .no_phone + ld c, POKEGEARSTATE_PHONEINIT + ld b, POKEGEARCARD_PHONE + jr .switch_page + +.no_phone + ld a, [wPokegearFlags] + bit POKEGEAR_MAP_CARD_F, a + jr z, .no_map + ld c, POKEGEARSTATE_MAPCHECKREGION + ld b, POKEGEARCARD_MAP + jr .switch_page + +.no_map + ld c, POKEGEARSTATE_CLOCKINIT + ld b, POKEGEARCARD_CLOCK +.switch_page + call Pokegear_SwitchPage + ret + +.cancel + ld hl, wJumptableIndex + set 7, [hl] + ret + +PokegearPhone_Init: + ld hl, wJumptableIndex + inc [hl] + xor a + ld [wPokegearPhoneScrollPosition], a + ld [wPokegearPhoneCursorPosition], a + ld [wPokegearPhoneSelectedPerson], a + call InitPokegearTilemap + call ExitPokegearRadio_HandleMusic + ld hl, PokegearAskWhoCallText + call PrintText + ret + +PokegearPhone_Joypad: + ld hl, hJoyPressed + ld a, [hl] + and B_BUTTON + jr nz, .b + ld a, [hl] + and A_BUTTON + jr nz, .a + ld hl, hJoyLast + ld a, [hl] + and D_LEFT + jr nz, .left + ld a, [hl] + and D_RIGHT + jr nz, .right + call PokegearPhone_GetDPad + ret + +.left + ld a, [wPokegearFlags] + bit POKEGEAR_MAP_CARD_F, a + jr z, .no_map + ld c, POKEGEARSTATE_MAPCHECKREGION + ld b, POKEGEARCARD_MAP + jr .switch_page + +.no_map + ld c, POKEGEARSTATE_CLOCKINIT + ld b, POKEGEARCARD_CLOCK + jr .switch_page + +.right + ld a, [wPokegearFlags] + bit POKEGEAR_RADIO_CARD_F, a + ret z + ld c, POKEGEARSTATE_RADIOINIT + ld b, POKEGEARCARD_RADIO +.switch_page + call Pokegear_SwitchPage + ret + +.b + ld hl, wJumptableIndex + set 7, [hl] + ret + +.a + ld hl, wPhoneList + ld a, [wPokegearPhoneScrollPosition] + ld e, a + ld d, 0 + add hl, de + ld a, [wPokegearPhoneCursorPosition] + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + and a + ret z + ld [wPokegearPhoneSelectedPerson], a + hlcoord 1, 4 + ld a, [wPokegearPhoneCursorPosition] + ld bc, SCREEN_WIDTH * 2 + call AddNTimes + ld [hl], "▷" + call PokegearPhoneContactSubmenu + jr c, .quit_submenu + ld hl, wJumptableIndex + inc [hl] + ret + +.quit_submenu + ld a, POKEGEARSTATE_PHONEJOYPAD + ld [wJumptableIndex], a + ret + +PokegearPhone_MakePhoneCall: + call GetMapPhoneService + and a + jr nz, .no_service + ld hl, wOptions + res NO_TEXT_SCROLL, [hl] + xor a + ldh [hInMenu], a + ld de, SFX_CALL + call PlaySFX + ld hl, .GearEllipseText + call PrintText + call WaitSFX + ld de, SFX_CALL + call PlaySFX + ld hl, .GearEllipseText + call PrintText + call WaitSFX + ld a, [wPokegearPhoneSelectedPerson] + ld b, a + call Function901a1 + ld c, 10 + call DelayFrames + ld hl, wOptions + set NO_TEXT_SCROLL, [hl] + ld a, $1 + ldh [hInMenu], a + call PokegearPhone_UpdateCursor + ld hl, wJumptableIndex + inc [hl] + ret + +.no_service + farcall Phone_NoSignal + ld hl, .GearOutOfServiceText + call PrintText + ld a, POKEGEARSTATE_PHONEJOYPAD + ld [wJumptableIndex], a + ld hl, PokegearAskWhoCallText + call PrintText + ret + +.GearEllipseText: + text_far _GearEllipseText + text_end + +.GearOutOfServiceText: + text_far _GearOutOfServiceText + text_end + +PokegearPhone_FinishPhoneCall: + ldh a, [hJoyPressed] + and A_BUTTON | B_BUTTON + ret z + farcall HangUp + ld a, POKEGEARSTATE_PHONEJOYPAD + ld [wJumptableIndex], a + ld hl, PokegearAskWhoCallText + call PrintText + ret + +PokegearPhone_GetDPad: + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .up + ld a, [hl] + and D_DOWN + jr nz, .down + ret + +.up + ld hl, wPokegearPhoneCursorPosition + ld a, [hl] + and a + jr z, .scroll_page_up + dec [hl] + jr .done_joypad_same_page + +.scroll_page_up + ld hl, wPokegearPhoneScrollPosition + ld a, [hl] + and a + ret z + dec [hl] + jr .done_joypad_update_page + +.down + ld hl, wPokegearPhoneCursorPosition + ld a, [hl] + cp PHONE_DISPLAY_HEIGHT - 1 + jr nc, .scroll_page_down + inc [hl] + jr .done_joypad_same_page + +.scroll_page_down + ld hl, wPokegearPhoneScrollPosition + ld a, [hl] + cp CONTACT_LIST_SIZE - PHONE_DISPLAY_HEIGHT + ret nc + inc [hl] + jr .done_joypad_update_page + +.done_joypad_same_page + xor a + ldh [hBGMapMode], a + call PokegearPhone_UpdateCursor + call WaitBGMap + ret + +.done_joypad_update_page + xor a + ldh [hBGMapMode], a + call PokegearPhone_UpdateDisplayList + call WaitBGMap + ret + +PokegearPhone_UpdateCursor: + ld a, " " +x = 4 +rept PHONE_DISPLAY_HEIGHT + hlcoord 1, x + ld [hl], a +x = x + 2 +endr + hlcoord 1, 4 + ld a, [wPokegearPhoneCursorPosition] + ld bc, 2 * SCREEN_WIDTH + call AddNTimes + ld [hl], "▶" + ret + +PokegearPhone_UpdateDisplayList: + hlcoord 1, 3 + ld b, PHONE_DISPLAY_HEIGHT * 2 + 1 + ld a, " " +.row + ld c, SCREEN_WIDTH - 2 +.col + ld [hli], a + dec c + jr nz, .col + inc hl + inc hl + dec b + jr nz, .row + ld a, [wPokegearPhoneScrollPosition] + ld e, a + ld d, 0 + ld hl, wPhoneList + add hl, de + xor a + ld [wPokegearPhoneLoadNameBuffer], a +.loop + ld a, [hli] + push hl + push af + hlcoord 2, 4 + ld a, [wPokegearPhoneLoadNameBuffer] + ld bc, 2 * SCREEN_WIDTH + call AddNTimes + ld d, h + ld e, l + pop af + ld b, a + call Function90374 + pop hl + ld a, [wPokegearPhoneLoadNameBuffer] + inc a + ld [wPokegearPhoneLoadNameBuffer], a + cp PHONE_DISPLAY_HEIGHT + jr c, .loop + call PokegearPhone_UpdateCursor + ret + +PokegearPhone_DeletePhoneNumber: + ld hl, wPhoneList + ld a, [wPokegearPhoneScrollPosition] + ld e, a + ld d, 0 + add hl, de + ld a, [wPokegearPhoneCursorPosition] + ld e, a + ld d, 0 + add hl, de + ld [hl], 0 + ld hl, wPhoneList + ld c, CONTACT_LIST_SIZE +.loop + ld a, [hli] + and a + jr nz, .skip + ld a, [hld] + ld [hli], a + ld [hl], 0 +.skip + dec c + jr nz, .loop + ret + +PokegearPhoneContactSubmenu: + ld hl, wPhoneList + ld a, [wPokegearPhoneScrollPosition] + ld e, a + ld d, 0 + add hl, de + ld a, [wPokegearPhoneCursorPosition] + ld e, a + ld d, 0 + add hl, de + ld c, [hl] + farcall CheckCanDeletePhoneNumber + ld a, c + and a + jr z, .cant_delete + ld hl, .CallDeleteCancelJumptable + ld de, .CallDeleteCancelStrings + jr .got_menu_data + +.cant_delete + ld hl, .CallCancelJumptable + ld de, .CallCancelStrings +.got_menu_data + xor a + ldh [hBGMapMode], a + push hl + push de + ld a, [de] + ld l, a + inc de + ld a, [de] + ld h, a + inc de + push hl + bccoord -1, -2, 0 + add hl, bc + ld a, [de] + inc de + sla a + ld b, a + ld c, 8 + push de + call Textbox + pop de + pop hl + inc hl + call PlaceString + pop de + xor a + ld [wPokegearPhoneSubmenuCursor], a + call .UpdateCursor + call WaitBGMap +.loop + push de + call JoyTextDelay + pop de + ld hl, hJoyPressed + ld a, [hl] + and D_UP + jr nz, .d_up + ld a, [hl] + and D_DOWN + jr nz, .d_down + ld a, [hl] + and A_BUTTON | B_BUTTON + jr nz, .a_b + call DelayFrame + jr .loop + +.d_up + ld hl, wPokegearPhoneSubmenuCursor + ld a, [hl] + and a + jr z, .loop + dec [hl] + call .UpdateCursor + jr .loop + +.d_down + ld hl, 2 + add hl, de + ld a, [wPokegearPhoneSubmenuCursor] + inc a + cp [hl] + jr nc, .loop + ld [wPokegearPhoneSubmenuCursor], a + call .UpdateCursor + jr .loop + +.a_b + xor a + ldh [hBGMapMode], a + call PokegearPhone_UpdateDisplayList + ld a, $1 + ldh [hBGMapMode], a + pop hl + ldh a, [hJoyPressed] + and B_BUTTON + jr nz, .Cancel + ld a, [wPokegearPhoneSubmenuCursor] + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.Cancel: + ld hl, PokegearAskWhoCallText + call PrintText + scf + ret + +.Delete: + ld hl, PokegearAskDeleteText + call MenuTextbox + call YesNoBox + call ExitMenu + jr c, .CancelDelete + call PokegearPhone_DeletePhoneNumber + xor a + ldh [hBGMapMode], a + call PokegearPhone_UpdateDisplayList + ld hl, PokegearAskWhoCallText + call PrintText + call WaitBGMap +.CancelDelete: + scf + ret + +.Call: + and a + ret + +.UpdateCursor: + push de + ld a, [de] + inc de + ld l, a + ld a, [de] + inc de + ld h, a + ld a, [de] + ld c, a + push hl + ld a, " " + ld de, SCREEN_WIDTH * 2 +.clear_column + ld [hl], a + add hl, de + dec c + jr nz, .clear_column + pop hl + ld a, [wPokegearPhoneSubmenuCursor] + ld bc, SCREEN_WIDTH * 2 + call AddNTimes + ld [hl], "▶" + pop de + ret + +.CallDeleteCancelStrings: + dwcoord 10, 6 + db 3 + db "CALL" + next "DELETE" + next "CANCEL" + db "@" + +.CallDeleteCancelJumptable: + dw .Call + dw .Delete + dw .Cancel + +.CallCancelStrings: + dwcoord 10, 8 + db 2 + db "CALL" + next "CANCEL" + db "@" + +.CallCancelJumptable: + dw .Call + dw .Cancel + +; unused + ldh a, [hHours] + cp 12 + jr c, .am + sub 12 + ld [wTempByteValue], a + scf + ret + +.am + ld [wTempByteValue], a + and a + ret + +Pokegear_SwitchPage: + ld de, SFX_READ_TEXT_2 + call PlaySFX + ld a, c + ld [wJumptableIndex], a + ld a, b + ld [wPokegearCard], a + call DeleteSpriteAnimStruct2ToEnd + ret + +ExitPokegearRadio_HandleMusic: + ld a, [wPokegearRadioMusicPlaying] + cp RESTART_MAP_MUSIC + jr z, .restart_map_music + cp ENTER_MAP_MUSIC + call z, PlayMapMusicBike + xor a + ld [wPokegearRadioMusicPlaying], a + ret + +.restart_map_music + call RestartMapMusic + xor a + ld [wPokegearRadioMusicPlaying], a + ret + +DeleteSpriteAnimStruct2ToEnd: + ld hl, wSpriteAnim2 + ld bc, wSpriteAnimationStructsEnd - wSpriteAnim2 + xor a + call ByteFill + ld a, 2 + ld [wSpriteAnimCount], a + ret + +Pokegear_LoadTilemapRLE: + ; Format: repeat count, tile ID + ; Terminated with -1 + hlcoord 0, 0 +.loop + ld a, [de] + cp -1 + ret z + ld b, a + inc de + ld a, [de] + ld c, a + inc de + ld a, b +.load + ld [hli], a + dec c + jr nz, .load + jr .loop + +PokegearAskWhoCallText: + text_far _PokegearAskWhoCallText + text_end + +PokegearPressButtonText: + text_far _PokegearPressButtonText + text_end + +PokegearAskDeleteText: + text_far _PokegearAskDeleteText + text_end + +PokegearSpritesGFX: +INCBIN "gfx/pokegear/pokegear_sprites.2bpp.lz" + +RadioTilemapRLE: +INCBIN "gfx/pokegear/radio.tilemap.rle" +PhoneTilemapRLE: +INCBIN "gfx/pokegear/phone.tilemap.rle" +ClockTilemapRLE: +INCBIN "gfx/pokegear/clock.tilemap.rle" + +_UpdateRadioStation: + jr UpdateRadioStation + +; called from engine/sprite_anims.asm + +AnimateTuningKnob: + push bc + call .TuningKnob + pop bc + ld a, [wRadioTuningKnob] + ld hl, SPRITEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.TuningKnob: + ld hl, hJoyLast + ld a, [hl] + and D_DOWN + jr nz, .down + ld a, [hl] + and D_UP + jr nz, .up + ret + +.down + ld hl, wRadioTuningKnob + ld a, [hl] + and a + ret z + dec [hl] + dec [hl] + jr .update + +.up + ld hl, wRadioTuningKnob + ld a, [hl] + cp 80 + ret nc + inc [hl] + inc [hl] +.update +UpdateRadioStation: + ld hl, wRadioTuningKnob + ld d, [hl] + ld hl, RadioChannels +.loop + ld a, [hli] + cp -1 + jr z, .nostation + cp d + jr z, .foundstation + inc hl + inc hl + jr .loop + +.nostation + call NoRadioStation + ret + +.foundstation + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .returnafterstation + push de + jp hl + +.returnafterstation + ld a, [wPokegearRadioChannelBank] + and a + ret z + xor a + ldh [hBGMapMode], a + hlcoord 2, 9 + call PlaceString + ld a, $1 + ldh [hBGMapMode], a + ret + +; unused + ld [wPokegearRadioChannelBank], a + ld a, [hli] + ld [wPokegearRadioChannelAddr], a + ld a, [hli] + ld [wPokegearRadioChannelAddr + 1], a + ret + +RadioChannels: +; entries correspond to constants/radio_constants.asm + +; frequency value given here = 4 × ingame_frequency − 2 + dbw 16, .PKMNTalkAndPokedexShow ; 04.5 + dbw 28, .PokemonMusic ; 07.5 + dbw 32, .LuckyChannel ; 08.5 + dbw 52, .RuinsOfAlphRadio ; 13.5 + dbw 64, .PlacesAndPeople ; 16.5 + dbw 72, .LetsAllSing ; 18.5 + dbw 78, .PokeFluteRadio ; 20.0 + dbw 80, .EvolutionRadio ; 20.5 + db -1 + +.PKMNTalkAndPokedexShow: +; Pokédex Show in the morning + +; Oak's Pokémon Talk in the afternoon and evening + call .InJohto + jr nc, .NoSignal + ld a, [wTimeOfDay] + and a + jp z, LoadStation_PokedexShow + jp LoadStation_OaksPokemonTalk + +.PokemonMusic: + call .InJohto + jr nc, .NoSignal + jp LoadStation_PokemonMusic + +.LuckyChannel: + call .InJohto + jr nc, .NoSignal + jp LoadStation_LuckyChannel + +.RuinsOfAlphRadio: + ld a, [wPokegearMapPlayerIconLandmark] + cp LANDMARK_RUINS_OF_ALPH + jr nz, .NoSignal + jp LoadStation_UnownRadio + +.PlacesAndPeople: + call .InJohto + jr c, .NoSignal + jp LoadStation_PlacesAndPeople + +.LetsAllSing: + call .InJohto + jr c, .NoSignal + jp LoadStation_LetsAllSing + +.PokeFluteRadio: + call .InJohto + jr c, .NoSignal + ld a, [wPokegearFlags] + bit POKEGEAR_EXPN_CARD_F, a + jr z, .NoSignal + jp LoadStation_PokeFluteRadio + +.EvolutionRadio: +; This station airs in the Lake of Rage area when Team Rocket is still in Mahogany. + ld a, [wStatusFlags] + bit STATUSFLAGS_ROCKET_SIGNAL_F, a + jr z, .NoSignal + ld a, [wPokegearMapPlayerIconLandmark] + cp LANDMARK_MAHOGANY_TOWN + jr z, .ok + cp LANDMARK_ROUTE_43 + jr z, .ok + cp LANDMARK_LAKE_OF_RAGE + jr nz, .NoSignal +.ok + jp LoadStation_EvolutionRadio + +.NoSignal: + call NoRadioStation + ret + +.InJohto: +; if in Johto or on the S.S. Aqua, set carry + +; otherwise clear carry + ld a, [wPokegearMapPlayerIconLandmark] + cp LANDMARK_FAST_SHIP + jr z, .johto + cp KANTO_LANDMARK + jr c, .johto +.kanto + and a + ret + +.johto + scf + ret + +LoadStation_OaksPokemonTalk: + xor a ; OAKS_POKEMON_TALK + ld [wCurRadioLine], a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, OaksPKMNTalkName + ret + +LoadStation_PokedexShow: + ld a, POKEDEX_SHOW + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, PokedexShowName + ret + +LoadStation_PokemonMusic: + ld a, POKEMON_MUSIC + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, PokemonMusicName + ret + +LoadStation_LuckyChannel: + ld a, LUCKY_CHANNEL + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, LuckyChannelName + ret + +LoadStation_UnownRadio: + ld a, UNOWN_RADIO + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, UnownStationName + ret + +LoadStation_PlacesAndPeople: + ld a, PLACES_AND_PEOPLE + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, PlacesAndPeopleName + ret + +LoadStation_LetsAllSing: + ld a, LETS_ALL_SING + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, LetsAllSingName + ret + +LoadStation_RocketRadio: + ld a, ROCKET_RADIO + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, LetsAllSingName + ret + +LoadStation_PokeFluteRadio: + ld a, POKE_FLUTE_RADIO + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, PokeFluteStationName + ret + +LoadStation_EvolutionRadio: + ld a, EVOLUTION_RADIO + ld [wCurRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, BANK(PlayRadioShow) + ld hl, PlayRadioShow + call Radio_BackUpFarCallParams + ld de, UnownStationName + ret + +Unreferenced_LoadStation: + ret + +RadioMusicRestartDE: + push de + ld a, e + ld [wPokegearRadioMusicPlaying], a + ld de, MUSIC_NONE + call PlayMusic + pop de + ld a, e + ld [wMapMusic], a + call PlayMusic + ret + +RadioMusicRestartPokemonChannel: + push de + ld a, RESTART_MAP_MUSIC + ld [wPokegearRadioMusicPlaying], a + ld de, MUSIC_NONE + call PlayMusic + pop de + ld de, MUSIC_POKEMON_CHANNEL + call PlayMusic + ret + +Radio_BackUpFarCallParams: + ld [wPokegearRadioChannelBank], a + ld a, l + ld [wPokegearRadioChannelAddr], a + ld a, h + ld [wPokegearRadioChannelAddr + 1], a + ret + +NoRadioStation: +; no radio music + ld de, MUSIC_NONE + call PlayMusic + ld a, ENTER_MAP_MUSIC + ld [wPokegearRadioMusicPlaying], a +; no radio name + xor a + ldh [hBGMapMode], a + hlcoord 1, 8 + lb bc, 3, 18 + call ClearBox + hlcoord 0, 12 + lb bc, 4, 18 + call Textbox +; no radio channel + xor a + ld [wPokegearRadioChannelBank], a + ld [wPokegearRadioChannelAddr], a + ld [wPokegearRadioChannelAddr + 1], a + ld a, $1 + ldh [hBGMapMode], a + ret + +OaksPKMNTalkName: db "OAK's <PK><MN> Talk@" +PokedexShowName: db "#DEX Show@" +PokemonMusicName: db "#MON Music@" +LuckyChannelName: db "Lucky Channel@" +UnownStationName: db "?????@" + +PlacesAndPeopleName: db "Places & People@" +LetsAllSingName: db "Let's All Sing!@" +PokeFluteStationName: db "# FLUTE@" + +_TownMap: + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + + ld a, [wVramState] + push af + xor a + ld [wVramState], a + + call ClearBGPalettes + call ClearTilemap + call ClearSprites + call DisableLCD + call Pokegear_LoadGFX + farcall ClearSpriteAnims + ld a, 8 + call SkipMusic + ld a, LCDC_DEFAULT + ldh [rLCDC], a + call TownMap_GetCurrentLandmark + ld [wTownMapPlayerIconLandmark], a + ld [wTownMapCursorLandmark], a + xor a + ldh [hBGMapMode], a + call .InitTilemap + call WaitBGMap2 + ld a, [wTownMapPlayerIconLandmark] + call PokegearMap_InitPlayerIcon + ld a, [wTownMapCursorLandmark] + call PokegearMap_InitCursor + ld a, c + ld [wTownMapCursorObjectPointer], a + ld a, b + ld [wTownMapCursorObjectPointer + 1], a + ld b, SCGB_POKEGEAR_PALS + call GetSGBLayout + call SetPalettes + ldh a, [hCGB] + and a + jr z, .dmg + ld a, %11100100 + call DmgToCgbObjPal0 + call DelayFrame + +.dmg + ld a, [wTownMapPlayerIconLandmark] + cp KANTO_LANDMARK + jr nc, .kanto + ld d, KANTO_LANDMARK - 1 + ld e, 1 + call .loop + jr .resume + +.kanto + call TownMap_GetKantoLandmarkLimits + call .loop + +.resume + pop af + ld [wVramState], a + pop af + ldh [hInMenu], a + pop af + ld [wOptions], a + call ClearBGPalettes + ret + +.loop + call JoyTextDelay + ld hl, hJoyPressed + ld a, [hl] + and B_BUTTON + ret nz + + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .pressed_up + + ld a, [hl] + and D_DOWN + jr nz, .pressed_down +.loop2 + push de + farcall PlaySpriteAnimations + pop de + call DelayFrame + jr .loop + +.pressed_up + ld hl, wTownMapCursorLandmark + ld a, [hl] + cp d + jr c, .okay + ld a, e + dec a + ld [hl], a + +.okay + inc [hl] + jr .next + +.pressed_down + ld hl, wTownMapCursorLandmark + ld a, [hl] + cp e + jr nz, .okay2 + ld a, d + inc a + ld [hl], a + +.okay2 + dec [hl] + +.next + push de + ld a, [wTownMapCursorLandmark] + call PokegearMap_UpdateLandmarkName + ld a, [wTownMapCursorObjectPointer] + ld c, a + ld a, [wTownMapCursorObjectPointer + 1] + ld b, a + ld a, [wTownMapCursorLandmark] + call PokegearMap_UpdateCursorPosition + pop de + jr .loop2 + +.InitTilemap: + ld a, [wTownMapPlayerIconLandmark] + cp KANTO_LANDMARK + jr nc, .kanto2 + ld e, JOHTO_REGION + jr .okay_tilemap + +.kanto2 + ld e, KANTO_REGION +.okay_tilemap + farcall PokegearMap + ld a, $07 + ld bc, 6 + hlcoord 1, 0 + call ByteFill + hlcoord 0, 0 + ld [hl], $06 + hlcoord 7, 0 + ld [hl], $17 + hlcoord 7, 1 + ld [hl], $16 + hlcoord 7, 2 + ld [hl], $26 + ld a, $07 + ld bc, NAME_LENGTH + hlcoord 8, 2 + call ByteFill + hlcoord 19, 2 + ld [hl], $17 + ld a, [wTownMapCursorLandmark] + call PokegearMap_UpdateLandmarkName + farcall TownMapPals + ret + +PlayRadio: + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call .PlayStation + ld c, 100 + call DelayFrames +.loop + call JoyTextDelay + ldh a, [hJoyPressed] + and A_BUTTON | B_BUTTON + jr nz, .stop + ld a, [wPokegearRadioChannelAddr] + ld l, a + ld a, [wPokegearRadioChannelAddr + 1] + ld h, a + ld a, [wPokegearRadioChannelBank] + and a + jr z, .zero + rst FarCall +.zero + call DelayFrame + jr .loop + +.stop + pop af + ld [wOptions], a + call ExitPokegearRadio_HandleMusic + ret + +.PlayStation: + ld a, ENTER_MAP_MUSIC + ld [wPokegearRadioMusicPlaying], a + ld hl, .StationPointers + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .jump_return + push de + jp hl + +.jump_return + push de + hlcoord 0, 12 + lb bc, 4, 18 + call Textbox + hlcoord 1, 14 + ld [hl], "“" + pop de + hlcoord 2, 14 + call PlaceString + ld h, b + ld l, c + ld [hl], "”" + call WaitBGMap + ret + +.StationPointers: +; entries correspond to MAPRADIO_* constants + dw .OakOrPnP + dw LoadStation_OaksPokemonTalk + dw LoadStation_PokedexShow + dw LoadStation_PokemonMusic + dw LoadStation_LuckyChannel + dw LoadStation_UnownRadio + dw LoadStation_PlacesAndPeople + dw LoadStation_LetsAllSing + dw LoadStation_RocketRadio + +.OakOrPnP: + call IsInJohto + and a + jr nz, .kanto + call UpdateTime + ld a, [wTimeOfDay] + and a + jp z, LoadStation_PokedexShow + jp LoadStation_OaksPokemonTalk + +.kanto + jp LoadStation_PlacesAndPeople + +PokegearMap: + ld a, e + and a + jr nz, .kanto + call LoadTownMapGFX + call FillJohtoMap + ret + +.kanto + call LoadTownMapGFX + call FillKantoMap + ret + +_FlyMap: + call ClearBGPalettes + call ClearTilemap + call ClearSprites + ld hl, hInMenu + ld a, [hl] + push af + ld [hl], $1 + xor a + ldh [hBGMapMode], a + farcall ClearSpriteAnims + call LoadTownMapGFX + ld de, FlyMapLabelBorderGFX + ld hl, vTiles2 tile $30 + lb bc, BANK(FlyMapLabelBorderGFX), 6 + call Request1bpp + call FlyMap + call ret_91bfd + ld b, SCGB_POKEGEAR_PALS + call GetSGBLayout + call SetPalettes +.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 FlyMapScroll + call GetMapCursorCoordinates + farcall PlaySpriteAnimations + call DelayFrame + jr .loop + +.pressedB + ld a, -1 + jr .exit + +.pressedA + ld a, [wTownMapPlayerIconLandmark] + ld l, a + ld h, 0 + add hl, hl + ld de, Flypoints + 1 + add hl, de + ld a, [hl] +.exit + ld [wTownMapPlayerIconLandmark], a + pop af + ldh [hInMenu], a + call ClearBGPalettes + ld a, $90 + ldh [hWY], a + xor a ; LOW(vBGMap0) + ldh [hBGMapAddress], a + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + ld a, [wTownMapPlayerIconLandmark] + ld e, a + ret + +FlyMapScroll: + ld a, [wStartFlypoint] + ld e, a + ld a, [wEndFlypoint] + ld d, a + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .ScrollNext + ld a, [hl] + and D_DOWN + jr nz, .ScrollPrev + ret + +.ScrollNext: + ld hl, wTownMapPlayerIconLandmark + ld a, [hl] + cp d + jr nz, .NotAtEndYet + ld a, e + dec a + ld [hl], a +.NotAtEndYet: + inc [hl] + call CheckIfVisitedFlypoint + jr z, .ScrollNext + jr .Finally + +.ScrollPrev: + ld hl, wTownMapPlayerIconLandmark + ld a, [hl] + cp e + jr nz, .NotAtStartYet + ld a, d + inc a + ld [hl], a +.NotAtStartYet: + dec [hl] + call CheckIfVisitedFlypoint + jr z, .ScrollPrev +.Finally: + call TownMapBubble + call WaitBGMap + xor a + ldh [hBGMapMode], a + ret + +TownMapBubble: +; Draw the bubble containing the location text in the town map HUD + +; Top-left corner + hlcoord 1, 0 + ld a, $30 + ld [hli], a +; Top row + ld bc, 16 + ld a, " " + call ByteFill +; Top-right corner + ld a, $31 + ld [hl], a + hlcoord 1, 1 + +; Middle row + ld bc, SCREEN_WIDTH - 2 + ld a, " " + call ByteFill + +; Bottom-left corner + hlcoord 1, 2 + ld a, $32 + ld [hli], a +; Bottom row + ld bc, 16 + ld a, " " + call ByteFill +; Bottom-right corner + ld a, $33 + ld [hl], a + +; Print "Where?" + hlcoord 2, 0 + ld de, .Where + call PlaceString +; Print the name of the default flypoint + call .Name +; Up/down arrows + hlcoord 18, 1 + ld [hl], $34 + ret + +.Where: + db "Where?@" + +.Name: +; We need the map location of the default flypoint + ld a, [wTownMapPlayerIconLandmark] + ld l, a + ld h, 0 + add hl, hl ; two bytes per flypoint + ld de, Flypoints + add hl, de + ld e, [hl] + farcall GetLandmarkName + hlcoord 2, 1 + ld de, wStringBuffer1 + call PlaceString + ret + +GetMapCursorCoordinates: + ld a, [wTownMapPlayerIconLandmark] + ld l, a + ld h, 0 + add hl, hl + ld de, Flypoints + add hl, de + ld e, [hl] + farcall GetLandmarkCoords + ld a, [wTownMapCursorCoordinates] + ld c, a + ld a, [wTownMapCursorCoordinates + 1] + ld b, a + ld hl, 4 + add hl, bc + ld [hl], e + ld hl, 5 + add hl, bc + ld [hl], d + ret + +CheckIfVisitedFlypoint: +; Check if the flypoint loaded in [hl] has been visited yet. + push bc + push de + push hl + ld l, [hl] + ld h, 0 + add hl, hl + ld de, Flypoints + 1 + add hl, de + ld c, [hl] + call HasVisitedSpawn + pop hl + pop de + pop bc + and a + ret + +HasVisitedSpawn: +; Check if spawn point c has been visited. + ld hl, wVisitedSpawns + ld b, CHECK_FLAG + ld d, 0 + predef SmallFarFlagAction + ld a, c + ret + +INCLUDE "data/maps/flypoints.asm" + +ret_91bfd: + ret + +FlyMap: + ld a, [wMapGroup] + ld b, a + ld a, [wMapNumber] + ld c, a + call GetWorldMapLocation +; If we're not in a valid location, i.e. Pokecenter floor 2F, +; the backup map information is used. + cp LANDMARK_SPECIAL + jr nz, .CheckRegion + ld a, [wBackupMapGroup] + ld b, a + ld a, [wBackupMapNumber] + ld c, a + call GetWorldMapLocation +.CheckRegion: +; The first 46 locations are part of Johto. The rest are in Kanto. + cp KANTO_LANDMARK + jr nc, .KantoFlyMap +.JohtoFlyMap: +; Note that .NoKanto should be modified in tandem with this branch + push af +; Start from New Bark Town + ld a, FLY_NEW_BARK + ld [wTownMapPlayerIconLandmark], a +; Flypoints begin at New Bark Town... + ld [wStartFlypoint], a +; ..and end at Silver Cave. + ld a, FLY_MT_SILVER + ld [wEndFlypoint], a +; Fill out the map + call FillJohtoMap + call .MapHud + pop af + call TownMapPlayerIcon + ret + +.KantoFlyMap: +; The event that there are no flypoints enabled in a map is not +; accounted for. As a result, if you attempt to select a flypoint +; when there are none enabled, the game will crash. Additionally, +; the flypoint selection has a default starting point that +; can be flown to even if none are enabled. +; To prevent both of these things from happening when the player +; enters Kanto, fly access is restricted until Indigo Plateau is +; visited and its flypoint enabled. + push af + ld c, SPAWN_INDIGO + call HasVisitedSpawn + and a + jr z, .NoKanto +; Kanto's map is only loaded if we've visited Indigo Plateau + +; Flypoints begin at Pallet Town... + ld a, FLY_PALLET + ld [wStartFlypoint], a +; ...and end at Indigo Plateau + ld a, FLY_INDIGO + ld [wEndFlypoint], a +; Because Indigo Plateau is the first flypoint the player +; visits, it's made the default flypoint. + ld [wTownMapPlayerIconLandmark], a +; Fill out the map + call FillKantoMap + call .MapHud + pop af + call TownMapPlayerIcon + ret + +.NoKanto: +; If Indigo Plateau hasn't been visited, we use Johto's map instead + +; Start from New Bark Town + ld a, FLY_NEW_BARK + ld [wTownMapPlayerIconLandmark], a +; Flypoints begin at New Bark Town... + ld [wStartFlypoint], a +; ..and end at Silver Cave + ld a, FLY_MT_SILVER + ld [wEndFlypoint], a + call FillJohtoMap + pop af +.MapHud: + call TownMapBubble + call TownMapPals + hlbgcoord 0, 0 ; BG Map 0 + call TownMapBGUpdate + call TownMapMon + ld a, c + ld [wTownMapCursorCoordinates], a + ld a, b + ld [wTownMapCursorCoordinates + 1], a + ret + +Pokedex_GetArea: +; e: Current landmark + ld a, [wTownMapPlayerIconLandmark] + push af + ld a, [wTownMapCursorLandmark] + push af + ld a, e + ld [wTownMapPlayerIconLandmark], a + call ClearSprites + xor a + ldh [hBGMapMode], a + ld a, $1 + ldh [hInMenu], a + ld de, PokedexNestIconGFX + ld hl, vTiles0 tile $7f + lb bc, BANK(PokedexNestIconGFX), 1 + call Request2bpp + call .GetPlayerOrFastShipIcon + ld hl, vTiles0 tile $78 + ld c, 4 + call Request2bpp + call LoadTownMapGFX + call FillKantoMap + call .PlaceString_MonsNest + call TownMapPals + hlbgcoord 0, 0, vBGMap1 + call TownMapBGUpdate + call FillJohtoMap + call .PlaceString_MonsNest + call TownMapPals + hlbgcoord 0, 0 + call TownMapBGUpdate + ld b, SCGB_POKEGEAR_PALS + call GetSGBLayout + call SetPalettes + xor a + ldh [hBGMapMode], a + xor a ; JOHTO_REGION + call .GetAndPlaceNest +.loop + call JoyTextDelay + ld hl, hJoyPressed + ld a, [hl] + and A_BUTTON | B_BUTTON + jr nz, .a_b + ldh a, [hJoypadDown] + and SELECT + jr nz, .select + call .LeftRightInput + call .BlinkNestIcons + jr .next + +.select + call .HideNestsShowPlayer +.next + call DelayFrame + jr .loop + +.a_b + call ClearSprites + pop af + ld [wTownMapCursorLandmark], a + pop af + ld [wTownMapPlayerIconLandmark], a + ret + +.LeftRightInput: + ld a, [hl] + and D_LEFT + jr nz, .left + ld a, [hl] + and D_RIGHT + jr nz, .right + ret + +.left + ldh a, [hWY] + cp $90 + ret z + call ClearSprites + ld a, $90 + ldh [hWY], a + xor a ; JOHTO_REGION + call .GetAndPlaceNest + ret + +.right + ld a, [wStatusFlags] + bit STATUSFLAGS_HALL_OF_FAME_F, a + ret z + ldh a, [hWY] + and a + ret z + call ClearSprites + xor a + ldh [hWY], a + ld a, KANTO_REGION + call .GetAndPlaceNest + ret + +.BlinkNestIcons: + ldh a, [hVBlankCounter] + ld e, a + and $f + ret nz + ld a, e + and $10 + jr nz, .copy_sprites + call ClearSprites + ret + +.copy_sprites + hlcoord 0, 0 + ld de, wVirtualOAM + ld bc, wVirtualOAMEnd - wVirtualOAM + call CopyBytes + ret + +.PlaceString_MonsNest: + hlcoord 0, 0 + ld bc, SCREEN_WIDTH + ld a, " " + call ByteFill + hlcoord 0, 1 + ld a, $06 + ld [hli], a + ld bc, SCREEN_WIDTH - 2 + ld a, $07 + call ByteFill + ld [hl], $17 + call GetPokemonName + hlcoord 2, 0 + call PlaceString + ld h, b + ld l, c + ld de, .String_SNest + call PlaceString + ret + +.String_SNest: + db "'S NEST@" + +.GetAndPlaceNest: + ld [wTownMapCursorLandmark], a + ld e, a + farcall FindNest ; load nest landmarks into wTilemap[0,0] + decoord 0, 0 + ld hl, wVirtualOAMSprite00 +.nestloop + ld a, [de] + and a + jr z, .done_nest + push de + ld e, a + push hl + farcall GetLandmarkCoords + pop hl + ; load into OAM + ld a, d + sub 4 + ld [hli], a ; y + ld a, e + sub 4 + ld [hli], a ; x + ld a, $7f ; nest icon + ld [hli], a ; tile id + xor a + ld [hli], a ; attributes + ; next + pop de + inc de + jr .nestloop + +.done_nest + ld hl, wVirtualOAM + decoord 0, 0 + ld bc, wVirtualOAMEnd - wVirtualOAM + call CopyBytes + ret + +.HideNestsShowPlayer: + call .CheckPlayerLocation + ret c + ld a, [wTownMapPlayerIconLandmark] + ld e, a + farcall GetLandmarkCoords + ld c, e + ld b, d + ld de, .PlayerOAM + ld hl, wVirtualOAMSprite00 +.ShowPlayerLoop: + ld a, [de] + cp $80 + jr z, .clear_oam + add b + ld [hli], a ; y + inc de + ld a, [de] + add c + ld [hli], a ; x + inc de + ld a, [de] + add $78 ; where the player's sprite is loaded + ld [hli], a ; tile id + inc de + xor a ; PAL_OW_RED + ld [hli], a ; attributes + jr .ShowPlayerLoop + +.clear_oam + ld hl, wVirtualOAMSprite04 + ld bc, wVirtualOAMEnd - wVirtualOAMSprite04 + xor a + call ByteFill + ret + +.PlayerOAM: + ; y pxl, x pxl, tile offset + db -1 * 8, -1 * 8, 0 ; top left + db -1 * 8, 0 * 8, 1 ; top right + db 0 * 8, -1 * 8, 2 ; bottom left + db 0 * 8, 0 * 8, 3 ; bottom right + db $80 ; terminator + +.CheckPlayerLocation: +; Don't show the player's sprite if you're +; not in the same region as what's currently +; on the screen. + ld a, [wTownMapPlayerIconLandmark] + cp LANDMARK_FAST_SHIP + jr z, .johto + cp KANTO_LANDMARK + jr c, .johto +.kanto + ld a, [wTownMapCursorLandmark] + and a + jr z, .clear + jr .ok + +.johto + ld a, [wTownMapCursorLandmark] + and a + jr nz, .clear +.ok + and a + ret + +.clear + ld hl, wVirtualOAM + ld bc, wVirtualOAMEnd - wVirtualOAM + xor a + call ByteFill + scf + ret + +.GetPlayerOrFastShipIcon: + ld a, [wTownMapPlayerIconLandmark] + cp LANDMARK_FAST_SHIP + jr z, .FastShip + ld de, ChrisSpriteGFX + ld b, BANK(ChrisSpriteGFX) + ret + +.FastShip: + ld de, FastShipGFX + ld b, BANK(FastShipGFX) + ret + +TownMapBGUpdate: +; Update BG Map tiles and attributes + +; BG Map address + ld a, l + ldh [hBGMapAddress], a + ld a, h + ldh [hBGMapAddress + 1], a +; Only update palettes on CGB + ldh a, [hCGB] + and a + jr z, .tiles +; BG Map mode 2 (palettes) + ld a, 2 + ldh [hBGMapMode], a +; The BG Map is updated in thirds, so we wait + +; 3 frames to update the whole screen's palettes. + ld c, 3 + call DelayFrames +.tiles +; Update BG Map tiles + call WaitBGMap +; Turn off BG Map update + xor a + ldh [hBGMapMode], a + ret + +FillJohtoMap: + ld de, JohtoMap + jr FillTownMap + +FillKantoMap: + ld de, KantoMap +FillTownMap: + hlcoord 0, 0 +.loop + ld a, [de] + cp -1 + ret z + ld a, [de] + ld [hli], a + inc de + jr .loop + +TownMapPals: +; Assign palettes based on tile ids + hlcoord 0, 0 + decoord 0, 0, wAttrmap + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT +.loop +; Current tile + ld a, [hli] + push hl +; The palette map covers tiles $00 to $5f; $60 and above use palette 0 + cp $60 + jr nc, .pal0 + +; The palette data is condensed to nybbles, least-significant first. + ld hl, .PalMap + srl a + jr c, .odd +; Even-numbered tile ids take the bottom nybble... + add l + ld l, a + ld a, h + adc 0 + ld h, a + ld a, [hl] + and PALETTE_MASK + jr .update + +.odd +; ...and odd ids take the top. + add l + ld l, a + ld a, h + adc 0 + ld h, a + ld a, [hl] + swap a + and PALETTE_MASK + jr .update + +.pal0 + xor a +.update + pop hl + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .loop + ret + +.PalMap: +INCLUDE "gfx/pokegear/town_map_palette_map.asm" + +TownMapMon: +; Draw the FlyMon icon at town map location + +; Get FlyMon species + ld a, [wCurPartyMon] + ld hl, wPartySpecies + ld e, a + ld d, $0 + add hl, de + ld a, [hl] + ld [wTempIconSpecies], a +; Get FlyMon icon + ld e, $08 ; starting tile in VRAM + farcall GetSpeciesIcon +; Animation/palette + depixel 0, 0 + ld a, SPRITE_ANIM_INDEX_PARTY_MON + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $08 + ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID + add hl, bc + ld [hl], SPRITE_ANIM_SEQ_NULL + ret + +TownMapPlayerIcon: +; Draw the player icon at town map location in a + push af + ld de, ChrisSpriteGFX +; Standing icon + ld hl, vTiles0 tile $10 + lb bc, BANK(ChrisSpriteGFX), 4 + call Request2bpp +; Walking icon + ld de, ChrisSpriteGFX + 12 tiles + ld hl, vTiles0 tile $14 + lb bc, BANK(ChrisSpriteGFX), 4 + ld a, BANK(ChrisSpriteGFX) ; does nothing + call Request2bpp +; Animation/palette + depixel 0, 0 + ld a, SPRITE_ANIM_INDEX_RED_WALK + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $10 + pop af + ld e, a + push bc + farcall GetLandmarkCoords + pop bc + ld hl, SPRITEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], e + ld hl, SPRITEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ret + +LoadTownMapGFX: + ld hl, TownMapGFX + ld de, vTiles2 + lb bc, BANK(TownMapGFX), 48 + call DecompressRequest2bpp + ret + +JohtoMap: +INCBIN "gfx/pokegear/johto.bin" + +KantoMap: +INCBIN "gfx/pokegear/kanto.bin" + +PokedexNestIconGFX: +INCBIN "gfx/pokegear/dexmap_nest_icon.2bpp" +FlyMapLabelBorderGFX: +INCBIN "gfx/pokegear/flymap_label_border.1bpp" + +Unreferenced_Function92264: + xor a + ld [wTownMapPlayerIconLandmark], a + call ClearBGPalettes + call ClearTilemap + call ClearSprites + ld hl, hInMenu + ld a, [hl] + push af + ld [hl], $1 + xor a + ldh [hBGMapMode], a + farcall ClearSpriteAnims + call LoadTownMapGFX + ld de, FlyMapLabelBorderGFX + ld hl, vTiles2 tile $30 + lb bc, BANK(FlyMapLabelBorderGFX), 6 + call Request1bpp + call FillKantoMap + call TownMapBubble + call TownMapPals + hlbgcoord 0, 0, vBGMap1 + call TownMapBGUpdate + call FillJohtoMap + call TownMapBubble + call TownMapPals + hlbgcoord 0, 0 + call TownMapBGUpdate + call TownMapMon + ld a, c + ld [wTownMapCursorCoordinates], a + ld a, b + ld [wTownMapCursorCoordinates + 1], a + ld b, SCGB_POKEGEAR_PALS + call GetSGBLayout + call SetPalettes +.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 .HandleDPad + call GetMapCursorCoordinates + farcall PlaySpriteAnimations + call DelayFrame + jr .loop + +.pressedB + ld a, -1 + jr .finished_a_b + +.pressedA + ld a, [wTownMapPlayerIconLandmark] + ld l, a + ld h, 0 + add hl, hl + ld de, Flypoints + 1 + add hl, de + ld a, [hl] +.finished_a_b + ld [wTownMapPlayerIconLandmark], a + pop af + ldh [hInMenu], a + call ClearBGPalettes + ld a, $90 + ldh [hWY], a + xor a ; LOW(vBGMap0) + ldh [hBGMapAddress], a + ld a, HIGH(vBGMap0) + ldh [hBGMapAddress + 1], a + ld a, [wTownMapPlayerIconLandmark] + ld e, a + ret + +.HandleDPad: + ld hl, hJoyLast + ld a, [hl] + and D_DOWN | D_RIGHT + jr nz, .down_right + ld a, [hl] + and D_UP | D_LEFT + jr nz, .up_left + ret + +.down_right + ld hl, wTownMapPlayerIconLandmark + ld a, [hl] + cp FLY_INDIGO + jr c, .okay_dr + ld [hl], -1 +.okay_dr + inc [hl] + jr .continue + +.up_left + ld hl, wTownMapPlayerIconLandmark + ld a, [hl] + and a + jr nz, .okay_ul + ld [hl], FLY_INDIGO + 1 +.okay_ul + dec [hl] +.continue + ld a, [wTownMapPlayerIconLandmark] + cp KANTO_FLYPOINT + jr c, .johto + call FillKantoMap + xor a + ld b, $9c + jr .finish + +.johto + call FillJohtoMap + ld a, $90 + ld b, $98 +.finish + ldh [hWY], a + ld a, b + ldh [hBGMapAddress + 1], a + call TownMapBubble + call WaitBGMap + xor a + ldh [hBGMapMode], a + ret diff --git a/engine/pokegear/radio.asm b/engine/pokegear/radio.asm new file mode 100644 index 00000000..77ba764e --- /dev/null +++ b/engine/pokegear/radio.asm @@ -0,0 +1,1417 @@ +PlayRadioShow: +; If we're already in the radio program proper, we don't need to be here. + ld a, [wCurRadioLine] + cp POKE_FLUTE_RADIO + jr nc, .ok +; If Team Rocket is not occupying the radio tower, we don't need to be here. + ld a, [wStatusFlags2] + bit STATUSFLAGS2_ROCKETS_IN_RADIO_TOWER_F, a + jr z, .ok +; If we're in Kanto, we don't need to be here. + call IsInJohto + and a + jr nz, .ok +; Team Rocket broadcasts on all stations. + ld a, ROCKET_RADIO + ld [wCurRadioLine], a +.ok +; Jump to the currently loaded station. The index to which we need to jump is in wCurRadioLine. + ld a, [wCurRadioLine] + ld e, a + ld d, 0 + ld hl, RadioJumptable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +RadioJumptable: +; entries correspond to constants/radio_constants.asm + dw OaksPKMNTalk1 ; $00 + dw PokedexShow1 ; $01 + dw BenMonMusic1 ; $02 + dw LuckyNumberShow1 ; $03 + dw PeoplePlaces1 ; $04 + dw FernMonMusic1 ; $05 + dw RocketRadio1 ; $06 + dw PokeFluteRadio ; $07 + dw UnownRadio ; $08 + dw EvolutionRadio ; $09 +; OaksPKMNTalk + dw OaksPKMNTalk2 ; $0a + dw OaksPKMNTalk3 ; $0b + dw OaksPKMNTalk4 ; $0c + dw OaksPKMNTalk5 ; $0d + dw OaksPKMNTalk6 ; $0e + dw OaksPKMNTalk7 ; $0f + dw OaksPKMNTalk8 ; $10 + dw OaksPKMNTalk9 ; $11 + dw PokedexShow2 ; $12 + dw PokedexShow3 ; $13 + dw PokedexShow4 ; $14 + dw PokedexShow5 ; $15 +; Ben Music + dw BenMonMusic2 ; $16 + dw BenMonMusic3 ; $17 + dw BenFernMusic4 ; $18 + dw BenFernMusic5 ; $19 + dw BenFernMusic6 ; $1a + dw BenFernMusic7 ; $1b + dw FernMonMusic2 ; $1c +; Lucky Number Show + dw LuckyNumberShow2 ; $1d + dw LuckyNumberShow3 ; $1e + dw LuckyNumberShow4 ; $1f + dw LuckyNumberShow5 ; $20 + dw LuckyNumberShow6 ; $21 + dw LuckyNumberShow7 ; $22 + dw LuckyNumberShow8 ; $23 + dw LuckyNumberShow9 ; $24 + dw LuckyNumberShow10 ; $25 + dw LuckyNumberShow11 ; $26 + dw LuckyNumberShow12 ; $27 + dw LuckyNumberShow13 ; $28 + dw LuckyNumberShow14 ; $29 + dw LuckyNumberShow15 ; $2a +; People & Places + dw PeoplePlaces2 ; $2b + dw PeoplePlaces3 ; $2c + dw PeoplePlaces4 ; $2d + dw PeoplePlaces5 ; $2e + dw PeoplePlaces6 ; $2f + dw PeoplePlaces7 ; $30 +; Rocket Radio + dw RocketRadio2 ; $31 + dw RocketRadio3 ; $32 + dw RocketRadio4 ; $33 + dw RocketRadio5 ; $34 + dw RocketRadio6 ; $35 + dw RocketRadio7 ; $36 + dw RocketRadio8 ; $37 + dw RocketRadio9 ; $38 + dw RocketRadio10 ; $39 +; More Pokemon Channel stuff + dw OaksPKMNTalk10 ; $3a + dw OaksPKMNTalk11 ; $3b + dw OaksPKMNTalk12 ; $3c + dw OaksPKMNTalk13 ; $3d + dw OaksPKMNTalk14 ; $3e + dw RadioScroll ; $3f +; More Pokemon Channel stuff + dw PokedexShow6 ; $40 + dw PokedexShow7 ; $41 + dw PokedexShow8 ; $42 + +PrintRadioLine: + ld [wNextRadioLine], a + ld hl, wRadioText + ld a, [wNumRadioLinesPrinted] + cp 2 + jr nc, .print + inc hl + ld [hl], TX_START + inc a + ld [wNumRadioLinesPrinted], a + cp 2 + jr nz, .print + bccoord 1, 16 + call PlaceHLTextAtBC + jr .skip +.print + call PrintTextboxText +.skip + ld a, RADIO_SCROLL + ld [wCurRadioLine], a + ld a, 100 + ld [wRadioTextDelay], a + ret + +ReplacePeriodsWithSpaces: + push hl + ld b, SCREEN_WIDTH * 2 +.loop + ld a, [hl] + cp "." + jr nz, .next + ld [hl], " " + +.next + inc hl + dec b + jr nz, .loop + pop hl + ret + +RadioScroll: + ld hl, wRadioTextDelay + ld a, [hl] + and a + jr z, .proceed + dec [hl] + ret +.proceed + ld a, [wNextRadioLine] + ld [wCurRadioLine], a + ld a, [wNumRadioLinesPrinted] + cp 1 + call nz, CopyBottomLineToTopLine + jp ClearBottomLine + +OaksPKMNTalk1: + ld a, 5 + ld [wOaksPKMNTalkSegmentCounter], a + call StartRadioStation + ld hl, OPT_IntroText1 + ld a, OAKS_POKEMON_TALK_2 + jp NextRadioLine + +OaksPKMNTalk2: + ld hl, OPT_IntroText2 + ld a, OAKS_POKEMON_TALK_3 + jp NextRadioLine + +OaksPKMNTalk3: + ld hl, OPT_IntroText3 + ld a, OAKS_POKEMON_TALK_4 + jp NextRadioLine + +OaksPKMNTalk4: +; Choose a random route, and a random Pokemon from that route. +.sample + call Random + and %11111 + cp (OaksPKMNTalkRoutes.End - OaksPKMNTalkRoutes) / 2 + jr nc, .sample + ; We now have a number between 0 and 14. + ld hl, OaksPKMNTalkRoutes + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld b, [hl] + inc hl + ld c, [hl] + ; bc now contains the chosen map's group and number indices. + push bc + + ; Search the JohtoGrassWildMons array for the chosen map. + ld hl, JohtoGrassWildMons +.loop + ld a, BANK(JohtoGrassWildMons) + call GetFarByte + cp -1 + jr z, .overflow + inc hl + cp b + jr nz, .next + ld a, BANK(JohtoGrassWildMons) + call GetFarByte + cp c + jr z, .done +.next + dec hl + ld de, GRASS_WILDDATA_LENGTH + add hl, de + jr .loop + +.done + ; Point hl to the list of morning Pokémon., skipping percentages +rept 4 + inc hl +endr + ; Generate a number, either 0, 1, or 2, to choose a time of day. +.loop2 + call Random + maskbits NUM_DAYTIMES + cp DARKNESS_F + jr z, .loop2 + + ld bc, 2 * NUM_GRASSMON + call AddNTimes +.loop3 + ; Choose one of the middle three Pokemon. + call Random + and NUM_GRASSMON + cp 2 + jr c, .loop3 + cp 5 + jr nc, .loop3 + ld e, a + ld d, 0 + add hl, de + add hl, de + inc hl ; skip level + ld a, BANK(JohtoGrassWildMons) + call GetFarByte + ld [wNamedObjectIndexBuffer], a + ld [wCurPartySpecies], a + call GetPokemonName + ld hl, wStringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, MON_NAME_LENGTH + call CopyBytes + + ; Now that we've chosen our wild Pokemon, + ; let's recover the map index info and get its name. + pop bc + call GetWorldMapLocation + ld e, a + callfar GetLandmarkName + ld hl, OPT_OakText1 + call CopyRadioTextToRAM + ld a, OAKS_POKEMON_TALK_5 + jp PrintRadioLine + +.overflow + pop bc + ld a, OAKS_POKEMON_TALK + jp PrintRadioLine + +INCLUDE "data/radio/oaks_pkmn_talk_routes.asm" + +OaksPKMNTalk5: + ld hl, OPT_OakText2 + ld a, OAKS_POKEMON_TALK_6 + jp NextRadioLine + +OaksPKMNTalk6: + ld hl, OPT_OakText3 + ld a, OAKS_POKEMON_TALK_7 + jp NextRadioLine + +OPT_IntroText1: + text_far _OPT_IntroText1 + text_end + +OPT_IntroText2: + text_far _OPT_IntroText2 + text_end + +OPT_IntroText3: + text_far _OPT_IntroText3 + text_end + +OPT_OakText1: + text_far _OPT_OakText1 + text_end + +OPT_OakText2: + text_far _OPT_OakText2 + text_end + +OPT_OakText3: + text_far _OPT_OakText3 + text_end + +OaksPKMNTalk7: + ld a, [wCurPartySpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, OPT_MaryText1 + ld a, OAKS_POKEMON_TALK_8 + jp NextRadioLine + +OPT_MaryText1: + text_far _OPT_MaryText1 + text_end + +OaksPKMNTalk8: + ; 0-15 are all valid indexes into .Adverbs, + ; so no need for a retry loop + call Random + maskbits NUM_OAKS_POKEMON_TALK_ADVERBS + ld e, a + ld d, 0 + ld hl, .Adverbs + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld a, OAKS_POKEMON_TALK_9 + jp NextRadioLine + +.Adverbs: +; there are NUM_OAKS_POKEMON_TALK_ADVERBS entries + dw .OPT_SweetAdorablyText + dw .OPT_WigglySlicklyText + dw .OPT_AptlyNamedText + dw .OPT_UndeniablyKindOfText + dw .OPT_UnbearablyText + dw .OPT_WowImpressivelyText + dw .OPT_AlmostPoisonouslyText + dw .OPT_SensuallyText + dw .OPT_MischievouslyText + dw .OPT_TopicallyText + dw .OPT_AddictivelyText + dw .OPT_LooksInWaterText + dw .OPT_EvolutionMustBeText + dw .OPT_ProvocativelyText + dw .OPT_FlippedOutText + dw .OPT_HeartMeltinglyText + +.OPT_SweetAdorablyText: + text_far _OPT_SweetAdorablyText + text_end + +.OPT_WigglySlicklyText: + text_far _OPT_WigglySlicklyText + text_end + +.OPT_AptlyNamedText: + text_far _OPT_AptlyNamedText + text_end + +.OPT_UndeniablyKindOfText: + text_far _OPT_UndeniablyKindOfText + text_end + +.OPT_UnbearablyText: + text_far _OPT_UnbearablyText + text_end + +.OPT_WowImpressivelyText: + text_far _OPT_WowImpressivelyText + text_end + +.OPT_AlmostPoisonouslyText: + text_far _OPT_AlmostPoisonouslyText + text_end + +.OPT_SensuallyText: + text_far _OPT_SensuallyText + text_end + +.OPT_MischievouslyText: + text_far _OPT_MischievouslyText + text_end + +.OPT_TopicallyText: + text_far _OPT_TopicallyText + text_end + +.OPT_AddictivelyText: + text_far _OPT_AddictivelyText + text_end + +.OPT_LooksInWaterText: + text_far _OPT_LooksInWaterText + text_end + +.OPT_EvolutionMustBeText: + text_far _OPT_EvolutionMustBeText + text_end + +.OPT_ProvocativelyText: + text_far _OPT_ProvocativelyText + text_end + +.OPT_FlippedOutText: + text_far _OPT_FlippedOutText + text_end + +.OPT_HeartMeltinglyText: + text_far _OPT_HeartMeltinglyText + text_end + +OaksPKMNTalk9: + ; 0-15 are all valid indexes into .Adjectives, + ; so no need for a retry loop + call Random + maskbits NUM_OAKS_POKEMON_TALK_ADJECTIVES + ld e, a + ld d, 0 + ld hl, .Adjectives + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wOaksPKMNTalkSegmentCounter] + dec a + ld [wOaksPKMNTalkSegmentCounter], a + ld a, OAKS_POKEMON_TALK_4 + jr nz, .ok + ld a, 5 + ld [wOaksPKMNTalkSegmentCounter], a + ld a, OAKS_POKEMON_TALK_10 +.ok + jp NextRadioLine + +.Adjectives: +; there are NUM_OAKS_POKEMON_TALK_ADJECTIVES entries + dw .OPT_CuteText + dw .OPT_WeirdText + dw .OPT_PleasantText + dw .OPT_BoldSortOfText + dw .OPT_FrighteningText + dw .OPT_SuaveDebonairText + dw .OPT_PowerfulText + dw .OPT_ExcitingText + dw .OPT_NowText + dw .OPT_InspiringText + dw .OPT_FriendlyText + dw .OPT_HotHotHotText + dw .OPT_StimulatingText + dw .OPT_GuardedText + dw .OPT_LovelyText + dw .OPT_SpeedyText + +.OPT_CuteText: + text_far _OPT_CuteText + text_end + +.OPT_WeirdText: + text_far _OPT_WeirdText + text_end + +.OPT_PleasantText: + text_far _OPT_PleasantText + text_end + +.OPT_BoldSortOfText: + text_far _OPT_BoldSortOfText + text_end + +.OPT_FrighteningText: + text_far _OPT_FrighteningText + text_end + +.OPT_SuaveDebonairText: + text_far _OPT_SuaveDebonairText + text_end + +.OPT_PowerfulText: + text_far _OPT_PowerfulText + text_end + +.OPT_ExcitingText: + text_far _OPT_ExcitingText + text_end + +.OPT_NowText: + text_far _OPT_NowText + text_end + +.OPT_InspiringText: + text_far _OPT_InspiringText + text_end + +.OPT_FriendlyText: + text_far _OPT_FriendlyText + text_end + +.OPT_HotHotHotText: + text_far _OPT_HotHotHotText + text_end + +.OPT_StimulatingText: + text_far _OPT_StimulatingText + text_end + +.OPT_GuardedText: + text_far _OPT_GuardedText + text_end + +.OPT_LovelyText: + text_far _OPT_LovelyText + text_end + +.OPT_SpeedyText: + text_far _OPT_SpeedyText + text_end + +OaksPKMNTalk10: + farcall RadioMusicRestartPokemonChannel + ld hl, OPT_RestartText + call PrintText + call WaitBGMap + ld hl, OPT_PokemonChannelText + call PrintText + ld a, OAKS_POKEMON_TALK_11 + ld [wCurRadioLine], a + ld a, 100 + ld [wRadioTextDelay], a + ret + +OPT_PokemonChannelText: + text_far _OPT_PokemonChannelText + text_end + +OPT_RestartText: + text_end + +OaksPKMNTalk11: + ld hl, wRadioTextDelay + dec [hl] + ret nz + hlcoord 9, 14 + ld de, .pokemon_string + ld a, OAKS_POKEMON_TALK_12 + jp PlaceRadioString + +.pokemon_string + db "#MON@" + +OaksPKMNTalk12: + ld hl, wRadioTextDelay + dec [hl] + ret nz + hlcoord 1, 16 + ld de, .pokemon_channel_string + ld a, OAKS_POKEMON_TALK_13 + jp PlaceRadioString + +.pokemon_channel_string + db "#MON Channel@" + +OaksPKMNTalk13: + ld hl, wRadioTextDelay + dec [hl] + ret nz + hlcoord 12, 16 + ld de, .terminator + ld a, OAKS_POKEMON_TALK_14 + jp PlaceRadioString + +.terminator + db "@" + +OaksPKMNTalk14: + ld hl, wRadioTextDelay + dec [hl] + ret nz + ld de, MUSIC_POKEMON_TALK + callfar RadioMusicRestartDE + ld hl, .terminator + call PrintText + ld a, OAKS_POKEMON_TALK_4 + ld [wNextRadioLine], a + xor a + ld [wNumRadioLinesPrinted], a + ld a, RADIO_SCROLL + ld [wCurRadioLine], a + ld a, 10 + ld [wRadioTextDelay], a + ret + +.terminator + db "@" + +PlaceRadioString: + ld [wCurRadioLine], a + ld a, 100 + ld [wRadioTextDelay], a + jp PlaceString + +CopyBottomLineToTopLine: + hlcoord 0, 15 + decoord 0, 13 + ld bc, SCREEN_WIDTH * 2 + jp CopyBytes + +ClearBottomLine: + hlcoord 1, 15 + ld bc, SCREEN_WIDTH - 2 + ld a, " " + call ByteFill + hlcoord 1, 16 + ld bc, SCREEN_WIDTH - 2 + ld a, " " + jp ByteFill + +PokedexShow1: + call StartRadioStation +.loop + call Random + cp NUM_POKEMON + jr nc, .loop + ld c, a + push bc + ld a, c + call CheckCaughtMon + pop bc + jr z, .loop + inc c + ld a, c + ld [wCurPartySpecies], a + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, PokedexShowText + ld a, POKEDEX_SHOW_2 + jp NextRadioLine + +PokedexShow2: + ld a, [wCurPartySpecies] + dec a + ld hl, PokedexDataPointerTable + ld c, a + ld b, 0 + add hl, bc + add hl, bc + rlca + rlca + and %11 + add BANK("Pokedex Entries 001-064") + push af + ld a, BANK(PokedexDataPointerTable) + call GetFarHalfword + pop af + push af + push hl + call CopyDexEntryPart1 + dec hl + ld [hl], "<DONE>" + ld hl, wPokedexShowPointerAddr + call CopyRadioTextToRAM + pop hl + pop af + call CopyDexEntryPart2 +rept 4 + inc hl +endr + ld a, l + ld [wPokedexShowPointerAddr], a + ld a, h + ld [wPokedexShowPointerAddr + 1], a + ld a, POKEDEX_SHOW_3 + jp PrintRadioLine + +PokedexShow3: + call CopyDexEntry + ld a, POKEDEX_SHOW_4 + jp PrintRadioLine + +PokedexShow4: + call CopyDexEntry + ld a, POKEDEX_SHOW_5 + jp PrintRadioLine + +PokedexShow5: + call CopyDexEntry + ld a, POKEDEX_SHOW_6 + jp PrintRadioLine + +PokedexShow6: + call CopyDexEntry + ld a, POKEDEX_SHOW_7 + jp PrintRadioLine + +PokedexShow7: + call CopyDexEntry + ld a, POKEDEX_SHOW_8 + jp PrintRadioLine + +PokedexShow8: + call CopyDexEntry + ld a, POKEDEX_SHOW + jp PrintRadioLine + +CopyDexEntry: + ld a, [wPokedexShowPointerAddr] + ld l, a + ld a, [wPokedexShowPointerAddr + 1] + ld h, a + ld a, [wPokedexShowPointerBank] + push af + push hl + call CopyDexEntryPart1 + dec hl + ld [hl], "<DONE>" + ld hl, wPokedexShowPointerAddr + call CopyRadioTextToRAM + pop hl + pop af + call CopyDexEntryPart2 + ret + +CopyDexEntryPart1: + ld de, wPokedexShowPointerBank + ld bc, SCREEN_WIDTH - 1 + call FarCopyBytes + ld hl, wPokedexShowPointerAddr + ld [hl], TX_START + inc hl + ld [hl], "<LINE>" + inc hl +.loop + ld a, [hli] + cp "@" + ret z + cp "<NEXT>" + ret z + cp "<DEXEND>" + ret z + jr .loop + +CopyDexEntryPart2: + ld d, a +.loop + ld a, d + call GetFarByte + inc hl + cp "@" + jr z, .okay + cp "<NEXT>" + jr z, .okay + cp "<DEXEND>" + jr nz, .loop +.okay + ld a, l + ld [wPokedexShowPointerAddr], a + ld a, h + ld [wPokedexShowPointerAddr + 1], a + ld a, d + ld [wPokedexShowPointerBank], a + ret + +PokedexShowText: + text_far _PokedexShowText + text_end + +BenMonMusic1: + call StartPokemonMusicChannel + ld hl, BenIntroText1 + ld a, POKEMON_MUSIC_2 + jp NextRadioLine + +BenMonMusic2: + ld hl, BenIntroText2 + ld a, POKEMON_MUSIC_3 + jp NextRadioLine + +BenMonMusic3: + ld hl, BenIntroText3 + ld a, POKEMON_MUSIC_4 + jp NextRadioLine + +FernMonMusic1: + call StartPokemonMusicChannel + ld hl, FernIntroText1 + ld a, LETS_ALL_SING_2 + jp NextRadioLine + +FernMonMusic2: + ld hl, FernIntroText2 + ld a, POKEMON_MUSIC_4 + jp NextRadioLine + +BenFernMusic4: + ld hl, BenFernText1 + ld a, POKEMON_MUSIC_5 + jp NextRadioLine + +BenFernMusic5: + call GetWeekday + and 1 + ld hl, BenFernText2A + jr z, .SunTueThurSun + ld hl, BenFernText2B +.SunTueThurSun: + ld a, POKEMON_MUSIC_6 + jp NextRadioLine + +BenFernMusic6: + call GetWeekday + and 1 + ld hl, BenFernText3A + jr z, .SunTueThurSun + ld hl, BenFernText3B +.SunTueThurSun: + ld a, POKEMON_MUSIC_7 + jp NextRadioLine + +BenFernMusic7: + ret + +StartPokemonMusicChannel: + call RadioTerminator + call PrintText + ld de, MUSIC_POKEMON_MARCH + call GetWeekday + and 1 + jr z, .SunTueThurSun + ld de, MUSIC_POKEMON_LULLABY +.SunTueThurSun: + callfar RadioMusicRestartDE + ret + +BenIntroText1: + text_far _BenIntroText1 + text_end + +BenIntroText2: + text_far _BenIntroText2 + text_end + +BenIntroText3: + text_far _BenIntroText3 + text_end + +FernIntroText1: + text_far _FernIntroText1 + text_end + +FernIntroText2: + text_far _FernIntroText2 + text_end + +BenFernText1: + text_far _BenFernText1 + text_end + +BenFernText2A: + text_far _BenFernText2A + text_end + +BenFernText2B: + text_far _BenFernText2B + text_end + +BenFernText3A: + text_far _BenFernText3A + text_end + +BenFernText3B: + text_far _BenFernText3B + text_end + +LuckyNumberShow1: + call StartRadioStation + callfar CheckLuckyNumberShowFlag + jr nc, .dontreset + callfar ResetLuckyNumberShowFlag +.dontreset + ld hl, LC_Text1 + ld a, LUCKY_NUMBER_SHOW_2 + jp NextRadioLine + +LuckyNumberShow2: + ld hl, LC_Text2 + ld a, LUCKY_NUMBER_SHOW_3 + jp NextRadioLine + +LuckyNumberShow3: + ld hl, LC_Text3 + ld a, LUCKY_NUMBER_SHOW_4 + jp NextRadioLine + +LuckyNumberShow4: + ld hl, LC_Text4 + ld a, LUCKY_NUMBER_SHOW_5 + jp NextRadioLine + +LuckyNumberShow5: + ld hl, LC_Text5 + ld a, LUCKY_NUMBER_SHOW_6 + jp NextRadioLine + +LuckyNumberShow6: + ld hl, LC_Text6 + ld a, LUCKY_NUMBER_SHOW_7 + jp NextRadioLine + +LuckyNumberShow7: + ld hl, LC_Text7 + ld a, LUCKY_NUMBER_SHOW_8 + jp NextRadioLine + +LuckyNumberShow8: + ld hl, wStringBuffer1 + ld de, wLuckyIDNumber + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 + call PrintNum + ld a, "@" + ld [wStringBuffer1 + 5], a + ld hl, LC_Text8 + ld a, LUCKY_NUMBER_SHOW_9 + jp NextRadioLine + +LuckyNumberShow9: + ld hl, LC_Text9 + ld a, LUCKY_NUMBER_SHOW_10 + jp NextRadioLine + +LuckyNumberShow10: + ld hl, LC_Text7 + ld a, LUCKY_NUMBER_SHOW_11 + jp NextRadioLine + +LuckyNumberShow11: + ld hl, LC_Text8 + ld a, LUCKY_NUMBER_SHOW_12 + jp NextRadioLine + +LuckyNumberShow12: + ld hl, LC_Text10 + ld a, LUCKY_NUMBER_SHOW_13 + jp NextRadioLine + +LuckyNumberShow13: + ld hl, LC_Text11 + call Random + and a + ld a, LUCKY_CHANNEL + jr nz, .okay + ld a, LUCKY_NUMBER_SHOW_14 +.okay + jp NextRadioLine + +LuckyNumberShow14: + ld hl, LC_DragText1 + ld a, LUCKY_NUMBER_SHOW_15 + jp NextRadioLine + +LuckyNumberShow15: + ld hl, LC_DragText2 + ld a, LUCKY_CHANNEL + jp NextRadioLine + +LC_Text1: + text_far _LC_Text1 + text_end + +LC_Text2: + text_far _LC_Text2 + text_end + +LC_Text3: + text_far _LC_Text3 + text_end + +LC_Text4: + text_far _LC_Text4 + text_end + +LC_Text5: + text_far _LC_Text5 + text_end + +LC_Text6: + text_far _LC_Text6 + text_end + +LC_Text7: + text_far _LC_Text7 + text_end + +LC_Text8: + text_far _LC_Text8 + text_end + +LC_Text9: + text_far _LC_Text9 + text_end + +LC_Text10: + text_far _LC_Text10 + text_end + +LC_Text11: + text_far _LC_Text11 + text_end + +LC_DragText1: + text_far _LC_DragText1 + text_end + +LC_DragText2: + text_far _LC_DragText2 + text_end + +PeoplePlaces1: + call StartRadioStation + ld hl, PnP_Text1 + ld a, PLACES_AND_PEOPLE_2 + jp NextRadioLine + +PeoplePlaces2: + ld hl, PnP_Text2 + ld a, PLACES_AND_PEOPLE_3 + jp NextRadioLine + +PeoplePlaces3: + ld hl, PnP_Text3 + call Random + cp 49 percent - 1 + ld a, PLACES_AND_PEOPLE_4 ; People + jr c, .ok + ld a, PLACES_AND_PEOPLE_6 ; Places +.ok + jp NextRadioLine + +PnP_Text1: + text_far _PnP_Text1 + text_end + +PnP_Text2: + text_far _PnP_Text2 + text_end + +PnP_Text3: + text_far _PnP_Text3 + text_end + +PeoplePlaces4: ; People + call Random + maskbits NUM_TRAINER_CLASSES + inc a + cp NUM_TRAINER_CLASSES + jr nc, PeoplePlaces4 + push af + ld hl, PnP_HiddenPeople + ld a, [wStatusFlags] + bit STATUSFLAGS_HALL_OF_FAME_F, a + jr z, .ok + ld hl, PnP_HiddenPeople_BeatE4 + ld a, [wKantoBadges] + cp %11111111 ; all badges + jr nz, .ok + ld hl, PnP_HiddenPeople_BeatKanto +.ok + pop af + ld c, a + ld de, 1 + push bc + call IsInArray + pop bc + jr c, PeoplePlaces4 + push bc + callfar GetTrainerClassName + ld de, wStringBuffer1 + call CopyName1 + pop bc + ld b, 1 + callfar GetTrainerName + ld hl, PnP_Text4 + ld a, PLACES_AND_PEOPLE_5 + jp NextRadioLine + +INCLUDE "data/radio/pnp_hidden_people.asm" + +PnP_Text4: + text_far _PnP_Text4 + text_end + +PeoplePlaces5: + ; 0-15 are all valid indexes into .Adjectives, + ; so no need for a retry loop + call Random + maskbits NUM_PNP_PEOPLE_ADJECTIVES + ld e, a + ld d, 0 + ld hl, .Adjectives + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call Random + cp 4 percent + ld a, PLACES_AND_PEOPLE + jr c, .ok + call Random + cp 49 percent - 1 + ld a, PLACES_AND_PEOPLE_4 ; People + jr c, .ok + ld a, PLACES_AND_PEOPLE_6 ; Places +.ok + jp NextRadioLine + +.Adjectives: +; there are NUM_PNP_PEOPLE_ADJECTIVES entries + dw PnP_CuteText + dw PnP_LazyText + dw PnP_HappyText + dw PnP_NoisyText + dw PnP_PrecociousText + dw PnP_BoldText + dw PnP_PickyText + dw PnP_SortOfOKText + dw PnP_SoSoText + dw PnP_GreatText + dw PnP_MyTypeText + dw PnP_CoolText + dw PnP_InspiringText + dw PnP_WeirdText + dw PnP_RightForMeText + dw PnP_OddText + +PnP_CuteText: + text_far _PnP_CuteText + text_end + +PnP_LazyText: + text_far _PnP_LazyText + text_end + +PnP_HappyText: + text_far _PnP_HappyText + text_end + +PnP_NoisyText: + text_far _PnP_NoisyText + text_end + +PnP_PrecociousText: + text_far _PnP_PrecociousText + text_end + +PnP_BoldText: + text_far _PnP_BoldText + text_end + +PnP_PickyText: + text_far _PnP_PickyText + text_end + +PnP_SortOfOKText: + text_far _PnP_SortOfOKText + text_end + +PnP_SoSoText: + text_far _PnP_SoSoText + text_end + +PnP_GreatText: + text_far _PnP_GreatText + text_end + +PnP_MyTypeText: + text_far _PnP_MyTypeText + text_end + +PnP_CoolText: + text_far _PnP_CoolText + text_end + +PnP_InspiringText: + text_far _PnP_InspiringText + text_end + +PnP_WeirdText: + text_far _PnP_WeirdText + text_end + +PnP_RightForMeText: + text_far _PnP_RightForMeText + text_end + +PnP_OddText: + text_far _PnP_OddText + text_end + +PeoplePlaces6: ; Places + call Random + cp (PnP_Places.End - PnP_Places) / 2 + jr nc, PeoplePlaces6 + ld hl, PnP_Places + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld b, [hl] + inc hl + ld c, [hl] + call GetWorldMapLocation + ld e, a + callfar GetLandmarkName + ld hl, PnP_Text5 + ld a, PLACES_AND_PEOPLE_7 + jp NextRadioLine + +INCLUDE "data/radio/pnp_places.asm" + +PnP_Text5: + text_far _PnP_Text5 + text_end + +PeoplePlaces7: + ; 0-15 are all valid indexes into .Adjectives, + ; so no need for a retry loop + call Random + maskbits NUM_PNP_PLACES_ADJECTIVES + ld e, a + ld d, 0 + ld hl, .Adjectives + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call CopyRadioTextToRAM + call Random + cp 4 percent + ld a, PLACES_AND_PEOPLE + jr c, .ok + call Random + cp 49 percent - 1 + ld a, PLACES_AND_PEOPLE_4 ; People + jr c, .ok + ld a, PLACES_AND_PEOPLE_6 ; Places +.ok + jp PrintRadioLine + +.Adjectives: +; there are NUM_PNP_PLACES_ADJECTIVES entries + dw PnP_CuteText + dw PnP_LazyText + dw PnP_HappyText + dw PnP_NoisyText + dw PnP_PrecociousText + dw PnP_BoldText + dw PnP_PickyText + dw PnP_SortOfOKText + dw PnP_SoSoText + dw PnP_GreatText + dw PnP_MyTypeText + dw PnP_CoolText + dw PnP_InspiringText + dw PnP_WeirdText + dw PnP_RightForMeText + dw PnP_OddText + +RocketRadio1: + call StartRadioStation + ld hl, RocketRadioText1 + ld a, ROCKET_RADIO_2 + jp NextRadioLine + +RocketRadio2: + ld hl, RocketRadioText2 + ld a, ROCKET_RADIO_3 + jp NextRadioLine + +RocketRadio3: + ld hl, RocketRadioText3 + ld a, ROCKET_RADIO_4 + jp NextRadioLine + +RocketRadio4: + ld hl, RocketRadioText4 + ld a, ROCKET_RADIO_5 + jp NextRadioLine + +RocketRadio5: + ld hl, RocketRadioText5 + ld a, ROCKET_RADIO_6 + jp NextRadioLine + +RocketRadio6: + ld hl, RocketRadioText6 + ld a, ROCKET_RADIO_7 + jp NextRadioLine + +RocketRadio7: + ld hl, RocketRadioText7 + ld a, ROCKET_RADIO_8 + jp NextRadioLine + +RocketRadio8: + ld hl, RocketRadioText8 + ld a, ROCKET_RADIO_9 + jp NextRadioLine + +RocketRadio9: + ld hl, RocketRadioText9 + ld a, ROCKET_RADIO_10 + jp NextRadioLine + +RocketRadio10: + ld hl, RocketRadioText10 + ld a, ROCKET_RADIO + jp NextRadioLine + +RocketRadioText1: + text_far _RocketRadioText1 + text_end + +RocketRadioText2: + text_far _RocketRadioText2 + text_end + +RocketRadioText3: + text_far _RocketRadioText3 + text_end + +RocketRadioText4: + text_far _RocketRadioText4 + text_end + +RocketRadioText5: + text_far _RocketRadioText5 + text_end + +RocketRadioText6: + text_far _RocketRadioText6 + text_end + +RocketRadioText7: + text_far _RocketRadioText7 + text_end + +RocketRadioText8: + text_far _RocketRadioText8 + text_end + +RocketRadioText9: + text_far _RocketRadioText9 + text_end + +RocketRadioText10: + text_far _RocketRadioText10 + text_end + +PokeFluteRadio: + call StartRadioStation + ld a, 1 + ld [wNumRadioLinesPrinted], a + ret + +UnownRadio: + call StartRadioStation + ld a, 1 + ld [wNumRadioLinesPrinted], a + ret + +EvolutionRadio: + call StartRadioStation + ld a, 1 + ld [wNumRadioLinesPrinted], a + ret + +CopyRadioTextToRAM: + ld a, [hl] + cp TX_FAR + jp z, FarCopyRadioText + ld de, wRadioText + ld bc, SCREEN_WIDTH * 2 + jp CopyBytes + +StartRadioStation: + ld a, [wNumRadioLinesPrinted] + and a + ret nz + call RadioTerminator + call PrintText + ld hl, RadioChannelSongs + ld a, [wCurRadioLine] + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + callfar RadioMusicRestartDE + ret + +INCLUDE "data/radio/channel_music.asm" + +NextRadioLine: + push af + call CopyRadioTextToRAM + pop af + jp PrintRadioLine diff --git a/engine/billspctop.asm b/engine/pokemon/bills_pc_top.asm index b0ec59a5..0975c750 100644 --- a/engine/billspctop.asm +++ b/engine/pokemon/bills_pc_top.asm @@ -1,82 +1,81 @@ -BillsPC_: - call BillsPC_CheckHavePokemon +_BillsPC: + call .CheckCanUsePC ret c - call BillsPC_LogIn - call BillsPC_UsePC - jp BillsPC_LogOut + call .LogIn + call .UseBillsPC + jp .LogOut -BillsPC_CheckHavePokemon: ; e3e5 (3:63e5) - ld a, [wPokemonData] +.CheckCanUsePC: + ld a, [wPartyCount] and a ret nz - ld hl, Text_GottaHavePokemon + ld hl, .PCGottaHavePokemonText call MenuTextboxBackup scf ret -Text_GottaHavePokemon: - text_far Text_GottaHavePokemon_ - db "@" +.PCGottaHavePokemonText: + text_far _PCGottaHavePokemonText + text_end -BillsPC_LogIn: ; e3f7 (3:63f7) +.LogIn: xor a ldh [hBGMapMode], a call LoadStandardMenuHeader - call Functione566 + call ClearPCItemScreen ld hl, wOptions ld a, [hl] push af - set 4, [hl] - ld hl, Text_BillsPCWhat + set NO_TEXT_SCROLL, [hl] + ld hl, .PCWhatText call PrintText pop af ld [wOptions], a - call Functionda5 + call LoadFontsBattleExtra ret -Text_BillsPCWhat: - text_far Text_BillsPCWhat_ - db "@" +.PCWhatText: + text_far _PCWhatText + text_end -BillsPC_LogOut: ; e41a (3:641a) +.LogOut: call CloseSubmenu ret -BillsPC_UsePC: ; e41e (3:641e) - ld hl, BillsPC_TopMenuDataHeader +.UseBillsPC: + ld hl, .MenuHeader call LoadMenuHeader ld a, $1 -.asm_e426 +.loop ld [wMenuCursorBuffer], a call SetPalettes xor a ld [wWhichIndexSet], a ldh [hBGMapMode], a call DoNthMenu - jr c, .asm_e446 + jr c, .cancel ld a, [wMenuCursorBuffer] push af ld a, [wMenuSelection] - ld hl, BillsPC_TopMenuJumptable + ld hl, .Jumptable rst JumpTable pop bc ld a, b - jr nc, .asm_e426 -.asm_e446 + jr nc, .loop +.cancel call CloseWindow ret -BillsPC_TopMenuDataHeader: - db $40 - db 00, 00 - db 17, 19 - dw .MenuData2 - db 1 - -.MenuData2: - db $80 - db 0 - dw BillsPC_TopMenuItems +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR ; flags + db 0 ; items + dw .items dw PlaceMenuStrings dw .strings @@ -87,16 +86,20 @@ BillsPC_TopMenuDataHeader: db "MOVE <PK><MN> W/O MAIL@" db "SEE YA!@" -BillsPC_TopMenuJumptable: +.Jumptable: dw BillsPC_WithdrawMenu dw BillsPC_DepositMenu dw BillsPC_ChangeBoxMenu dw BillsPC_MovePKMNMenu dw BillsPC_SeeYa -BillsPC_TopMenuItems: - db 5 - db 0, 1, 2, 3, 4 +.items + db 5 ; # items + db 0 ; WITHDRAW + db 1 ; DEPOSIT + db 2 ; CHANGE BOX + db 3 ; MOVE PKMN + db 4 ; SEE YA! db -1 BillsPC_SeeYa: @@ -105,125 +108,127 @@ BillsPC_SeeYa: BillsPC_MovePKMNMenu: call LoadStandardMenuHeader - farcall IsAnyPokemonHoldingMail ; 11:488c - jr nc, .asm_e4bb - ld hl, Text_PleaseRemoveMailBeforeMovePkmnWOMail + farcall IsAnyMonHoldingMail + jr nc, .no_mail + ld hl, .PCMonHoldingMailText call PrintText - jr .asm_e4cf + jr .quit -.asm_e4bb - farcall StartMovePkmnWOMail_SaveGame ; 5:4bd2 - jr c, .asm_e4cf - farcall MovePKMNWithoutMail_ ; 38:6f47 +.no_mail + farcall StartMoveMonWOMail_SaveGame + jr c, .quit + farcall _MovePKMNWithoutMail call ReturnToMapFromSubmenu - call Functione566 -.asm_e4cf + call ClearPCItemScreen + +.quit call CloseWindow and a ret -Text_PleaseRemoveMailBeforeMovePkmnWOMail: - text_far Text_PleaseRemoveMailBeforeMovePkmnWOMail_ - db "@" +.PCMonHoldingMailText: + text_far _PCMonHoldingMailText + text_end BillsPC_DepositMenu: call LoadStandardMenuHeader - farcall DepositPokemon_ ; 38:6b9e + farcall _DepositPKMN call ReturnToMapFromSubmenu - call Functione566 + call ClearPCItemScreen call CloseWindow and a ret -Functione4ed: +Unreferenced_Functione4ed: ld a, [wPartyCount] and a - jr z, .asm_e4f9 - cp $2 - jr c, .asm_e501 + jr z, .no_mon + cp 2 + jr c, .only_one_mon and a ret -.asm_e4f9 - ld hl, Text_YouDontHaveASinglePokemon +.no_mon + ld hl, .PCNoSingleMonText call MenuTextboxBackup scf ret -.asm_e501 - ld hl, Text_ItsYourLastPokemon +.only_one_mon + ld hl, .PCCantDepositLastMonText call MenuTextboxBackup scf ret -Text_YouDontHaveASinglePokemon: - text_far Text_YouDontHaveASinglePokemon_ - db "@" +.PCNoSingleMonText: + text_far _PCNoSingleMonText + text_end -Text_ItsYourLastPokemon: - text_far Text_ItsYourLastPokemon_ - db "@" +.PCCantDepositLastMonText: + text_far _PCCantDepositLastMonText + text_end -CheckCurPartyMonFainted: ; e513 (3:6513) +CheckCurPartyMonFainted: ld hl, wPartyMon1HP - ld de, $30 + ld de, PARTYMON_STRUCT_LENGTH ld b, $0 -.asm_e51b +.loop ld a, [wCurPartyMon] cp b - jr z, .asm_e526 + jr z, .skip ld a, [hli] or [hl] - jr nz, .asm_e532 + jr nz, .notfainted dec hl -.asm_e526 + +.skip inc b ld a, [wPartyCount] cp b - jr z, .asm_e530 + jr z, .done add hl, de - jr .asm_e51b + jr .loop -.asm_e530 +.done scf ret -.asm_e532 +.notfainted and a ret BillsPC_WithdrawMenu: call LoadStandardMenuHeader - farcall WithdrawPokemon_ ; 38:6d71 + farcall _WithdrawPKMN call ReturnToMapFromSubmenu - call Functione566 + call ClearPCItemScreen call CloseWindow and a ret -Functione548: +Unreferenced_Functione548: ld a, [wPartyCount] - cp $6 + cp PARTY_LENGTH jr nc, .asm_e551 and a ret .asm_e551 - ld hl, Text_CantTakeAnyMorePokemon + ld hl, PCCantTakeText call MenuTextboxBackup scf ret -Text_CantTakeAnyMorePokemon: - text_far Text_CantTakeAnyMorePokemon_ - db "@" +PCCantTakeText: + text_far _PCCantTakeText + text_end BillsPC_ChangeBoxMenu: - farcall ChangeBox_ ; 38:7d25 + farcall _ChangeBox and a ret -Functione566: ; e566 (3:6566) +ClearPCItemScreen: call DisableSpriteUpdates xor a ldh [hBGMapMode], a @@ -237,32 +242,32 @@ Functione566: ; e566 (3:6566) lb bc, 10, 18 call Textbox hlcoord 0, 12 - ld bc, IncGradGBPalTable_13 + lb bc, 4, 18 call Textbox call WaitBGMap2 - call SetPalettes + call SetPalettes ; load regular palettes? ret -CopyBoxmonToTempMon +CopyBoxmonToTempMon: ld a, [wCurPartyMon] ld hl, sBoxMon1Species - ld bc, $20 + ld bc, BOXMON_STRUCT_LENGTH call AddNTimes ld de, wTempMonSpecies - ld bc, $20 + ld bc, BOXMON_STRUCT_LENGTH ld a, BANK(sBoxMon1Species) call OpenSRAM call CopyBytes call CloseSRAM ret -Function65b4: +Unreferenced_LoadBoxMonListing: ld a, [wCurBox] cp b - jr z, .asm_e5cc + jr z, .same_box ld a, b - ld hl, Bank3BoxAddrs - ld bc, $3 + ld hl, .BoxAddrs + ld bc, 3 call AddNTimes ld a, [hli] push af @@ -270,29 +275,30 @@ Function65b4: ld h, [hl] ld l, a pop af - jr .asm_e5d1 + jr .okay -.asm_e5cc +.same_box ld a, BANK(sBoxCount) ld hl, sBoxCount -.asm_e5d1 + +.okay call OpenSRAM ld a, [hl] - ld bc, sBoxMon1 - sBox + ld bc, sBoxMons - sBox add hl, bc ld b, a ld c, $0 - ld de, wMisc + ld de, wBoxPartialData ld a, b and a - jr z, .asm_e645 -.asm_e5e3 + jr z, .empty_box +.loop push hl push bc ld a, c - ld bc, $0 + ld bc, sBoxMon1Species - sBoxMons add hl, bc - ld bc, $20 + ld bc, BOXMON_STRUCT_LENGTH call AddNTimes ld a, [hl] ld [de], a @@ -301,6 +307,7 @@ Function65b4: call GetBaseData pop bc pop hl + push hl push bc ld a, c @@ -310,24 +317,26 @@ Function65b4: call CopyBytes pop bc pop hl + push hl push bc ld a, c - ld bc, $1f + ld bc, MON_LEVEL add hl, bc - ld bc, $20 + ld bc, BOXMON_STRUCT_LENGTH call AddNTimes ld a, [hl] ld [de], a inc de pop bc pop hl + push hl push bc ld a, c - ld bc, $15 + ld bc, MON_DVS add hl, bc - ld bc, $20 + ld bc, BOXMON_STRUCT_LENGTH call AddNTimes ld a, [hli] and $f0 @@ -337,24 +346,25 @@ Function65b4: swap a or b ld b, a - ld a, [wd12d] + ld a, [wBaseGender] cp b ld a, $1 - jr c, .asm_e63d + jr c, .okay2 xor a -.asm_e63d +.okay2 ld [de], a inc de pop bc pop hl + inc c dec b - jr nz, .asm_e5e3 -.asm_e645 + jr nz, .loop +.empty_box call CloseSRAM ret -Bank3BoxAddrs: +.BoxAddrs: dba sBox1 dba sBox2 dba sBox3 diff --git a/engine/pokemon/breeding.asm b/engine/pokemon/breeding.asm new file mode 100644 index 00000000..ee1afd25 --- /dev/null +++ b/engine/pokemon/breeding.asm @@ -0,0 +1,935 @@ +CheckBreedmonCompatibility: + call .CheckBreedingGroupCompatibility + ld c, $0 + jp nc, .done + ld a, [wBreedMon1Species] + ld [wCurPartySpecies], a + ld a, [wBreedMon1DVs] + ld [wTempMonDVs], a + ld a, [wBreedMon1DVs + 1] + ld [wTempMonDVs + 1], a + ld a, TEMPMON + ld [wMonType], a + predef GetGender + jr c, .genderless + ld b, $1 + jr nz, .breedmon2 + inc b + +.breedmon2 + push bc + ld a, [wBreedMon2Species] + ld [wCurPartySpecies], a + ld a, [wBreedMon2DVs] + ld [wTempMonDVs], a + ld a, [wBreedMon2DVs + 1] + ld [wTempMonDVs + 1], a + ld a, TEMPMON + ld [wMonType], a + predef GetGender + pop bc + jr c, .genderless + ld a, $1 + jr nz, .compare_gender + inc a + +.compare_gender + cp b + jr nz, .compute + +.genderless + ld c, $0 + ld a, [wBreedMon1Species] + cp DITTO + jr z, .ditto1 + ld a, [wBreedMon2Species] + cp DITTO + jr nz, .done + jr .compute + +.ditto1 + ld a, [wBreedMon2Species] + cp DITTO + jr z, .done + +.compute + call .CheckDVs + ld c, 255 + jp z, .done + ld a, [wBreedMon2Species] + ld b, a + ld a, [wBreedMon1Species] + cp b + ld c, 254 + jr z, .compare_ids + ld c, 128 +.compare_ids + ; Speed up + ld a, [wBreedMon1ID] + ld b, a + ld a, [wBreedMon2ID] + cp b + jr nz, .done + ld a, [wBreedMon1ID + 1] + ld b, a + ld a, [wBreedMon2ID + 1] + cp b + jr nz, .done + ld a, c + sub 77 + ld c, a + +.done + ld a, c + ld [wBreedingCompatibility], a + ret + +.CheckDVs: +; If Defense DVs match and the lower 3 bits of the Special DVs match, +; avoid breeding + ld a, [wBreedMon1DVs] + and %1111 + ld b, a + ld a, [wBreedMon2DVs] + and %1111 + cp b + ret nz + ld a, [wBreedMon1DVs + 1] + and %111 + ld b, a + ld a, [wBreedMon2DVs + 1] + and %111 + cp b + ret + +.CheckBreedingGroupCompatibility: +; If either mon is in the No Eggs group, +; they are not compatible. + ld a, [wBreedMon2Species] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseEggGroups] + cp EGG_NONE * $11 + jr z, .Incompatible + + ld a, [wBreedMon1Species] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseEggGroups] + cp EGG_NONE * $11 + jr z, .Incompatible + +; Ditto is automatically compatible with everything. +; If not Ditto, load the breeding groups into b/c and d/e. + ld a, [wBreedMon2Species] + cp DITTO + jr z, .Compatible + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseEggGroups] + push af + and $f + ld b, a + pop af + and $f0 + swap a + ld c, a + + ld a, [wBreedMon1Species] + cp DITTO + jr z, .Compatible + ld [wCurSpecies], a + push bc + call GetBaseData + pop bc + ld a, [wBaseEggGroups] + push af + and $f + ld d, a + pop af + and $f0 + swap a + ld e, a + + ld a, d + cp b + jr z, .Compatible + cp c + jr z, .Compatible + + ld a, e + cp b + jr z, .Compatible + cp c + jr z, .Compatible + +.Incompatible: + and a + ret + +.Compatible: + scf + ret + +DoEggStep:: + ld de, wPartySpecies + ld hl, wPartyMon1Happiness + ld c, 0 +.loop + ld a, [de] + inc de + cp -1 + ret z + cp EGG + jr nz, .next + dec [hl] + jr nz, .next + ld a, 1 + and a + ret + +.next + push de + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + pop de + jr .loop + +OverworldHatchEgg:: + call RefreshScreen + call LoadStandardMenuHeader + call HatchEggs + call ExitAllMenus + call RestartMapMusic + jp CloseText + +HatchEggs: + ld de, wPartySpecies + ld hl, wPartyMon1Happiness + xor a + ld [wCurPartyMon], a + +.loop + ld a, [de] + inc de + cp -1 + jp z, .done + push de + push hl + cp EGG + jp nz, .next + ld a, [hl] + and a + jp nz, .next + ld [hl], $78 + + push de + + ld a, [wCurPartyMon] + ld hl, wPartyMon1Species + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld a, [hl] + ld [wCurPartySpecies], a + dec a + call SetSeenAndCaughtMon + + ld a, [wCurPartySpecies] + cp TOGEPI + jr nz, .nottogepi + ; set the event flag for hatching togepi + ld de, EVENT_TOGEPI_HATCHED + ld b, SET_FLAG + call EventFlagAction +.nottogepi + + pop de + + ld a, [wCurPartySpecies] + dec de + ld [de], a + ld [wNamedObjectIndexBuffer], a + ld [wCurSpecies], a + call GetPokemonName + xor a + ld [wUnusedEggHatchFlag], a + call GetBaseData + ld a, [wCurPartyMon] + ld hl, wPartyMon1 + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + push hl + ld bc, MON_MAXHP + add hl, bc + ld d, h + ld e, l + pop hl + push hl + ld bc, MON_LEVEL + add hl, bc + ld a, [hl] + ld [wCurPartyLevel], a + pop hl + push hl + ld bc, MON_STATUS + add hl, bc + xor a + ld [hli], a + ld [hl], a + pop hl + push hl + ld bc, MON_STAT_EXP - 1 + add hl, bc + ld b, FALSE + predef CalcMonStats + pop bc + ld hl, MON_MAXHP + add hl, bc + ld d, h + ld e, l + ld hl, MON_HP + add hl, bc + ld a, [de] + inc de + ld [hli], a + ld a, [de] + ld [hl], a + ld hl, MON_ID + add hl, bc + ld a, [wPlayerID] + ld [hli], a + ld a, [wPlayerID + 1] + ld [hl], a + ld a, [wCurPartyMon] + ld hl, wPartyMonOT + ld bc, NAME_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, wPlayerName + call CopyBytes + ld hl, .Text_HatchEgg + call PrintText + ld a, [wCurPartyMon] + ld hl, wPartyMonNicknames + ld bc, MON_NAME_LENGTH + call AddNTimes + ld d, h + ld e, l + push de + ld hl, .BreedAskNicknameText + call PrintText + call YesNoBox + pop de + jr c, .nonickname + + ld a, TRUE + ld [wUnusedEggHatchFlag], a + xor a + ld [wMonType], a + push de + ld b, NAME_MON + farcall NamingScreen + pop hl + ld de, wStringBuffer1 + call InitName + jr .next + +.nonickname + ld hl, wStringBuffer1 + ld bc, MON_NAME_LENGTH + call CopyBytes + +.next + ld hl, wCurPartyMon + inc [hl] + pop hl + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + pop de + jp .loop + +.done + ret + +.Text_HatchEgg: + ; Huh? @ @ + text_far Text_BreedHuh + text_asm + ld hl, wVramState + res 0, [hl] + push hl + push de + push bc + ld a, [wCurPartySpecies] + push af + call EggHatch_AnimationSequence + ld hl, .BreedClearboxText + call PrintText + pop af + ld [wCurPartySpecies], a + pop bc + pop de + pop hl + ld hl, .BreedEggHatchText + ret + +.BreedClearboxText: + text_far _BreedClearboxText + text_end + +.BreedEggHatchText: + text_far _BreedEggHatchText + text_end + +.BreedAskNicknameText: + text_far _BreedAskNicknameText + text_end + +InitEggMoves: + call GetHeritableMoves + ld d, h + ld e, l + ld b, NUM_MOVES +.loop + ld a, [de] + and a + jr z, .done + ld hl, wEggMonMoves + ld c, NUM_MOVES +.next + ld a, [de] + cp [hl] + jr z, .skip + inc hl + dec c + jr nz, .next + call GetEggMove + jr nc, .skip + call LoadEggMove + +.skip + inc de + dec b + jr nz, .loop + +.done + ret + +GetEggMove: + push bc + ld a, [wEggMonSpecies] + dec a + ld c, a + ld b, 0 + ld hl, EggMovePointers + add hl, bc + add hl, bc + ld a, BANK(EggMovePointers) + call GetFarHalfword +.loop + ld a, BANK("Egg Moves") + call GetFarByte + cp -1 + jr z, .reached_end + ld b, a + ld a, [de] + cp b + jr z, .done_carry + inc hl + jr .loop + +.reached_end + call GetBreedmonMovePointer + ld b, NUM_MOVES +.loop2 + ld a, [de] + cp [hl] + jr z, .found_eggmove + inc hl + dec b + jr z, .inherit_tmhm + jr .loop2 + +.found_eggmove + ld a, [wEggMonSpecies] + dec a + ld c, a + ld b, 0 + ld hl, EvosAttacksPointers + add hl, bc + add hl, bc + ld a, BANK(EvosAttacksPointers) + call GetFarHalfword +.loop3 + ld a, BANK("Evolutions and Attacks") + call GetFarByte + inc hl + and a + jr nz, .loop3 +.loop4 + ld a, BANK("Evolutions and Attacks") + call GetFarByte + and a + jr z, .inherit_tmhm + inc hl + ld a, BANK("Evolutions and Attacks") + call GetFarByte + ld b, a + ld a, [de] + cp b + jr z, .done_carry + inc hl + jr .loop4 + +.inherit_tmhm + ld hl, TMHMMoves +.loop5 + ld a, BANK(TMHMMoves) + call GetFarByte + inc hl + and a + jr z, .done + ld b, a + ld a, [de] + cp b + jr nz, .loop5 + ld [wPutativeTMHMMove], a + predef CanLearnTMHMMove + ld a, c + and a + jr z, .done + +.done_carry + pop bc + scf + ret + +.done + pop bc + and a + ret + +LoadEggMove: + push de + push bc + ld a, [de] + ld b, a + ld hl, wEggMonMoves + ld c, NUM_MOVES +.loop + ld a, [hli] + and a + jr z, .done + dec c + jr nz, .loop + ld de, wEggMonMoves + ld hl, wEggMonMoves + 1 + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + +.done + dec hl + ld [hl], b + ld hl, wEggMonMoves + ld de, wEggMonPP + predef FillPP + pop bc + pop de + ret + +GetHeritableMoves: + ld hl, wBreedMon2Moves + ld a, [wBreedMon1Species] + cp DITTO + jr z, .ditto1 + ld a, [wBreedMon2Species] + cp DITTO + jr z, .ditto2 + ld a, [wBreedMotherOrNonDitto] + and a + ret z + ld hl, wBreedMon1Moves + ret + +.ditto1 + ld a, [wCurPartySpecies] + push af + ld a, [wBreedMon2Species] + ld [wCurPartySpecies], a + ld a, [wBreedMon2DVs] + ld [wTempMonDVs], a + ld a, [wBreedMon2DVs + 1] + ld [wTempMonDVs + 1], a + ld a, TEMPMON + ld [wMonType], a + predef GetGender + jr c, .inherit_mon2_moves + jr nz, .inherit_mon2_moves + jr .inherit_mon1_moves + +.ditto2 + ld a, [wCurPartySpecies] + push af + ld a, [wBreedMon1Species] + ld [wCurPartySpecies], a + ld a, [wBreedMon1DVs] + ld [wTempMonDVs], a + ld a, [wBreedMon1DVs + 1] + ld [wTempMonDVs + 1], a + ld a, TEMPMON + ld [wMonType], a + predef GetGender + jr c, .inherit_mon1_moves + jr nz, .inherit_mon1_moves + +.inherit_mon2_moves + ld hl, wBreedMon2Moves + pop af + ld [wCurPartySpecies], a + ret + +.inherit_mon1_moves + ld hl, wBreedMon1Moves + pop af + ld [wCurPartySpecies], a + ret + +GetBreedmonMovePointer: + ld hl, wBreedMon1Moves + ld a, [wBreedMon1Species] + cp DITTO + ret z + ld a, [wBreedMon2Species] + cp DITTO + jr z, .ditto + ld a, [wBreedMotherOrNonDitto] + and a + ret z + +.ditto + ld hl, wBreedMon2Moves + ret + +GetEggFrontpic: + push de + ld [wCurPartySpecies], a + ld [wCurSpecies], a + call GetBaseData + ld hl, wBattleMonDVs + predef GetUnownLetter + pop de + predef_jump GetMonFrontpic + +Hatch_UpdateFrontpicBGMapCenter: + push af + call WaitTop + push hl + push bc + hlcoord 0, 0 + ld bc, SCREEN_HEIGHT * SCREEN_WIDTH + ld a, " " + call ByteFill + pop bc + pop hl + ld a, b + ldh [hBGMapAddress + 1], a + ld a, c + ldh [hGraphicStartTile], a + lb bc, 7, 7 + predef PlaceGraphic + pop af + call Hatch_LoadFrontpicPal + call SetPalettes + jp WaitBGMap + +EggHatch_DoAnimFrame: + push hl + push de + push bc + callfar PlaySpriteAnimations + call DelayFrame + pop bc + pop de + pop hl + ret + +EggHatch_AnimationSequence: + ld a, [wNamedObjectIndexBuffer] + ld [wJumptableIndex], a + ld a, [wCurSpecies] + push af + ld de, MUSIC_NONE + call PlayMusic + farcall BlankScreen + call DisableLCD + ld hl, EggHatchGFX + ld de, vTiles0 tile $00 + ld bc, 2 tiles + ld a, BANK(EggHatchGFX) + call FarCopyBytes + farcall ClearSpriteAnims + ld de, vTiles2 tile $00 + ld a, [wJumptableIndex] + call GetEggFrontpic + ld de, vTiles2 tile $31 + ld a, EGG + call GetEggFrontpic + ld de, MUSIC_EVOLUTION + call PlayMusic + call EnableLCD + hlcoord 7, 4 + ld b, HIGH(vBGMap0) + ld c, $31 ; Egg tiles start here + ld a, EGG + call Hatch_UpdateFrontpicBGMapCenter + ld c, 80 + call DelayFrames + xor a + ld [wFrameCounter], a + ldh a, [hSCX] + ld b, a +.outerloop + ld hl, wFrameCounter + ld a, [hl] + inc [hl] + cp 8 + jr nc, .done + ld e, [hl] +.loop +; wobble e times + ld a, 2 + ldh [hSCX], a + ld a, -2 + ld [wGlobalAnimXOffset], a + call EggHatch_DoAnimFrame + ld c, 2 + call DelayFrames + ld a, -2 + ldh [hSCX], a + ld a, 2 + ld [wGlobalAnimXOffset], a + call EggHatch_DoAnimFrame + ld c, 2 + call DelayFrames + dec e + jr nz, .loop + ld c, 16 + call DelayFrames + call EggHatch_CrackShell + jr .outerloop + +.done + ld de, SFX_EGG_HATCH + call PlaySFX + xor a + ldh [hSCX], a + ld [wGlobalAnimXOffset], a + call ClearSprites + call Hatch_InitShellFragments + hlcoord 6, 3 + ld b, HIGH(vBGMap0) + ld c, $00 ; Hatchling tiles start here + ld a, [wJumptableIndex] + call Hatch_UpdateFrontpicBGMapCenter + call Hatch_ShellFragmentLoop + call WaitSFX + ld a, [wJumptableIndex] + call PlayMonCry + pop af + ld [wCurSpecies], a + ret + +Hatch_LoadFrontpicPal: + ld [wPlayerHPPal], a + ld b, SCGB_EVOLUTION + ld c, $0 + jp GetSGBLayout + +EggHatch_CrackShell: + ld a, [wFrameCounter] + dec a + and $7 + cp $7 + ret z + srl a + ret nc + swap a + srl a + add 9 * 8 + ld d, a + ld e, 11 * 8 + ld a, SPRITE_ANIM_INDEX_EGG_CRACK + call InitSpriteAnimStruct + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $0 + ld de, SFX_EGG_CRACK + jp PlaySFX + +EggHatchGFX: +INCBIN "gfx/evo/egg_hatch.2bpp" + +Hatch_InitShellFragments: + farcall ClearSpriteAnims + ld hl, .SpriteData +.loop + ld a, [hli] + cp -1 + jr z, .done + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + push hl + push bc + + ld a, SPRITE_ANIM_INDEX_EGG_HATCH + call InitSpriteAnimStruct + + ld hl, SPRITEANIMSTRUCT_TILE_ID + add hl, bc + ld [hl], $0 + + pop de + ld a, e + ld hl, SPRITEANIMSTRUCT_FRAMESET_ID + add hl, bc + add [hl] + ld [hl], a + + ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX + add hl, bc + ld [hl], d + + pop hl + jr .loop +.done + ld de, SFX_EGG_HATCH + call PlaySFX + call EggHatch_DoAnimFrame + ret + +shell_fragment: MACRO +; y tile, y pxl, x tile, x pxl, frameset offset, ??? + db (\1 * 8) % $100 + \2, (\3 * 8) % $100 + \4, \5 - SPRITE_ANIM_FRAMESET_EGG_HATCH_1, \6 +ENDM + +.SpriteData: + shell_fragment 10, 4, 9, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $3c + shell_fragment 11, 4, 9, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $04 + shell_fragment 10, 4, 10, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $30 + shell_fragment 11, 4, 10, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $10 + shell_fragment 10, 4, 11, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_3, $24 + shell_fragment 11, 4, 11, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_4, $1c + shell_fragment 10, 0, 9, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $36 + shell_fragment 12, 0, 9, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $0a + shell_fragment 10, 0, 10, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_3, $2a + shell_fragment 12, 0, 10, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_4, $16 + db -1 + +Hatch_ShellFragmentLoop: + ld c, 129 +.loop + call EggHatch_DoAnimFrame + dec c + jr nz, .loop + ret + +DayCareMon1: + ld hl, LeftWithDayCareManText + call PrintText + ld a, [wBreedMon1Species] + call PlayMonCry + ld a, [wDayCareLady] + bit DAYCARELADY_HAS_MON_F, a + jr z, DayCareMonCursor + call PromptButton + ld hl, wBreedMon2Nick + call DayCareMonCompatibilityText + jp PrintText + +DayCareMon2: + ld hl, LeftWithDayCareLadyText + call PrintText + ld a, [wBreedMon2Species] + call PlayMonCry + ld a, [wDayCareMan] + bit DAYCAREMAN_HAS_MON_F, a + jr z, DayCareMonCursor + call PromptButton + ld hl, wBreedMon1Nick + call DayCareMonCompatibilityText + jp PrintText + +DayCareMonCursor: + jp WaitPressAorB_BlinkCursor + +LeftWithDayCareLadyText: + text_far _LeftWithDayCareLadyText + text_end + +LeftWithDayCareManText: + text_far _LeftWithDayCareManText + text_end + +DayCareMonCompatibilityText: + push bc + ld de, wStringBuffer1 + ld bc, NAME_LENGTH + call CopyBytes + call CheckBreedmonCompatibility + pop bc + ld a, [wBreedingCompatibility] + ld hl, .BreedBrimmingWithEnergyText + cp -1 + jr z, .done + ld hl, .BreedNoInterestText + and a + jr z, .done + ld hl, .BreedAppearsToCareForText + cp 230 + jr nc, .done + cp 70 + ld hl, .BreedFriendlyText + jr nc, .done + ld hl, .BreedShowsInterestText + +.done + ret + +.BreedBrimmingWithEnergyText: + text_far _BreedBrimmingWithEnergyText + text_end + +.BreedNoInterestText: + text_far _BreedNoInterestText + text_end + +.BreedAppearsToCareForText: + text_far _BreedAppearsToCareForText + text_end + +.BreedFriendlyText: + text_far _BreedFriendlyText + text_end + +.BreedShowsInterestText: + text_far _BreedShowsInterestText + text_end + +Unreferenced_DayCareMonPrintEmptyString: + ld hl, .string + ret + +.string + db "@" diff --git a/engine/pokemon/breedmon_level_growth.asm b/engine/pokemon/breedmon_level_growth.asm new file mode 100644 index 00000000..c6356dd6 --- /dev/null +++ b/engine/pokemon/breedmon_level_growth.asm @@ -0,0 +1,27 @@ +GetBreedMon1LevelGrowth: + ld hl, wBreedMon1Stats + ld de, wTempMon + ld bc, BOXMON_STRUCT_LENGTH + call CopyBytes + callfar CalcLevel + ld a, [wBreedMon1Level] + ld b, a + ld a, d + ld e, a + sub b + ld d, a + ret + +GetBreedMon2LevelGrowth: + ld hl, wBreedMon2Stats + ld de, wTempMon + ld bc, BOXMON_STRUCT_LENGTH + call CopyBytes + callfar CalcLevel + ld a, [wBreedMon2Level] + ld b, a + ld a, d + ld e, a + sub b + ld d, a + ret diff --git a/engine/pokemon/correct_nick_errors.asm b/engine/pokemon/correct_nick_errors.asm new file mode 100644 index 00000000..421bf92d --- /dev/null +++ b/engine/pokemon/correct_nick_errors.asm @@ -0,0 +1,74 @@ +CorrectNickErrors:: +; error-check monster nick before use +; must be a peace offering to gamesharkers + +; input: de = nick location + + push bc + push de + ld b, MON_NAME_LENGTH + +.checkchar +; end of nick? + ld a, [de] + cp "@" ; terminator + jr z, .end + +; check if this char is a text command + ld hl, .textcommands + dec hl +.loop +; next entry + inc hl +; reached end of commands table? + ld a, [hl] + cp -1 + jr z, .done + +; is the current char between this value (inclusive)... + ld a, [de] + cp [hl] + inc hl + jr c, .loop +; ...and this one? + cp [hl] + jr nc, .loop + +; replace it with a "?" + ld a, "?" + ld [de], a + jr .loop + +.done +; next char + inc de +; reached end of nick without finding a terminator? + dec b + jr nz, .checkchar + +; change nick to "?@" + pop de + push de + ld a, "?" + ld [de], a + inc de + ld a, "@" + ld [de], a +.end +; if the nick has any errors at this point it's out of our hands + pop de + pop bc + ret + +.textcommands +; table defining which characters are actually text commands +; format: + ; ≥ < + db "<NULL>", "ガ" + db "<PLAY_G>", "<JP_18>" + 1 + db "<NI>", "<NO>" + 1 + db "<ROUTE>", "<GREEN>" + 1 + db "<ENEMY>", "<ENEMY>" + 1 + db "<MOM>", "<TM>" + 1 + db "<ROCKET>", "┘" + 1 + db -1 ; end diff --git a/engine/health.asm b/engine/pokemon/health.asm index a94a3ec3..d11a073b 100755 --- a/engine/health.asm +++ b/engine/pokemon/health.asm @@ -1,54 +1,62 @@ -HealParty: ; c69d (3:469d) +HealParty: xor a ld [wCurPartyMon], a ld hl, wPartySpecies -.asm_c6a4 +.loop ld a, [hli] - cp $ff - jr z, .asm_c6bb - cp $fd - jr z, .asm_c6b2 + cp -1 + jr z, .done + cp EGG + jr z, .next + push hl - call Functionc6bc + call HealPartyMon pop hl -.asm_c6b2 + +.next ld a, [wCurPartyMon] inc a ld [wCurPartyMon], a - jr .asm_c6a4 + jr .loop -.asm_c6bb +.done ret -Functionc6bc: ; c6bc (3:46bc) - ld a, $0 +HealPartyMon: + ld a, MON_SPECIES call GetPartyParamLocation ld d, h ld e, l - ld hl, $20 + + ld hl, MON_STATUS add hl, de xor a ld [hli], a ld [hl], a - ld hl, $24 + + ld hl, MON_MAXHP add hl, de + + ; bc = MON_HP ld b, h ld c, l dec bc dec bc + ld a, [hli] ld [bc], a inc bc ld a, [hl] ld [bc], a - farcall Functionf900 + + farcall RestoreAllPP ret ComputeHPBarPixels: ; e = bc * (6 * 8) / de ld a, b or c - jr z, .asm_c722 + jr z, .zero push hl xor a ldh [hMultiplicand + 0], a @@ -62,7 +70,7 @@ ComputeHPBarPixels: ; We need de to be under 256 because hDivisor is only 1 byte. ld a, d and a - jr z, .asm_c711 + jr z, .divide ; divide de and hProduct by 4 srl d rr e @@ -78,25 +86,25 @@ ComputeHPBarPixels: ldh [hDividend + 3], a ld a, b ldh [hDividend + 2], a -.asm_c711 +.divide ld a, e - ldh [hPrintNum5], a - ld b, $4 + ldh [hDivisor], a + ld b, 4 call Divide - ldh a, [hPrintNum4] + ldh a, [hQuotient + 3] ld e, a pop hl and a ret nz - ld e, $1 + ld e, 1 ret -.asm_c722 - ld e, $0 +.zero + ld e, 0 ret -AnimateHPBar: ; c725 (3:4725) +AnimateHPBar: call WaitBGMap - call AnimateHPBar_ + call _AnimateHPBar call WaitBGMap ret diff --git a/engine/pokemon/knows_move.asm b/engine/pokemon/knows_move.asm new file mode 100644 index 00000000..9fe0f6ac --- /dev/null +++ b/engine/pokemon/knows_move.asm @@ -0,0 +1,24 @@ +KnowsMove: + ld a, MON_MOVES + call GetPartyParamLocation + ld a, [wPutativeTMHMMove] + ld b, a + ld c, NUM_MOVES +.loop + ld a, [hli] + cp b + jr z, .knows_move + dec c + jr nz, .loop + and a + ret + +.knows_move + ld hl, .KnowsMoveText + call PrintText + scf + ret + +.KnowsMoveText: + text_far _KnowsMoveText + text_end diff --git a/engine/pokemon/learn.asm b/engine/pokemon/learn.asm new file mode 100644 index 00000000..2c66dcd5 --- /dev/null +++ b/engine/pokemon/learn.asm @@ -0,0 +1,239 @@ +LearnMove: + call LoadTilemapToTempTilemap + ld a, [wCurPartyMon] + ld hl, wPartyMonNicknames + call GetNick + ld hl, wStringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, MON_NAME_LENGTH + call CopyBytes + +.loop + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [wCurPartyMon] + call AddNTimes + ld d, h + ld e, l + ld b, NUM_MOVES +; Get the first empty move slot. This routine also serves to +; determine whether the Pokemon learning the moves already has +; all four slots occupied, in which case one would need to be +; deleted. +.next + ld a, [hl] + and a + jr z, .learn + inc hl + dec b + jr nz, .next +; If we're here, we enter the routine for forgetting a move +; to make room for the new move we're trying to learn. + push de + call ForgetMove + pop de + jp c, .cancel + + push hl + push de + ld [wNamedObjectIndexBuffer], a + + ld b, a + ld a, [wBattleMode] + and a + jr z, .not_disabled + ld a, [wDisabledMove] + cp b + jr nz, .not_disabled + xor a + ld [wDisabledMove], a + ld [wPlayerDisableCount], a +.not_disabled + + call GetMoveName + ld hl, Text_1_2_and_Poof ; 1, 2 and… + call PrintText + pop de + pop hl + +.learn + ld a, [wPutativeTMHMMove] + ld [hl], a + ld bc, MON_PP - MON_MOVES + add hl, bc + + push hl + push de + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + pop de + pop hl + + ld [hl], a + + ld a, [wBattleMode] + and a + jp z, .learned + + ld a, [wCurPartyMon] + ld b, a + ld a, [wCurBattleMon] + cp b + jp nz, .learned + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jp nz, .learned + + ld h, d + ld l, e + ld de, wBattleMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld bc, wPartyMon1PP - (wPartyMon1Moves + NUM_MOVES) + add hl, bc + ld de, wBattleMonPP + ld bc, NUM_MOVES + call CopyBytes + jp .learned + +.cancel + ld hl, StopLearningMoveText + call PrintText + call YesNoBox + jp c, .loop + + ld hl, DidNotLearnMoveText + call PrintText + ld b, 0 + ret + +.learned + ld hl, LearnedMoveText + call PrintText + ld b, 1 + ret + +ForgetMove: + push hl + ld hl, AskForgetMoveText + call PrintText + call YesNoBox + pop hl + ret c + ld bc, -NUM_MOVES + add hl, bc + push hl + ld de, wListMoves_MoveIndicesBuffer + ld bc, NUM_MOVES + call CopyBytes + pop hl +.loop + push hl + ld hl, MoveAskForgetText + call PrintText + hlcoord 5, 2 + ld b, NUM_MOVES * 2 + ld c, MOVE_NAME_LENGTH + call Textbox + hlcoord 5 + 2, 2 + 2 + ld a, SCREEN_WIDTH * 2 + ld [wBuffer1], a + predef ListMoves + ; w2DMenuData + ld a, $4 + ld [w2DMenuCursorInitY], a + ld a, $6 + ld [w2DMenuCursorInitX], a + ld a, [wNumMoves] + inc a + ld [w2DMenuNumRows], a + ld a, $1 + ld [w2DMenuNumCols], a + ld [wMenuCursorY], a + ld [wMenuCursorX], a + ld a, $3 + ld [wMenuJoypadFilter], a + ld a, $20 + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + ld a, $20 + ld [w2DMenuCursorOffsets], a + call StaticMenuJoypad + push af + call SafeLoadTempTilemapToTilemap + pop af + pop hl + bit 1, a + jr nz, .cancel + push hl + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + push af + push bc + call IsHMMove + pop bc + pop de + ld a, d + jr c, .hmmove + pop hl + add hl, bc + and a + ret + +.hmmove + ld hl, MoveCantForgetHMText + call PrintText + pop hl + jr .loop + +.cancel + scf + ret + +LearnedMoveText: + text_far _LearnedMoveText + text_end + +MoveAskForgetText: + text_far _MoveAskForgetText + text_end + +StopLearningMoveText: + text_far _StopLearningMoveText + text_end + +DidNotLearnMoveText: + text_far _DidNotLearnMoveText + text_end + +AskForgetMoveText: + text_far _AskForgetMoveText + text_end + +Text_1_2_and_Poof: + text_far Text_MoveForgetCount ; 1, 2 and… + text_asm + push de + ld de, SFX_SWITCH_POKEMON + call PlaySFX + pop de + ld hl, .MoveForgotText + ret + +.MoveForgotText: + text_far _MoveForgotText + text_end + +MoveCantForgetHMText: + text_far _MoveCantForgetHMText + text_end diff --git a/engine/pokemon/mail_2.asm b/engine/pokemon/mail_2.asm new file mode 100644 index 00000000..f7cfe5c7 --- /dev/null +++ b/engine/pokemon/mail_2.asm @@ -0,0 +1,901 @@ +ReadPartyMonMail: + ld a, [wCurPartyMon] + ld hl, sPartyMail + ld bc, MAIL_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l +ReadAnyMail: + push de + call ClearBGPalettes + call ClearSprites + call ClearTilemap + call DisableLCD + call LoadFontsExtra + pop de + call .LoadGFX + call EnableLCD + call WaitBGMap + ld a, [wBuffer3] + ld e, a + farcall LoadMailPalettes + call SetPalettes + xor a + ldh [hJoyPressed], a + call .loop + call ClearBGPalettes + call DisableLCD + call LoadStandardFont + jp EnableLCD + +.loop + call GetJoypad + ldh 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 PrintMailAndExit ; printer + pop af + ld [wJumptableIndex], a + jr .loop + +.LoadGFX: + ld h, d + ld l, e + push hl + ld a, BANK(sPartyMail) + call OpenSRAM + ld de, sPartyMon1MailAuthorID - sPartyMon1Mail + add hl, de + ld a, [hli] + ld [wBuffer1], a + ld a, [hli] + ld [wBuffer2], a + ld a, [hli] + ld [wCurPartySpecies], 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 [wBuffer3], a + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .done + pop bc + push de + jp hl +.done + ret + +MailGFXPointers: + 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 + +LoadSurfMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, SurfMailBorderGFX + ld c, 8 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailLaprasGFX + ld c, 6 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld de, SurfMailWaveGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + jr FinishLoadingSurfLiteBlueMailGFX + +LoadLiteBlueMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, LiteBlueMailBorderGFX + ld c, 8 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailDratiniGFX + ld c, 6 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld de, PortraitMailUnderlineGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + +FinishLoadingSurfLiteBlueMailGFX: + ld de, SurfLiteBlueMailSmallShapesGFX + ld c, 2 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld c, 2 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, SurfLiteBlueMailLargeShapesGFX + ld c, 8 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld c, 8 * LEN_1BPP_TILE + 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 + +LoadEonMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, EonMailBorder1GFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, EonMailBorder2GFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, EonMailBorder2GFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, EonMailBorder1GFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, SurfMailBorderGFX + 6 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailEeveeGFX + ld c, 6 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld hl, vTiles2 tile $3d + ld de, MailLargeCircleGFX + ld c, 4 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, EonMailBorder2GFX + ld c, 1 * LEN_1BPP_TILE + 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 + +LoadLovelyMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, LovelyMailBorderGFX + ld c, 5 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailPoliwagGFX + ld c, 6 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld de, LovelyMailUnderlineGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, LovelyMailLargeHeartGFX + ld c, 4 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, LovelyMailSmallHeartGFX + ld c, 1 * LEN_1BPP_TILE + 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 + +LovelyEonMail_PlaceIcons: + 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 + +LoadMorphMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld bc, 5 * LEN_1BPP_TILE + call MailGFX_GenerateMonochromeTilesColor2 + ld de, MorphMailBorderCornerGFX + 3 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MorphMailBorderCornerGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MorphMailBorderGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, EonMailBorder1GFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, MorphMailDividerGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailDittoGFX + ld c, 6 * LEN_1BPP_TILE + 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 + +LoadBlueSkyMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, EonMailBorder1GFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld a, $ff + ld bc, 1 tiles + call ByteFill + ld de, BlueSkyMailGrassGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld de, MailDragoniteGFX + ld c, 23 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld de, MailCloudGFX + ld c, 6 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, FlowerMailBorderGFX + 6 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, MailCloudGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, MailCloudGFX + 2 * LEN_1BPP_TILE + ld c, 2 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, MailCloudGFX + 5 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + 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 + +Mail_Place6TileRow: + ld b, $6 +.loop + ld [hli], a + inc a + dec b + jr nz, .loop + ret + +LoadFlowerMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, FlowerMailBorderGFX + ld c, 8 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, MailOddishGFX + ld c, 4 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + ld de, FlowerMailBorderGFX + 6 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, FlowerMailFlowerGFX + ld c, 4 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld c, 4 * LEN_1BPP_TILE + 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 + +LoadPortraitMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, PortraitMailBorderGFX + ld c, 5 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, PortraitMailUnderlineGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld hl, vTiles2 tile $3d + ld de, PortraitMailLargePokeballGFX + ld c, 4 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, PortraitMailSmallPokeballGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + + call DrawMailBorder2 + hlcoord 8, 15 + ld a, $36 + ld b, $a + call Mail_DrawRowLoop + call LovelyEonMail_PlaceIcons + ld a, $1 + ld [wUnownLetter], a + hlcoord 1, 10 + call PrepMonFrontpic + pop hl + jp MailGFX_PlaceMessage + +LoadMusicMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld de, MusicMailBorderGFX + ld c, 4 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MorphMailBorderGFX + ld c, 2 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailNatuGFX + ld c, 6 * LEN_1BPP_TILE + call LoadMailGFX_Color3 + xor a + ld bc, 1 tiles + call ByteFill + ld de, MusicMailLargeNoteGFX + ld c, 3 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, MusicMailSmallNoteGFX + ld c, 1 * LEN_1BPP_TILE + 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 + +LoadMirageMailGFX: + push bc + ld hl, vTiles2 tile $31 + ld bc, 5 * LEN_1BPP_TILE + call MailGFX_GenerateMonochromeTilesColor2 + ld de, BlueSkyMailGrassGFX + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, MailMewGFX + ld c, 18 * LEN_1BPP_TILE + call LoadMailGFX_Color2 + ld de, LiteBlueMailBorderGFX + 1 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + call LoadMailGFX_Color1 + ld de, LiteBlueMailBorderGFX + 6 * LEN_1BPP_TILE + ld c, 1 * LEN_1BPP_TILE + 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 + +MailGFX_GenerateMonochromeTilesColor2: +.loop + xor a + ld [hli], a + ld a, $ff + ld [hli], a + dec bc + ld a, b + or c + jr nz, .loop + ret + +MailGFX_PlaceMessage: + ld bc, MAIL_STRUCT_LENGTH + ld de, wTempMail + ld a, BANK(sPartyMail) + call OpenSRAM + 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, [wBuffer3] + 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 + +Unreferenced_Functionbb4c5: +.loop + ld a, [hl] + xor $ff + ld [hli], a + dec bc + ld a, b + or c + jr nz, .loop + ret + +DrawMailBorder: + 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 + +DrawMailBorder2: + 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 + +Mail_Place14TileAlternatingRow: + push af + ld b, 14 / 2 + jr Mail_PlaceAlternatingRow + +Mail_Place16TileAlternatingRow: + push af + ld b, 16 / 2 + jr Mail_PlaceAlternatingRow + +Mail_Place18TileAlternatingRow: + push af + ld b, 18 / 2 + +Mail_PlaceAlternatingRow: +.loop + ld [hli], a + inc a + ld [hli], a + dec a + dec b + jr nz, .loop + ld [hl], a + pop af + ret + +Mail_Place14TileAlternatingColumn: + push af + ld b, 14 / 2 + jr Mail_PlaceAlternatingColumn + +Mail_Place16TileAlternatingColumn: + push af + ld b, 16 / 2 + +Mail_PlaceAlternatingColumn: +.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 + +Mail_Draw7TileRow: + ld b, $7 + jr Mail_DrawRowLoop + +Mail_Draw13TileRow: + ld b, $d + jr Mail_DrawRowLoop + +Mail_Draw16TileRow: + ld b, $10 + jr Mail_DrawRowLoop + +Mail_DrawTopBottomBorder: + ld b, SCREEN_WIDTH - 2 + jr Mail_DrawRowLoop + +Mail_DrawFullWidthBorder: + ld b, SCREEN_WIDTH + +Mail_DrawRowLoop: +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +Mail_DrawLeftRightBorder: + ld b, SCREEN_HEIGHT - 2 + ld de, SCREEN_WIDTH +.loop + ld [hl], a + add hl, de + dec b + jr nz, .loop + ret + +Mail_Draw2x2Graphic: + 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 + +Mail_Draw3x2Graphic: + 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 + +LoadMailGFX_Color1: +.loop + ld a, [de] + inc de + ld [hli], a + xor a + ld [hli], a + dec c + jr nz, .loop + ret + +LoadMailGFX_Color2: +.loop + xor a + ld [hli], a + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + ret + +LoadMailGFX_Color3: +.loop + ld a, [de] + inc de + ld [hli], a + ld [hli], a + dec c + jr nz, .loop + ret + +INCLUDE "gfx/mail.asm" + +ItemIsMail: + ld a, d + ld hl, MailItems + ld de, 1 + jp IsInArray + +INCLUDE "data/items/mail_items.asm" diff --git a/engine/pokemon/mon_menu.asm b/engine/pokemon/mon_menu.asm new file mode 100644 index 00000000..aa211ae1 --- /dev/null +++ b/engine/pokemon/mon_menu.asm @@ -0,0 +1,1293 @@ +HasNoItems: + ld a, [wNumItems] + and a + ret nz + ld a, [wNumKeyItems] + and a + ret nz + ld a, [wNumBalls] + and a + ret nz + ld hl, wTMsHMs + ld b, NUM_TMS + NUM_HMS +.loop + ld a, [hli] + and a + jr nz, .done + dec b + jr nz, .loop + scf + ret +.done + and a + ret + +TossItemFromPC: + push de + call PartyMonItemName + farcall _CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .key_item + ld hl, .ItemsTossOutHowManyText + call MenuTextbox + farcall SelectQuantityToToss + push af + call CloseWindow + call ExitMenu + pop af + jr c, .quit + ld hl, .ItemsThrowAwayText + call MenuTextbox + call YesNoBox + push af + call ExitMenu + pop af + jr c, .quit + pop hl + ld a, [wCurItemQuantity] + call TossItem + call PartyMonItemName + ld hl, .ItemsDiscardedText + call MenuTextbox + call ExitMenu + and a + ret + +.key_item + call .CantToss +.quit + pop hl + scf + ret + +.ItemsTossOutHowManyText: + text_far _ItemsTossOutHowManyText + text_end + +.ItemsThrowAwayText: + text_far _ItemsThrowAwayText + text_end + +.ItemsDiscardedText: + text_far _ItemsDiscardedText + text_end + +.CantToss: + ld hl, .ItemsTooImportantText + call MenuTextboxBackup + ret + +.ItemsTooImportantText: + text_far _ItemsTooImportantText + text_end + +CantUseItem: + ld hl, ItemsOakWarningText + call MenuTextboxWaitButton + ret + +ItemsOakWarningText: + text_far _ItemsOakWarningText + text_end + +PartyMonItemName: + ld a, [wCurItem] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call CopyName1 + ret + +CancelPokemonAction: + farcall InitPartyMenuWithCancel + farcall UnfreezeMonIcons + ld a, 1 + ret + +PokemonActionSubmenu: + hlcoord 1, 15 + lb bc, 2, 18 + call ClearBox + farcall MonSubmenu + call GetCurNick + ld a, [wMenuSelection] + ld hl, .Actions + ld de, 3 + call IsInArray + jr nc, .nothing + + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.nothing + ld a, 0 + ret + +.Actions: + dbw MONMENUITEM_CUT, MonMenu_Cut + dbw MONMENUITEM_FLY, MonMenu_Fly + dbw MONMENUITEM_SURF, MonMenu_Surf + dbw MONMENUITEM_STRENGTH, MonMenu_Strength + dbw MONMENUITEM_FLASH, MonMenu_Flash + dbw MONMENUITEM_WHIRLPOOL, MonMenu_Whirlpool + dbw MONMENUITEM_DIG, MonMenu_Dig + dbw MONMENUITEM_TELEPORT, MonMenu_Teleport + dbw MONMENUITEM_SOFTBOILED, MonMenu_Softboiled_MilkDrink + dbw MONMENUITEM_MILKDRINK, MonMenu_Softboiled_MilkDrink + dbw MONMENUITEM_HEADBUTT, MonMenu_Headbutt + dbw MONMENUITEM_WATERFALL, MonMenu_Waterfall + dbw MONMENUITEM_ROCKSMASH, MonMenu_RockSmash + dbw MONMENUITEM_SWEETSCENT, MonMenu_SweetScent + dbw MONMENUITEM_STATS, OpenPartyStats + dbw MONMENUITEM_SWITCH, SwitchPartyMons + dbw MONMENUITEM_ITEM, GiveTakePartyMonItem + dbw MONMENUITEM_CANCEL, CancelPokemonAction + dbw MONMENUITEM_MOVE, ManagePokemonMoves + dbw MONMENUITEM_MAIL, MonMailAction + +SwitchPartyMons: +; Don't try if there's nothing to switch! + ld a, [wPartyCount] + cp 2 + jr c, .DontSwitch + + ld a, [wCurPartyMon] + inc a + ld [wSwitchMon], a + + farcall HoldSwitchmonIcon + farcall InitPartyMenuNoCancel + + ld a, PARTYMENUACTION_MOVE + ld [wPartyMenuActionText], a + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + + hlcoord 0, 1 + ld bc, SCREEN_WIDTH * 2 + ld a, [wSwitchMon] + dec a + call AddNTimes + ld [hl], "▷" + call WaitBGMap + call SetPalettes + call DelayFrame + + farcall PartyMenuSelect + bit 1, b + jr c, .DontSwitch + + farcall _SwitchPartyMons + + xor a + ld [wPartyMenuActionText], a + + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + + ld a, 1 + ret + +.DontSwitch: + xor a + ld [wPartyMenuActionText], a + call CancelPokemonAction + ret + +GiveTakePartyMonItem: +; Eggs can't hold items! + ld a, [wCurPartySpecies] + cp EGG + jr z, .cancel + + ld hl, GiveTakeItemMenuData + call LoadMenuHeader + call VerticalMenu + call ExitMenu + jr c, .cancel + + call GetCurNick + ld hl, wStringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, MON_NAME_LENGTH + call CopyBytes + ld a, [wMenuCursorY] + cp 1 + jr nz, .take + + call LoadStandardMenuHeader + call ClearPalettes + call .GiveItem + call ClearPalettes + call LoadFontsBattleExtra + call ExitMenu + ld a, 0 + ret + +.take + call TakePartyItem + ld a, 3 + ret + +.cancel + ld a, 3 + ret + +.GiveItem: + farcall DepositSellInitPackBuffers + +.loop + farcall DepositSellPack + + ld a, [wPackUsedItem] + and a + jr z, .quit + + ld a, [wCurPocket] + cp KEY_ITEM_POCKET + jr z, .next + + call CheckTossableItem + ld a, [wItemAttributeParamBuffer] + and a + jr nz, .next + + call TryGiveItemToPartymon + jr .quit + +.next + ld hl, ItemCantHeldText + call MenuTextboxBackup + jr .loop + +.quit + ret + +TryGiveItemToPartymon: + call SpeechTextbox + call PartyMonItemName + call GetPartyItemLocation + ld a, [hl] + and a + jr z, .give_item_to_mon + + push hl + ld d, a + farcall ItemIsMail + pop hl + jr c, .please_remove_mail + ld a, [hl] + jr .already_holding_item + +.give_item_to_mon + call GiveItemToPokemon + ld hl, PokemonHoldItemText + call MenuTextboxBackup + call GivePartyItem + ret + +.please_remove_mail + ld hl, PokemonRemoveMailText + call MenuTextboxBackup + ret + +.already_holding_item + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, PokemonAskSwapItemText + call StartMenuYesNo + jr c, .abort + + call GiveItemToPokemon + ld a, [wNamedObjectIndexBuffer] + push af + ld a, [wCurItem] + ld [wNamedObjectIndexBuffer], a + pop af + ld [wCurItem], a + call ReceiveItemFromPokemon + jr nc, .bag_full + + ld hl, PokemonSwapItemText + call MenuTextboxBackup + ld a, [wNamedObjectIndexBuffer] + ld [wCurItem], a + call GivePartyItem + ret + +.bag_full + ld a, [wNamedObjectIndexBuffer] + ld [wCurItem], a + call ReceiveItemFromPokemon + ld hl, ItemStorageFullText + call MenuTextboxBackup + +.abort + ret + +GivePartyItem: + call GetPartyItemLocation + ld a, [wCurItem] + ld [hl], a + ld d, a + farcall ItemIsMail + jr nc, .done + call ComposeMailMessage + +.done + ret + +TakePartyItem: + call SpeechTextbox + call GetPartyItemLocation + ld a, [hl] + and a + jr z, .asm_13053 + + ld [wCurItem], a + call ReceiveItemFromPokemon + jr nc, .asm_1305b + + farcall ItemIsMail + call GetPartyItemLocation + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + ld [hl], NO_ITEM + call GetItemName + ld hl, PokemonTookItemText + call MenuTextboxBackup + jr .asm_13061 + +.asm_13053 + ld hl, PokemonNotHoldingText + call MenuTextboxBackup + jr .asm_13061 + +.asm_1305b + ld hl, ItemStorageFullText + call MenuTextboxBackup + +.asm_13061 + ret + +GiveTakeItemMenuData: + db MENU_SPRITE_ANIMS | MENU_BACKUP_TILES ; flags + menu_coords 12, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .Items + db 1 ; default option + +.Items: + db STATICMENU_CURSOR ; flags + db 2 ; # items + db "GIVE@" + db "TAKE@" + +PokemonSwapItemText: + text_far _PokemonSwapItemText + text_end + +PokemonHoldItemText: + text_far _PokemonHoldItemText + text_end + +PokemonRemoveMailText: + text_far _PokemonRemoveMailText + text_end + +PokemonNotHoldingText: + text_far _PokemonNotHoldingText + text_end + +ItemStorageFullText: + text_far _ItemStorageFullText + text_end + +PokemonTookItemText: + text_far _PokemonTookItemText + text_end + +PokemonAskSwapItemText: + text_far _PokemonAskSwapItemText + text_end + +ItemCantHeldText: + text_far _ItemCantHeldText + text_end + +GetPartyItemLocation: + push af + ld a, MON_ITEM + call GetPartyParamLocation + pop af + ret + +ReceiveItemFromPokemon: + ld a, 1 + ld [wItemQuantityChangeBuffer], a + ld hl, wNumItems + jp ReceiveItem + +GiveItemToPokemon: + ld a, 1 + ld [wItemQuantityChangeBuffer], a + ld hl, wNumItems + jp TossItem + +StartMenuYesNo: + call MenuTextbox + call YesNoBox + jp ExitMenu + +ComposeMailMessage: + ld de, wTempMailMessage + farcall _ComposeMailMessage + ld hl, wPlayerName + ld de, wTempMailAuthor + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld hl, wPlayerID + ld bc, 2 + call CopyBytes + ld a, [wCurPartySpecies] + ld [de], a + inc de + ld a, [wCurItem] + ld [de], a + ld a, [wCurPartyMon] + ld hl, sPartyMail + ld bc, MAIL_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, wTempMail + ld bc, MAIL_STRUCT_LENGTH + ld a, BANK(sPartyMail) + call OpenSRAM + call CopyBytes + call CloseSRAM + ret + +MonMailAction: +; If in the time capsule or trade center, +; selecting the mail only allows you to +; read the mail. + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + jr z, .read + cp LINK_TRADECENTER + jr z, .read + +; Show the READ/TAKE/QUIT menu. + ld hl, .MenuHeader + call LoadMenuHeader + call VerticalMenu + call ExitMenu + +; Interpret the menu. + jp c, .done + ld a, [wMenuCursorY] + cp $1 + jr z, .read + cp $2 + jr z, .take + jp .done + +.read + farcall ReadPartyMonMail + ld a, $0 + ret + +.take + ld hl, .MailAskSendToPCText + call StartMenuYesNo + jr c, .RemoveMailToBag + ld a, [wCurPartyMon] + ld b, a + farcall SendMailToPC + jr c, .MailboxFull + ld hl, .MailSentToPCText + call MenuTextboxBackup + jr .done + +.MailboxFull: + ld hl, .MailboxFullText + call MenuTextboxBackup + jr .done + +.RemoveMailToBag: + ld hl, .MailLoseMessageText + call StartMenuYesNo + jr c, .done + call GetPartyItemLocation + ld a, [hl] + ld [wCurItem], a + call ReceiveItemFromPokemon + jr nc, .BagIsFull + call GetPartyItemLocation + ld [hl], $0 + call GetCurNick + ld hl, .MailDetachedText + call MenuTextboxBackup + jr .done + +.BagIsFull: + ld hl, .MailNoSpaceText + call MenuTextboxBackup + jr .done + +.done + ld a, $3 + ret + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 9, 10, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw .MenuData + db 1 ; default option + +.MenuData: + db STATICMENU_CURSOR ; flags + db 3 ; items + db "READ@" + db "TAKE@" + db "QUIT@" + +.MailLoseMessageText: + text_far _MailLoseMessageText + text_end + +.MailDetachedText: + text_far _MailDetachedText + text_end + +.MailNoSpaceText: + text_far _MailNoSpaceText + text_end + +.MailAskSendToPCText: + text_far _MailAskSendToPCText + text_end + +.MailboxFullText: + text_far _MailboxFullText + text_end + +.MailSentToPCText: + text_far _MailSentToPCText + text_end + +OpenPartyStats: + call LoadStandardMenuHeader + call ClearSprites +; PartyMon + xor a + ld [wMonType], a + call LowVolume + predef StatsScreenInit + call MaxVolume + call Call_ExitMenu + ld a, 0 + ret + +MonMenu_Cut: + farcall CutFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Fly: + farcall FlyFunction + ld a, [wFieldMoveSucceeded] + cp $2 + jr z, .Fail + cp $0 + jr z, .Error + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +.Error: + ld a, $0 + ret + +.Unreferenced: + ld a, $1 + ret + +MonMenu_Flash: + farcall FlashFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Strength: + farcall StrengthFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Whirlpool: + farcall WhirlpoolFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Waterfall: + farcall WaterfallFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Teleport: + farcall TeleportFunction + ld a, [wFieldMoveSucceeded] + and a + jr z, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Surf: + farcall SurfFunction + ld a, [wFieldMoveSucceeded] + and a + jr z, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Dig: + farcall DigFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_Softboiled_MilkDrink: + call .CheckMonHasEnoughHP + jr nc, .NotEnoughHP + farcall Softboiled_MilkDrinkFunction + jr .finish + +.NotEnoughHP: + ld hl, .PokemonNotEnoughHPText + call PrintText + +.finish + xor a + ld [wPartyMenuActionText], a + ld a, $3 + ret + +.PokemonNotEnoughHPText: + text_far _PokemonNotEnoughHPText + text_end + +.CheckMonHasEnoughHP: +; Need to have at least (MaxHP / 5) HP left. + ld a, MON_MAXHP + call GetPartyParamLocation + ld a, [hli] + ldh [hDividend + 0], a + ld a, [hl] + ldh [hDividend + 1], a + ld a, 5 + ldh [hDivisor], a + ld b, 2 + call Divide + ld a, MON_HP + 1 + call GetPartyParamLocation + ldh a, [hQuotient + 3] + sub [hl] + dec hl + ldh a, [hQuotient + 2] + sbc [hl] + ret + +MonMenu_Headbutt: + farcall HeadbuttFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_RockSmash: + farcall RockSmashFunction + ld a, [wFieldMoveSucceeded] + cp $1 + jr nz, .Fail + ld b, $4 + ld a, $2 + ret + +.Fail: + ld a, $3 + ret + +MonMenu_SweetScent: + farcall SweetScentFromMenu + ld b, $4 + ld a, $2 + ret + +ChooseMoveToDelete: + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call LoadFontsBattleExtra + call .ChooseMoveToDelete + pop bc + ld a, b + ld [wOptions], a + push af + call ClearBGPalettes + pop af + ret + +.ChooseMoveToDelete + call SetUpMoveScreenBG + ld de, DeleteMoveScreenAttrs + call SetMenuAttributes + call SetUpMoveList + ld hl, w2DMenuFlags1 + set 6, [hl] + jr .enter_loop + +.loop + call ScrollingMenuJoypad + bit B_BUTTON_F, a + jp nz, .b_button + bit A_BUTTON_F, a + jp nz, .a_button + +.enter_loop + call PrepareToPlaceMoveData + call PlaceMoveData + jp .loop + +.a_button + and a + jr .finish + +.b_button + scf + +.finish + push af + xor a + ld [wSwitchMon], a + ld hl, w2DMenuFlags1 + res 6, [hl] + call ClearSprites + call ClearTilemap + pop af + ret + +DeleteMoveScreenAttrs: + db 3, 1 + db 3, 1 + db $40, $00 + dn 2, 0 + db D_UP | D_DOWN | A_BUTTON | B_BUTTON + +ManagePokemonMoves: + ld a, [wCurPartySpecies] + cp EGG + jr z, .egg + ld hl, wOptions + ld a, [hl] + push af + set NO_TEXT_SCROLL, [hl] + call MoveScreenLoop + pop af + ld [wOptions], a + call ClearBGPalettes + +.egg + ld a, $0 + ret + +MoveScreenLoop: + ld a, [wCurPartyMon] + inc a + ld [wPartyMenuCursor], a + call SetUpMoveScreenBG + call PlaceMoveScreenArrows + ld de, MoveScreenAttributes + call SetMenuAttributes +.loop + call SetUpMoveList + ld hl, w2DMenuFlags1 + set 6, [hl] + jr .skip_joy + +.joy_loop + call ScrollingMenuJoypad + bit 1, a + jp nz, .b_button + bit 0, a + jp nz, .a_button + bit 4, a + jp nz, .d_right + bit 5, a + jp nz, .d_left + +.skip_joy + call PrepareToPlaceMoveData + ld a, [wMoveSwapBuffer] + and a + jr nz, .moving_move + call PlaceMoveData + jp .joy_loop + +.moving_move + ld a, " " + hlcoord 1, 11 + ld bc, 5 + call ByteFill + hlcoord 1, 12 + lb bc, 5, SCREEN_WIDTH - 2 + call ClearBox + hlcoord 1, 12 + ld de, String_MoveWhere + call PlaceString + jp .joy_loop +.b_button + call PlayClickSFX + call WaitSFX + ld a, [wMoveSwapBuffer] + and a + jp z, .exit + + ld a, [wMoveSwapBuffer] + ld [wMenuCursorY], a + xor a + ld [wMoveSwapBuffer], a + hlcoord 1, 2 + lb bc, 8, SCREEN_WIDTH - 2 + call ClearBox + jp .loop + +.d_right + ld a, [wMoveSwapBuffer] + and a + jp nz, .joy_loop + + ld a, [wCurPartyMon] + ld b, a + push bc + call .cycle_right + pop bc + ld a, [wCurPartyMon] + cp b + jp z, .joy_loop + jp MoveScreenLoop + +.d_left + ld a, [wMoveSwapBuffer] + and a + jp nz, .joy_loop + ld a, [wCurPartyMon] + ld b, a + push bc + call .cycle_left + pop bc + ld a, [wCurPartyMon] + cp b + jp z, .joy_loop + jp MoveScreenLoop + +.cycle_right + ld a, [wCurPartyMon] + inc a + ld [wCurPartyMon], a + ld c, a + ld b, 0 + ld hl, wPartySpecies + add hl, bc + ld a, [hl] + cp -1 + jr z, .cycle_left + cp EGG + ret nz + jr .cycle_right + +.cycle_left + ld a, [wCurPartyMon] + and a + ret z +.cycle_left_loop + ld a, [wCurPartyMon] + dec a + ld [wCurPartyMon], a + ld c, a + ld b, 0 + ld hl, wPartySpecies + add hl, bc + ld a, [hl] + cp EGG + ret nz + ld a, [wCurPartyMon] + and a + jr z, .cycle_right + jr .cycle_left_loop + +.a_button + call PlayClickSFX + call WaitSFX + ld a, [wMoveSwapBuffer] + and a + jr nz, .place_move + ld a, [wMenuCursorY] + ld [wMoveSwapBuffer], a + call PlaceHollowCursor + jp .moving_move + +.place_move + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [wCurPartyMon] + call AddNTimes + push hl + call .copy_move + pop hl + ld bc, $15 + add hl, bc + call .copy_move + ld a, [wBattleMode] + jr z, .swap_moves + ld hl, wBattleMonMoves + ld bc, $20 + ld a, [wCurPartyMon] + call AddNTimes + push hl + call .copy_move + pop hl + ld bc, 6 + add hl, bc + call .copy_move + +.swap_moves + ld de, SFX_SWITCH_POKEMON + call PlaySFX + call WaitSFX + ld de, SFX_SWITCH_POKEMON + call PlaySFX + call WaitSFX + hlcoord 1, 2 + lb bc, 8, 18 + call ClearBox + hlcoord 10, 10 + lb bc, 1, 9 + call ClearBox + jp .loop + +.copy_move + push hl + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, $0 + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wMoveSwapBuffer] + 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 + +.exit + xor a + ld [wMoveSwapBuffer], a + ld hl, w2DMenuFlags1 + res 6, [hl] + call ClearSprites + jp ClearTilemap + +MoveScreenAttributes: + db 3, 1 + db 3, 1 + db $40, $00 + dn 2, 0 + db D_UP | D_DOWN | D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON + +String_MoveWhere: + db "Where?@" + +SetUpMoveScreenBG: + call ClearBGPalettes + call ClearTilemap + call ClearSprites + xor a + ldh [hBGMapMode], a + farcall LoadStatsScreenPageTilesGFX + farcall ClearSpriteAnims2 + ld a, [wCurPartyMon] + ld e, a + ld d, $0 + ld hl, wPartySpecies + add hl, de + ld a, [hl] + ld [wTempIconSpecies], a + ld e, MONICON_MOVES + farcall LoadMenuMonIcon + hlcoord 0, 1 + ld b, 9 + ld c, 18 + call Textbox + hlcoord 0, 11 + ld b, 5 + ld c, 18 + call Textbox + hlcoord 2, 0 + lb bc, 2, 3 + call ClearBox + xor a + ld [wMonType], a + ld hl, wPartyMonNicknames + ld a, [wCurPartyMon] + call GetNick + hlcoord 5, 1 + call PlaceString + push bc + farcall CopyMonToTempMon + pop hl + call PrintLevel + ld hl, wPlayerHPPal + call SetHPPal + ld b, SCGB_MOVE_LIST + call GetSGBLayout + hlcoord 16, 0 + lb bc, 1, 3 + jp ClearBox + +SetUpMoveList: + xor a + ldh [hBGMapMode], a + ld [wMoveSwapBuffer], a + ld [wMonType], a + predef CopyMonToTempMon + ld hl, wTempMonMoves + ld de, wListMoves_MoveIndicesBuffer + ld bc, NUM_MOVES + call CopyBytes + ld a, SCREEN_WIDTH * 2 + ld [wBuffer1], a + hlcoord 2, 3 + predef ListMoves + hlcoord 10, 4 + predef ListMovePP + call WaitBGMap + call SetPalettes + ld a, [wNumMoves] + inc a + ld [w2DMenuNumRows], a + hlcoord 0, 11 + ld b, 5 + ld c, 18 + jp Textbox + +PrepareToPlaceMoveData: + ld hl, wPartyMon1Moves + ld bc, PARTYMON_STRUCT_LENGTH + ld a, [wCurPartyMon] + call AddNTimes + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + ld [wCurSpecies], a + hlcoord 1, 12 + lb bc, 5, 18 + jp ClearBox + +PlaceMoveData: + xor a + ldh [hBGMapMode], a + hlcoord 0, 10 + ld de, String_MoveType_Top + call PlaceString + hlcoord 0, 11 + ld de, String_MoveType_Bottom + call PlaceString + hlcoord 11, 12 + ld de, String_MoveAtk + call PlaceString + ld a, [wCurSpecies] + ld b, a + hlcoord 2, 12 + predef PrintMoveType + ld a, [wCurSpecies] + dec a + ld hl, Moves + MOVE_POWER + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + hlcoord 16, 12 + cp 2 + jr c, .no_power + ld [wDeciramBuffer], a + ld de, wDeciramBuffer + lb bc, 1, 3 + call PrintNum + jr .description + +.no_power + ld de, String_MoveNoPower + call PlaceString + +.description + hlcoord 1, 14 + predef PrintMoveDesc + ld a, $1 + ldh [hBGMapMode], a + ret + +String_MoveType_Top: + db "┌─────┐@" +String_MoveType_Bottom: + db "│TYPE/└@" +String_MoveAtk: + db "ATTK/@" +String_MoveNoPower: + db "---@" + +PlaceMoveScreenArrows: + call PlaceMoveScreenLeftArrow + call PlaceMoveScreenRightArrow + ret + +PlaceMoveScreenLeftArrow: + ld a, [wCurPartyMon] + and a + ret z + ld c, a + ld e, a + ld d, 0 + ld hl, wPartyCount + add hl, de +.loop + ld a, [hl] + and a + jr z, .prev + cp EGG + jr z, .prev + cp NUM_POKEMON + 1 + jr c, .legal + +.prev + dec hl + dec c + jr nz, .loop + ret + +.legal + hlcoord 16, 0 + ld [hl], "◀" + ret + +PlaceMoveScreenRightArrow: + ld a, [wCurPartyMon] + inc a + ld c, a + ld a, [wPartyCount] + cp c + ret z + ld e, c + ld d, 0 + ld hl, wPartySpecies + add hl, de +.loop + ld a, [hl] + cp -1 + ret z + and a + jr z, .next + cp EGG + jr z, .next + cp NUM_POKEMON + 1 + jr c, .legal + +.next + inc hl + jr .loop + +.legal + hlcoord 18, 0 + ld [hl], "▶" + ret diff --git a/engine/pokemon/mon_submenu.asm b/engine/pokemon/mon_submenu.asm new file mode 100644 index 00000000..148f1da6 --- /dev/null +++ b/engine/pokemon/mon_submenu.asm @@ -0,0 +1,290 @@ +INCLUDE "data/mon_menu.asm" + +MonSubmenu: + xor a + ldh [hBGMapMode], a + call GetMonSubmenuItems + farcall FreezeMonIcons + ld hl, .MenuHeader + call LoadMenuHeader + call .GetTopCoord + call PopulateMonMenu + + ld a, 1 + ldh [hBGMapMode], a + call MonMenuLoop + ld [wMenuSelection], a + + call ExitMenu + ret + +.MenuHeader: + db MENU_BACKUP_TILES ; flags + menu_coords 6, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw 0 + db 1 ; default option + +.GetTopCoord: +; TopCoord = 1 + BottomCoord - 2 * (NumSubmenuItems + 1) + ld a, [wBuffer1] + inc a + add a + ld b, a + ld a, [wMenuBorderBottomCoord] + sub b + inc a + ld [wMenuBorderTopCoord], a + call MenuBox + ret + +MonMenuLoop: +.loop + ld a, MENU_UNUSED_3 | MENU_BACKUP_TILES_2 ; flags + ld [wMenuDataFlags], a + ld a, [wBuffer1] ; items + ld [wMenuDataItems], a + call InitVerticalMenuCursor + ld hl, w2DMenuFlags1 + set 6, [hl] + call StaticMenuJoypad + ld de, SFX_READ_TEXT_2 + call PlaySFX + ldh a, [hJoyPressed] + bit A_BUTTON_F, a + jr nz, .select + bit B_BUTTON_F, a + jr nz, .cancel + jr .loop + +.cancel + ld a, MONMENUITEM_CANCEL + ret + +.select + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, 0 + ld hl, wBuffer2 + add hl, bc + ld a, [hl] + ret + +PopulateMonMenu: + call MenuBoxCoord2Tile + ld bc, 2 * SCREEN_WIDTH + 2 + add hl, bc + ld de, wBuffer2 +.loop + ld a, [de] + inc de + cp -1 + ret z + push de + push hl + call GetMonMenuString + pop hl + call PlaceString + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop de + jr .loop + +GetMonMenuString: + ld hl, MonMenuOptions + 1 + ld de, 3 + call IsInArray + dec hl + ld a, [hli] + cp MONMENU_MENUOPTION + jr z, .NotMove + inc hl + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetMoveName + ret + +.NotMove: + inc hl + ld a, [hl] + dec a + ld hl, MonMenuOptionStrings + call GetNthString + ld d, h + ld e, l + ret + +GetMonSubmenuItems: + call ResetMonSubmenu + ld a, [wCurPartySpecies] + cp EGG + jr z, .egg + ld a, [wLinkMode] + and a + jr nz, .skip_moves + ld a, MON_MOVES + call GetPartyParamLocation + ld d, h + ld e, l + ld c, NUM_MOVES +.loop + push bc + push de + ld a, [de] + and a + jr z, .next + push hl + call IsFieldMove + pop hl + jr nc, .next + call AddMonMenuItem + +.next + pop de + inc de + pop bc + dec c + jr nz, .loop + +.skip_moves + ld a, MONMENUITEM_STATS + call AddMonMenuItem + ld a, MONMENUITEM_SWITCH + call AddMonMenuItem + ld a, MONMENUITEM_MOVE + call AddMonMenuItem + ld a, [wLinkMode] + and a + jr nz, .skip2 + push hl + ld a, MON_ITEM + call GetPartyParamLocation + ld d, [hl] + farcall ItemIsMail + pop hl + ld a, MONMENUITEM_MAIL + jr c, .ok + ld a, MONMENUITEM_ITEM + +.ok + call AddMonMenuItem + +.skip2 + ld a, [wBuffer1] + cp NUM_MONMENU_ITEMS + jr z, .ok2 + ld a, MONMENUITEM_CANCEL + call AddMonMenuItem + +.ok2 + call TerminateMonSubmenu + ret + +.egg + ld a, MONMENUITEM_STATS + call AddMonMenuItem + ld a, MONMENUITEM_SWITCH + call AddMonMenuItem + ld a, MONMENUITEM_CANCEL + call AddMonMenuItem + call TerminateMonSubmenu + ret + +IsFieldMove: + ld b, a + ld hl, MonMenuOptions +.next + ld a, [hli] + cp -1 + jr z, .nope + cp MONMENU_MENUOPTION + jr z, .nope + ld d, [hl] + inc hl + ld a, [hli] + cp b + jr nz, .next + ld a, d + scf + +.nope + ret + +ResetMonSubmenu: + xor a + ld [wBuffer1], a + ld hl, wBuffer2 + ld bc, NUM_MONMENU_ITEMS + 1 + call ByteFill + ret + +TerminateMonSubmenu: + ld a, [wBuffer1] + ld e, a + ld d, 0 + ld hl, wBuffer2 + add hl, de + ld [hl], -1 + ret + +AddMonMenuItem: + push hl + push de + push af + ld a, [wBuffer1] + ld e, a + inc a + ld [wBuffer1], a + ld d, 0 + ld hl, wBuffer2 + add hl, de + pop af + ld [hl], a + pop de + pop hl + ret + +BattleMonMenu: + ld hl, MenuHeader_0x24e44 + call CopyMenuHeader + xor a + ldh [hBGMapMode], a + call MenuBox + call UpdateSprites + call PlaceVerticalMenuItems + call WaitBGMap + call CopyMenuData + ld a, [wMenuDataFlags] + bit 7, a + jr z, .set_carry + call InitVerticalMenuCursor + ld hl, w2DMenuFlags1 + set 6, [hl] + call StaticMenuJoypad + ld de, SFX_READ_TEXT_2 + call PlaySFX + ldh a, [hJoyPressed] + bit B_BUTTON_F, a + jr z, .clear_carry + ret z + +.set_carry + scf + ret + +.clear_carry + and a + ret + +MenuHeader_0x24e44: + db 0 ; flags + menu_coords 11, 11, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1 + dw MenuData_0x24e4c + db 1 ; default option + +MenuData_0x24e4c: + db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags + db 3 ; items + db "SWITCH@" + db "STATS@" + db "CANCEL@" diff --git a/engine/move_mon.asm b/engine/pokemon/move_mon.asm index 7410375f..b1988f68 100755 --- a/engine/move_mon.asm +++ b/engine/pokemon/move_mon.asm @@ -1,34 +1,47 @@ -TryAddMonToParty:: ; d892 (3:5892) +RANDY_OT_ID EQU 01001 + +TryAddMonToParty: +; Check if to copy wild mon or generate a new one + ; Whose is it? ld de, wPartyCount ld a, [wMonType] and $f - jr z, .asm_d89f + jr z, .getpartylocation ; PARTYMON ld de, wOTPartyCount -.asm_d89f + +.getpartylocation + ; Do we have room for it? ld a, [de] inc a - cp $7 + cp PARTY_LENGTH + 1 ret nc + ; Increase the party count ld [de], a - ld a, [de] - ldh [hMoveMon], a + ld a, [de] ; Why are we doing this? + ldh [hMoveMon], a ; HRAM backup add e ld e, a - jr nc, .asm_d8ad + jr nc, .loadspecies inc d -.asm_d8ad + +.loadspecies + ; Load the species of the Pokemon into the party list. + ; The terminator is usually here, but it'll be back. ld a, [wCurPartySpecies] ld [de], a + ; Load the terminator into the next slot. inc de - ld a, $ff + ld a, -1 ld [de], a - ld hl, wPartyMon1OT + ; Now let's load the OT name. + ld hl, wPartyMonOT ld a, [wMonType] and $f - jr z, .asm_d8c2 + jr z, .loadOTname ld hl, wOTPartyMonOT -.asm_d8c2 - ldh a, [hMoveMon] + +.loadOTname + ldh a, [hMoveMon] ; Restore index from backup dec a call SkipNames ld d, h @@ -36,11 +49,12 @@ TryAddMonToParty:: ; d892 (3:5892) ld hl, wPlayerName ld bc, NAME_LENGTH call CopyBytes + ; Only initialize the nickname for party mon ld a, [wMonType] and a - jr nz, .asm_d8f6 + jr nz, .skipnickname ld a, [wCurPartySpecies] - ld [wd151], a + ld [wNamedObjectIndexBuffer], a call GetPokemonName ld hl, wPartyMonNicknames ldh a, [hMoveMon] @@ -49,74 +63,83 @@ TryAddMonToParty:: ; d892 (3:5892) ld d, h ld e, l ld hl, wStringBuffer1 - ld bc, NAME_LENGTH + ld bc, MON_NAME_LENGTH call CopyBytes -.asm_d8f6 + +.skipnickname ld hl, wPartyMon1Species ld a, [wMonType] and $f - jr z, .asm_d903 - ld hl, wOTPartyMon1 -.asm_d903 + jr z, .initializeStats + ld hl, wOTPartyMon1Species + +.initializeStats ldh a, [hMoveMon] dec a ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes GeneratePartyMonStats: +; wBattleMode specifies whether it's a wild mon or not. +; wMonType specifies whether it's an opposing mon or not. +; wCurPartySpecies/wCurPartyLevel specify the species and level. +; hl points to the wPartyMon struct to fill. + ld e, l ld d, h push hl + + ; Initialize the species ld a, [wCurPartySpecies] ld [wCurSpecies], a call GetBaseData - ld a, [wd120] + ld a, [wBaseDexNo] ld [de], a inc de + + ; Copy the item if it's a wild mon ld a, [wBattleMode] and a ld a, $0 - jr z, .asm_d928 + jr z, .skipitem ld a, [wEnemyMonItem] -.asm_d928 +.skipitem ld [de], a inc de + + ; Copy the moves if it's a wild mon push de ld h, d ld l, e ld a, [wBattleMode] and a - jr z, .asm_d949 + jr z, .randomlygeneratemoves ld a, [wMonType] and a - jr nz, .asm_d949 + jr nz, .randomlygeneratemoves ld de, wEnemyMonMoves +rept NUM_MOVES - 1 ld a, [de] inc de ld [hli], a - ld a, [de] - inc de - ld [hli], a - ld a, [de] - inc de - ld [hli], a +endr ld a, [de] ld [hl], a - jr .asm_d956 + jr .next -.asm_d949 +.randomlygeneratemoves xor a +rept NUM_MOVES - 1 ld [hli], a - ld [hli], a - ld [hli], a +endr ld [hl], a - ld [wBuffer1], a + ld [wEvolutionOldSpecies], a predef FillMoves -.asm_d956 + +.next pop de +rept NUM_MOVES inc de - inc de - inc de - inc de +endr ; Initialize ID. ld a, [wPlayerID] @@ -145,47 +168,53 @@ GeneratePartyMonStats: ; Initialize stat experience. xor a ld b, MON_DVS - MON_STAT_EXP -.asm_d980 +.loop ld [de], a inc de dec b - jr nz, .asm_d980 + jr nz, .loop + pop hl push hl ld a, [wMonType] and $f - jr z, .asm_d998 + jr z, .registerpokedex + push hl - farcall GetTrainerDVs ; 9:7271 + farcall GetTrainerDVs pop hl - jr .asm_d9bb + jr .initializeDVs -.asm_d998 +.registerpokedex ld a, [wCurPartySpecies] - ld [wd151], a + ld [wTempSpecies], a dec a push de call CheckCaughtMon - ld a, [wd151] + ld a, [wTempSpecies] dec a call SetSeenAndCaughtMon pop de + pop hl push hl ld a, [wBattleMode] and a - jr nz, .asm_d9f9 + jr nz, .copywildmonDVs + call Random ld b, a call Random ld c, a -.asm_d9bb +.initializeDVs ld a, b ld [de], a inc de ld a, c ld [de], a inc de + + ; Initialize PP. push hl push de inc hl @@ -193,33 +222,45 @@ GeneratePartyMonStats: call FillPP pop de pop hl +rept NUM_MOVES inc de - inc de - inc de - inc de - ld a, $46 +endr + + ; Initialize happiness. + ld a, BASE_HAPPINESS ld [de], a inc de + xor a + ; PokerusStatus ld [de], a inc de + ; CaughtData/CaughtTime/CaughtLevel ld [de], a inc de + ; CaughtGender/CaughtLocation ld [de], a inc de + + ; Initialize level. ld a, [wCurPartyLevel] ld [de], a inc de + xor a + ; Status ld [de], a inc de + ; Unused ld [de], a inc de - ld bc, $a + + ; Initialize HP. + ld bc, MON_STAT_EXP - 1 add hl, bc - ld a, $1 + ld a, 1 ld c, a - ld b, $0 + ld b, FALSE call CalcMonStatC ldh a, [hProduct + 2] ld [de], a @@ -227,128 +268,147 @@ GeneratePartyMonStats: ldh a, [hProduct + 3] ld [de], a inc de - jr .asm_da2f + jr .initstats -.asm_d9f9 - ld a, [wEnemyMonMovesEnd] +.copywildmonDVs + ld a, [wEnemyMonDVs] ld [de], a inc de - ld a, [wEnemyMonMovesEnd + 1] + ld a, [wEnemyMonDVs + 1] ld [de], a inc de + push hl ld hl, wEnemyMonPP - ld b, $4 -.asm_da09 + ld b, NUM_MOVES +.wildmonpploop ld a, [hli] ld [de], a inc de dec b - jr nz, .asm_da09 + jr nz, .wildmonpploop pop hl - ld a, $46 + + ; Initialize happiness. + ld a, BASE_HAPPINESS ld [de], a inc de + xor a + ; PokerusStatus ld [de], a inc de + ; CaughtData/CaughtTime/CaughtLevel ld [de], a inc de + ; CaughtGender/CaughtLocation ld [de], a inc de + + ; Initialize level. ld a, [wCurPartyLevel] ld [de], a inc de + ld hl, wEnemyMonStatus + ; Copy wEnemyMonStatus ld a, [hli] ld [de], a inc de + ; Copy EnemyMonUnused ld a, [hli] ld [de], a inc de + ; Copy wEnemyMonHP ld a, [hli] ld [de], a inc de ld a, [hl] ld [de], a inc de -.asm_da2f + +.initstats ld a, [wBattleMode] dec a - jr nz, .asm_da41 + jr nz, .generatestats ld hl, wEnemyMonMaxHP - ld bc, $c + ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP call CopyBytes pop hl - jr .asm_da4b + jr .registerunowndex -.asm_da41 +.generatestats pop hl - ld bc, $a + ld bc, MON_STAT_EXP - 1 add hl, bc - ld b, $0 + ld b, FALSE call CalcMonStats -.asm_da4b + +.registerunowndex ld a, [wMonType] and $f - jr nz, .asm_da71 + jr nz, .done ld a, [wCurPartySpecies] - cp $c9 - jr nz, .asm_da71 + cp UNOWN + jr nz, .done ld hl, wPartyMon1DVs - ld a, [wPokemonData] + ld a, [wPartyCount] dec a ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes predef GetUnownLetter callfar UpdateUnownDex -.asm_da71 - scf + +.done + scf ; When this function returns, the carry flag indicates success vs failure. ret -FillPP: ; da73 (3:5a73) +FillPP: push bc - ld b, $4 -.asm_da76 + ld b, NUM_MOVES +.loop ld a, [hli] and a - jr z, .asm_da95 + jr z, .next dec a push hl push de push bc - ld hl, $5afe - ld bc, $7 + ld hl, Moves + ld bc, MOVE_LENGTH call AddNTimes ld de, wStringBuffer1 - ld a, $10 + ld a, BANK(Moves) call FarCopyBytes pop bc pop de pop hl - ld a, [wStringBuffer1 + 5] -.asm_da95 + ld a, [wStringBuffer1 + MOVE_PP] + +.next ld [de], a inc de dec b - jr nz, .asm_da76 + jr nz, .loop pop bc ret -AddTempmonToParty: ; da9c (3:5a9c) +AddTempmonToParty: ld hl, wPartyCount ld a, [hl] - cp $6 + cp PARTY_LENGTH scf ret z + inc a ld [hl], a ld c, a - ld b, $0 + ld b, 0 add hl, bc ld a, [wCurPartySpecies] ld [hli], a ld [hl], $ff + ld hl, wPartyMon1Species ld a, [wPartyCount] dec a @@ -358,44 +418,48 @@ AddTempmonToParty: ; da9c (3:5a9c) ld d, h ld hl, wTempMonSpecies call CopyBytes - ld hl, wPartyMon6StatsEnd + + ld hl, wPartyMonOT ld a, [wPartyCount] dec a call SkipNames ld d, h ld e, l - ld hl, wOTPartyMon6StatsEnd + ld hl, wOTPartyMonOT ld a, [wCurPartyMon] call SkipNames ld bc, NAME_LENGTH call CopyBytes + ld hl, wPartyMonNicknames ld a, [wPartyCount] dec a call SkipNames ld d, h ld e, l - ld hl, wOTPartyMon1Nickname + ld hl, wOTPartyMonNicknames ld a, [wCurPartyMon] call SkipNames - ld bc, NAME_LENGTH + ld bc, MON_NAME_LENGTH call CopyBytes + ld a, [wCurPartySpecies] - ld [wd151], a + ld [wNamedObjectIndexBuffer], a cp EGG - jr z, .asm_db18 + jr z, .egg dec a call SetSeenAndCaughtMon ld hl, wPartyMon1Happiness - ld a, [wPokemonData] + ld a, [wPartyCount] dec a ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes - ld [hl], 70 -.asm_db18 + ld [hl], BASE_HAPPINESS +.egg + ld a, [wCurPartySpecies] cp UNOWN - jr nz, .asm_db43 + jr nz, .done ld hl, wPartyMon1DVs ld a, [wPartyCount] dec a @@ -405,62 +469,76 @@ AddTempmonToParty: ; da9c (3:5a9c) callfar UpdateUnownDex ld a, [wFirstUnownSeen] and a - jr nz, .asm_db43 - ld a, [wd11e] + jr nz, .done + ld a, [wUnownLetter] ld [wFirstUnownSeen], a -.asm_db43 +.done + and a ret -SendGetMonIntoFromBox: ; db45 (3:5b45) - ld a, $1 +SendGetMonIntoFromBox: +; Sents/Gets mon into/from Box depending on Parameter +; wPokemonWithdrawDepositParameter == 0: get mon into Party +; wPokemonWithdrawDepositParameter == 1: sent mon into Box +; wPokemonWithdrawDepositParameter == 2: get mon from DayCare +; wPokemonWithdrawDepositParameter == 3: put mon into DayCare + + ld a, BANK(sBoxCount) call OpenSRAM ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_db66 - cp $2 - jr z, .asm_db66 - cp $3 + jr z, .check_IfPartyIsFull + cp DAY_CARE_WITHDRAW + jr z, .check_IfPartyIsFull + cp DAY_CARE_DEPOSIT ld hl, wBreedMon1Species - jr z, .asm_dba1 + jr z, .breedmon + + ; we want to sent a mon into the Box + ; so check if there's enough space ld hl, sBoxCount ld a, [hl] cp MONS_PER_BOX - jr nz, .asm_db6f - jp Functiondcb7 + jr nz, .there_is_room + jp CloseSRAM_And_SetCarryFlag -.asm_db66 +.check_IfPartyIsFull ld hl, wPartyCount ld a, [hl] - cp $6 - jp z, Functiondcb7 -.asm_db6f + cp PARTY_LENGTH + jp z, CloseSRAM_And_SetCarryFlag + +.there_is_room inc a ld [hl], a ld c, a - ld b, $0 + ld b, 0 add hl, bc ld a, [wPokemonWithdrawDepositParameter] - cp $2 + cp DAY_CARE_WITHDRAW ld a, [wBreedMon1Species] - jr z, .asm_db82 + jr z, .okay1 ld a, [wCurPartySpecies] -.asm_db82 + +.okay1 ld [hli], a ld [hl], $ff ld a, [wPokemonWithdrawDepositParameter] dec a - ld hl, wPartyMons + ld hl, wPartyMon1Species ld bc, PARTYMON_STRUCT_LENGTH - ld a, [wPokemonData] - jr nz, .asm_db9d + ld a, [wPartyCount] + jr nz, .okay2 ld hl, sBoxMon1Species ld bc, BOXMON_STRUCT_LENGTH ld a, [sBoxCount] -.asm_db9d - dec a + +.okay2 + dec a ; wPartyCount - 1 call AddNTimes -.asm_dba1 + +.breedmon push hl ld e, l ld d, h @@ -468,84 +546,96 @@ SendGetMonIntoFromBox: ; db45 (3:5b45) and a ld hl, sBoxMon1Species ld bc, BOXMON_STRUCT_LENGTH - jr z, .asm_dbbd - cp $2 + jr z, .okay3 + cp DAY_CARE_WITHDRAW ld hl, wBreedMon1Species - jr z, .asm_dbc3 + jr z, .okay4 ld hl, wPartyMon1Species ld bc, PARTYMON_STRUCT_LENGTH -.asm_dbbd + +.okay3 ld a, [wCurPartyMon] call AddNTimes -.asm_dbc3 + +.okay4 ld bc, BOXMON_STRUCT_LENGTH call CopyBytes ld a, [wPokemonWithdrawDepositParameter] - cp $3 + cp DAY_CARE_DEPOSIT ld de, wBreedMon1OT - jr z, .asm_dbe8 + jr z, .okay5 dec a ld hl, wPartyMonOT - ld a, [wPokemonData] - jr nz, .asm_dbe2 + ld a, [wPartyCount] + jr nz, .okay6 ld hl, sBoxMonOT ld a, [sBoxCount] -.asm_dbe2 + +.okay6 dec a call SkipNames ld d, h ld e, l -.asm_dbe8 + +.okay5 ld hl, sBoxMonOT ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_dbfb + jr z, .okay7 ld hl, wBreedMon1OT - cp $2 - jr z, .asm_dc01 - ld hl, wPartyMon6StatsEnd -.asm_dbfb + cp DAY_CARE_WITHDRAW + jr z, .okay8 + ld hl, wPartyMonOT + +.okay7 ld a, [wCurPartyMon] call SkipNames -.asm_dc01 + +.okay8 ld bc, NAME_LENGTH call CopyBytes ld a, [wPokemonWithdrawDepositParameter] - cp $3 + cp DAY_CARE_DEPOSIT ld de, wBreedMon1Nick - jr z, .asm_dc26 + jr z, .okay9 dec a - ld hl, wPartyMon1Nickname - ld a, [wPokemonData] - jr nz, .asm_dc20 + ld hl, wPartyMonNicknames + ld a, [wPartyCount] + jr nz, .okay10 ld hl, sBoxMonNicknames ld a, [sBoxCount] -.asm_dc20 + +.okay10 dec a call SkipNames ld d, h ld e, l -.asm_dc26 + +.okay9 ld hl, sBoxMonNicknames ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_dc39 + jr z, .okay11 ld hl, wBreedMon1Nick - cp $2 - jr z, .asm_dc3f - ld hl, wPartyMon1Nickname -.asm_dc39 + cp DAY_CARE_WITHDRAW + jr z, .okay12 + ld hl, wPartyMonNicknames + +.okay11 ld a, [wCurPartyMon] call SkipNames -.asm_dc3f - ld bc, NAME_LENGTH + +.okay12 + ld bc, MON_NAME_LENGTH call CopyBytes pop hl + ld a, [wPokemonWithdrawDepositParameter] - cp $1 - jr z, .asm_dcaa - cp $3 - jp z, Functiondcb2 + cp PC_DEPOSIT + jr z, .took_out_of_box + cp DAY_CARE_DEPOSIT + jp z, .CloseSRAM_And_ClearCarryFlag + push hl srl a add $2 @@ -555,35 +645,38 @@ SendGetMonIntoFromBox: ; db45 (3:5b45) ld a, d ld [wCurPartyLevel], a pop hl + ld b, h ld c, l - ld hl, $1f + ld hl, MON_LEVEL add hl, bc ld [hl], a - ld hl, $24 + ld hl, MON_MAXHP add hl, bc ld d, h ld e, l - ld hl, $a + ld hl, MON_STAT_EXP - 1 add hl, bc + push bc - ld b, $1 + ld b, TRUE call CalcMonStats pop bc + ld a, [wPokemonWithdrawDepositParameter] and a - jr nz, Functiondcb2 - ld hl, $20 + jr nz, .CloseSRAM_And_ClearCarryFlag + ld hl, MON_STATUS add hl, bc xor a ld [hl], a - ld hl, $22 + ld hl, MON_HP add hl, bc ld d, h ld e, l ld a, [wCurPartySpecies] - cp $fd - jr z, .asm_dca4 + cp EGG + jr z, .egg inc hl inc hl ld a, [hli] @@ -591,86 +684,88 @@ SendGetMonIntoFromBox: ; db45 (3:5b45) ld a, [hl] inc de ld [de], a - jr Functiondcb2 + jr .CloseSRAM_And_ClearCarryFlag -.asm_dca4 +.egg xor a ld [de], a inc de ld [de], a - jr Functiondcb2 + jr .CloseSRAM_And_ClearCarryFlag -.asm_dcaa +.took_out_of_box ld a, [sBoxCount] dec a ld b, a - call Functiondcbc -Functiondcb2: ; dcb2 (3:5cb2) + call RestorePPOfDepositedPokemon +.CloseSRAM_And_ClearCarryFlag: call CloseSRAM and a ret -Functiondcb7: ; dcb7 (3:5cb7) +CloseSRAM_And_SetCarryFlag: call CloseSRAM scf ret -Functiondcbc: ; dcbc (3:5cbc) +RestorePPOfDepositedPokemon: ld a, b - ld hl, sBoxMon1Species + ld hl, sBoxMons ld bc, BOXMON_STRUCT_LENGTH call AddNTimes ld b, h ld c, l - ld hl, $17 + ld hl, MON_PP add hl, bc push hl push bc ld de, wTempMonPP - ld bc, $4 + ld bc, NUM_MOVES call CopyBytes pop bc - ld hl, $2 + ld hl, MON_MOVES add hl, bc push hl ld de, wTempMonMoves - ld bc, $4 + ld bc, NUM_MOVES call CopyBytes pop hl pop de + ld a, [wMenuCursorY] push af ld a, [wMonType] push af - ld b, $0 -.asm_dcf2 + ld b, 0 +.loop ld a, [hli] and a - jr z, .asm_dd1e + jr z, .done ld [wTempMonMoves], a - ld a, $2 + ld a, BOXMON ld [wMonType], a ld a, b ld [wMenuCursorY], a push bc push hl push de - farcall GetMaxPPOfMove ; same bank + farcall GetMaxPPOfMove pop de pop hl - ld a, [wd151] + ld a, [wTempPP] ld b, a ld a, [de] - and $c0 + and %11000000 add b ld [de], a pop bc inc de inc b ld a, b - cp $4 - jr c, .asm_dcf2 -.asm_dd1e + cp NUM_MOVES + jr c, .loop + +.done pop af ld [wMonType], a pop af @@ -685,12 +780,12 @@ RetrieveMonFromDayCareMan: call WaitSFX call GetBreedMon1LevelGrowth ld a, b - ld [wMovementBufferCount], a + ld [wceed], a ld a, e ld [wCurPartyLevel], a xor a ld [wPokemonWithdrawDepositParameter], a - jp Functiondd6a + jp RetrieveBreedmon RetrieveMonFromDayCareLady: ld a, [wBreedMon2Species] @@ -700,40 +795,41 @@ RetrieveMonFromDayCareLady: call WaitSFX call GetBreedMon2LevelGrowth ld a, b - ld [wMovementBufferCount], a + ld [wceed], a ld a, e ld [wCurPartyLevel], a - ld a, $1 + ld a, PC_DEPOSIT ld [wPokemonWithdrawDepositParameter], a - jp Functiondd6a ; super long jump + jp RetrieveBreedmon -Functiondd6a: ; dd6a (3:5d6a) - ld hl, wPokemonData +RetrieveBreedmon: + ld hl, wPartyCount ld a, [hl] - cp $6 - jr nz, .asm_dd74 - scf ; We shouldn't be here if we've come this far. + cp PARTY_LENGTH + jr nz, .room_in_party + scf ret -.asm_dd74 +.room_in_party inc a ld [hl], a ld c, a - ld b, $0 + ld b, 0 add hl, bc ld a, [wPokemonWithdrawDepositParameter] and a ld a, [wBreedMon1Species] ld de, wBreedMon1Nick - jr z, .asm_dd8c + jr z, .okay ld a, [wBreedMon2Species] ld de, wBreedMon2Nick -.asm_dd8c + +.okay ld [hli], a ld [wCurSpecies], a ld a, $ff ld [hl], a - ld hl, wPartyMon1Nickname + ld hl, wPartyMonNicknames ld a, [wPartyCount] dec a call SkipNames @@ -752,60 +848,60 @@ Functiondd6a: ; dd6a (3:5d6a) pop hl call CopyBytes push hl - call Functionde20 + call GetLastPartyMon pop hl ld bc, BOXMON_STRUCT_LENGTH call CopyBytes call GetBaseData - call Functionde20 + call GetLastPartyMon ld b, d ld c, e - ld hl, $1f + ld hl, MON_LEVEL add hl, bc ld a, [wCurPartyLevel] ld [hl], a - ld hl, $24 + ld hl, MON_MAXHP add hl, bc ld d, h ld e, l ld hl, $a add hl, bc push bc - ld b, $1 + ld b, TRUE call CalcMonStats ld hl, wPartyMon1Moves - ld a, [wPokemonData] + ld a, [wPartyCount] dec a ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes ld d, h ld e, l ld a, $1 - ld [wCurHPAnim], a + ld [wBuffer1], a predef FillMoves ld a, [wPartyCount] dec a ld [wCurPartyMon], a - farcall Functionc6bc ; same bank + farcall HealPartyMon ld a, [wCurPartyLevel] ld d, a callfar CalcExpAtLevel pop bc ld hl, $8 add hl, bc - ldh a, [hQuotient] + ldh a, [hMultiplicand] ld [hli], a - ldh a, [hPrintNum3] + ldh a, [hMultiplicand + 1] ld [hli], a - ldh a, [hPrintNum4] + ldh a, [hMultiplicand + 2] ld [hl], a and a ret -Functionde20: ; de20 (3:5e20) +GetLastPartyMon: ld a, [wPartyCount] dec a - ld hl, wPartyMon1 + ld hl, wPartyMon1Species ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes ld d, h @@ -814,47 +910,50 @@ Functionde20: ; de20 (3:5e20) DepositMonWithDayCareMan: ld de, wBreedMon1Nick - call Functionde4a - xor a + call DepositBreedmon + xor a ; REMOVE_PARTY ld [wPokemonWithdrawDepositParameter], a jp RemoveMonFromPartyOrBox DepositMonWithDayCareLady: ld de, wBreedMon2Nick - call Functionde4a - xor a + call DepositBreedmon + xor a ; REMOVE_PARTY ld [wPokemonWithdrawDepositParameter], a jp RemoveMonFromPartyOrBox -Functionde4a: ; de4a (3:5e4a) +DepositBreedmon: ld a, [wCurPartyMon] ld hl, wPartyMonNicknames call SkipNames call CopyBytes ld a, [wCurPartyMon] - ld hl, wPartyMon1OT + ld hl, wPartyMonOT call SkipNames call CopyBytes ld a, [wCurPartyMon] - ld hl, wPartyMon1 + ld hl, wPartyMon1Species ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes ld bc, BOXMON_STRUCT_LENGTH jp CopyBytes -SendMonIntoBox: ; de74 (3:5e74) - ld a, $1 +SendMonIntoBox: +; Sends the mon into one of Bills Boxes +; the data comes mainly from 'wEnemyMon:' + ld a, BANK(sBoxCount) call OpenSRAM ld de, sBoxCount ld a, [de] - cp $14 - jp nc, Functiondf48 + cp MONS_PER_BOX + jp nc, .full inc a ld [de], a + ld a, [wCurPartySpecies] ld [wCurSpecies], a ld c, a -.asm_de8b +.loop inc de ld a, [de] ld b, a @@ -862,25 +961,31 @@ SendMonIntoBox: ; de74 (3:5e74) ld c, b ld [de], a inc a - jr nz, .asm_de8b + jr nz, .loop + call GetBaseData - call Functiondf4d + call ShiftBoxMon + ld hl, wPlayerName ld de, sBoxMonOT ld bc, NAME_LENGTH call CopyBytes + ld a, [wCurPartySpecies] - ld [wd151], a + ld [wNamedObjectIndexBuffer], a call GetPokemonName + ld de, sBoxMonNicknames ld hl, wStringBuffer1 - ld bc, NAME_LENGTH + ld bc, MON_NAME_LENGTH call CopyBytes + ld hl, wEnemyMon - ld de, sBoxMon1Species - ld bc, $6 + ld de, sBoxMon1 + ld bc, 1 + 1 + NUM_MOVES ; species + item + moves call CopyBytes - ld hl, wGameData + + ld hl, wPlayerID ld a, [hli] ld [de], a inc de @@ -892,31 +997,35 @@ SendMonIntoBox: ; de74 (3:5e74) ld d, a callfar CalcExpAtLevel pop de - ldh a, [hQuotient] + ldh a, [hProduct + 1] ld [de], a inc de - ldh a, [hPrintNum3] + ldh a, [hProduct + 2] ld [de], a inc de - ldh a, [hPrintNum4] + ldh a, [hProduct + 3] ld [de], a inc de + + ; Set all 5 Experience Values to 0 xor a - ld b, $a -.asm_deeb + ld b, 2 * 5 +.loop2 ld [de], a inc de dec b - jr nz, .asm_deeb - ld hl, wEnemyMonMovesEnd - ld b, $6 -.asm_def5 + jr nz, .loop2 + + ld hl, wEnemyMonDVs + ld b, 2 + NUM_MOVES ; DVs and PP ; wEnemyMonHappiness - wEnemyMonDVs +.loop3 ld a, [hli] ld [de], a inc de dec b - jr nz, .asm_def5 - ld a, $46 + jr nz, .loop3 + + ld a, BASE_HAPPINESS ld [de], a inc de xor a @@ -932,90 +1041,109 @@ SendMonIntoBox: ; de74 (3:5e74) dec a call SetSeenAndCaughtMon ld a, [wCurPartySpecies] - cp $c9 - jr nz, .asm_df26 + cp UNOWN + jr nz, .not_unown ld hl, sBoxMon1DVs predef GetUnownLetter callfar UpdateUnownDex -.asm_df26 + +.not_unown ld hl, sBoxMon1Moves ld de, wTempMonMoves - ld bc, $4 + ld bc, NUM_MOVES call CopyBytes + ld hl, sBoxMon1PP ld de, wTempMonPP - ld bc, $4 + ld bc, NUM_MOVES call CopyBytes - ld b, $0 - call Functiondcbc + + ld b, 0 + call RestorePPOfDepositedPokemon + call CloseSRAM scf ret -Functiondf48: ; df48 (3:5f48) +.full call CloseSRAM and a ret -Functiondf4d: ; df4d (3:5f4d) +ShiftBoxMon: ld hl, sBoxMonOT ld bc, NAME_LENGTH - call Functiondf65 + call .shift + ld hl, sBoxMonNicknames - ld bc, NAME_LENGTH - call Functiondf65 - ld hl, sBoxMon1Species + ld bc, MON_NAME_LENGTH + call .shift + + ld hl, sBoxMons ld bc, BOXMON_STRUCT_LENGTH -Functiondf65: ; df65 (3:5f65) + +.shift ld a, [sBoxCount] - cp $2 + cp 2 ret c + push hl call AddNTimes dec hl ld e, l ld d, h pop hl + ld a, [sBoxCount] dec a call AddNTimes dec hl + push hl ld a, [sBoxCount] dec a - ld hl, $0 + ld hl, 0 call AddNTimes ld c, l ld b, h pop hl -.asm_df89 +.loop ld a, [hld] ld [de], a dec de dec bc ld a, c or b - jr nz, .asm_df89 + jr nz, .loop ret -GiveEgg: ; df92 (3:5f92) +GiveEgg:: ld a, [wCurPartySpecies] push af callfar GetPreEvolution callfar GetPreEvolution ld a, [wCurPartySpecies] dec a + +; TryAddMonToParty sets Seen and Caught flags +; when it is successful. This routine will make +; sure that we aren't newly setting flags. push af call CheckCaughtMon pop af push bc call CheckSeenMon push bc + call TryAddMonToParty + +; If we haven't caught this Pokemon before receiving +; the Egg, reset the flag that was just set by +; TryAddMonToParty. pop bc ld a, c and a - jr nz, .asm_dfc9 + jr nz, .skip_caught_flag ld a, [wCurPartySpecies] dec a ld c, a @@ -1023,11 +1151,15 @@ GiveEgg: ; df92 (3:5f92) ld hl, wPokedexCaught ld b, RESET_FLAG predef SmallFarFlagAction -.asm_dfc9 + +.skip_caught_flag +; If we haven't seen this Pokemon before receiving +; the Egg, reset the flag that was just set by +; TryAddMonToParty. pop bc ld a, c and a - jr nz, .asm_dfdf + jr nz, .skip_seen_flag ld a, [wCurPartySpecies] dec a ld c, a @@ -1035,26 +1167,27 @@ GiveEgg: ; df92 (3:5f92) ld hl, wPokedexSeen ld b, RESET_FLAG predef SmallFarFlagAction -.asm_dfdf + +.skip_seen_flag pop af ld [wCurPartySpecies], a - ld a, [wPokemonData] + ld a, [wPartyCount] dec a ld bc, PARTYMON_STRUCT_LENGTH ld hl, wPartyMon1Species call AddNTimes ld a, [wCurPartySpecies] ld [hl], a - ld hl, wPokemonData + ld hl, wPartyCount ld a, [hl] - ld b, $0 + ld b, 0 ld c, a add hl, bc - ld a, $fd + ld a, EGG ld [hl], a - ld a, [wPokemonData] + ld a, [wPartyCount] dec a - ld hl, wPartyMon1Nickname + ld hl, wPartyMonNicknames call SkipNames ld de, String_Egg call CopyName2 @@ -1064,11 +1197,12 @@ GiveEgg: ; df92 (3:5f92) ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes ld a, [wDebugFlags] - bit 1, a - ld a, $1 - jr nz, .asm_e028 + bit DEBUG_FIELD_F, a + ld a, 1 + jr nz, .got_init_happiness ld a, [wBaseEggSteps] -.asm_e028 + +.got_init_happiness ld [hl], a ld a, [wPartyCount] dec a @@ -1084,119 +1218,132 @@ GiveEgg: ; df92 (3:5f92) String_Egg: db "EGG@" -RemoveMonFromPartyOrBox: ; e03f (3:603f) +RemoveMonFromPartyOrBox: ld hl, wPartyCount + ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e050 - ld a, $1 + jr z, .okay + + ld a, BANK(sBoxCount) call OpenSRAM ld hl, sBoxCount -.asm_e050 + +.okay ld a, [hl] dec a ld [hli], a ld a, [wCurPartyMon] ld c, a - ld b, $0 + ld b, 0 add hl, bc ld e, l ld d, h inc de -.asm_e05d +.loop ld a, [de] inc de ld [hli], a inc a - jr nz, .asm_e05d - ld hl, wPartyMon6StatsEnd - ld d, $5 + jr nz, .loop + ld hl, wPartyMonOT + ld d, PARTY_LENGTH - 1 ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e073 + jr z, .party ld hl, sBoxMonOT - ld d, $13 -.asm_e073 + ld d, MONS_PER_BOX - 1 + +.party + ; If this is the last mon in our party (box), + ; shift all the other mons up to close the gap. ld a, [wCurPartyMon] call SkipNames ld a, [wCurPartyMon] cp d - jr nz, .asm_e084 - ld [hl], $ff - jp .asm_e0f6 + jr nz, .delete_inside + ld [hl], -1 + jp .finish -.asm_e084 +.delete_inside + ; Shift the OT names ld d, h ld e, l - ld bc, NAME_LENGTH + ld bc, MON_NAME_LENGTH add hl, bc ld bc, wPartyMonNicknames ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e096 + jr z, .party2 ld bc, sBoxMonNicknames -.asm_e096 +.party2 call CopyDataUntil - ld hl, wPartyMon1 + ; Shift the struct + ld hl, wPartyMons ld bc, PARTYMON_STRUCT_LENGTH ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e0ab - ld hl, sBoxMon1Species + jr z, .party4 + ld hl, sBoxMons ld bc, BOXMON_STRUCT_LENGTH -.asm_e0ab +.party4 ld a, [wCurPartyMon] call AddNTimes ld d, h ld e, l ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e0c2 + jr z, .party5 ld bc, BOXMON_STRUCT_LENGTH add hl, bc ld bc, sBoxMonOT - jr .asm_e0c9 + jr .copy -.asm_e0c2 +.party5 ld bc, PARTYMON_STRUCT_LENGTH add hl, bc ld bc, wPartyMonOT -.asm_e0c9 +.copy call CopyDataUntil + ; Shift the nicknames ld hl, wPartyMonNicknames ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e0d8 + jr z, .party6 ld hl, sBoxMonNicknames -.asm_e0d8 - ld bc, NAME_LENGTH +.party6 + ld bc, MON_NAME_LENGTH ld a, [wCurPartyMon] call AddNTimes ld d, h ld e, l - ld bc, NAME_LENGTH + ld bc, MON_NAME_LENGTH add hl, bc ld bc, wPartyMonNicknamesEnd ld a, [wPokemonWithdrawDepositParameter] and a - jr z, .asm_e0f3 - ld bc, sBoxEnd -.asm_e0f3 + jr z, .party7 + ld bc, sBoxMonNicknamesEnd +.party7 call CopyDataUntil -.asm_e0f6 + ; Mail time! +.finish ld a, [wPokemonWithdrawDepositParameter] and a jp nz, CloseSRAM ld a, [wLinkMode] and a ret nz - ld a, $0 + ; Shift mail + ld a, BANK(sPartyMail) call OpenSRAM - ld hl, wPokemonData + ; If this is the last mon in our party, no need to shift mail. + ld hl, wPartyCount ld a, [wCurPartyMon] cp [hl] - jr z, .asm_e137 - ld hl, s0_a600 + jr z, .close_sram + ; Shift our mail messages up. + ld hl, sPartyMail ld bc, MAIL_STRUCT_LENGTH call AddNTimes push hl @@ -1204,7 +1351,7 @@ RemoveMonFromPartyOrBox: ; e03f (3:603f) pop de ld a, [wCurPartyMon] ld b, a -.asm_e120 +.loop2 push bc push hl ld bc, MAIL_STRUCT_LENGTH @@ -1218,8 +1365,8 @@ RemoveMonFromPartyOrBox: ; e03f (3:603f) inc b ld a, [wPartyCount] cp b - jr nz, .asm_e120 -.asm_e137 + jr nz, .loop2 +.close_sram jp CloseSRAM ComputeNPCTrademonStats: @@ -1239,7 +1386,7 @@ ComputeNPCTrademonStats: push de ld a, MON_STAT_EXP - 1 call GetPartyParamLocation - ld b, $1 + ld b, TRUE call CalcMonStats pop de ld a, MON_HP @@ -1251,14 +1398,14 @@ ComputeNPCTrademonStats: ld [hl], a ret -CalcMonStats: ; e16d -; Calculates all 6 Stats of a Pkmn +CalcMonStats: +; Calculates all 6 Stats of a mon ; b: Take into account stat EXP if TRUE -; 'c' counts from 1-6 and points with 'BaseStats' to the base value +; 'c' counts from 1-6 and points with 'wBaseStats' to the base value ; hl is the path to the Stat EXP -; results in $ffb7 and $ffb8 are saved in [de] +; de points to where the final stats will be saved - ld c, $0 + ld c, STAT_HP - 1 ; first stat .loop inc c call CalcMonStatC @@ -1269,12 +1416,11 @@ CalcMonStats: ; e16d ld [de], a inc de ld a, c - cp STAT_SDEF + cp STAT_SDEF ; last stat jr nz, .loop ret -; e17b -CalcMonStatC: ; e181 +CalcMonStatC: ; 'c' is 1-6 and points to the BaseStat ; 1: HP ; 2: Attack @@ -1288,16 +1434,16 @@ CalcMonStatC: ; e181 ld a, b ld d, a push hl - ld hl, wd121 + ld hl, wBaseStats dec hl ; has to be decreased, because 'c' begins with 1 - ld b, $0 + ld b, 0 add hl, bc ld a, [hl] ld e, a pop hl push hl ld a, c - cp STAT_SDEF + cp STAT_SDEF ; last stat jr nz, .not_spdef dec hl dec hl @@ -1310,11 +1456,11 @@ CalcMonStatC: ; e181 add hl, bc .sqrt_loop xor a - ldh [hMultiplicand], a + ldh [hMultiplicand + 0], a ldh [hMultiplicand + 1], a inc b ld a, b - cp $ff + cp -1 jr z, .no_stat_exp ldh [hMultiplicand + 2], a ldh [hMultiplier], a @@ -1346,29 +1492,29 @@ CalcMonStatC: ; e181 jr z, .Special cp STAT_SDEF jr z, .Special -; DV_HP = (DV_ATK & 1) << 3 + (DV_DEF & 1) << 2 + (DV_SPD & 1) << 1 + (DV_SPC & 1) +; DV_HP = (DV_ATK & 1) << 3 | (DV_DEF & 1) << 2 | (DV_SPD & 1) << 1 | (DV_SPC & 1) push bc ld a, [hl] swap a - and $1 + and 1 add a add a add a ld b, a ld a, [hli] - and $1 + and 1 add a add a add b ld b, a ld a, [hl] swap a - and $1 + and 1 add a add b ld b, a ld a, [hl] - and $1 + and 1 add b pop bc jr .GotDV @@ -1435,45 +1581,45 @@ CalcMonStatC: ; e181 call Divide ld a, c cp STAT_HP - ld a, 5 + ld a, STAT_MIN_NORMAL jr nz, .not_hp ld a, [wCurPartyLevel] ld b, a - ldh a, [hQuotient + 2] + ldh a, [hQuotient + 3] add b ldh [hMultiplicand + 2], a jr nc, .no_overflow_3 - ldh a, [hQuotient + 1] + ldh a, [hQuotient + 2] inc a ldh [hMultiplicand + 1], a .no_overflow_3 - ld a, 10 + ld a, STAT_MIN_HP .not_hp ld b, a - ldh a, [hQuotient + 2] + ldh a, [hQuotient + 3] add b ldh [hMultiplicand + 2], a jr nc, .no_overflow_4 - ldh a, [hQuotient + 1] + ldh a, [hQuotient + 2] inc a ldh [hMultiplicand + 1], a .no_overflow_4 - ldh a, [hQuotient + 1] - cp (1000 / $100) + 1 + ldh a, [hQuotient + 2] + cp HIGH(MAX_STAT_VALUE + 1) + 1 jr nc, .max_stat - cp 1000 / $100 + cp HIGH(MAX_STAT_VALUE + 1) jr c, .stat_value_okay - ldh a, [hQuotient + 2] - cp 1000 % $100 + ldh a, [hQuotient + 3] + cp LOW(MAX_STAT_VALUE + 1) jr c, .stat_value_okay .max_stat - ld a, 999 / $100 + ld a, HIGH(MAX_STAT_VALUE) ldh [hMultiplicand + 1], a - ld a, 999 % $100 + ld a, LOW(MAX_STAT_VALUE) ldh [hMultiplicand + 2], a .stat_value_okay @@ -1482,15 +1628,15 @@ CalcMonStatC: ; e181 pop hl ret -GivePoke: ; Give a Pokemon from script +GivePoke:: push de push bc - xor a + xor a ; PARTYMON ld [wMonType], a call TryAddMonToParty - jr nc, .asm_e2c9 - ld hl, wPartyMon1Nickname - ld a, [wPokemonData] + jr nc, .failed + ld hl, wPartyMonNicknames + ld a, [wPartyCount] dec a ld [wCurPartyMon], a call SkipNames @@ -1498,27 +1644,27 @@ GivePoke: ; Give a Pokemon from script ld e, l pop bc ld a, b - ld b, $0 + ld b, 0 push bc push de push af - ld a, [wd002] + ld a, [wCurItem] and a - jr z, .asm_e2fa + jr z, .done ld a, [wCurPartyMon] ld hl, wPartyMon1Item ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes - ld a, [wd002] + ld a, [wCurItem] ld [hl], a - jr .asm_e2fa + jr .done -.asm_e2c9 +.failed ld a, [wCurPartySpecies] ld [wTempEnemyMonSpecies], a callfar LoadEnemyMon call SendMonIntoBox - jp nc, Functione3af + jp nc, .FailedToGiveMon ld a, BOXMON ld [wMonType], a xor a @@ -1526,18 +1672,19 @@ GivePoke: ; Give a Pokemon from script ld de, wMonOrItemNameBuffer pop bc ld a, b - ld b, $1 + ld b, 1 push bc push de push af - ld a, [wd002] + ld a, [wCurItem] and a - jr z, .asm_e2fa - ld a, [wd002] + jr z, .done + ld a, [wCurItem] ld [sBoxMon1Item], a -.asm_e2fa + +.done ld a, [wCurPartySpecies] - ld [wd151], a + ld [wNamedObjectIndexBuffer], a ld [wTempEnemyMonSpecies], a call GetPokemonName ld hl, wStringBuffer1 @@ -1546,7 +1693,7 @@ GivePoke: ; Give a Pokemon from script call CopyBytes pop af and a - jr z, .asm_e381 + jr z, .wildmon pop de pop bc pop hl @@ -1567,26 +1714,28 @@ GivePoke: ; Give a Pokemon from script and a push de push bc - jr nz, .asm_e360 + jr nz, .send_to_box + push hl ld a, [wCurPartyMon] - ld hl, wPartyMon1OT + ld hl, wPartyMonOT call SkipNames ld d, h ld e, l pop hl +.otnameloop ld a, [wScriptBank] call FarCopyBytes ld a, [wCurPartyMon] ld hl, wPartyMon1ID ld bc, PARTYMON_STRUCT_LENGTH call AddNTimes - ld a, 01001 / $100 + ld a, HIGH(RANDY_OT_ID) ld [hli], a - ld [hl], 01001 % $100 - jr .asm_e38d + ld [hl], LOW(RANDY_OT_ID) + jr .skip_nickname -.asm_e360 +.send_to_box ld a, BANK(sBoxMonOT) call OpenSRAM ld de, sBoxMonOT @@ -1599,20 +1748,21 @@ GivePoke: ; Give a Pokemon from script call Random ld [hl], a call CloseSRAM - jr .asm_e38d + jr .skip_nickname -.asm_e381 - callfar Functionc7cd0 +.wildmon + callfar GiveANickname_YesNo pop de - jr c, .asm_e38d + jr c, .skip_nickname call InitNickname -.asm_e38d + +.skip_nickname pop bc pop de ld a, b and a ret z - ld hl, TextJump_WasSentToBillsPC + ld hl, WasSentToBillsPCText call PrintText ld a, BANK(sBoxMonNicknames) call OpenSRAM @@ -1624,28 +1774,28 @@ GivePoke: ; Give a Pokemon from script ld b, $1 ret -Functione3af: ; e3af (3:63af) +.FailedToGiveMon: pop bc pop de ld b, $2 ret -TextJump_WasSentToBillsPC: - text_far Text_WasSentToBillsPC - db "@" +WasSentToBillsPCText: + text_far _WasSentToBillsPCText + text_end -InitNickname: ; e3b9 (3:63b9) +InitNickname: push de call LoadStandardMenuHeader call DisableSpriteUpdates pop de push de - ld b, $0 + ld b, NAME_MON farcall NamingScreen pop hl ld de, wStringBuffer1 call InitName - ld a, $4 ; XXX could this be in bank 4 in pokered? + ld a, $4 ; ExitAllMenus is in bank 0, XXX could this be in bank 4 in pokered? ld hl, ExitAllMenus rst FarCall ret diff --git a/engine/pokemon/move_mon_wo_mail.asm b/engine/pokemon/move_mon_wo_mail.asm new file mode 100644 index 00000000..79f70d05 --- /dev/null +++ b/engine/pokemon/move_mon_wo_mail.asm @@ -0,0 +1,133 @@ +InsertPokemonIntoBox: + ld a, BANK(sBoxCount) + call OpenSRAM + ld hl, sBoxCount + call InsertSpeciesIntoBoxOrParty + ld a, [sBoxCount] + dec a + ld [wNextBoxOrPartyIndex], a + ld hl, sBoxMonNicknames + ld bc, MON_NAME_LENGTH + ld de, wBufferMonNick + call InsertDataIntoBoxOrParty + ld a, [sBoxCount] + dec a + ld [wNextBoxOrPartyIndex], a + ld hl, sBoxMonOT + ld bc, NAME_LENGTH + ld de, wBufferMonOT + call InsertDataIntoBoxOrParty + ld a, [sBoxCount] + dec a + ld [wNextBoxOrPartyIndex], a + ld hl, sBoxMons + ld bc, BOXMON_STRUCT_LENGTH + ld de, wBufferMon + call InsertDataIntoBoxOrParty + ld hl, wBufferMonMoves + ld de, wTempMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld hl, wBufferMonPP + ld de, wTempMonPP + ld bc, NUM_MOVES + call CopyBytes + ld a, [wCurPartyMon] + ld b, a + farcall RestorePPOfDepositedPokemon + jp CloseSRAM + +InsertPokemonIntoParty: + ld hl, wPartyCount + call InsertSpeciesIntoBoxOrParty + ld a, [wPartyCount] + dec a + ld [wNextBoxOrPartyIndex], a + ld hl, wPartyMonNicknames + ld bc, MON_NAME_LENGTH + ld de, wBufferMonNick + call InsertDataIntoBoxOrParty + ld a, [wPartyCount] + dec a + ld [wNextBoxOrPartyIndex], a + ld hl, wPartyMonOT + ld bc, NAME_LENGTH + ld de, wBufferMonOT + call InsertDataIntoBoxOrParty + ld a, [wPartyCount] + dec a + ld [wNextBoxOrPartyIndex], a + ld hl, wPartyMons + ld bc, PARTYMON_STRUCT_LENGTH + ld de, wBufferMon + call InsertDataIntoBoxOrParty + ret + +InsertSpeciesIntoBoxOrParty: + inc [hl] + inc hl + ld a, [wCurPartyMon] + ld c, a + ld b, 0 + add hl, bc + ld a, [wCurPartySpecies] + ld c, a +.loop + ld a, [hl] + ld [hl], c + inc hl + inc c + ld c, a + jr nz, .loop + ret + +InsertDataIntoBoxOrParty: + push de + push hl + push bc + ld a, [wNextBoxOrPartyIndex] + dec a + call AddNTimes + push hl + add hl, bc + ld d, h + ld e, l + pop hl +.loop + push bc + ld a, [wNextBoxOrPartyIndex] + ld b, a + ld a, [wCurPartyMon] + cp b + pop bc + jr z, .insert + push hl + push de + push bc + call CopyBytes + pop bc + pop de + pop hl + push hl + ld a, l + sub c + ld l, a + ld a, h + sbc b + ld h, a + pop de + ld a, [wNextBoxOrPartyIndex] + dec a + ld [wNextBoxOrPartyIndex], a + jr .loop + +.insert + pop bc + pop hl + ld a, [wCurPartyMon] + call AddNTimes + ld d, h + ld e, l + pop hl + call CopyBytes + ret diff --git a/engine/pokemon/print_move_description.asm b/engine/pokemon/print_move_description.asm new file mode 100644 index 00000000..e002e3d1 --- /dev/null +++ b/engine/pokemon/print_move_description.asm @@ -0,0 +1,16 @@ +PrintMoveDesc: + push hl + ld hl, MoveDescriptions + ld a, [wCurSpecies] + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, BANK(MoveDescriptions) + call GetFarHalfword + ld d, h + ld e, l + pop hl + ld a, BANK(MoveDescriptions) + jp FarString diff --git a/engine/pokemon/search2.asm b/engine/pokemon/search2.asm new file mode 100644 index 00000000..c33d84ed --- /dev/null +++ b/engine/pokemon/search2.asm @@ -0,0 +1,134 @@ +_FindPartyMonAboveLevel: + ld hl, wPartyMon1Level + call FindAboveLevel + ret + +_FindPartyMonAtLeastThatHappy: + ld hl, wPartyMon1Happiness + call FindAtLeastThatHappy + ret + +_FindPartyMonThatSpecies: + ld hl, wPartyMon1Species + jp FindThatSpecies + +_FindPartyMonThatSpeciesYourTrainerID: + ld hl, wPartyMon1Species + call FindThatSpecies + ret z + ld a, c + ld hl, wPartyMon1ID + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld a, [wPlayerID] + cp [hl] + jr nz, .nope + inc hl + ld a, [wPlayerID + 1] + cp [hl] + jr nz, .nope + ld a, $1 + and a + ret + +.nope + xor a + ret + +FindAtLeastThatHappy: +; Sets the bits for the Pokemon that have a happiness greater than or equal to b. +; The lowest bits are used. Sets z if no Pokemon in your party is at least that happy. + ld c, $0 + ld a, [wPartyCount] + ld d, a +.loop + ld a, d + dec a + push hl + push bc + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + pop bc + ld a, b + cp [hl] + pop hl + jr z, .greater_equal + jr nc, .lower + +.greater_equal + ld a, c + or $1 + ld c, a + +.lower + sla c + dec d + jr nz, .loop + call RetroactivelyIgnoreEggs + ld a, c + and a + ret + +FindAboveLevel: + ld c, $0 + ld a, [wPartyCount] + ld d, a +.loop + ld a, d + dec a + push hl + push bc + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + pop bc + ld a, b + cp [hl] + pop hl + jr c, .greater + ld a, c + or $1 + ld c, a + +.greater + sla c + dec d + jr nz, .loop + call RetroactivelyIgnoreEggs + ld a, c + and a + ret + +FindThatSpecies: +; Find species b in your party. +; If you have no Pokemon, returns c = -1 and z. +; If that species is in your party, returns its location in c, and nz. +; Otherwise, returns z. + ld c, -1 + ld hl, wPartySpecies +.loop + ld a, [hli] + cp -1 + ret z + inc c + cp b + jr nz, .loop + ld a, $1 + and a + ret + +RetroactivelyIgnoreEggs: + ld e, %11111110 + ld hl, wPartySpecies +.loop + ld a, [hli] + cp -1 + ret z + cp EGG + jr nz, .skip_notegg + ld a, c + and e + ld c, a + +.skip_notegg + rlc e + jr .loop diff --git a/engine/predef.asm b/engine/predef.asm index b0d0eb56..e18765b0 100755 --- a/engine/predef.asm +++ b/engine/predef.asm @@ -25,4 +25,4 @@ GetPredefPointer:: ret -INCLUDE "data/predef_pointers.asm"
\ No newline at end of file +INCLUDE "data/predef_pointers.asm" diff --git a/engine/rtc/rtc.asm b/engine/rtc/rtc.asm new file mode 100644 index 00000000..e56bed45 --- /dev/null +++ b/engine/rtc/rtc.asm @@ -0,0 +1,210 @@ +Unreferenced_StopRTC: + ld a, SRAM_ENABLE + ld [MBC3SRamEnable], a + call LatchClock + ld a, RTC_DH + ld [MBC3SRamBank], a + ld a, [MBC3RTC] + set 6, a ; halt + ld [MBC3RTC], a + call CloseSRAM + ret + +StartRTC: + ld a, SRAM_ENABLE + ld [MBC3SRamEnable], a + call LatchClock + ld a, RTC_DH + ld [MBC3SRamBank], a + ld a, [MBC3RTC] + res 6, a ; halt + ld [MBC3RTC], a + call CloseSRAM + ret + +GetTimeOfDay:: +; get time of day based on the current hour + ldh a, [hHours] ; hour + ld hl, TimesOfDay + +.check +; if we're within the given time period, +; get the corresponding time of day + cp [hl] + jr c, .match +; else, get the next entry + inc hl + inc hl +; try again + jr .check + +.match +; get time of day + inc hl + ld a, [hl] + ld [wTimeOfDay], a + ret + +TimesOfDay: +; hours for the time of day +; 0400-0959 morn | 1000-1759 day | 1800-0359 nite + db MORN_HOUR, NITE_F + db DAY_HOUR, MORN_F + db NITE_HOUR, DAY_F + db MAX_HOUR, NITE_F + db -1, MORN_F + +Unreferenced_1404e: + db 20, NITE_F + db 40, MORN_F + db 60, DAY_F + db -1, MORN_F + +StageRTCTimeForSave: + call UpdateTime + ld hl, wRTC + ld a, [wCurDay] + ld [hli], a + ldh a, [hHours] + ld [hli], a + ldh a, [hMinutes] + ld [hli], a + ldh a, [hSeconds] + ld [hli], a + ret + +SaveRTC: + ld a, SRAM_ENABLE + ld [MBC3SRamEnable], a + call LatchClock + ld hl, MBC3RTC + ld a, RTC_DH + ld [MBC3SRamBank], a + res 7, [hl] + ld a, BANK(sRTCStatusFlags) + ld [MBC3SRamBank], a + xor a + ld [sRTCStatusFlags], a + call CloseSRAM + ret + +StartClock:: + call _GetClock + call GetClock + call _FixDays + call FixDays + jr nc, .skip_set + ; bit 5: Day count exceeds 139 + ; bit 6: Day count exceeds 255 + call RecordRTCStatus ; set flag on sRTCStatusFlags + +.skip_set + call StartRTC + ret + +_FixDays: + ld hl, hRTCDayHi + bit 7, [hl] + jr nz, .set_bit_7 + bit 6, [hl] + jr nz, .set_bit_7 + xor a + ret + +.set_bit_7 + ; Day count exceeds 16383 + ld a, %10000000 + call RecordRTCStatus ; set bit 7 on sRTCStatusFlags + ret + +_GetClock: + ld a, SRAM_ENABLE + ld [MBC3SRamEnable], a + call LatchClock + ld a, RTC_DH + ld [MBC3SRamBank], a + ld a, [MBC3RTC] + push af + call CloseSRAM + pop af + bit 6, a ; halt + ret z + + ld a, BANK(sRTCStatusFlags) + call OpenSRAM + ld a, $34 + ld [sUnusedRTCMinutes], a + ld a, $12 + ld [sUnusedRTCHours], a + call CloseSRAM + ret + +ClockContinue: + call CheckRTCStatus + ld c, a + and %11000000 ; Day count exceeded 255 or 16383 + jr nz, .time_overflow + + ld a, c + and %00100000 ; Day count exceeded 139 + jr z, .dont_update + + call UpdateTime + ld a, [wRTC + 0] + ld b, a + ld a, [wCurDay] + cp b + jr c, .dont_update + +.time_overflow + farcall ClearDailyTimers + ret + +.dont_update + xor a + ret + +_InitTime:: + call GetClock + call FixDays + ld hl, hRTCSeconds + ld de, wStartSecond + + ld a, [wStringBuffer2 + 3] + sub [hl] + dec hl + jr nc, .okay_secs + add 60 +.okay_secs + ld [de], a + dec de + + ld a, [wStringBuffer2 + 2] + sbc [hl] + dec hl + jr nc, .okay_mins + add 60 +.okay_mins + ld [de], a + dec de + + ld a, [wStringBuffer2 + 1] + sbc [hl] + dec hl + jr nc, .okay_hrs + add 24 +.okay_hrs + ld [de], a + dec de + + ld a, [wStringBuffer2] + sbc [hl] + dec hl + jr nc, .okay_days + add 140 + ld c, 7 + call SimpleDivide + +.okay_days + ld [de], a + ret diff --git a/engine/rtc/timeset.asm b/engine/rtc/timeset.asm new file mode 100644 index 00000000..b89d1af7 --- /dev/null +++ b/engine/rtc/timeset.asm @@ -0,0 +1,722 @@ +TIMESET_UP_ARROW EQU "♂" ; $ef +TIMESET_DOWN_ARROW EQU "♀" ; $f5 + +InitClock: +; Ask the player to set the time. + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + + ld a, $0 + ld [wSpriteUpdatesEnabled], a + ld a, $10 + ld [wMusicFade], a + ld a, LOW(MUSIC_NONE) + ld [wMusicFadeID], a + ld a, HIGH(MUSIC_NONE) + ld [wMusicFadeID + 1], a + ld c, 8 + call DelayFrames + call RotateFourPalettesLeft + call ClearTilemap + call ClearSprites + xor a + ldh [hBGMapMode], a + call LoadStandardFont + ld de, TimeSetBackgroundGFX + ld hl, vTiles2 tile $00 + lb bc, BANK(TimeSetBackgroundGFX), 1 + call Request1bpp + ld de, TimeSetUpArrowGFX + ld hl, vTiles2 tile $01 + lb bc, BANK(TimeSetUpArrowGFX), 1 + call Request1bpp + ld de, TimeSetDownArrowGFX + ld hl, vTiles2 tile $02 + lb bc, BANK(TimeSetDownArrowGFX), 1 + call Request1bpp + call .ClearScreen + call WaitBGMap + call RotateFourPalettesRight + ld hl, OakTimeWokeUpText + call PrintText + ld hl, wTimeSetBuffer + ld bc, wTimeSetBufferEnd - wTimeSetBuffer + xor a + call ByteFill + ld a, 10 ; default hour = 10 AM + ld [wInitHourBuffer], a + +.loop + ld hl, OakTimeWhatTimeIsItText + call PrintText + hlcoord 3, 7 + lb bc, 2, 15 + call Textbox + hlcoord 11, 7 + ld [hl], $1 + hlcoord 11, 10 + ld [hl], $2 + hlcoord 4, 9 + call DisplayHourOClock + ld c, 10 + call DelayFrames + +.SetHourLoop: + call JoyTextDelay + call SetHour + jr nc, .SetHourLoop + + ld a, [wInitHourBuffer] + ld [wStringBuffer2 + 1], a + call .ClearScreen + ld hl, OakTimeWhatHoursText + call PrintText + call YesNoBox + jr nc, .HourIsSet + call .ClearScreen + jr .loop + +.HourIsSet: + ld hl, OakTimeHowManyMinutesText + call PrintText + hlcoord 11, 7 + lb bc, 2, 7 + call Textbox + hlcoord 15, 7 + ld [hl], $1 + hlcoord 15, 10 + ld [hl], $2 + hlcoord 12, 9 + call DisplayMinutesWithMinString + ld c, 10 + call DelayFrames + +.SetMinutesLoop: + call JoyTextDelay + call SetMinutes + jr nc, .SetMinutesLoop + + ld a, [wInitMinuteBuffer] + ld [wStringBuffer2 + 2], a + call .ClearScreen + ld hl, OakTimeWhoaMinutesText + call PrintText + call YesNoBox + jr nc, .MinutesAreSet + call .ClearScreen + jr .HourIsSet + +.MinutesAreSet: + call InitTimeOfDay + ld hl, OakText_ResponseToSetTime + call PrintText + call WaitPressAorB_BlinkCursor + pop af + ldh [hInMenu], a + ret + +.ClearScreen: + xor a + ldh [hBGMapMode], a + hlcoord 0, 0 + ld bc, SCREEN_HEIGHT * SCREEN_WIDTH + xor a + call ByteFill + ld a, $1 + ldh [hBGMapMode], a + ret + +SetHour: + ldh a, [hJoyPressed] + and A_BUTTON + jr nz, .Confirm + + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .up + ld a, [hl] + and D_DOWN + jr nz, .down + call DelayFrame + and a + ret + +.down + ld hl, wInitHourBuffer + ld a, [hl] + and a + jr nz, .DecreaseThroughMidnight + ld a, 23 + 1 +.DecreaseThroughMidnight: + dec a + ld [hl], a + jr .okay + +.up + ld hl, wInitHourBuffer + ld a, [hl] + cp 23 + jr c, .AdvanceThroughMidnight + ld a, -1 +.AdvanceThroughMidnight: + inc a + ld [hl], a + +.okay + hlcoord 4, 9 + ld a, " " + ld bc, 15 + call ByteFill + hlcoord 4, 9 + call DisplayHourOClock + call WaitBGMap + and a + ret + +.Confirm: + scf + ret + +DisplayHourOClock: + push hl + ld a, [wInitHourBuffer] + ld c, a + ld e, l + ld d, h + call PrintHour + inc hl + ld de, String_oclock + call PlaceString + pop hl + ret + +UnreferencedFunction907ba: + ld h, d + ld l, e + push hl + call DisplayHourOClock + pop de + inc de + inc de + ld a, ":" + ld [de], a + inc de + push de + ld hl, 3 + add hl, de + ld a, [de] + inc de + ld [hli], a + ld a, [de] + ld [hl], a + pop hl + call DisplayMinutesWithMinString + inc hl + inc hl + inc hl + ret + +SetMinutes: + ldh a, [hJoyPressed] + and A_BUTTON + jr nz, .a_button + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .d_up + ld a, [hl] + and D_DOWN + jr nz, .d_down + call DelayFrame + and a + ret + +.d_down + ld hl, wInitMinuteBuffer + ld a, [hl] + and a + jr nz, .decrease + ld a, 59 + 1 +.decrease + dec a + ld [hl], a + jr .finish_dpad + +.d_up + ld hl, wInitMinuteBuffer + ld a, [hl] + cp 59 + jr c, .increase + ld a, -1 +.increase + inc a + ld [hl], a +.finish_dpad + hlcoord 12, 9 + ld a, " " + ld bc, 7 + call ByteFill + hlcoord 12, 9 + call DisplayMinutesWithMinString + call WaitBGMap + and a + ret +.a_button + scf + ret + +DisplayMinutesWithMinString: + ld de, wInitMinuteBuffer + call PrintTwoDigitNumberLeftAlign + inc hl + ld de, String_min + call PlaceString + ret + +PrintTwoDigitNumberLeftAlign: + push hl + ld a, " " + ld [hli], a + ld [hl], a + pop hl + lb bc, PRINTNUM_LEFTALIGN | 1, 2 + call PrintNum + ret + +OakTimeWokeUpText: + text_far _OakTimeWokeUpText + text_end + +OakTimeWhatTimeIsItText: + text_far _OakTimeWhatTimeIsItText + text_end + +String_oclock: + db "o'clock@" + +OakTimeWhatHoursText: + ; What?@ @ + text_far _OakTimeWhatHoursText + text_asm + hlcoord 1, 16 + call DisplayHourOClock + ld hl, .OakTimeHoursQuestionMarkText + ret + +.OakTimeHoursQuestionMarkText: + text_far _OakTimeHoursQuestionMarkText + text_end + +OakTimeHowManyMinutesText: + text_far _OakTimeHowManyMinutesText + text_end + +String_min: + db "min.@" + +OakTimeWhoaMinutesText: + ; Whoa!@ @ + text_far _OakTimeWhoaMinutesText + text_asm + hlcoord 7, 14 + call DisplayMinutesWithMinString + ld hl, .OakTimeMinutesQuestionMarkText + ret + +.OakTimeMinutesQuestionMarkText: + text_far _OakTimeMinutesQuestionMarkText + text_end + +OakText_ResponseToSetTime: + text_asm + decoord 1, 14 + ld a, [wInitHourBuffer] + ld c, a + call PrintHour + ld [hl], ":" + inc hl + ld de, wInitMinuteBuffer + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ld b, h + ld c, l + ld a, [wInitHourBuffer] + cp MORN_HOUR + jr c, .nite + cp DAY_HOUR + 1 + jr c, .morn + cp NITE_HOUR + jr c, .day +.nite + ld hl, .OakTimeSoDarkText + ret +.morn + ld hl, .OakTimeOversleptText + ret +.day + ld hl, .OakTimeYikesText + ret + +.OakTimeOversleptText: + text_far _OakTimeOversleptText + text_end + +.OakTimeYikesText: + text_far _OakTimeYikesText + text_end + +.OakTimeSoDarkText: + text_far _OakTimeSoDarkText + text_end + +TimeSetBackgroundGFX: +INCBIN "gfx/new_game/timeset_bg.1bpp" +TimeSetUpArrowGFX: +INCBIN "gfx/new_game/up_arrow.1bpp" +TimeSetDownArrowGFX: +INCBIN "gfx/new_game/down_arrow.1bpp" + +SetDayOfWeek: + ldh a, [hInMenu] + push af + ld a, $1 + ldh [hInMenu], a + ld de, TimeSetUpArrowGFX + ld hl, vTiles0 tile TIMESET_UP_ARROW + lb bc, BANK(TimeSetUpArrowGFX), 1 + call Request1bpp + ld de, TimeSetDownArrowGFX + ld hl, vTiles0 tile TIMESET_DOWN_ARROW + lb bc, BANK(TimeSetDownArrowGFX), 1 + call Request1bpp + xor a + ld [wTempDayOfWeek], a +.loop + hlcoord 0, 12 + lb bc, 4, 18 + call Textbox + call LoadStandardMenuHeader + ld hl, .OakTimeWhatDayIsItText + call PrintText + hlcoord 9, 3 + lb bc, 2, 9 + call Textbox + hlcoord 14, 3 + ld [hl], TIMESET_UP_ARROW + hlcoord 14, 6 + ld [hl], TIMESET_DOWN_ARROW + hlcoord 10, 5 + call .PlaceWeekdayString + call ApplyTilemap + ld c, 10 + call DelayFrames +.loop2 + call JoyTextDelay + call .GetJoypadAction + jr nc, .loop2 + call ExitMenu + call UpdateSprites + ld hl, .ConfirmWeekdayText + call PrintText + call YesNoBox + jr c, .loop + ld a, [wTempDayOfWeek] + ld [wStringBuffer2], a + call InitDayOfWeek + call LoadStandardFont + pop af + ldh [hInMenu], a + ret + +.GetJoypadAction: + ldh a, [hJoyPressed] + and A_BUTTON + jr z, .not_A + scf + ret + +.not_A + ld hl, hJoyLast + ld a, [hl] + and D_UP + jr nz, .d_up + ld a, [hl] + and D_DOWN + jr nz, .d_down + call DelayFrame + and a + ret + +.d_down + ld hl, wTempDayOfWeek + ld a, [hl] + and a + jr nz, .decrease + ld a, SATURDAY + 1 + +.decrease + dec a + ld [hl], a + jr .finish_dpad + +.d_up + ld hl, wTempDayOfWeek + ld a, [hl] + cp 6 + jr c, .increase + ld a, SUNDAY - 1 + +.increase + inc a + ld [hl], a + +.finish_dpad + xor a + ldh [hBGMapMode], a + hlcoord 10, 4 + lb bc, 2, 9 + call ClearBox + hlcoord 10, 5 + call .PlaceWeekdayString + call WaitBGMap + and a + ret + +.PlaceWeekdayString: + push hl + ld a, [wTempDayOfWeek] + ld e, a + ld d, 0 + ld hl, .WeekdayStrings + add hl, de + add hl, de + ld a, [hli] + ld d, [hl] + ld e, a + pop hl + call PlaceString + ret + +.WeekdayStrings: +; entries correspond to wCurDay constants (see constants/wram_constants.asm) + dw .Sunday + dw .Monday + dw .Tuesday + dw .Wednesday + dw .Thursday + dw .Friday + dw .Saturday + dw .Sunday + +.Sunday: db " SUNDAY@" +.Monday: db " MONDAY@" +.Tuesday: db " TUESDAY@" +.Wednesday: db "WEDNESDAY@" +.Thursday: db "THURSDAY@" +.Friday: db " FRIDAY@" +.Saturday: db "SATURDAY@" + +.OakTimeWhatDayIsItText: + text_far _OakTimeWhatDayIsItText + text_end + +.ConfirmWeekdayText: + text_asm + hlcoord 1, 14 + call .PlaceWeekdayString + ld hl, .OakTimeIsItText + ret + +.OakTimeIsItText: + text_far _OakTimeIsItText + text_end + +InitialSetDSTFlag: + ld a, [wDST] + set 7, a + ld [wDST], a + predef UpdateTimePredef + hlcoord 1, 14 + lb bc, 3, 18 + call ClearBox + ld hl, .Text + call PlaceHLTextAtBC + ret + +.Text: + text_asm + call UpdateTime + ldh a, [hHours] + ld b, a + ldh a, [hMinutes] + ld c, a + decoord 1, 14 + farcall PrintHoursMins + ld hl, .DSTIsThatOKText + ret + +.DSTIsThatOKText: + text_far _DSTIsThatOKText + text_end + +InitialClearDSTFlag: + ld a, [wDST] + res 7, a + ld [wDST], a + predef UpdateTimePredef + hlcoord 1, 14 + lb bc, 3, 18 + call ClearBox + ld hl, .Text + call PlaceHLTextAtBC + ret + +.Text: + text_asm + call UpdateTime + ldh a, [hHours] + ld b, a + ldh a, [hMinutes] + ld c, a + decoord 1, 14 + farcall PrintHoursMins + ld hl, .TimeAskOkayText + ret + +.TimeAskOkayText: + text_far _TimeAskOkayText + text_end + +MrChrono: + hlcoord 1, 14 + lb bc, 3, SCREEN_WIDTH - 2 + call ClearBox + ld hl, .Text + call PlaceHLTextAtBC + ret + +.Text: + text_asm + call UpdateTime + + hlcoord 1, 14 + ld [hl], "R" + inc hl + ld [hl], "T" + inc hl + ld [hl], " " + inc hl + + ld de, hRTCDayLo + call .PrintTime + + hlcoord 1, 16 + ld [hl], "D" + inc hl + ld [hl], "F" + inc hl + ld [hl], " " + inc hl + + ld de, wStartDay + call .PrintTime + + ld [hl], " " + inc hl + + ld a, [wDST] + bit 7, a + jr z, .off + + ld [hl], "O" + inc hl + ld [hl], "N" + inc hl + jr .done + +.off + ld [hl], "O" + inc hl + ld [hl], "F" + inc hl + ld [hl], "F" + inc hl + +.done + ld hl, .NowOnDebug + ret + +.NowOnDebug: + text "<PARA>Now on DEBUG…" + prompt + +.PrintTime: + lb bc, 1, 3 + call PrintNum + ld [hl], "." + inc hl + inc de + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ld [hl], ":" + inc hl + inc de + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret + +PrintHour: + ld l, e + ld h, d + push bc + call GetTimeOfDayString + call PlaceString + ld l, c + ld h, b + inc hl + pop bc + call AdjustHourForAMorPM + ld [wDeciramBuffer], a + ld de, wDeciramBuffer + call PrintTwoDigitNumberLeftAlign + ret + +GetTimeOfDayString: + ld a, c + cp MORN_HOUR + jr c, .nite + cp DAY_HOUR + jr c, .morn + cp NITE_HOUR + jr c, .day +.nite + ld de, .nite_string + ret +.morn + ld de, .morn_string + ret +.day + ld de, .day_string + ret + +.nite_string: db "NITE@" +.morn_string: db "MORN@" +.day_string: db "DAY@" + +AdjustHourForAMorPM: +; Convert the hour stored in c (0-23) to a 1-12 value + ld a, c + or a + jr z, .midnight + cp NOON_HOUR + ret c + ret z + sub NOON_HOUR + ret + +.midnight + ld a, NOON_HOUR + ret diff --git a/engine/sine.asm b/engine/sine.asm deleted file mode 100644 index e22d785a..00000000 --- a/engine/sine.asm +++ /dev/null @@ -1,40 +0,0 @@ -_Sine:: ; 8ac9 (2:4ac9) - ld a, e - and $3f - cp $20 - jr nc, .negative - call .GetSine - ld a, h - ret -.negative - and $1f - call .GetSine - ld a, h - xor $ff - inc a - ret - -.GetSine: ; 8adf (2:4adf) - 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 -.loop - srl a - jr nc, .no_add - add hl, de -.no_add - sla e - rl d - and a - jr nz, .loop - ret - -.SineWave: - sine_table $100 diff --git a/engine/smallflag.asm b/engine/smallflag.asm new file mode 100644 index 00000000..04cbfcc2 --- /dev/null +++ b/engine/smallflag.asm @@ -0,0 +1,71 @@ +SmallFarFlagAction: +; Perform action b on bit c in flag array hl. +; If checking a flag, check flag array d:hl unless d is 0. + +; For longer flag arrays, see FlagAction. + + push hl + push bc + +; Divide by 8 to get the byte we want. + push bc + srl c + srl c + srl c + ld b, 0 + add hl, bc + pop bc + +; Which bit we want from the byte + ld a, c + and 7 + ld c, a + +; Shift left until we can mask the bit + ld a, 1 + jr z, .shifted +.shift + add a + dec c + jr nz, .shift +.shifted + ld c, a + +; What are we doing to this flag? + dec b + jr z, .set ; 1 = SET_FLAG + dec b + jr z, .check ; 2 = CHECK_FLAG +; 0 = RESET_FLAG + +.reset + ld a, c + cpl + and [hl] + ld [hl], a + jr .done + +.set + ld a, [hl] + or c + ld [hl], a + jr .done + +.check + ld a, d + cp 0 + jr nz, .farcheck + + ld a, [hl] + and c + jr .done + +.farcheck + call GetFarByte + and c + +.done + pop bc + pop hl + ld c, a + ret diff --git a/engine/specials.asm b/engine/specials.asm deleted file mode 100755 index ad6c2085..00000000 --- a/engine/specials.asm +++ /dev/null @@ -1,572 +0,0 @@ -Special:: ; c22b - ld hl, SpecialsPointers ; $4239 - add hl, de - add hl, de - add hl, de - ld b, [hl] - inc hl - ld a, [hli] - ld h, [hl] - ld l, a - ld a, b - rst FarCall - ret - -; Special routines can be used with the "special" map script command. -; They often use wScriptVar for arguments and return values. - -add_special: MACRO -; Some ROM0 specials have a nonzero bank. -\1Special:: -IF _NARG == 1 - dba \1 -ELSE - dbw \2, \1 -ENDC -ENDM - -SpecialsPointers: - add_special WarpToSpawnPoint - -; Communications - add_special SetBitsForLinkTradeRequest - add_special WaitForLinkedFriend - add_special CheckLinkTimeout - add_special TryQuickSave - add_special CheckBothSelectedSameRoom - add_special FailedLinkToPast - add_special CloseLink - add_special WaitForOtherPlayerToExit - add_special SetBitsForBattleRequest - add_special SetBitsForTimeCapsuleRequest - add_special CheckTimeCapsuleCompatibility - add_special EnterTimeCapsule - add_special TradeCenter - add_special Colosseum - add_special TimeCapsule - add_special CableClubCheckWhichChris - add_special CheckMysteryGift - add_special GetMysteryGiftItem - add_special UnlockMysteryGift - -; Map events - add_special BugContestJudging - add_special CheckPartyFullAfterContest - add_special ContestDropOffMons - add_special ContestReturnMons - add_special GiveParkBalls - add_special CheckMagikarpLength - add_special MagikarpHouseSign - add_special HealParty - add_special PokemonCenterPC - add_special PlayersHousePC - add_special DayCareMan - add_special DayCareLady - add_special DayCareManOutside - add_special MoveDeletion - add_special BankOfMom - add_special MagnetTrain - add_special NameRival - add_special SetDayOfWeek - add_special OverworldTownMap - add_special UnownPrinter - add_special MapRadio - add_special UnownPuzzle - add_special SlotMachine - add_special CardFlip - add_special DummyNonfunctionalGameCornerGame - add_special ClearBGPalettesBufferScreen - add_special FadeOutPalettes - add_special FadeBlackQuickly - add_special FadeInPalettes - add_special FadeInQuickly - add_special ReloadSpritesNoPalettes, $02 - add_special ClearBGPalettes - add_special UpdateTimePals - add_special ClearTilemap - add_special UpdateSprites - add_special ReplacePlayerSprite - add_special GameCornerPrizeMonCheckDex - add_special UnusedSetSeenMon - add_special WaitSFX, $03 - add_special PlayMapMusic - add_special RestartMapMusic - add_special HealMachineAnim - add_special SurfStartStep - add_special FindPartyMonAboveLevel - add_special FindPartyMonAtLeastThatHappy - add_special FindPartyMonThatSpecies - add_special FindPartyMonThatSpeciesYourTrainerID - add_special UnusedCheckUnusedTwoDayTimer - add_special DayCareMon1 - add_special DayCareMon2 - add_special SelectRandomBugContestContestants - add_special ActivateFishingSwarm - add_special ToggleMaptileDecorations - add_special ToggleDecorationsVisibility - add_special GiveShuckle - add_special ReturnShuckle - add_special BillsGrandfather - add_special CheckPokerus - add_special DisplayCoinCaseBalance - add_special DisplayMoneyAndCoinBalance - add_special PlaceMoneyTopRight - add_special CheckForLuckyNumberWinners - add_special CheckLuckyNumberShowFlag - add_special ResetLuckyNumberShowFlag - add_special PrintTodaysLuckyNumber - add_special SelectApricornForKurt - add_special NameRater - add_special DisplayLinkRecord - add_special GetFirstPokemonHappiness - add_special CheckFirstMonIsEgg - add_special RandomUnseenWildMon - add_special RandomPhoneWildMon - add_special RandomPhoneMon - add_special LoadUsedSpritesGFX - add_special PlaySlowCry - add_special SnorlaxAwake - add_special YoungerHaircutBrother - add_special OlderHaircutBrother - add_special DaisysGrooming - add_special PlayCurMonCry - add_special ProfOaksPCBoot - add_special GameboyCheck - add_special TrainerHouse - add_special PhotoStudio - add_special InitRoamMons - add_special FadeOutMusic - add_special Diploma - add_special PrintDiploma - add_special InitialSetDSTFlag - add_special InitialClearDSTFlag - add_special MrChrono - add_special SpecialNone - -SpecialNone: ; c389 - ret - -GameCornerPrizeMonCheckDex: ; c38a - ld a, [wScriptVar] - dec a - call CheckCaughtMon - ret nz - ld a, [wScriptVar] - dec a - call SetSeenAndCaughtMon - call FadeToMenu - ld a, [wScriptVar] - ld [wd151], a - farcall NewPokedexEntry - call ExitAllMenus - ret - -UnusedSetSeenMon: ; c3ac - ld a, [wScriptVar] - dec a - call SetSeenMon - ret - -FindPartyMonAboveLevel: ; c3b4 - ld a, [wScriptVar] - ld b, a - farcall PartySearch_MaximumLevel ; same bank - jr z, asm_c3f2 - jr asm_c3ec - -FindPartyMonAtLeastThatHappy: ; c3c2 - ld a, [wScriptVar] - ld b, a - farcall PartySearch_MinimumHappiness ; same bank - jr z, asm_c3f2 - jr asm_c3ec - -FindPartyMonThatSpecies: ; c3d0 - ld a, [wScriptVar] - ld b, a - farcall PartySearch_SameSpecies ; same bank - jr z, asm_c3f2 - jr asm_c3ec - -FindPartyMonThatSpeciesYourTrainerID: ; c3de - ld a, [wScriptVar] - ld b, a - farcall PartySearch_SameSpeciesAndYourID ; same bank - jr z, asm_c3f2 - jr asm_c3ec - -asm_c3ec - ld a, $1 - ld [wScriptVar], a - ret - -asm_c3f2 - xor a - ld [wScriptVar], a - ret - -NameRival: ; c3f7 - ld b, $2 - ld de, wRivalName - farcall NamingScreen_ - ld hl, wRivalName - ld de, .DefaultName - call InitName - ret - -.DefaultName: -IF DEF(GOLD) - db "SILVER@" -ENDC - -IF DEF(SILVER) - db "GOLD@" -ENDC - -NameRater: - farcall _NameRater - ret - -OverworldTownMap: ; c41a (3:441a) - call FadeToMenu - farcall Function9188a - call ExitAllMenus - ret - -UnownPrinter: ; c427 (3:4427) - call FadeToMenu - farcall Function16e3a - call ExitAllMenus - ret - -DisplayLinkRecord: ; c434 (3:4434) - call FadeToMenu - farcall Function3f55d - call ExitAllMenus - ret - -PlayersHousePC: ; c441 (3:4441) - xor a - ld [wScriptVar], a - farcall Function159b0 - ld a, c - ld [wScriptVar], a - ret - -CheckMysteryGift: ; c450 (3:4450) - ld a, $0 - call OpenSRAM - ld a, [$abe2] - and a - jr z, .asm_c45c - inc a -.asm_c45c - ld [wScriptVar], a - call CloseSRAM - ret - -GetMysteryGiftItem: ; c463 (3:4463) - ld a, $0 - call OpenSRAM - ld a, [$abe2] - ld [wd002], a - ld a, $1 - ld [wItemQuantityChangeBuffer], a - ld hl, wNumItems - call ReceiveItem - jr nc, .asm_c497 - xor a - ld [$abe2], a - call CloseSRAM - ld a, [wd002] - ld [wd151], a - call GetItemName - ld hl, ReceivedMysteryGiftText ; $449f - call PrintText - ld a, $1 - ld [wScriptVar], a - ret - -.asm_c497 - call CloseSRAM - xor a - ld [wScriptVar], a - ret - -ReceivedMysteryGiftText: - text_far ReceivedMysteryGiftText_ - db "@" - -BugContestJudging: ; c4a4 (3:44a4) - farcall Function13a5f - ld a, b - ld [wScriptVar], a - ret - -MapRadio: ; c4af (3:44af) - ld a, [wScriptVar] - ld e, a - farcall Function919c1 - ret - -UnownPuzzle: ; c4ba (3:44ba) - call FadeToMenu - farcall Functione199d - ld a, [wFieldMoveSucceeded] - ld [wScriptVar], a - call ExitAllMenus - ret - -SlotMachine: ; c4cd (3:44cd) - call Functionc508 - ret c - ld a, BANK(Function92c36) - ld hl, Function92c36 - call Functionc4f4 - ret - -CardFlip: ; c4da (3:44da) - call Functionc508 - ret c - ld a, BANK(Functione0909) - ld hl, Functione0909 - call Functionc4f4 - ret - -DummyNonfunctionalGameCornerGame: ; c4e7 (3:44e7) - call Functionc508 - ret c - ld a, BANK(Functione2668) - ld hl, Functione2668 - call Functionc4f4 - ret - -Functionc4f4: ; c4f4 (3:44f4) - call FarQueueScript - call FadeToMenu - ld hl, wQueuedScriptBank - ld a, [hli] - push af - ld a, [hli] - ld h, [hl] - ld l, a - pop af - rst FarCall - call ExitAllMenus - ret - -Functionc508: ; c508 (3:4508) - ld hl, wCoins - ld a, [hli] - or [hl] - jr z, .asm_c51e - ld a, COIN_CASE - ld [wd002], a - ld hl, wNumItems - call CheckItem - jr nc, .asm_c523 - and a - ret - -.asm_c51e - ld hl, .NoCoinsText - jr .asm_c526 - -.asm_c523 - ld hl, .NoCoinCaseText -.asm_c526 - call PrintText - scf - ret - -.NoCoinsText: - text_far NoCoinsText_ - db "@" - -.NoCoinCaseText: - text_far NoCoinCaseText_ - db "@" - -ClearBGPalettesBufferScreen: ; c535 (3:4535) - call ClearBGPalettes - call BufferScreen - ret - -Functionc53c: ; c53c (3:453c) - jr c, .asm_c543 - xor a - ld [wScriptVar], a - ret - -.asm_c543 - ld a, $1 - ld [wScriptVar], a - ret - -UnusedCheckUnusedTwoDayTimer: ; c549 (3:4549) - farcall Function118f8 - ld a, [wUnusedTwoDayTimer] - ld [wScriptVar], a - ret - -ActivateFishingSwarm: ; c556 (3:4556) - ld a, [wScriptVar] - ld [wFishingSwarmFlag], a - jr .asm_c566 - -.asm_c55e - ld a, d - ld [wDunsparceMapGroup], a - ld a, e - ld [wDunsparceMapNumber], a -.asm_c566 - SetFlag ENGINE_SPECIAL_WILDDATA - ret - -Functionc56c: - CheckFlagHL ENGINE_SPECIAL_WILDDATA - jr z, .asm_c578 - xor a - ld [wScriptVar], a - ret - -.asm_c578 - ld a, $1 - ld [wScriptVar], a - xor a - ld [wFishingSwarmFlag], a - ld [wDunsparceMapGroup], a - ld [wDunsparceMapNumber], a - ret - -CheckPokerus: ; c588 (3:4588) - farcall Functionc7a40 - jp Functionc53c - -ResetLuckyNumberShowFlag: ; c591 (3:4591) - farcall Function11917 - ClearFlag ENGINE_LUCKY_NUMBER_SHOW - farcall LoadOrRegenerateLuckyIDNumber - ret - -CheckLuckyNumberShowFlag: ; c5a3 (3:45a3) - farcall Function1192e - jp Functionc53c - -CountUnown: ; c5ac (3:45ac) - ld hl, wUnownDex - ld b, $0 -.asm_c5b1 - ld a, [hli] - and a - ret z - inc b - ld a, b - cp $1a - jr c, .asm_c5b1 - ret - -SelectApricornForKurt: ; c5bb (3:45bb) - farcall Function24b8d - ld a, c - ld [wScriptVar], a - and a - ret z - ld [wd002], a - ld a, $1 - ld [wItemQuantityChangeBuffer], a - ld hl, wNumItems - call TossItem - ret - -SnorlaxAwake: ; c5d6 (3:45d6) - ld a, [wChannelsEnd] - cp $40 - jr nz, .asm_c5fb - ld a, [wXCoord] - ld b, a - ld a, [wYCoord] - ld c, a - ld hl, .ProximityCoords -.asm_c5e8 - ld a, [hli] - cp $ff - jr z, .asm_c5fb - cp b - jr nz, .asm_c5f8 - ld a, [hli] - cp c - jr nz, .asm_c5e8 - ld a, $1 - jr .asm_c5fc - -.asm_c5f8 - inc hl - jr .asm_c5e8 - -.asm_c5fb - xor a -.asm_c5fc - ld [wScriptVar], a - ret - -.ProximityCoords: - ; x, y - db 33, 8 ; left - db 34, 10 ; below - db 35, 10 ; below - db 36, 8 ; right - db 36, 9 ; right - db -1 - -PlayCurMonCry: ; c60b (3:460b) - ld a, [wCurPartySpecies] - jp PlayMonCry - -GameboyCheck: ; c611 (3:4611) - ldh a, [hCGB] - and a - jr nz, .asm_c622 - ldh a, [hSGB] - and a - jr nz, .asm_c61e - xor a - jr .asm_c624 - -.asm_c61e - ld a, $1 - jr .asm_c624 - -.asm_c622 - ld a, $2 -.asm_c624 - ld [wScriptVar], a - ret - -FadeOutMusic: ; c628 (3:4628) - ld a, $0 - ld [wMusicFadeID], a - ld a, $0 - ld [wMusicFadeID + 1], a - ld a, $2 - ld [wMusicFade], a - ret - -Diploma: ; c638 (3:4638) - call FadeToMenu - farcall Functione0002 - call ExitAllMenus - ret - -PrintDiploma: ; c645 (3:4645) - call FadeToMenu - farcall Function84684 - call ExitAllMenus - ret - -TrainerHouse: ; c652 (3:4652) - ld a, $0 - call OpenSRAM - ld a, [$abfd] - ld [wScriptVar], a - jp CloseSRAM diff --git a/engine/step_types.asm b/engine/step_types.asm deleted file mode 100755 index 91858f98..00000000 --- a/engine/step_types.asm +++ /dev/null @@ -1,719 +0,0 @@ -StepTypesJumptable: ; 4b1e - dw ObjectMovementReset - dw MapObjectMovementPattern - dw Function4e02 - dw Function4db4 - dw Function4df8 - dw Function4de3 - dw Function4e2d - dw Function4e1e - dw Function4b5d - dw Function4b96 - dw Function4e5a - dw Function4dd6 - dw Function4bef - dw Function4c60 - dw Function4ceb - dw Function4ea4 - dw Function4d55 - dw Function4d86 - dw Function4d9f - dw Function4edb - dw Function4f0a - dw Function4f0a - dw Function4f4e - dw Function4f51 - dw Function4dc7 - -Function4b50: ; 4b50 (1:4b50) - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4b5d: ; 4b5d (1:4b5d) - call Object28AnonymousJumptable - dw Function4b64 - dw Function4b80 - -Function4b64: - call AddStepVector - call Function4f7d - ld hl, $a - add hl, bc - dec [hl] - ret nz - call CopyNextCoordsTileToStandingCoordsTile - call GetNextTile - ld hl, $5 - add hl, bc - res 3, [hl] - call IncrementObjectStructField28 - ret - -Function4b80: - call AddStepVector - call Function4f7d - ld hl, $a - add hl, bc - dec [hl] - ret nz - call CopyNextCoordsTileToStandingCoordsTile - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4b96: ; 4b96 (1:4b96) - call Object28AnonymousJumptable - dw Function4ba1 - dw Function4ba9 - dw Function4bc9 - dw Function4bd4 - -Function4ba1: - ld hl, wPlayerStepFlags - set 7, [hl] - call IncrementObjectStructField28 -Function4ba9: - call Function4f7d - call UpdatePlayerStep - ld hl, $a - add hl, bc - dec [hl] - ret nz - call CopyNextCoordsTileToStandingCoordsTile - ld hl, $5 - add hl, bc - res 3, [hl] - ld hl, wPlayerStepFlags - set 6, [hl] - set 4, [hl] - call IncrementObjectStructField28 - ret - -Function4bc9: - call GetNextTile - ld hl, wPlayerStepFlags - set 7, [hl] - call IncrementObjectStructField28 -Function4bd4: - call Function4f7d - call UpdatePlayerStep - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, wPlayerStepFlags - set 6, [hl] - call CopyNextCoordsTileToStandingCoordsTile - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4bef: ; 4bef (1:4bef) - call Object28AnonymousJumptable - dw Function4bfa - dw Function4c09 - dw Function4c19 - dw Function4c34 - -Function4bfa: - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $a - add hl, bc - ld [hl], $10 - call IncrementObjectStructField28 -Function4c09: - ld hl, $b - add hl, bc - ld [hl], $4 - ld hl, $a - add hl, bc - dec [hl] - ret nz - call IncrementObjectStructField28 - ret - -Function4c19: - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $1f - add hl, bc - ld [hl], $10 - ld hl, $a - add hl, bc - ld [hl], $10 - ld hl, $5 - add hl, bc - res 3, [hl] - call IncrementObjectStructField28 -Function4c34: - ld hl, $b - add hl, bc - ld [hl], $4 - ld hl, $1f - add hl, bc - inc [hl] - ld a, [hl] - ld d, $60 - call Sine - ld a, h - sub $60 - ld hl, $1a - add hl, bc - ld [hl], a - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4c60: ; 4c60 (1:4c60) - call Object28AnonymousJumptable - dw Function4c71 - dw Function4c81 - dw Function4c8a - dw Function4ca0 - dw Function4cc2 - dw Function4ccc - dw Function4cd8 - -Function4c71: - ld hl, $b - add hl, bc - ld [hl], $0 - ld hl, $a - add hl, bc - ld [hl], $10 - call IncrementObjectStructField28 - ret - -Function4c81: - ld hl, $a - add hl, bc - dec [hl] - ret nz - call IncrementObjectStructField28 -Function4c8a: - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $1f - add hl, bc - ld [hl], $0 - ld hl, $a - add hl, bc - ld [hl], $10 - call IncrementObjectStructField28 - ret - -Function4ca0: - ld hl, $b - add hl, bc - ld [hl], $4 - ld hl, $1f - add hl, bc - inc [hl] - ld a, [hl] - ld d, $60 - call Sine - ld a, h - sub $60 - ld hl, $1a - add hl, bc - ld [hl], a - ld hl, $a - add hl, bc - dec [hl] - ret nz - call IncrementObjectStructField28 -Function4cc2: - ld hl, $a - add hl, bc - ld [hl], $10 - call IncrementObjectStructField28 - ret - -Function4ccc: - ld hl, $b - add hl, bc - ld [hl], $4 - ld hl, $a - add hl, bc - dec [hl] - ret nz -Function4cd8: - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $1a - add hl, bc - ld [hl], $0 - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4ceb: ; 4ceb (1:4ceb) - call Object28AnonymousJumptable - dw Function4cf6 - dw Function4d05 - dw Function4d26 - dw Function4d42 - -Function4cf6: - ld hl, $b - add hl, bc - ld [hl], $0 - ld hl, $a - add hl, bc - ld [hl], $10 - call IncrementObjectStructField28 -Function4d05: - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $b - add hl, bc - ld [hl], $2 - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $1f - add hl, bc - ld [hl], $0 - ld hl, $a - add hl, bc - ld [hl], $10 - call IncrementObjectStructField28 -Function4d26: - ld hl, $1f - add hl, bc - inc [hl] - ld a, [hl] - ld d, $60 - call Sine - ld a, h - sub $60 - ld hl, $1a - add hl, bc - ld [hl], a - ld hl, $a - add hl, bc - dec [hl] - ret nz - call IncrementObjectStructField28 -Function4d42: - ld hl, $c - add hl, bc - ld [hl], $0 - ld hl, $1a - add hl, bc - ld [hl], $0 - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4d55: ; 4d55 (1:4d55) - call Object28AnonymousJumptable - dw Function4d5c - dw Function4d6b - -Function4d5c: - ld hl, $a - add hl, bc - ld [hl], $8 - ld hl, $1a - add hl, bc - ld [hl], $0 - call IncrementObjectStructField28 -Function4d6b: - ld hl, $1a - add hl, bc - ld a, [hl] - xor $1 - ld [hl], a - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $1a - add hl, bc - ld [hl], $0 - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4d86: ; 4d86 (1:4d86) - call Function4d8c - jp Function4b50 - -Function4d8c: ; 4d8c (1:4d8c) - ld hl, $a - add hl, bc - ld a, [hl] - and $1 - ld a, $1 - jr z, .asm_4d99 - ld a, $0 -.asm_4d99 - ld hl, $b - add hl, bc - ld [hl], a - ret - -Function4d9f: ; 4d9f (1:4d9f) - ld hl, $a - add hl, bc - ld a, [hl] - and $1 - ld a, $4 - jr z, .asm_4dac - ld a, $5 -.asm_4dac - ld hl, $b - add hl, bc - ld [hl], a - jp Function4b50 - -Function4db4: ; 4db4 (1:4db4) - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4dc7: ; 4dc7 (1:4dc7) - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $a - add hl, bc - dec [hl] - ret nz - jp DeleteMapObject - -Function4dd6: ; 4dd6 (1:4dd6) - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4de3: ; 4de3 (1:4de3) - call Object28AnonymousJumptable - dw Function4dea - dw Function4df8 - -Function4dea: - call RestoreDefaultMovement - call GetInitialFacing - ld hl, $8 - add hl, bc - ld [hl], a - call IncrementObjectStructField28 -Function4df8: ; 4df8 (1:4df8) - call Function4f5a - ld hl, $7 - add hl, bc - ld [hl], $ff - ret - -Function4e02: ; 4e02 (1:4e02) - call Function4f5a - call AddStepVector - ld hl, $a - add hl, bc - dec [hl] - ret nz - call CopyNextCoordsTileToStandingCoordsTile - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4e1e: ; 4e1e (1:4e1e) - call AddStepVector - ld hl, $a - add hl, bc - dec [hl] - ret nz - call CopyNextCoordsTileToStandingCoordsTile - jp Function4af6 - -Function4e2d: ; 4e2d (1:4e2d) - call Object28AnonymousJumptable - dw Function4e34 - dw Function4e3c - -Function4e34: - ld hl, wPlayerStepFlags - set 7, [hl] - call IncrementObjectStructField28 -Function4e3c: - call UpdatePlayerStep - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, wPlayerStepFlags - set 6, [hl] - call CopyNextCoordsTileToStandingCoordsTile - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4e5a: ; 4e5a (1:4e5a) - call Object28AnonymousJumptable - dw Function4e65 - dw Function4e7b - dw Function4e84 - dw Function4e97 - -Function4e65: - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $c - add hl, bc - ld a, [hl] - ld [hl], $2 - ld hl, $a - add hl, bc - ld [hl], $2 - call IncrementObjectStructField28 -Function4e7b: - ld hl, $a - add hl, bc - dec [hl] - ret nz - call IncrementObjectStructField28 -Function4e84: - ld hl, $1d - add hl, bc - ld a, [hl] - ld hl, $8 - add hl, bc - ld [hl], a - ld hl, $a - add hl, bc - ld [hl], $2 - call IncrementObjectStructField28 -Function4e97: - ld hl, $a - add hl, bc - dec [hl] - ret nz - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4ea4: ; 4ea4 (1:4ea4) - call AddStepVector - ld hl, $a - add hl, bc - dec [hl] - ret nz - push bc - ld hl, $10 - add hl, bc - ld d, [hl] - ld hl, $11 - add hl, bc - ld e, [hl] - ld hl, $1 - add hl, bc - ld a, [hl] - ld b, a - farcall CopyDECoordsToMapObject - pop bc - ld hl, $5 - add hl, bc - res 2, [hl] - call CopyNextCoordsTileToStandingCoordsTile - ld hl, $7 - add hl, bc - ld [hl], $ff - ld hl, $9 - add hl, bc - ld [hl], $1 - ret - -Function4edb: ; 4edb (1:4edb) - ld hl, $1d - add hl, bc - ld e, [hl] - inc hl - ld d, [hl] - ld hl, $0 - add hl, de - ld a, [hl] - and a - jr z, .asm_4f07 - ld hl, $17 - add hl, de - ld a, [hl] - ld hl, $17 - add hl, bc - ld [hl], a - ld hl, $18 - add hl, de - ld a, [hl] - ld hl, $18 - add hl, bc - ld [hl], a - ld hl, $a - add hl, bc - ld a, [hl] - and a - ret z - dec [hl] - ret nz -.asm_4f07 - jp DeleteMapObject - -Function4f0a: ; 4f0a (1:4f0a) - call Object28AnonymousJumptable - dw Function4f11 - dw Function4f1a - -Function4f11: - xor a - ld hl, $1d - add hl, bc - ld [hl], a - call IncrementObjectStructField28 -Function4f1a: - ld hl, $1d - add hl, bc - ld d, [hl] - ld a, [wPlayerStepVectorY] - sub d - ld [wPlayerStepVectorY], a - ld hl, $a - add hl, bc - dec [hl] - jr z, .asm_4f3f - ld a, [hl] - call Function4f43 - ld hl, $1d - add hl, bc - ld [hl], a - ld d, a - ld a, [wPlayerStepVectorY] - add d - ld [wPlayerStepVectorY], a - ret - -.asm_4f3f - call DeleteMapObject - ret - -Function4f43: ; 4f43 (1:4f43) - ld hl, $1e - add hl, bc - and $1 - ld a, [hl] - ret z - cpl - inc a - ret - -Function4f4e: ; 4f4e (1:4f4e) - call Object28AnonymousJumptable -Function4f51: ; 4f51 (1:4f51) - call Object28AnonymousJumptable - dw Function4f5a - dw Function4f5a - dw Function4f5a - -Function4f5a: ; 4f5a (1:4f5a) - ret - -Function4f5b: - ld hl, $1d - add hl, bc - inc [hl] - ld a, [hl] - srl a - srl a - and $7 - ld l, a - ld h, $0 - ld de, .data - add hl, de - ld a, [hl] - ld hl, $1a - add hl, bc - ld [hl], a - ret - -.data - db 0, -1, -2, -3, -4, -3, -2, -1 - -Function4f7d: ; 4f7d (1:4f7d) - call GetStepVector - ld a, h - ld hl, $1f - add hl, bc - ld e, [hl] - add e - ld [hl], a - nop - srl e - ld d, $0 - ld hl, .data - add hl, de - ld a, [hl] - ld hl, $1a - add hl, bc - ld [hl], a - ret - -.data - db -4, -6, -8, -10, -11, -12, -12, -12 - db -11, -10, -9, -8, -6, -4, 0, 0 - -Function4fa8: - ld a, [wce87] - ld hl, wce88 - ld [hl], a - ld a, $3e - ld [wce87], a - ld a, [hl] - ret diff --git a/engine/tilesets/map_palettes.asm b/engine/tilesets/map_palettes.asm new file mode 100644 index 00000000..858098e6 --- /dev/null +++ b/engine/tilesets/map_palettes.asm @@ -0,0 +1,110 @@ +_SwapTextboxPalettes:: + hlcoord 0, 0 + decoord 0, 0, wAttrmap + ld b, SCREEN_HEIGHT +.loop + ld c, SCREEN_WIDTH +.innerloop + ld a, [hli] + push hl + srl a + jr c, .UpperNybble + ld hl, wTilesetPalettes + add [hl] + ld l, a + ld a, [wTilesetPalettes + 1] + adc 0 + ld h, a + ld a, [hl] + and $f + bit 3, a + jr z, .next + jr .asm_8038 + +.UpperNybble: + ld hl, wTilesetPalettes + add [hl] + ld l, a + ld a, [wTilesetPalettes + 1] + adc 0 + ld h, a + ld a, [hl] + swap a + and $f + bit 3, a + jr z, .next + +.asm_8038 + ld a, [wMapGroup] + dec a + ld hl, Unknown85d7 + add l + ld l, a + jr nc, .asm_8044 + inc h +.asm_8044 + ld a, [hl] + +.next + pop hl + ld [de], a + inc de + dec c + jr nz, .innerloop + dec b + jr nz, .loop + ret + +_ScrollBGMapPalettes:: + ld hl, wBGMapBuffer + ld de, wBGMapPalBuffer +.loop + ld a, [hli] + push hl + srl a + jr c, .UpperNybble + +; .LowerNybble + ld hl, wTilesetPalettes + add [hl] + ld l, a + ld a, [wTilesetPalettes + 1] + adc 0 + ld h, a + ld a, [hl] + and $f + bit 3, a + jr z, .next + jr .asm_8083 + +.UpperNybble: + ld hl, wTilesetPalettes + add [hl] + ld l, a + ld a, [wTilesetPalettes + 1] + adc 0 + ld h, a + ld a, [hl] + swap a + and $f + bit 3, a + jr z, .next + +.asm_8083 + ld a, [wMapGroup] + dec a + ld hl, Unknown85d7 + add l + ld l, a + jr nc, .asm_808f + inc h +.asm_808f + ld a, [hl] + +.next + pop hl + ld [de], a + inc de + dec c + jr nz, .loop + ret diff --git a/engine/title.asm b/engine/title.asm deleted file mode 100755 index 94863c56..00000000 --- a/engine/title.asm +++ /dev/null @@ -1,450 +0,0 @@ -IntroSequence: ; 6241 (1:6241) - callfar Copyright_GFPresents - jr c, StartTitleScreen - callfar GoldSilverIntro -StartTitleScreen: - call InitTitleScreen - call DelayFrame -.asm_6255 - call TitleScreenFrame - jr nc, .asm_6255 - call ClearSprites - call ClearBGPalettes - ld hl, rLCDC - res 2, [hl] - call ClearTilemap - xor a - ldh [hLCDCPointer], a - ld b, $8 - call GetSGBLayout - call UpdateTimePals - ld a, [wce64] - cp $5 - jr c, .asm_627b - xor a -.asm_627b - 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 - -.Jumptable - dw MainMenu_ - dw DeleteSaveData - dw IntroSequence - dw IntroSequence - dw ResetClock - -InitTitleScreen: ; 6291 (1:6291) - call ClearBGPalettes - xor a - ld [wTimeOfDayPal], a - ld de, MUSIC_NONE - call PlayMusic - call ClearTilemap - call DisableLCD - call ClearSprites - xor a - ldh [hBGMapMode], a - ldh [hMapAnims], a - ldh [hSCY], a - ldh [hSCX], a - ld hl, $8000 - ld bc, $2000 - xor a - call ByteFill - farcall ClearAnimatedObjectBuffer - - ld hl, TitleScreenGFX1 - ld de, $9000 - ld a, BANK(TitleScreenGFX1) - call FarDecompress - - ld hl, TitleScreenGFX2 - ld de, $8800 - ld a, BANK(TitleScreenGFX2) - call FarDecompress - - ld hl, TitleScreenGFX4 - ld de, $8000 - ld a, BANK(TitleScreenGFX4) - call FarDecompress - - ld hl, TitleScreenGFX3 - ld de, $8f80 - ld bc, $80 - ld a, BANK(TitleScreenGFX3) - call FarCopyBytes - - call Function636e - call Function63b6 - ld hl, wAnimatedObjectDynamicVTileOffsets - xor a - ld [hli], a - ld [hl], a - ld hl, rLCDC - set 2, [hl] - call EnableLCD - xor a - ld hl, wce63 - ld [hli], a - ld [hli], a - ld [hli], a - ld [hl], a - ld de, $6058 - ld a, $2c ; HO-OH - call InitSpriteAnimStruct - ld hl, wAnimatedObjectStruct1 - ld de, wAnimatedObjectStruct10 - ld bc, $a - call CopyBytes - ld hl, wAnimatedObjectStruct1 - ld [hl], $0 - ld hl, wc700 - ld bc, $90 - xor a - call ByteFill - ld a, $43 - ldh [hLCDCPointer], a - ld b, $c - call GetSGBLayout - call Function6341 - ld de, MUSIC_TITLE - call PlayMusic - ret - -Function6341: ; 6341 (1:6341) - ldh a, [hCGB] - and a - jr nz, .asm_6365 - ldh a, [hSGB] - and a - jr nz, .asm_6358 - ld a, $d8 - ldh [rBGP], a -IF DEF(GOLD) - ld a, $ff - ldh [rOBP0], a - ld a, $f8 -ENDC -IF DEF(SILVER) - ld a, $f0 - ldh [rOBP0], a - ld a, $f0 -ENDC - ldh [rOBP1], a - ret - -.asm_6358 - ld a, $e4 - ldh [rBGP], a -IF DEF(GOLD) - ld a, $ff - ldh [rOBP0], a - ld a, $e4 -ENDC -IF DEF(SILVER) - ld a, $f0 - ldh [rOBP0], a - ld a, $e0 -ENDC - ldh [rOBP1], a - ret - -.asm_6365 - ld a, $e4 - call DmgToCgbBGPals -IF DEF(SILVER) - ld a, $e0 -ENDC - call DmgToCgbObjPal0 - ret - -Function636e: ; 636e (1:636e) - ldh a, [hCGB] - and a - ret z - ld a, $1 - ldh [rVBK], a - ld hl, $9800 - ld bc, $240 - xor a - call ByteFill - ld hl, $9800 - ld bc, $714 - ld a, $1 - call Function63a6 - ld hl, $98c5 - ld bc, $10a - ld a, $3 - call Function63a6 - ld hl, $9980 - ld bc, $a0 - ld a, $4 - call ByteFill - ld a, $0 - ldh [rVBK], a - ret - -Function63a6: ; 63a6 (1:63a6) - push bc - push hl -.asm_63a8 - ld [hli], a - dec c - jr nz, .asm_63a8 - pop hl - ld bc, $20 - add hl, bc - pop bc - dec b - jr nz, Function63a6 - ret - -Function63b6: ; 63b6 (1:63b6) - ld hl, GSIntroTilemap ; $4616 - ld de, $9800 -.asm_63bc - ld a, BANK(GSIntroTilemap) ; $26 - call GetFarByte - cp $ff - jr z, .asm_63ca - inc hl - ld [de], a - inc de - jr .asm_63bc - -.asm_63ca - ldh a, [hCGB] - and a - ret nz - ld hl, $9960 - ld bc, $20 - ld a, $50 - call ByteFill - ret - -TitleScreenFrame: ; 63da (1:63da) - call Function63fe - ld a, [wce63] - bit 7, a - jr nz, .asm_63fc - call Function640f - ld a, $1 - ldh [hOAMUpdate], a - farcall AnimatedObjects_PlayFrame - xor a - ldh [hOAMUpdate], a - call Function64b1 - call DelayFrame - and a - ret - -.asm_63fc - scf - ret - -Function63fe: ; 63fe (1:63fe) -IF DEF(GOLD) - ldh a, [hVBlankCounter] - and $7 - ret nz -ENDC - ld hl, wc75f - ld a, [hl] - dec a - ld bc, $28 - call ByteFill - ret - -Function640f: ; 640f (1:640f) - ld e, a - ld d, $0 - ld hl, .Jumptable ; $641b - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - jp hl - -.Jumptable - dw Function6426 - dw Function6434 - dw Function648b - -Function6421: - ld hl, wce63 - inc [hl] - ret - -Function6426: - ld hl, wce63 - inc [hl] - ld hl, wce65 -IF DEF(GOLD) - ld de, $13c0 -ENDC -IF DEF(SILVER) - ld de, $1140 -ENDC - ld [hl], e - inc hl - ld [hl], d - ret - -Function6434: - ld hl, wce65 - ld e, [hl] - inc hl - ld d, [hl] - ld a, e - or d - jr z, .asm_646b - dec de - ld [hl], d - dec hl - ld [hl], e - call GetJoypad - ld hl, hJoyDown - ld a, [hl] - and D_UP + B_BUTTON + SELECT - cp D_UP + B_BUTTON + SELECT - jr z, .asm_6460 - ld a, [hl] - and D_DOWN + B_BUTTON + SELECT - cp D_DOWN + B_BUTTON + SELECT - jr z, .asm_6480 - ld a, [hl] - and START | A_BUTTON - jr nz, .asm_645c - ret - -.asm_645c - ld a, $0 - jr .asm_6462 - -.asm_6460 - ld a, $1 -.asm_6462 - ld [wce64], a - ld hl, wce63 - set 7, [hl] - ret - -.asm_646b - ld hl, wce63 - inc [hl] - xor a - ld [wMusicFadeID], a - ld [wMusicFadeID + 1], a - ld hl, wMusicFade - ld [hl], $8 - ld hl, wce65 - inc [hl] - ret - -.asm_6480 - ld a, $4 - ld [wce64], a - ld hl, wce63 - set 7, [hl] - ret - -Function648b: - ld hl, wce65 - inc [hl] - ld a, [wMusicFade] - and a - ret nz - ld a, $2 - ld [wce64], a - ld hl, wce63 - set 7, [hl] - ret - -DeleteSaveData: - farcall DeleteSaveData_ - jp Init - -ResetClock: - farcall ResetClock_ - jp Init - -Function64b1: ; 64b1 (1:64b1) - ld a, [wce65] - and $3 - ret nz -IF DEF(GOLD) - ld bc, wAnimatedObjectStruct10Index - ld hl, $a - add hl, bc - ld l, [hl] - ld h, $0 - add hl, hl - add hl, hl - ld de, .Data_64e0 - add hl, de - ld a, [wce65] - and $4 - srl a - srl a - ld e, a - ld d, $0 - add hl, de - add hl, de - ld a, [hli] - and a - ret z - ld e, a - ld d, [hl] -ENDC - -IF DEF(SILVER) - ld de, $7c58 -ENDC - ld a, $f - call InitSpriteAnimStruct - ret - -IF DEF(GOLD) -.Data_64e0: - db $5c, $50, $00, $00 - db $5c, $68, $5c, $58 - db $5c, $68, $5c, $78 - db $5c, $88, $5c, $78 - db $00, $00, $5c, $78 - db $00, $00, $5c, $58 -ENDC - -Copyright: - call ClearTilemap - call LoadFontsExtra - ld de, CopyrightGFX - ld hl, vTiles2 tile $60 - lb bc, BANK(CopyrightGFX), 30 - call Request2bpp - hlcoord 2, 7 - ld de, CopyrightString - jp PlaceString - -CopyrightString: - db $60, $61, $62, $63, $7a, $7b, $7c, $7d - db $65, $66, $67, $68, $69, $6a - next $60, $61, $62, $63, $7a, $7b, $7c, $7d - db $6b, $6c, $6d, $6e, $6f, $70, $71, $72 - next $60, $61, $62, $63, $7a, $7b, $7c, $7d - db $73, $74, $75, $76, $77, $78, $79, $71, $72 - db "@" - -GameInit:: ; 6545 (1:6545) - call ClearWindowData - ld a, $5 - ld hl, $4f60 - rst FarCall - jp IntroSequence diff --git a/engine/variables.asm b/engine/variables.asm deleted file mode 100755 index 7e6906ee..00000000 --- a/engine/variables.asm +++ /dev/null @@ -1,119 +0,0 @@ -GetVarAction_:: - ld a, c - cp NUM_VARS - jr c, .valid - xor a -.valid - ld c, a - ld b, 0 - ld hl, .VarActionTable - add hl, bc - add hl, bc - add hl, bc - ld e, [hl] - inc hl - ld d, [hl] - inc hl - ld b, [hl] - ld a, b - and RETVAR_EXECUTE - jr nz, .call - ld a, b - and RETVAR_ADDR_DE - ret nz - ld a, [de] - jr .loadstringbuffer2 - -.call - call _de_ - ret - -.loadstringbuffer2 - ld de, wStringBuffer2 - ld [de], a - ret - -.VarActionTable: - dwb wStringBuffer2, RETVAR_STRBUF2 - dwb wPartyCount, RETVAR_STRBUF2 - dwb .BattleResult, RETVAR_EXECUTE - dwb wBattleType, RETVAR_ADDR_DE - dwb wTimeOfDay, RETVAR_STRBUF2 - dwb .CountCaughtMons, RETVAR_EXECUTE - dwb .CountSeenMons, RETVAR_EXECUTE - dwb .CountBadges, RETVAR_EXECUTE - dwb wPlayerState, RETVAR_ADDR_DE - dwb .PlayerFacing, RETVAR_EXECUTE - dwb hHours, RETVAR_STRBUF2 - dwb .DayOfWeek, RETVAR_EXECUTE - dwb wMapGroup, RETVAR_STRBUF2 - dwb wMapNumber, RETVAR_STRBUF2 - dwb .UnownCaught, RETVAR_EXECUTE - dwb wPermission, RETVAR_STRBUF2 - dwb .BoxFreeSpace, RETVAR_EXECUTE - dwb wBugContestMinsRemaining, RETVAR_STRBUF2 - dwb wXCoord, RETVAR_STRBUF2 - dwb wYCoord, RETVAR_STRBUF2 - dwb wSpecialPhoneCallID, RETVAR_STRBUF2 - dwb 0, 0 - -.CountCaughtMons: ; 41cf -; Caught mons. - ld hl, wPokedexCaught - ld b, $20 - call CountSetBits - ld a, [wd151] - jp .loadstringbuffer2 - -.CountSeenMons: ; 41dd -; Seen mons. - ld hl, wPokedexSeen - ld b, $20 - call CountSetBits - ld a, [wd151] - jp .loadstringbuffer2 - -.CountBadges: ; 41eb -; Number of owned badges. - ld hl, wBadges - ld b, 2 - call CountSetBits - ld a, [wd151] - jp .loadstringbuffer2 - -.PlayerFacing: ; 41f9 -; The direction the player is facing. - ld a, [wPlayerDirection] - and $c - rrca - rrca - jp .loadstringbuffer2 - -.DayOfWeek: ; 4203 -; The day of the week. - call GetWeekday - jp .loadstringbuffer2 - -.UnownCaught: ; 4209 -; Number of unique Unown caught. - call CountUnown ; gold: c5ac | silver: c5aa - ld a, b - jp .loadstringbuffer2 - -.BoxFreeSpace: ; 4210 -; Remaining slots in the current box. - ld a, BANK(sBoxCount) - call OpenSRAM - ld hl, sBoxCount - ld a, MONS_PER_BOX - sub [hl] - ld b, a - call CloseSRAM - ld a, b - jp .loadstringbuffer2 - -.BattleResult: ; 4223 - ld a, [wBattleResult] - and $7f - jp .loadstringbuffer2 -; 422b |