diff options
Diffstat (limited to 'src')
36 files changed, 8128 insertions, 117 deletions
diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index c57825b4f..e66fdb2af 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_main.h" +#include "battle_anim.h" #include "util.h" #include "item.h" #include "random.h" diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index e871937e7..c19af4cb7 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -28,7 +28,7 @@ static u8 GetBattlerSpriteFinal_Y(u8 battlerId, u16 species, bool8 a3); static void sub_8075658(struct Sprite *sprite); static void sub_80757E8(struct Sprite *sprite); static bool8 sub_80758DC(void); -static void sub_8075EF0(struct Sprite *sprite); +static void AnimThrowProjectile_Step(struct Sprite *sprite); static void sub_80760D0(u8 taskId); static void AnimTask_BlendMonInAndOutSetup(struct Task *task); static void AnimTask_BlendMonInAndOutStep(u8 taskId); @@ -1336,7 +1336,7 @@ static u8 GetBattlerAtPosition_(u8 position) return GetBattlerAtPosition(position); } -void sub_8075D9C(struct Sprite *sprite) +void AnimSpriteOnMonPos(struct Sprite *sprite) { bool8 var; @@ -1390,7 +1390,7 @@ void TranslateAnimSpriteToTargetMonLocation(struct Sprite *sprite) StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); } -void sub_8075E80(struct Sprite *sprite) +void AnimThrowProjectile(struct Sprite *sprite) { InitSpritePosToAnimAttacker(sprite, 1); if (GetBattlerSide(gBattleAnimAttacker)) @@ -1400,10 +1400,10 @@ void sub_8075E80(struct Sprite *sprite) sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[3]; sprite->data[5] = gBattleAnimArgs[5]; InitAnimArcTranslation(sprite); - sprite->callback = sub_8075EF0; + sprite->callback = AnimThrowProjectile_Step; } -static void sub_8075EF0(struct Sprite *sprite) +static void AnimThrowProjectile_Step(struct Sprite *sprite) { if (TranslateAnimHorizontalArc(sprite)) DestroyAnimSprite(sprite); diff --git a/src/battle_controller_oak_old_man.c b/src/battle_controller_oak_old_man.c new file mode 100644 index 000000000..99391ab3e --- /dev/null +++ b/src/battle_controller_oak_old_man.c @@ -0,0 +1,2295 @@ +#include "global.h" +#include "task.h" +#include "pokemon.h" +#include "pokeball.h" +#include "party_menu.h" +#include "bg.h" +#include "data.h" +#include "palette.h" +#include "util.h" +#include "m4a.h" +#include "link.h" +#include "sound.h" +#include "item.h" +#include "item_menu.h" +#include "text.h" +#include "strings.h" +#include "string_util.h" +#include "window.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_controllers.h" +#include "battle_interface.h" +#include "battle_message.h" +#include "reshow_battle_screen.h" +#include "constants/songs.h" +#include "constants/items.h" + +static void OakOldManHandleGetMonData(void); +static void OakOldManHandleGetRawMonData(void); +static void OakOldManHandleSetMonData(void); +static void OakOldManHandleSetRawMonData(void); +static void OakOldManHandleLoadMonSprite(void); +static void OakOldManHandleSwitchInAnim(void); +static void OakOldManHandleReturnMonToBall(void); +static void OakOldManHandleDrawTrainerPic(void); +static void OakOldManHandleTrainerSlide(void); +static void OakOldManHandleTrainerSlideBack(void); +static void OakOldManHandleFaintAnimation(void); +static void OakOldManHandlePaletteFade(void); +static void OakOldManHandleSuccessBallThrowAnim(void); +static void OakOldManHandleBallThrowAnim(void); +static void OakOldManHandlePause(void); +static void OakOldManHandleMoveAnimation(void); +static void OakOldManHandlePrintString(void); +static void OakOldManHandlePrintSelectionString(void); +static void OakOldManHandleChooseAction(void); +static void OakOldManHandleUnknownYesNoBox(void); +static void OakOldManHandleChooseMove(void); +static void OakOldManHandleChooseItem(void); +static void OakOldManHandleChoosePokemon(void); +static void OakOldManHandleCmd23(void); +static void OakOldManHandleHealthBarUpdate(void); +static void OakOldManHandleExpUpdate(void); +static void OakOldManHandleStatusIconUpdate(void); +static void OakOldManHandleStatusAnimation(void); +static void OakOldManHandleStatusXor(void); +static void OakOldManHandleDataTransfer(void); +static void OakOldManHandleDMA3Transfer(void); +static void OakOldManHandlePlayBGM(void); +static void OakOldManHandleCmd32(void); +static void OakOldManHandleTwoReturnValues(void); +static void OakOldManHandleChosenMonReturnValue(void); +static void OakOldManHandleOneReturnValue(void); +static void OakOldManHandleOneReturnValue_Duplicate(void); +static void OakOldManHandleCmd37(void); +static void OakOldManHandleCmd38(void); +static void OakOldManHandleCmd39(void); +static void OakOldManHandleCmd40(void); +static void OakOldManHandleHitAnimation(void); +static void OakOldManHandleCmd42(void); +static void OakOldManHandlePlaySE(void); +static void OakOldManHandlePlayFanfare(void); +static void OakOldManHandleFaintingCry(void); +static void OakOldManHandleIntroSlide(void); +static void OakOldManHandleIntroTrainerBallThrow(void); +static void OakOldManHandleDrawPartyStatusSummary(void); +static void OakOldManHandleHidePartyStatusSummary(void); +static void OakOldManHandleEndBounceEffect(void); +static void OakOldManHandleSpriteInvisibility(void); +static void OakOldManHandleBattleAnimation(void); +static void OakOldManHandleLinkStandbyMsg(void); +static void OakOldManHandleResetActionMoveSelection(void); +static void OakOldManHandleCmd55(void); +static void OakOldManCmdEnd(void); + +static void OakOldManBufferRunCommand(void); +static void OakOldManBufferExecCompleted(void); +static void WaitForMonSelection(void); +static void CompleteWhenChoseItem(void); +static void sub_80E8704(void); +static void sub_80E7CD8(void); +static void sub_80E835C(void); +static void Task_LaunchLvlUpAnim(u8 taskId); +static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId); +static void CompleteOnInactiveTextPrinter2(void); +static void Task_PrepareToGiveExpWithExpBar(u8 taskId); +static void sub_80E804C(u8 taskId); +static void Task_UpdateLvlInHealthbox(u8 taskId); +static void sub_80E85D4(const u8 *text, u8 a1); +static u32 CopyOakOldManMonData(u8 monId, u8 *dst); +static void SetOakOldManMonData(u8 monId); +static void OakOldManDoMoveAnimation(void); +static void HandleInputChooseAction(void); +static void sub_80EB0A8(u8 taskId); + +static void (*const sOakOldManBufferCommands[CONTROLLER_CMDS_COUNT])(void) = +{ + OakOldManHandleGetMonData, + OakOldManHandleGetRawMonData, + OakOldManHandleSetMonData, + OakOldManHandleSetRawMonData, + OakOldManHandleLoadMonSprite, + OakOldManHandleSwitchInAnim, + OakOldManHandleReturnMonToBall, + OakOldManHandleDrawTrainerPic, + OakOldManHandleTrainerSlide, + OakOldManHandleTrainerSlideBack, + OakOldManHandleFaintAnimation, + OakOldManHandlePaletteFade, + OakOldManHandleSuccessBallThrowAnim, + OakOldManHandleBallThrowAnim, + OakOldManHandlePause, + OakOldManHandleMoveAnimation, + OakOldManHandlePrintString, + OakOldManHandlePrintSelectionString, + OakOldManHandleChooseAction, + OakOldManHandleUnknownYesNoBox, + OakOldManHandleChooseMove, + OakOldManHandleChooseItem, + OakOldManHandleChoosePokemon, + OakOldManHandleCmd23, + OakOldManHandleHealthBarUpdate, + OakOldManHandleExpUpdate, + OakOldManHandleStatusIconUpdate, + OakOldManHandleStatusAnimation, + OakOldManHandleStatusXor, + OakOldManHandleDataTransfer, + OakOldManHandleDMA3Transfer, + OakOldManHandlePlayBGM, + OakOldManHandleCmd32, + OakOldManHandleTwoReturnValues, + OakOldManHandleChosenMonReturnValue, + OakOldManHandleOneReturnValue, + OakOldManHandleOneReturnValue_Duplicate, + OakOldManHandleCmd37, + OakOldManHandleCmd38, + OakOldManHandleCmd39, + OakOldManHandleCmd40, + OakOldManHandleHitAnimation, + OakOldManHandleCmd42, + OakOldManHandlePlaySE, + OakOldManHandlePlayFanfare, + OakOldManHandleFaintingCry, + OakOldManHandleIntroSlide, + OakOldManHandleIntroTrainerBallThrow, + OakOldManHandleDrawPartyStatusSummary, + OakOldManHandleHidePartyStatusSummary, + OakOldManHandleEndBounceEffect, + OakOldManHandleSpriteInvisibility, + OakOldManHandleBattleAnimation, + OakOldManHandleLinkStandbyMsg, + OakOldManHandleResetActionMoveSelection, + OakOldManHandleCmd55, + OakOldManCmdEnd, +}; + +static void nullsub_81(void) +{ +} + +void SetControllerToOakOrOldMan(void) +{ + gBattlerControllerFuncs[gActiveBattler] = OakOldManBufferRunCommand; + gBattleStruct->field_94 = 0; + gBattleStruct->field_95 = 0; + gBattleStruct->field_96 = 0; + gBattleStruct->field_97 = 0; +} + +static void OakOldManBufferRunCommand(void) +{ + if (gBattleControllerExecFlags & gBitTable[gActiveBattler]) + { + if (gBattleBufferA[gActiveBattler][0] < ARRAY_COUNT(sOakOldManBufferCommands)) + sOakOldManBufferCommands[gBattleBufferA[gActiveBattler][0]](); + else + OakOldManBufferExecCompleted(); + } +} + +static void HandleInputChooseAction(void) +{ + u16 itemId = gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8); + + DoBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX, 7, 1); + DoBounceEffect(gActiveBattler, BOUNCE_MON, 7, 1); + if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + + switch (gActionSelectionCursor[gActiveBattler]) + { + case 0: + BtlController_EmitTwoReturnValues(1, B_ACTION_USE_MOVE, 0); + break; + case 1: + BtlController_EmitTwoReturnValues(1, B_ACTION_USE_ITEM, 0); + break; + case 2: + BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0); + break; + case 3: + BtlController_EmitTwoReturnValues(1, B_ACTION_RUN, 0); + break; + } + OakOldManBufferExecCompleted(); + } + else if (JOY_NEW(DPAD_LEFT)) + { + if (gActionSelectionCursor[gActiveBattler] & 1) // if is B_ACTION_USE_ITEM or B_ACTION_RUN + { + PlaySE(SE_SELECT); + ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); + gActionSelectionCursor[gActiveBattler] ^= 1; + ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); + } + } + else if (JOY_NEW(DPAD_RIGHT)) + { + if (!(gActionSelectionCursor[gActiveBattler] & 1)) // if is B_ACTION_USE_MOVE or B_ACTION_SWITCH + { + PlaySE(SE_SELECT); + ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); + gActionSelectionCursor[gActiveBattler] ^= 1; + ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); + } + } + else if (JOY_NEW(DPAD_UP)) + { + if (gActionSelectionCursor[gActiveBattler] & 2) // if is B_ACTION_SWITCH or B_ACTION_RUN + { + PlaySE(SE_SELECT); + ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); + gActionSelectionCursor[gActiveBattler] ^= 2; + ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); + } + } + else if (JOY_NEW(DPAD_DOWN)) + { + if (!(gActionSelectionCursor[gActiveBattler] & 2)) // if is B_ACTION_USE_MOVE or B_ACTION_USE_ITEM + { + PlaySE(SE_SELECT); + ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); + gActionSelectionCursor[gActiveBattler] ^= 2; + ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); + } + } + else if (JOY_NEW(B_BUTTON)) + { + if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + && GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT + && !(gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)]) + && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + if (gBattleBufferA[gActiveBattler][1] == B_ACTION_USE_ITEM) + { + // Add item to bag if it is a ball + if (itemId <= ITEM_PREMIER_BALL) + AddBagItem(itemId, 1); + else + return; + } + PlaySE(SE_SELECT); + BtlController_EmitTwoReturnValues(1, B_ACTION_CANCEL_PARTNER, 0); + OakOldManBufferExecCompleted(); + } + } + else if (JOY_NEW(START_BUTTON)) + { + SwapHpBarsWithHpText(); + } +} + +static void sub_80E7844(void) +{ + switch (gBattleStruct->field_94) + { + case 0: + gBattleStruct->field_96 = 64; + ++gBattleStruct->field_94; + // fall through + case 1: + if (--gBattleStruct->field_96 == 0) + { + PlaySE(SE_SELECT); + ActionSelectionDestroyCursorAt(0); + ActionSelectionCreateCursorAt(1, 0); + gBattleStruct->field_96 = 64; + ++gBattleStruct->field_94; + } + break; + case 2: + if (--gBattleStruct->field_96 == 0) + { + PlaySE(SE_SELECT); + BtlController_EmitTwoReturnValues(1, B_ACTION_USE_ITEM, 0); + OakOldManBufferExecCompleted(); + } + break; + } +} + +static void CompleteOnBattlerSpriteCallbackDummy(void) +{ + if (gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) + OakOldManBufferExecCompleted(); +} + +static void CompleteOnInactiveTextPrinter(void) +{ + if (!IsTextPrinterActive(0)) + OakOldManBufferExecCompleted(); +} + +static void sub_80E7930(void) +{ + if (!gPaletteFade.active) + { + gMain.inBattle = FALSE; + gMain.callback1 = gPreBattleCallback1; + SetMainCallback2(gMain.savedCallback); + } +} + +static void CompleteOnSpecialAnimDone(void) +{ + if (!gDoingBattleAnim) + OakOldManBufferExecCompleted(); +} + +void sub_80E7988(void) +{ + HandleInputChooseMove(); + if (!(gBattleControllerExecFlags & gBitTable[gActiveBattler])) + OakOldManBufferExecCompleted(); +} + +static void OpenPartyMenuToChooseMon(void) +{ + if (!gPaletteFade.active) + { + u8 caseId; + + gBattlerControllerFuncs[gActiveBattler] = WaitForMonSelection; + caseId = gTasks[gUnknown_3004FFC[gActiveBattler]].data[0]; + DestroyTask(gUnknown_3004FFC[gActiveBattler]); + FreeAllWindowBuffers(); + OpenPartyMenuInBattle(caseId); + } +} + +static void WaitForMonSelection(void) +{ + if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active) + { + if (gUnknown_203B0C0 == 1) + BtlController_EmitChosenMonReturnValue(1, gUnknown_203B0C1, gUnknown_203B0DC); + else + BtlController_EmitChosenMonReturnValue(1, 6, NULL); + OakOldManBufferExecCompleted(); + } +} + +static void OpenBagAndChooseItem(void) +{ + if (!gPaletteFade.active) + { + gBattlerControllerFuncs[gActiveBattler] = CompleteWhenChoseItem; + nullsub_44(); + FreeAllWindowBuffers(); + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + sub_8107ECC(); + else + sub_810AF74(); + } +} + +static void CompleteWhenChoseItem(void) +{ + if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active) + { + if (!sub_80EB2E0(4) + && gSpecialVar_ItemId == ITEM_POTION + && gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + sub_80EB2F4(4); + gBattlerControllerFuncs[gActiveBattler] = sub_80E8704; + } + else + { + BtlController_EmitOneReturnValue(1, gSpecialVar_ItemId); + OakOldManBufferExecCompleted(); + } + } +} + +static void sub_80E7B4C(void) +{ + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].flag_x80 + && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive) + sub_80F1720(gActiveBattler, &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]]); + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].flag_x80 + && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive) + sub_80F1720(gActiveBattler ^ BIT_FLANK, &gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]]); + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive) + { + if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + DestroySprite(&gSprites[gUnknown_3004FFC[gActiveBattler ^ BIT_FLANK]]); + UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK], + &gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], + HEALTHBOX_ALL); + sub_804BD94(gActiveBattler ^ BIT_FLANK); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK]); + } + DestroySprite(&gSprites[gUnknown_3004FFC[gActiveBattler]]); + UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], + &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], + HEALTHBOX_ALL); + sub_804BD94(gActiveBattler); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler]); + gBattleSpritesDataPtr->animationData->field_9_x1 = 0; + gBattlerControllerFuncs[gActiveBattler] = sub_80E7CD8; + } +} + +static void sub_80E7CD8(void) +{ + bool32 r4 = FALSE; + + if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) + r4 = TRUE; + if (r4 + && gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].field_1_x1 + && gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].field_1_x1) + { + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].flag_x80 = 0; + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].field_1_x1 = 0; + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].flag_x80 = 0; + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].field_1_x1 = 0; + FreeSpriteTilesByTag(0x27F9); + FreeSpritePaletteByTag(0x27F9); + CreateTask(c3_0802FDF4, 10); + HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); + gBattlerControllerFuncs[gActiveBattler] = sub_80E835C; + } +} + +#define tExpTask_monId data[0] +#define tExpTask_gainedExp data[1] +#define tExpTask_battler data[2] +#define tExpTask_frames data[10] + +static void Task_GiveExpToMon(u8 taskId) +{ + u32 monId = (u8)(gTasks[taskId].tExpTask_monId); + u8 battlerId = gTasks[taskId].tExpTask_battler; + s16 gainedExp = gTasks[taskId].tExpTask_gainedExp; + + if (IsDoubleBattle() == TRUE || monId != gBattlerPartyIndexes[battlerId]) // Give exp without moving the expbar. + { + struct Pokemon *mon = &gPlayerParty[monId]; + u16 species = GetMonData(mon, MON_DATA_SPECIES); + u8 level = GetMonData(mon, MON_DATA_LEVEL); + u32 currExp = GetMonData(mon, MON_DATA_EXP); + u32 nextLvlExp = gExperienceTables[gBaseStats[species].growthRate][level + 1]; + + if (currExp + gainedExp >= nextLvlExp) + { + u8 savedActiveBattler; + + SetMonData(mon, MON_DATA_EXP, &nextLvlExp); + CalculateMonStats(mon); + gainedExp -= nextLvlExp - currExp; + savedActiveBattler = gActiveBattler; + gActiveBattler = battlerId; + BtlController_EmitTwoReturnValues(1, RET_VALUE_LEVELED_UP, gainedExp); + gActiveBattler = savedActiveBattler; + if (IsDoubleBattle() == TRUE + && ((u16)(monId) == gBattlerPartyIndexes[battlerId] || (u16)(monId) == gBattlerPartyIndexes[battlerId ^ BIT_FLANK])) + gTasks[taskId].func = Task_LaunchLvlUpAnim; + else + gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter; + } + else + { + currExp += gainedExp; + SetMonData(mon, MON_DATA_EXP, &currExp); + gBattlerControllerFuncs[battlerId] = CompleteOnInactiveTextPrinter2; + DestroyTask(taskId); + } + } + else + { + gTasks[taskId].func = Task_PrepareToGiveExpWithExpBar; + } +} + +static void Task_PrepareToGiveExpWithExpBar(u8 taskId) +{ + u8 monIndex = gTasks[taskId].tExpTask_monId; + s32 gainedExp = gTasks[taskId].tExpTask_gainedExp; + u8 battlerId = gTasks[taskId].tExpTask_battler; + struct Pokemon *mon = &gPlayerParty[monIndex]; + u8 level = GetMonData(mon, MON_DATA_LEVEL); + u16 species = GetMonData(mon, MON_DATA_SPECIES); + u32 exp = GetMonData(mon, MON_DATA_EXP); + u32 currLvlExp = gExperienceTables[gBaseStats[species].growthRate][level]; + u32 expToNextLvl; + + exp -= currLvlExp; + expToNextLvl = gExperienceTables[gBaseStats[species].growthRate][level + 1] - currLvlExp; + SetBattleBarStruct(battlerId, gHealthboxSpriteIds[battlerId], expToNextLvl, exp, -gainedExp); + PlaySE(SE_EXP); + gTasks[taskId].func = sub_80E804C; +} + +static void sub_80E804C(u8 taskId) +{ + if (gTasks[taskId].tExpTask_frames < 13) + { + ++gTasks[taskId].tExpTask_frames; + } + else + { + u8 monId = gTasks[taskId].tExpTask_monId; + s16 gainedExp = gTasks[taskId].tExpTask_gainedExp; + u8 battlerId = gTasks[taskId].tExpTask_battler; + s16 newExpPoints; + + newExpPoints = MoveBattleBar(battlerId, gHealthboxSpriteIds[battlerId], EXP_BAR, 0); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[battlerId]); + if (newExpPoints == -1) // The bar has been filled with given exp points. + { + u8 level; + s32 currExp; + u16 species; + s32 expOnNextLvl; + + m4aSongNumStop(SE_EXP); + level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL); + currExp = GetMonData(&gPlayerParty[monId], MON_DATA_EXP); + species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); + expOnNextLvl = gExperienceTables[gBaseStats[species].growthRate][level + 1]; + if (currExp + gainedExp >= expOnNextLvl) + { + u8 savedActiveBattler; + + SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl); + CalculateMonStats(&gPlayerParty[monId]); + gainedExp -= expOnNextLvl - currExp; + savedActiveBattler = gActiveBattler; + gActiveBattler = battlerId; + BtlController_EmitTwoReturnValues(1, RET_VALUE_LEVELED_UP, gainedExp); + gActiveBattler = savedActiveBattler; + gTasks[taskId].func = Task_LaunchLvlUpAnim; + } + else + { + currExp += gainedExp; + SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp); + gBattlerControllerFuncs[battlerId] = CompleteOnInactiveTextPrinter2; + DestroyTask(taskId); + } + } + } +} + +static void Task_LaunchLvlUpAnim(u8 taskId) +{ + u8 battlerId = gTasks[taskId].tExpTask_battler; + u8 monIndex = gTasks[taskId].tExpTask_monId; + + if (IsDoubleBattle() == TRUE && monIndex == gBattlerPartyIndexes[battlerId ^ BIT_FLANK]) + battlerId ^= BIT_FLANK; + InitAndLaunchSpecialAnimation(battlerId, battlerId, battlerId, B_ANIM_LVL_UP); + gTasks[taskId].func = Task_UpdateLvlInHealthbox; +} + +static void Task_UpdateLvlInHealthbox(u8 taskId) +{ + u8 battlerId = gTasks[taskId].tExpTask_battler; + + if (!gBattleSpritesDataPtr->healthBoxesData[battlerId].specialAnimActive) + { + u8 monIndex = gTasks[taskId].tExpTask_monId; + + GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value. + if (IsDoubleBattle() == TRUE && monIndex == gBattlerPartyIndexes[battlerId ^ BIT_FLANK]) + UpdateHealthboxAttribute(gHealthboxSpriteIds[battlerId ^ BIT_FLANK], &gPlayerParty[monIndex], HEALTHBOX_ALL); + else + UpdateHealthboxAttribute(gHealthboxSpriteIds[battlerId], &gPlayerParty[monIndex], HEALTHBOX_ALL); + gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter; + } +} + +static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId) +{ + u8 monIndex = gTasks[taskId].tExpTask_monId; + u8 battlerId; + + GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value + battlerId = gTasks[taskId].tExpTask_battler; + gBattlerControllerFuncs[battlerId] = CompleteOnInactiveTextPrinter2; + DestroyTask(taskId); +} + +static void sub_80E82F4(void) +{ + if (gSprites[gBattlerSpriteIds[gActiveBattler]].pos1.y + gSprites[gBattlerSpriteIds[gActiveBattler]].pos2.y > DISPLAY_HEIGHT) + { + FreeOamMatrix(gSprites[gBattlerSpriteIds[gActiveBattler]].oam.matrixNum); + DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]); + SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gActiveBattler]); + OakOldManBufferExecCompleted(); + } +} + +static void sub_80E835C(void) +{ + u32 mask; + + switch (gBattleStruct->field_94) + { + case 0: + if (!gPaletteFade.active) + { + sub_80EEFC8(&gBattleStruct->field_95, &gBattleStruct->field_97, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); + BeginNormalPaletteFade(0xFFFFFF7E, + 4, + 0, + 8, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 1: + if (!gPaletteFade.active) + { + sub_80EB30C(); + ++gBattleStruct->field_94; + } + break; + case 2: + BattleStringExpandPlaceholdersToDisplayedString(gUnknown_83FDAE2); + BattlePutTextOnWindow(gDisplayedStringBattle, 24); + ++gBattleStruct->field_94; + break; + case 3: + if (!IsTextPrinterActive(24)) + { + mask = (gBitTable[gBattleStruct->field_95] | gBitTable[gBattleStruct->field_97]) << 16; + BeginNormalPaletteFade(mask, + 4, + 8, + 0, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 4: + if (!gPaletteFade.active) + { + BattleStringExpandPlaceholdersToDisplayedString(gUnknown_83FDB92); + BattlePutTextOnWindow(gDisplayedStringBattle, 24); + ++gBattleStruct->field_94; + } + break; + case 5: + if (!IsTextPrinterActive(24)) + { + mask = (gBitTable[gBattleStruct->field_95] | gBitTable[gBattleStruct->field_97]) << 16; + BeginNormalPaletteFade(mask, + 4, + 0, + 8, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 6: + if (!gPaletteFade.active) + { + BattleStringExpandPlaceholdersToDisplayedString(gUnknown_83FDBEF); + BattlePutTextOnWindow(gDisplayedStringBattle, 24); + ++gBattleStruct->field_94; + } + break; + case 7: + if (!IsTextPrinterActive(24)) + { + BeginNormalPaletteFade(0xFFFFFF7E, + 4, + 8, + 0, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 8: + if (!gPaletteFade.active) + { + sub_80EF0E0(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); + sub_80EB524(); + gBattleStruct->field_94 = 0; + OakOldManBufferExecCompleted(); + } + break; + } +} + +void sub_80E8570(void) +{ + sub_80E85D4(gUnknown_83FDC58, 1); +} + +static void sub_80E8584(void) +{ + sub_80E85D4(gUnknown_83FDC95, 64); +} + +void sub_80E8598(void) +{ + sub_80E85D4(gUnknown_83FDD23, 1); +} + +static void sub_80E85AC(void) +{ + sub_80E85D4(gUnknown_83FDD64, 64); +} + +void sub_80E85C0(void) +{ + sub_80E85D4(gUnknown_83FDDEB, 64); +} + +static void sub_80E85D4(const u8 *text, u8 a2) +{ + switch (gBattleStruct->field_94) + { + case 0: + if (!IsTextPrinterActive(0)) + { + gBattleStruct->field_97 = a2; + ++gBattleStruct->field_94; + } + break; + case 1: + if (--gBattleStruct->field_97 == 0) + { + BeginNormalPaletteFade(0xFFFFFF7E, + 4, + 0, + 8, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 2: + if (!gPaletteFade.active) + { + sub_80EB30C(); + ++gBattleStruct->field_94; + } + break; + case 3: + BattleStringExpandPlaceholdersToDisplayedString(text); + BattlePutTextOnWindow(gDisplayedStringBattle, 24); + ++gBattleStruct->field_94; + break; + case 4: + if (!IsTextPrinterActive(24)) + { + BeginNormalPaletteFade(0xFFFFFF7E, + 4, + 8, + 0, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 5: + if (!gPaletteFade.active) + { + sub_80EB524(); + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + OakOldManBufferExecCompleted(); + else + OpponentBufferExecCompleted(); + gBattleCommunication[MSG_DISPLAY] = 0; + gBattleStruct->field_94 = 0; + } + break; + } +} + +static void sub_80E8704(void) +{ + u32 mask; + + switch (gBattleStruct->field_94) + { + case 0: + if (!gPaletteFade.active) + { + sub_80EEFC8(&gBattleStruct->field_95, &gBattleStruct->field_97, gActiveBattler); + BeginNormalPaletteFade(0xFFFFFF7E, + 4, + 0, + 8, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 1: + if (!gPaletteFade.active) + { + mask = (gBitTable[gBattleStruct->field_95] | gBitTable[gBattleStruct->field_97]) << 16; + BeginNormalPaletteFade(mask, + 4, + 8, + 0, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 2: + if (!gPaletteFade.active) + { + sub_80EB30C(); + ++gBattleStruct->field_94; + } + break; + case 3: + BattleStringExpandPlaceholdersToDisplayedString(gUnknown_83FDCD2); + BattlePutTextOnWindow(gDisplayedStringBattle, 24); + ++gBattleStruct->field_94; + break; + case 4: + if (!IsTextPrinterActive(24)) + { + mask = (gBitTable[gBattleStruct->field_95] | gBitTable[gBattleStruct->field_97]) << 16; + BeginNormalPaletteFade(mask, + 4, + 0, + 8, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 5: + if (!gPaletteFade.active) + { + BeginNormalPaletteFade(0xFFFFFF7E, + 4, + 8, + 0, + RGB_BLACK); + ++gBattleStruct->field_94; + } + break; + case 6: + if (!gPaletteFade.active) + { + sub_80EB524(); + BtlController_EmitOneReturnValue(1, gSpecialVar_ItemId); + OakOldManBufferExecCompleted(); + gBattleStruct->field_94 = 0; + } + break; + } +} + +static void CompleteOnHealthbarDone(void) +{ + s16 hpValue = MoveBattleBar(gActiveBattler, gHealthboxSpriteIds[gActiveBattler], HEALTH_BAR, 0); + + SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler]); + if (hpValue != -1) + { + UpdateHpTextInHealthbox(gHealthboxSpriteIds[gActiveBattler], hpValue, HP_CURRENT); + } + else + { + HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); + OakOldManBufferExecCompleted(); + } +} + +static void CompleteOnInactiveTextPrinter2(void) +{ + if (!IsTextPrinterActive(0)) + OakOldManBufferExecCompleted(); +} + +static void DoHitAnimBlinkSpriteEffect(void) +{ + u8 spriteId = gBattlerSpriteIds[gActiveBattler]; + + if (gSprites[spriteId].data[1] == 32) + { + gSprites[spriteId].data[1] = 0; + gSprites[spriteId].invisible = FALSE; + gDoingBattleAnim = FALSE; + OakOldManBufferExecCompleted(); + } + else + { + if ((gSprites[spriteId].data[1] % 4) == 0) + gSprites[spriteId].invisible ^= 1; + ++gSprites[spriteId].data[1]; + } +} + +static void sub_80E89C4(void) +{ + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive) + { + FreeSpriteOamMatrix(&gSprites[gBattlerSpriteIds[gActiveBattler]]); + DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]); + SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gActiveBattler]); + OakOldManBufferExecCompleted(); + } +} + +static void CompleteOnBattlerSpriteCallbackDummy2(void) +{ + if (gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) + OakOldManBufferExecCompleted(); +} + +static void CompleteOnFinishedBattleAnimation(void) +{ + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animFromTableActive) + OakOldManBufferExecCompleted(); +} + +static void OakOldManBufferExecCompleted(void) +{ + gBattlerControllerFuncs[gActiveBattler] = OakOldManBufferRunCommand; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + u8 playerId = GetMultiplayerId(); + + PrepareBufferDataTransferLink(2, 4, &playerId); + gBattleBufferA[gActiveBattler][0] = CONTROLLER_TERMINATOR_NOP; + } + else + { + gBattleControllerExecFlags &= ~gBitTable[gActiveBattler]; + } +} + +static void CompleteOnFinishedStatusAnimation(void) +{ + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].statusAnimActive) + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleGetMonData(void) +{ + u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two pokemon, trying to get more will result in overwriting data + u32 size = 0; + u8 monToCheck; + s32 i; + + if (gBattleBufferA[gActiveBattler][2] == 0) + { + size += CopyOakOldManMonData(gBattlerPartyIndexes[gActiveBattler], monData); + } + else + { + monToCheck = gBattleBufferA[gActiveBattler][2]; + for (i = 0; i < PARTY_SIZE; ++i) + { + if (monToCheck & 1) + size += CopyOakOldManMonData(i, monData + size); + monToCheck >>= 1; + } + } + BtlController_EmitDataTransfer(1, size, monData); + OakOldManBufferExecCompleted(); +} + +static u32 CopyOakOldManMonData(u8 monId, u8 *dst) +{ + struct BattlePokemon battleMon; + struct MovePpInfo moveData; + u8 nickname[20]; + u8 *src; + s16 data16; + u32 data32; + s32 size = 0; + + switch (gBattleBufferA[gActiveBattler][1]) + { + case REQUEST_ALL_BATTLE: + battleMon.species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); + battleMon.item = GetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM); + for (size = 0; size < MAX_MON_MOVES; ++size) + { + battleMon.moves[size] = GetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + size); + battleMon.pp[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + size); + } + battleMon.ppBonuses = GetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES); + battleMon.friendship = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP); + battleMon.experience = GetMonData(&gPlayerParty[monId], MON_DATA_EXP); + battleMon.hpIV = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV); + battleMon.attackIV = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV); + battleMon.defenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV); + battleMon.speedIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV); + battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV); + battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV); + battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY); + battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS); + battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL); + battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP); + battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP); + battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK); + battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF); + battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED); + battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK); + battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF); + battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG); + battleMon.abilityNum = GetMonData(&gPlayerParty[monId], MON_DATA_ABILITY_NUM); + battleMon.otId = GetMonData(&gPlayerParty[monId], MON_DATA_OT_ID); + GetMonData(&gPlayerParty[monId], MON_DATA_NICKNAME, nickname); + StringCopy10(battleMon.nickname, nickname); + GetMonData(&gPlayerParty[monId], MON_DATA_OT_NAME, battleMon.otName); + src = (u8 *)&battleMon; + for (size = 0; size < sizeof(battleMon); ++size) + dst[size] = src[size]; + break; + case REQUEST_SPECIES_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_HELDITEM_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_MOVES_PP_BATTLE: + for (size = 0; size < MAX_MON_MOVES; ++size) + { + moveData.moves[size] = GetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + size); + moveData.pp[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + size); + } + moveData.ppBonuses = GetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES); + src = (u8 *)(&moveData); + for (size = 0; size < sizeof(moveData); ++size) + dst[size] = src[size]; + break; + case REQUEST_MOVE1_BATTLE: + case REQUEST_MOVE2_BATTLE: + case REQUEST_MOVE3_BATTLE: + case REQUEST_MOVE4_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBattler][1] - REQUEST_MOVE1_BATTLE); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_PP_DATA_BATTLE: + for (size = 0; size < MAX_MON_MOVES; ++size) + dst[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + size); + dst[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES); + ++size; + break; + case REQUEST_PPMOVE1_BATTLE: + case REQUEST_PPMOVE2_BATTLE: + case REQUEST_PPMOVE3_BATTLE: + case REQUEST_PPMOVE4_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBattler][1] - REQUEST_PPMOVE1_BATTLE); + size = 1; + break; + case REQUEST_OTID_BATTLE: + data32 = GetMonData(&gPlayerParty[monId], MON_DATA_OT_ID); + dst[0] = (data32 & 0x000000FF); + dst[1] = (data32 & 0x0000FF00) >> 8; + dst[2] = (data32 & 0x00FF0000) >> 16; + size = 3; + break; + case REQUEST_EXP_BATTLE: + data32 = GetMonData(&gPlayerParty[monId], MON_DATA_EXP); + dst[0] = (data32 & 0x000000FF); + dst[1] = (data32 & 0x0000FF00) >> 8; + dst[2] = (data32 & 0x00FF0000) >> 16; + size = 3; + break; + case REQUEST_HP_EV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_EV); + size = 1; + break; + case REQUEST_ATK_EV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV); + size = 1; + break; + case REQUEST_DEF_EV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV); + size = 1; + break; + case REQUEST_SPEED_EV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_EV); + size = 1; + break; + case REQUEST_SPATK_EV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV); + size = 1; + break; + case REQUEST_SPDEF_EV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV); + size = 1; + break; + case REQUEST_FRIENDSHIP_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP); + size = 1; + break; + case REQUEST_POKERUS_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS); + size = 1; + break; + case REQUEST_MET_LOCATION_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION); + size = 1; + break; + case REQUEST_MET_LEVEL_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL); + size = 1; + break; + case REQUEST_MET_GAME_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME); + size = 1; + break; + case REQUEST_POKEBALL_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL); + size = 1; + break; + case REQUEST_ALL_IVS_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV); + dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV); + dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV); + dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV); + dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV); + dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV); + size = 6; + break; + case REQUEST_HP_IV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV); + size = 1; + break; + case REQUEST_ATK_IV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV); + size = 1; + break; + case REQUEST_DEF_IV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV); + size = 1; + break; + case REQUEST_SPEED_IV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV); + size = 1; + break; + case REQUEST_SPATK_IV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV); + size = 1; + break; + case REQUEST_SPDEF_IV_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV); + size = 1; + break; + case REQUEST_PERSONALITY_BATTLE: + data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY); + dst[0] = (data32 & 0x000000FF); + dst[1] = (data32 & 0x0000FF00) >> 8; + dst[2] = (data32 & 0x00FF0000) >> 16; + dst[3] = (data32 & 0xFF000000) >> 24; + size = 4; + break; + case REQUEST_CHECKSUM_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_STATUS_BATTLE: + data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS); + dst[0] = (data32 & 0x000000FF); + dst[1] = (data32 & 0x0000FF00) >> 8; + dst[2] = (data32 & 0x00FF0000) >> 16; + dst[3] = (data32 & 0xFF000000) >> 24; + size = 4; + break; + case REQUEST_LEVEL_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL); + size = 1; + break; + case REQUEST_HP_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_MAX_HP_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_ATK_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_DEF_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_SPEED_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_SPATK_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_SPDEF_BATTLE: + data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF); + dst[0] = data16; + dst[1] = data16 >> 8; + size = 2; + break; + case REQUEST_COOL_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL); + size = 1; + break; + case REQUEST_BEAUTY_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY); + size = 1; + break; + case REQUEST_CUTE_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE); + size = 1; + break; + case REQUEST_SMART_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART); + size = 1; + break; + case REQUEST_TOUGH_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH); + size = 1; + break; + case REQUEST_SHEEN_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN); + size = 1; + break; + case REQUEST_COOL_RIBBON_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON); + size = 1; + break; + case REQUEST_BEAUTY_RIBBON_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON); + size = 1; + break; + case REQUEST_CUTE_RIBBON_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON); + size = 1; + break; + case REQUEST_SMART_RIBBON_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON); + size = 1; + break; + case REQUEST_TOUGH_RIBBON_BATTLE: + dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON); + size = 1; + break; + } + return size; +} + +static void OakOldManHandleGetRawMonData(void) +{ + PlayerHandleGetRawMonData(); +} + +static void OakOldManHandleSetMonData(void) +{ + u8 monToCheck; + u8 i; + + if (gBattleBufferA[gActiveBattler][2] == 0) + { + SetOakOldManMonData(gBattlerPartyIndexes[gActiveBattler]); + } + else + { + monToCheck = gBattleBufferA[gActiveBattler][2]; + for (i = 0; i < PARTY_SIZE; ++i) + { + if (monToCheck & 1) + SetOakOldManMonData(i); + monToCheck >>= 1; + } + } + OakOldManBufferExecCompleted(); +} + +static void SetOakOldManMonData(u8 monId) +{ + struct BattlePokemon *battlePokemon = (struct BattlePokemon *)&gBattleBufferA[gActiveBattler][3]; + struct MovePpInfo *moveData = (struct MovePpInfo *)&gBattleBufferA[gActiveBattler][3]; + s32 i; + + switch (gBattleBufferA[gActiveBattler][1]) + { + case REQUEST_ALL_BATTLE: + { + u8 iv; + + SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &battlePokemon->species); + SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &battlePokemon->item); + for (i = 0; i < MAX_MON_MOVES; ++i) + { + SetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + i, &battlePokemon->moves[i]); + SetMonData(&gPlayerParty[monId], MON_DATA_PP1 + i, &battlePokemon->pp[i]); + } + SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &battlePokemon->ppBonuses); + SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &battlePokemon->friendship); + SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &battlePokemon->experience); + iv = battlePokemon->hpIV; + SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &iv); + iv = battlePokemon->attackIV; + SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &iv); + iv = battlePokemon->defenseIV; + SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &iv); + iv = battlePokemon->speedIV; + SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV, &iv); + iv = battlePokemon->spAttackIV; + SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv); + iv = battlePokemon->spDefenseIV; + SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv); + SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality); + SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1); + SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level); + SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp); + SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP); + SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack); + SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense); + SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed); + SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack); + SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense); + } + break; + case REQUEST_SPECIES_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_HELDITEM_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_MOVES_PP_BATTLE: + for (i = 0; i < MAX_MON_MOVES; ++i) + { + SetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + i, &moveData->moves[i]); + SetMonData(&gPlayerParty[monId], MON_DATA_PP1 + i, &moveData->pp[i]); + } + SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &moveData->ppBonuses); + break; + case REQUEST_MOVE1_BATTLE: + case REQUEST_MOVE2_BATTLE: + case REQUEST_MOVE3_BATTLE: + case REQUEST_MOVE4_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBattler][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_PP_DATA_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBattler][3]); + SetMonData(&gPlayerParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBattler][4]); + SetMonData(&gPlayerParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBattler][5]); + SetMonData(&gPlayerParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBattler][6]); + SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &gBattleBufferA[gActiveBattler][7]); + break; + case REQUEST_PPMOVE1_BATTLE: + case REQUEST_PPMOVE2_BATTLE: + case REQUEST_PPMOVE3_BATTLE: + case REQUEST_PPMOVE4_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBattler][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_OTID_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_EXP_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_HP_EV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_ATK_EV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_DEF_EV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPEED_EV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_EV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPATK_EV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPDEF_EV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_FRIENDSHIP_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_POKERUS_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_MET_LOCATION_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_MET_LEVEL_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_MET_GAME_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_POKEBALL_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_ALL_IVS_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBattler][3]); + SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBattler][4]); + SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBattler][5]); + SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBattler][6]); + SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBattler][7]); + SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBattler][8]); + break; + case REQUEST_HP_IV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_ATK_IV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_DEF_IV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPEED_IV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPATK_IV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPDEF_IV_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_PERSONALITY_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_CHECKSUM_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_STATUS_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_LEVEL_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_HP_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_MAX_HP_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_ATK_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_DEF_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPEED_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPATK_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SPDEF_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_COOL_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_BEAUTY_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_CUTE_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SMART_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_TOUGH_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SHEEN_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_COOL_RIBBON_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_BEAUTY_RIBBON_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_CUTE_RIBBON_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_SMART_RIBBON_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBattler][3]); + break; + case REQUEST_TOUGH_RIBBON_BATTLE: + SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBattler][3]); + break; + } + HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); +} + +static void OakOldManHandleSetRawMonData(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleLoadMonSprite(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleSwitchInAnim(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleReturnMonToBall(void) +{ + if (gBattleBufferA[gActiveBattler][1] == 0) + { + InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SWITCH_OUT_PLAYER_MON); + gBattlerControllerFuncs[gActiveBattler] = sub_80E89C4; + } + else + { + FreeSpriteOamMatrix(&gSprites[gBattlerSpriteIds[gActiveBattler]]); + DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]); + SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gActiveBattler]); + OakOldManBufferExecCompleted(); + } +} + +static void OakOldManHandleDrawTrainerPic(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + DecompressTrainerBackPalette(gSaveBlock2Ptr->playerGender, gActiveBattler); + SetMultiuseSpriteTemplateToTrainerBack(gSaveBlock2Ptr->playerGender, GetBattlerPosition(gActiveBattler)); + gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, + 80, + (8 - gTrainerBackPicCoords[gSaveBlock2Ptr->playerGender].size) * 4 + 80, + 30); + } + else + { + DecompressTrainerBackPalette(5, gActiveBattler); + SetMultiuseSpriteTemplateToTrainerBack(5, GetBattlerPosition(gActiveBattler)); + gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, + 80, + (8 - gTrainerBackPicCoords[5].size) * 4 + 80, + 30); + } + gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler; + gSprites[gBattlerSpriteIds[gActiveBattler]].pos2.x = 240; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[0] = -2; + gSprites[gBattlerSpriteIds[gActiveBattler]].callback = sub_8033EEC; + gBattlerControllerFuncs[gActiveBattler] = CompleteOnBattlerSpriteCallbackDummy; +} + +static void OakOldManHandleTrainerSlide(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + DecompressTrainerBackPalette(gSaveBlock2Ptr->playerGender, gActiveBattler); + SetMultiuseSpriteTemplateToTrainerBack(gSaveBlock2Ptr->playerGender, GetBattlerPosition(gActiveBattler)); + gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, + 80, + (8 - gTrainerBackPicCoords[gSaveBlock2Ptr->playerGender].size) * 4 + 80, + 30); + } + else + { + DecompressTrainerBackPalette(5, gActiveBattler); + SetMultiuseSpriteTemplateToTrainerBack(5, GetBattlerPosition(gActiveBattler)); + gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, + 80, + (8 - gTrainerBackPicCoords[5].size) * 4 + 80, + 30); + } + gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler; + gSprites[gBattlerSpriteIds[gActiveBattler]].pos2.x = -96; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[0] = 2; + gSprites[gBattlerSpriteIds[gActiveBattler]].callback = sub_8033EEC; + gBattlerControllerFuncs[gActiveBattler] = CompleteOnBattlerSpriteCallbackDummy2; +} + +static void OakOldManHandleTrainerSlideBack(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleFaintAnimation(void) +{ + if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState == 0) + { + if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute) + InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SUBSTITUTE_TO_MON); + ++gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState; + } + else + { + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive) + { + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); + PlaySE12WithPanning(SE_POKE_DEAD, SOUND_PAN_ATTACKER); + gSprites[gBattlerSpriteIds[gActiveBattler]].data[1] = 0; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[2] = 5; + gSprites[gBattlerSpriteIds[gActiveBattler]].callback = sub_8012110; + gBattlerControllerFuncs[gActiveBattler] = sub_80E82F4; + } + } +} + +static void OakOldManHandlePaletteFade(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleSuccessBallThrowAnim(void) +{ + gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS; + gDoingBattleAnim = TRUE; + InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_SAFARI_BALL_THROW); + gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone; +} + +static void OakOldManHandleBallThrowAnim(void) +{ + u8 ballThrowCaseId = gBattleBufferA[gActiveBattler][1]; + + gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId; + gDoingBattleAnim = TRUE; + InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_SAFARI_BALL_THROW); + gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone; +} + +static void OakOldManHandlePause(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleMoveAnimation(void) +{ + u16 move = gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8); + + gAnimMoveTurn = gBattleBufferA[gActiveBattler][3]; + gAnimMovePower = gBattleBufferA[gActiveBattler][4] | (gBattleBufferA[gActiveBattler][5] << 8); + gAnimMoveDmg = gBattleBufferA[gActiveBattler][6] | (gBattleBufferA[gActiveBattler][7] << 8) | (gBattleBufferA[gActiveBattler][8] << 16) | (gBattleBufferA[gActiveBattler][9] << 24); + gAnimFriendship = gBattleBufferA[gActiveBattler][10]; + gWeatherMoveAnim = gBattleBufferA[gActiveBattler][12] | (gBattleBufferA[gActiveBattler][13] << 8); + gAnimDisableStructPtr = (struct DisableStruct *)&gBattleBufferA[gActiveBattler][16]; + gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; + if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE + { + OakOldManBufferExecCompleted(); + } + else + { + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = OakOldManDoMoveAnimation; + } +} + +static void OakOldManDoMoveAnimation(void) +{ + u16 move = gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8); + + switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState) + { + case 0: + if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute) + InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SUBSTITUTE_TO_MON); + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 1; + break; + case 1: + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive) + { + sub_8035450(0); + DoMoveAnim(move); + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 2; + } + break; + case 2: + gAnimScriptCallback(); + if (!gAnimScriptActive) + { + sub_8035450(1); + if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute) + InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_MON_TO_SUBSTITUTE); + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 3; + } + break; + case 3: + if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive) + { + CopyAllBattleSpritesInvisibilities(); + TrySetBehindSubstituteSpriteBit(gActiveBattler, gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8)); + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + OakOldManBufferExecCompleted(); + } + break; + } +} + +static void OakOldManHandlePrintString(void) +{ + u16 *stringId; + + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + stringId = (u16 *)(&gBattleBufferA[gActiveBattler][2]); + if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL && *stringId == 1) + { + OakOldManBufferExecCompleted(); + } + else + { + BufferStringBattle(*stringId); + if (sub_80D89B0(*stringId)) + BattlePutTextOnWindow(gDisplayedStringBattle, 64); + else + BattlePutTextOnWindow(gDisplayedStringBattle, 0); + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + switch (*stringId) + { + case 216: + if (!sub_80EB2E0(2)) + { + sub_80EB2F4(2); + gBattlerControllerFuncs[gActiveBattler] = sub_80E8584; + return; + } + break; + case 30: + gBattlerControllerFuncs[gActiveBattler] = sub_80E85AC; + return; + case 383: + gBattlerControllerFuncs[gActiveBattler] = sub_80E85C0; + return; + case 227: + gBattlerControllerFuncs[gActiveBattler] = sub_80E8598; + return; + } + } + gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter; + } +} + +static void OakOldManHandlePrintSelectionString(void) +{ + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + OakOldManHandlePrintString(); + else + OakOldManBufferExecCompleted(); +} + +static void sub_80EA690(void) +{ + if (!IsDma3ManagerBusyWithBgCopy()) + { + gBattle_BG0_X = 0; + gBattle_BG0_Y = 160; + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseAction; + else + gBattlerControllerFuncs[gActiveBattler] = sub_80E7844; + } +} + +static void OakOldManHandleChooseAction(void) +{ + s32 i; + + gBattlerControllerFuncs[gActiveBattler] = sub_80EA690; + BattlePutTextOnWindow(gUnknown_83FDA4C, 0); + BattlePutTextOnWindow(gUnknown_83FE725, 2); + for (i = 0; i < MAX_MON_MOVES; ++i) + ActionSelectionDestroyCursorAt((u8)i); + ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo); + else + BattleStringExpandPlaceholdersToDisplayedString(gUnknown_83FE6FA); + BattlePutTextOnWindow(gDisplayedStringBattle, 1); +} + +static void OakOldManHandleUnknownYesNoBox(void) +{ + OakOldManBufferExecCompleted(); +} + +static void sub_80EA798(void) +{ + if (!IsDma3ManagerBusyWithBgCopy()) + { + gBattle_BG0_X = 0; + gBattle_BG0_Y = 320; + gBattlerControllerFuncs[gActiveBattler] = sub_80E7988; + } +} + +static void OakOldManHandleChooseMove(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + InitMoveSelectionsVarsAndStrings(); + gBattlerControllerFuncs[gActiveBattler] = sub_80EA798; + } + else + { + switch (gBattleStruct->field_95) + { + case 0: + InitMoveSelectionsVarsAndStrings(); + ++gBattleStruct->field_95; + gBattleStruct->field_97 = 80; + // fall through + case 1: + if (--gBattleStruct->field_97 == 0) + { + PlaySE(SE_SELECT); + BtlController_EmitTwoReturnValues(1, 10, 0x100); + OakOldManBufferExecCompleted(); + } + break; + } + } +} + +static void OakOldManHandleChooseItem(void) +{ + s32 i; + + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK); + gBattlerControllerFuncs[gActiveBattler] = OpenBagAndChooseItem; + gBattlerInMenuId = gActiveBattler; + for (i = 0; i < 3; ++i) + gUnknown_203B0DC[i] = gBattleBufferA[gActiveBattler][i + 1]; +} + +static void OakOldManHandleChoosePokemon(void) +{ + s32 i; + + gUnknown_3004FFC[gActiveBattler] = CreateTask(TaskDummy, 0xFF); + gTasks[gUnknown_3004FFC[gActiveBattler]].data[0] = gBattleBufferA[gActiveBattler][1] & 0xF; + *(&gBattleStruct->battlerPreventingSwitchout) = gBattleBufferA[gActiveBattler][1] >> 4; + *(&gBattleStruct->field_8B) = gBattleBufferA[gActiveBattler][2]; + *(&gBattleStruct->abilityPreventingSwitchout) = gBattleBufferA[gActiveBattler][3]; + for (i = 0; i < 3; ++i) + gUnknown_203B0DC[i] = gBattleBufferA[gActiveBattler][4 + i]; + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK); + gBattlerControllerFuncs[gActiveBattler] = OpenPartyMenuToChooseMon; + gBattlerInMenuId = gActiveBattler; +} + +static void OakOldManHandleCmd23(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleHealthBarUpdate(void) +{ + s16 hpVal; + + LoadBattleBarGfx(0); + hpVal = gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8); + if (hpVal != INSTANT_HP_BAR_DROP) + { + u32 maxHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MAX_HP); + u32 curHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_HP); + + SetBattleBarStruct(gActiveBattler, gHealthboxSpriteIds[gActiveBattler], maxHP, curHP, hpVal); + } + else + { + u32 maxHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MAX_HP); + + SetBattleBarStruct(gActiveBattler, gHealthboxSpriteIds[gActiveBattler], maxHP, 0, hpVal); + UpdateHpTextInHealthbox(gHealthboxSpriteIds[gActiveBattler], 0, HP_CURRENT); + } + gBattlerControllerFuncs[gActiveBattler] = CompleteOnHealthbarDone; +} + +static void OakOldManHandleExpUpdate(void) +{ + u8 monId = gBattleBufferA[gActiveBattler][1]; + + if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_LEVEL) + { + OakOldManBufferExecCompleted(); + } + else + { + s16 expPointsToGive; + u8 taskId; + + LoadBattleBarGfx(1); + GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); // Unused return value. + expPointsToGive = T1_READ_16(&gBattleBufferA[gActiveBattler][2]); + taskId = CreateTask(Task_GiveExpToMon, 10); + gTasks[taskId].tExpTask_monId = monId; + gTasks[taskId].tExpTask_gainedExp = expPointsToGive; + gTasks[taskId].tExpTask_battler = gActiveBattler; + gBattlerControllerFuncs[gActiveBattler] = nullsub_81; + } +} + +static void OakOldManHandleStatusIconUpdate(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleStatusAnimation(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleStatusXor(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleDataTransfer(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleDMA3Transfer(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandlePlayBGM(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleCmd32(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleTwoReturnValues(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleChosenMonReturnValue(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleOneReturnValue(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleOneReturnValue_Duplicate(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleCmd37(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleCmd38(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleCmd39(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleCmd40(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleHitAnimation(void) +{ + if (gSprites[gBattlerSpriteIds[gActiveBattler]].invisible == TRUE) + { + OakOldManBufferExecCompleted(); + } + else + { + gDoingBattleAnim = TRUE; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[1] = 0; + DoHitAnimHealthboxEffect(gActiveBattler); + gBattlerControllerFuncs[gActiveBattler] = DoHitAnimBlinkSpriteEffect; + } +} + +static void OakOldManHandleCmd42(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandlePlaySE(void) +{ + PlaySE(gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8)); + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandlePlayFanfare(void) +{ + PlayFanfare(gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8)); + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleFaintingCry(void) +{ + u16 species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES); + + PlayCry1(species, 25); + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleIntroSlide(void) +{ + HandleIntroSlide(gBattleBufferA[gActiveBattler][1]); + gIntroSlideFlags |= 1; + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleIntroTrainerBallThrow(void) +{ + u8 paletteNum; + u8 taskId; + + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + SetSpritePrimaryCoordsFromSecondaryCoords(&gSprites[gBattlerSpriteIds[gActiveBattler]]); + gSprites[gBattlerSpriteIds[gActiveBattler]].data[0] = 50; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[2] = -40; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[4] = gSprites[gBattlerSpriteIds[gActiveBattler]].pos1.y; + gSprites[gBattlerSpriteIds[gActiveBattler]].callback = StartAnimLinearTranslation; + gSprites[gBattlerSpriteIds[gActiveBattler]].data[5] = gActiveBattler; + StoreSpriteCallbackInData6(&gSprites[gBattlerSpriteIds[gActiveBattler]], sub_80335F8); + StartSpriteAnim(&gSprites[gBattlerSpriteIds[gActiveBattler]], 1); + paletteNum = AllocSpritePalette(0xD6F8); + LoadCompressedPalette(gTrainerBackPicPaletteTable[gSaveBlock2Ptr->playerGender].data, 0x100 + paletteNum * 16, 32); + gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = paletteNum; + taskId = CreateTask(sub_80EB0A8, 5); + gTasks[taskId].data[0] = gActiveBattler; + if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusSummaryShown) + gTasks[gBattlerStatusSummaryTaskId[gActiveBattler]].func = Task_HidePartyStatusSummary; + gBattleSpritesDataPtr->animationData->field_9_x1 = 1; + gBattlerControllerFuncs[gActiveBattler] = nullsub_13; + } + else + { + if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusSummaryShown) + gTasks[gBattlerStatusSummaryTaskId[gActiveBattler]].func = Task_HidePartyStatusSummary; + OakOldManBufferExecCompleted(); + } +} + +static void sub_80EAF34(u8 battlerId) +{ + u16 species; + + gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies = SPECIES_NONE; + gBattlerPartyIndexes[battlerId] = gBattleBufferA[battlerId][1]; + species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES); + gUnknown_3004FFC[battlerId] = CreateInvisibleSpriteWithCallback(sub_8033E3C); + SetMultiuseSpriteTemplateToPokemon(species, GetBattlerPosition(battlerId)); + gBattlerSpriteIds[battlerId] = CreateSprite(&gMultiuseSpriteTemplate, + GetBattlerSpriteCoord(battlerId, 2), + GetBattlerSpriteDefault_Y(battlerId), + GetBattlerSpriteSubpriority(battlerId)); + gSprites[gUnknown_3004FFC[battlerId]].data[1] = gBattlerSpriteIds[battlerId]; + gSprites[gBattlerSpriteIds[battlerId]].data[0] = battlerId; + gSprites[gBattlerSpriteIds[battlerId]].data[2] = species; + gSprites[gBattlerSpriteIds[battlerId]].oam.paletteNum = battlerId; + StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerId]], gBattleMonForms[battlerId]); + gSprites[gBattlerSpriteIds[battlerId]].invisible = TRUE; + gSprites[gBattlerSpriteIds[battlerId]].callback = SpriteCallbackDummy; + gSprites[gUnknown_3004FFC[battlerId]].data[0] = DoPokeballSendOutAnimation(0, POKEBALL_PLAYER_SENDOUT); +} + +static void sub_80EB0A8(u8 taskId) +{ + if (gTasks[taskId].data[1] < 31) + { + ++gTasks[taskId].data[1]; + } + else + { + u8 savedActiveBattler = gActiveBattler; + + gActiveBattler = gTasks[taskId].data[0]; + gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler]; + sub_80EAF34(gActiveBattler); + gBattlerControllerFuncs[gActiveBattler] = sub_80E7B4C; + gActiveBattler = savedActiveBattler; + DestroyTask(taskId); + } +} + +static void OakOldManHandleDrawPartyStatusSummary(void) +{ + if (gBattleBufferA[gActiveBattler][1] != 0 + && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { + OakOldManBufferExecCompleted(); + } + else + { + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusSummaryShown = TRUE; + gBattlerStatusSummaryTaskId[gActiveBattler] = CreatePartyStatusSummarySprites(gActiveBattler, + (struct HpAndStatus *)&gBattleBufferA[gActiveBattler][4], + gBattleBufferA[gActiveBattler][1], + gBattleBufferA[gActiveBattler][2]); + OakOldManBufferExecCompleted(); + } +} + +static void OakOldManHandleHidePartyStatusSummary(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleEndBounceEffect(void) +{ + EndBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX); + EndBounceEffect(gActiveBattler, BOUNCE_MON); + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleSpriteInvisibility(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleBattleAnimation(void) +{ + u8 animationId = gBattleBufferA[gActiveBattler][1]; + u16 argument = gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8); + + if (TryHandleLaunchBattleTableAnimation(gActiveBattler, gActiveBattler, gActiveBattler, animationId, argument)) + OakOldManBufferExecCompleted(); + else + gBattlerControllerFuncs[gActiveBattler] = CompleteOnFinishedBattleAnimation; +} + +static void OakOldManHandleLinkStandbyMsg(void) +{ + switch (gBattleBufferA[gActiveBattler][1]) + { + case 0: + case 1: + EndBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX); + EndBounceEffect(gActiveBattler, BOUNCE_MON); + break; + case 2: + break; + } + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleResetActionMoveSelection(void) +{ + OakOldManBufferExecCompleted(); +} + +static void OakOldManHandleCmd55(void) +{ + gBattleOutcome = gBattleBufferA[gActiveBattler][1]; + FadeOutMapMusic(5); + BeginFastPaletteFade(3); + OakOldManBufferExecCompleted(); + if (!(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER) && gBattleTypeFlags & BATTLE_TYPE_LINK) + gBattlerControllerFuncs[gActiveBattler] = sub_80E7930; +} + +static void OakOldManCmdEnd(void) +{ +} + +bool8 sub_80EB2E0(u8 a1) +{ + return gBattleStruct->field_96 & a1; +} + +void sub_80EB2F4(u8 a1) +{ + gBattleStruct->field_96 |= a1; +} + +void sub_80EB30C(void) +{ + u32 width = 0x1A; + u32 pal = 7; + + FillBgTilemapBufferRect(0, 0x30, 0, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x31, 1, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x32, 2, 0xE, width, 1, pal); + FillBgTilemapBufferRect(0, 0x33, 0x1C, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x34, 0x1D, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x35, 0, 0xF, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x36, 1, 0xF, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x38, 0x1C, 0xF, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x39, 0x1D, 0xF, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x3A, 0, 0x10, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x3B, 1, 0x10, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x3C, 0x1C, 0x10, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x3D, 0x1D, 0x10, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x3A), 0, 0x11, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x3B), 1, 0x11, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x3C), 0x1C, 0x11, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x3D), 0x1D, 0x11, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x35), 0, 0x12, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x36), 1, 0x12, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x38), 0x1C, 0x12, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x39), 0x1D, 0x12, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x30), 0, 0x13, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x31), 1, 0x13, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x32), 2, 0x13, width, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x33), 0x1C, 0x13, 1, 1, pal); + FillBgTilemapBufferRect(0, BG_TILE_V_FLIP(0x34), 0x1D, 0x13, 1, 1, pal); +} + +void sub_80EB524(void) +{ + u32 pal = 0; + u32 width = 0x1A; + u32 height; + + FillBgTilemapBufferRect(0, 3, 0, 0xE, 1, 1, pal); + height = 4; + FillBgTilemapBufferRect(0, 4, 1, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 5, 2, 0xE, width, 1, pal); + FillBgTilemapBufferRect(0, 6, 0x1C, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 7, 0x1D, 0xE, 1, 1, pal); + FillBgTilemapBufferRect(0, 8, 0, 0xF, 1, height, pal); + FillBgTilemapBufferRect(0, 9, 1, 0xF, 1, height, pal); + FillBgTilemapBufferRect(0, 0xA, 2, 0xF, width, height, pal); + FillBgTilemapBufferRect(0, 0xB, 0x1C, 0xF, 1, height, pal); + FillBgTilemapBufferRect(0, 0xC, 0x1D, 0xF, 1, height, pal); + FillBgTilemapBufferRect(0, 0xD, 0, 0x13, 1, 1, pal); + FillBgTilemapBufferRect(0, 0xE, 1, 0x13, 1, 1, pal); + FillBgTilemapBufferRect(0, 0xF, 2, 0x13, width, 1, pal); + FillBgTilemapBufferRect(0, 0x10, 0x1C, 0x13, 1, 1, pal); + FillBgTilemapBufferRect(0, 0x11, 0x1D, 0x13, 1, 1, pal); +} diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 794b83b73..a9173f1a9 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -45,7 +45,7 @@ static void OpponentHandleTrainerSlideBack(void); static void OpponentHandleFaintAnimation(void); static void OpponentHandlePaletteFade(void); static void OpponentHandleSuccessBallThrowAnim(void); -static void OpponentHandleBallThrow(void); +static void OpponentHandleBallThrowAnim(void); static void OpponentHandlePause(void); static void OpponentHandleMoveAnimation(void); static void OpponentHandlePrintString(void); @@ -116,7 +116,7 @@ static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(void) = OpponentHandleFaintAnimation, OpponentHandlePaletteFade, OpponentHandleSuccessBallThrowAnim, - OpponentHandleBallThrow, + OpponentHandleBallThrowAnim, OpponentHandlePause, OpponentHandleMoveAnimation, OpponentHandlePrintString, @@ -1231,7 +1231,7 @@ static void OpponentHandleSuccessBallThrowAnim(void) OpponentBufferExecCompleted(); } -static void OpponentHandleBallThrow(void) +static void OpponentHandleBallThrowAnim(void) { OpponentBufferExecCompleted(); } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index a9bb5bc6e..f8d5958ba 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -839,7 +839,7 @@ void sub_802F6A8(void) else { m4aSongNumStop(SE_HINSI); - gMain.inBattle = 0; + gMain.inBattle = FALSE; gMain.callback1 = gPreBattleCallback1; SetMainCallback2(gMain.savedCallback); } @@ -1318,7 +1318,6 @@ static void WaitForMonSelection(void) BtlController_EmitChosenMonReturnValue(1, gUnknown_203B0C1, gUnknown_203B0DC); else BtlController_EmitChosenMonReturnValue(1, 6, NULL); - if ((gBattleBufferA[gActiveBattler][1] & 0xF) == 1) PrintLinkStandbyMsg(); PlayerBufferExecCompleted(); diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 544af1006..f3530fc4b 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -85,9 +85,9 @@ static void InitSinglePlayerBtlControllers(void) gBattleMainFunc = BeginBattleIntro; if (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE) { - gBattlerControllerFuncs[0] = SetControllerToPokedude; + gBattlerControllerFuncs[0] = SetControllerToPokeDude; gBattlerPositions[0] = B_POSITION_PLAYER_LEFT; - gBattlerControllerFuncs[1] = SetControllerToPokedude; + gBattlerControllerFuncs[1] = SetControllerToPokeDude; gBattlerPositions[1] = B_POSITION_OPPONENT_LEFT; gBattlersCount = 2; } @@ -95,8 +95,8 @@ static void InitSinglePlayerBtlControllers(void) { if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) gBattlerControllerFuncs[0] = SetControllerToSafari; - else if (gBattleTypeFlags & (BATTLE_TYPE_OLDMAN_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) - gBattlerControllerFuncs[0] = SetControllerToOakOrOldman; + else if (gBattleTypeFlags & (BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) + gBattlerControllerFuncs[0] = SetControllerToOakOrOldMan; else gBattlerControllerFuncs[0] = SetControllerToPlayer; gBattlerPositions[0] = B_POSITION_PLAYER_LEFT; @@ -110,13 +110,13 @@ static void InitSinglePlayerBtlControllers(void) gBattleMainFunc = BeginBattleIntro; if (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE) { - gBattlerControllerFuncs[0] = SetControllerToPokedude; + gBattlerControllerFuncs[0] = SetControllerToPokeDude; gBattlerPositions[0] = B_POSITION_PLAYER_LEFT; - gBattlerControllerFuncs[1] = SetControllerToPokedude; + gBattlerControllerFuncs[1] = SetControllerToPokeDude; gBattlerPositions[1] = B_POSITION_OPPONENT_LEFT; - gBattlerControllerFuncs[2] = SetControllerToPokedude; + gBattlerControllerFuncs[2] = SetControllerToPokeDude; gBattlerPositions[2] = B_POSITION_PLAYER_RIGHT; - gBattlerControllerFuncs[3] = SetControllerToPokedude; + gBattlerControllerFuncs[3] = SetControllerToPokeDude; gBattlerPositions[3] = B_POSITION_OPPONENT_RIGHT; gBattlersCount = MAX_BATTLERS_COUNT; } @@ -774,7 +774,7 @@ void BtlController_EmitPrintSelectionString(u8 bufferId, u16 stringID) sBattleBuffersTransferData[1] = CONTROLLER_PRINTSTRINGPLAYERONLY; sBattleBuffersTransferData[2] = stringID; sBattleBuffersTransferData[3] = (stringID & 0xFF00) >> 8; - stringInfo = (struct BattleMsgData*)(&sBattleBuffersTransferData[4]); + stringInfo = (struct BattleMsgData *)(&sBattleBuffersTransferData[4]); stringInfo->currentMove = gCurrentMove; stringInfo->originallyUsedMove = gChosenMove; stringInfo->lastItem = gLastUsedItem; diff --git a/src/battle_main.c b/src/battle_main.c new file mode 100644 index 000000000..1b1614a5a --- /dev/null +++ b/src/battle_main.c @@ -0,0 +1,4412 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_script_commands.h" +#include "battle_controllers.h" +#include "battle_interface.h" +#include "battle_main.h" +#include "battle_message.h" +#include "battle_scripts.h" +#include "battle_setup.h" +#include "battle_tower.h" +#include "battle_string_ids.h" +#include "berry.h" +#include "bg.h" +#include "data.h" +#include "decompress.h" +#include "dma3.h" +#include "event_data.h" +#include "evolution_scene.h" +#include "graphics.h" +#include "gpu_regs.h" +#include "help_system.h" +#include "international_string_util.h" +#include "item.h" +#include "link.h" +#include "link_rfu.h" +#include "load_save.h" +#include "main.h" +#include "malloc.h" +#include "m4a.h" +#include "palette.h" +#include "party_menu.h" +#include "pokeball.h" +#include "pokedex.h" +#include "pokemon.h" +#include "quest_log.h" +#include "random.h" +#include "roamer.h" +#include "safari_zone.h" +#include "scanline_effect.h" +#include "sound.h" +#include "sprite.h" +#include "string_util.h" +#include "strings.h" +#include "task.h" +#include "text.h" +#include "trig.h" +#include "vs_seeker.h" +#include "util.h" +#include "window.h" +#include "cable_club.h" +#include "constants/abilities.h" +#include "constants/battle_move_effects.h" +#include "constants/hold_effects.h" +#include "constants/items.h" +#include "constants/moves.h" +#include "constants/pokemon.h" +#include "constants/songs.h" +#include "constants/species.h" +#include "constants/trainers.h" +#include "constants/trainer_classes.h" + +static void sub_80111EC(struct Sprite *sprite); +static void HandleAction_UseMove(void); +static void HandleAction_Switch(void); +static void HandleAction_UseItem(void); +static void HandleAction_Run(void); +static void HandleAction_WatchesCarefully(void); +static void HandleAction_SafariZoneBallThrow(void); +static void HandleAction_ThrowPokeblock(void); +static void HandleAction_GoNear(void); +static void HandleAction_SafariZoneRun(void); +static void HandleAction_OldManBallThrow(void); +static void HandleAction_TryFinish(void); +static void HandleAction_NothingIsFainted(void); +static void HandleAction_ActionFinished(void); +static void HandleEndTurn_ContinueBattle(void); +static void HandleEndTurn_BattleWon(void); +static void HandleEndTurn_BattleLost(void); +static void HandleEndTurn_RanFromBattle(void); +static void HandleEndTurn_MonFled(void); +static void HandleEndTurn_FinishBattle(void); +static void CB2_InitBattleInternal(void); +static void CB2_PreInitMultiBattle(void); +static void CB2_HandleStartMultiBattle(void); +static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum); +static void CB2_HandleStartBattle(void); +static void TryCorrectShedinjaLanguage(struct Pokemon *mon); +static void BattleMainCB1(void); +static void CB2_QuitPokeDudeBattle(void); +static void sub_80111FC(struct Sprite *sprite); +static void sub_8011B94(void); +static void sub_8011BB0(void); +static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite); +static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite); +static void sub_8011E3C(struct Sprite *sprite); +static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite); +static void sub_8012060(struct Sprite *sprite); +static void oac_poke_ally_(struct Sprite *sprite); +static void SpriteCallbackDummy3(struct Sprite *sprite); +static void SpriteCB_BounceEffect(struct Sprite *sprite); +static void sub_8012398(struct Sprite *sprite); +static void BattleStartClearSetData(void); +static void BattleIntroGetMonsData(void); +static void TurnValuesCleanUp(bool8 var0); +static void SpecialStatusesClear(void); +static void BattleIntroPrepareBackgroundSlide(void); +static void BattleIntroDrawTrainersOrMonsSprites(void); +static void BattleIntroDrawPartySummaryScreens(void); +static void BattleIntroPrintTrainerWantsToBattle(void); +static void BattleIntroPrintWildMonAttacked(void); +static void BattleIntroPrintOpponentSendsOut(void); +static void BattleIntroPrintPlayerSendsOut(void); +static void BattleIntroRecordMonsToDex(void); +static void BattleIntroOpponentSendsOutMonAnimation(void); +static void BattleIntroPlayerSendsOutMonAnimation(void); +static void TryDoEventsBeforeFirstTurn(void); +static void HandleTurnActionSelectionState(void); +static void RunTurnActionsFunctions(void); +static void SetActionsAndBattlersTurnOrder(void); +static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void); +static void HandleEndTurn_FinishBattle(void); +static void FreeResetData_ReturnToOvOrDoEvolutions(void); +static void ReturnFromBattleToOverworld(void); +static void TryEvolvePokemon(void); +static void WaitForEvoSceneToFinish(void); + +EWRAM_DATA u16 gBattle_BG0_X = 0; +EWRAM_DATA u16 gBattle_BG0_Y = 0; +EWRAM_DATA u16 gBattle_BG1_X = 0; +EWRAM_DATA u16 gBattle_BG1_Y = 0; +EWRAM_DATA u16 gBattle_BG2_X = 0; +EWRAM_DATA u16 gBattle_BG2_Y = 0; +EWRAM_DATA u16 gBattle_BG3_X = 0; +EWRAM_DATA u16 gBattle_BG3_Y = 0; +EWRAM_DATA u16 gBattle_WIN0H = 0; +EWRAM_DATA u16 gBattle_WIN0V = 0; +EWRAM_DATA u16 gBattle_WIN1H = 0; +EWRAM_DATA u16 gBattle_WIN1V = 0; +EWRAM_DATA u8 gDisplayedStringBattle[300] = {0}; +EWRAM_DATA u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT] = {0}; +EWRAM_DATA u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT] = {0}; +EWRAM_DATA u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT] = {0}; +static EWRAM_DATA u32 gUnknown_2022AE8[25] = {0}; +EWRAM_DATA u32 gBattleTypeFlags = 0; +EWRAM_DATA u8 gBattleTerrain = 0; +EWRAM_DATA u32 gUnknown_2022B54 = 0; +EWRAM_DATA struct UnknownPokemonStruct4 gUnknown_2022B58[3] = {0}; +EWRAM_DATA u8 *gUnknown_2022BB8 = NULL; +EWRAM_DATA u8 *gUnknown_2022BBC = NULL; +EWRAM_DATA u16 *gUnknown_2022BC0 = NULL; +EWRAM_DATA u8 gBattleBufferA[MAX_BATTLERS_COUNT][0x200] = {0}; +EWRAM_DATA u8 gBattleBufferB[MAX_BATTLERS_COUNT][0x200] = {0}; +EWRAM_DATA u8 gActiveBattler = 0; +EWRAM_DATA u32 gBattleControllerExecFlags = 0; +EWRAM_DATA u8 gBattlersCount = 0; +EWRAM_DATA u16 gBattlerPartyIndexes[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gBattlerPositions[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gActionsByTurnOrder[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gBattlerByTurnOrder[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gCurrentTurnActionNumber = 0; +EWRAM_DATA u8 gCurrentActionFuncId = 0; +EWRAM_DATA struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gBattlerSpriteIds[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gCurrMovePos = 0; +EWRAM_DATA u8 gChosenMovePos = 0; +EWRAM_DATA u16 gCurrentMove = 0; +EWRAM_DATA u16 gChosenMove = 0; +EWRAM_DATA u16 gCalledMove = 0; +EWRAM_DATA s32 gBattleMoveDamage = 0; +EWRAM_DATA s32 gHpDealt = 0; +EWRAM_DATA s32 gTakenDmg[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gLastUsedItem = 0; +EWRAM_DATA u8 gLastUsedAbility = 0; +EWRAM_DATA u8 gBattlerAttacker = 0; +EWRAM_DATA u8 gBattlerTarget = 0; +EWRAM_DATA u8 gBattlerFainted = 0; +EWRAM_DATA u8 gEffectBattler = 0; +EWRAM_DATA u8 gPotentialItemEffectBattler = 0; +EWRAM_DATA u8 gAbsentBattlerFlags = 0; +EWRAM_DATA u8 gCritMultiplier = 0; +EWRAM_DATA u8 gMultiHitCounter = 0; +EWRAM_DATA const u8 *gBattlescriptCurrInstr = NULL; +EWRAM_DATA u32 gUnusedBattleMainVar = 0; +EWRAM_DATA u8 gChosenActionByBattler[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA const u8 *gSelectionBattleScripts[MAX_BATTLERS_COUNT] = {NULL}; +EWRAM_DATA u16 gLastPrintedMoves[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gLastMoves[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gLastLandedMoves[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gLastHitByType[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gLastResultingMoves[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gLockedMoves[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gLastHitBy[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gChosenMoveByBattler[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gMoveResultFlags = 0; +EWRAM_DATA u32 gHitMarker = 0; +static EWRAM_DATA u8 gUnknown_2023DD4[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gTakenDmgByBattler[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gUnknown_2023DDC = 0; +EWRAM_DATA u16 gSideStatuses[2] = {0}; +EWRAM_DATA struct SideTimer gSideTimers[2] = {0}; +EWRAM_DATA u32 gStatuses3[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gPauseCounterBattle = 0; +EWRAM_DATA u16 gPaydayMoney = 0; +EWRAM_DATA u16 gRandomTurnNumber = 0; +EWRAM_DATA u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT] = {0}; +EWRAM_DATA u8 gBattleOutcome = 0; +EWRAM_DATA struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA struct SpecialStatus gSpecialStatuses[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u16 gBattleWeather = 0; +EWRAM_DATA struct WishFutureKnock gWishFutureKnock = {0}; +EWRAM_DATA u16 gIntroSlideFlags = 0; +EWRAM_DATA u8 gSentPokesToOpponent[2] = {0}; +EWRAM_DATA u16 gDynamicBasePower = 0; +EWRAM_DATA u16 gExpShareExp = 0; +EWRAM_DATA struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA struct BattleScripting gBattleScripting = {0}; +EWRAM_DATA struct BattleStruct *gBattleStruct = NULL; +EWRAM_DATA u8 *gLinkBattleSendBuffer = NULL; +EWRAM_DATA u8 *gLinkBattleRecvBuffer = NULL; +EWRAM_DATA struct BattleResources *gBattleResources = NULL; +EWRAM_DATA u8 gActionSelectionCursor[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gMoveSelectionCursor[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gBattlerStatusSummaryTaskId[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA u8 gBattlerInMenuId = 0; +EWRAM_DATA bool8 gDoingBattleAnim = FALSE; +EWRAM_DATA u32 gTransformedPersonalities[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA struct BattleSpriteData *gBattleSpritesDataPtr = NULL; +EWRAM_DATA struct MonSpritesGfx *gMonSpritesGfxPtr = NULL; +EWRAM_DATA u16 gBattleMovePower = 0; +EWRAM_DATA u16 gMoveToLearn = 0; +EWRAM_DATA u8 gBattleMonForms[MAX_BATTLERS_COUNT] = {0}; + +void (*gPreBattleCallback1)(void); +void (*gBattleMainFunc)(void); +struct BattleResults gBattleResults; +u8 gLeveledUpInBattle; +void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(void); +u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT]; +u8 gMultiUsePlayerCursor; +u8 gNumberOfMovesToChoose; +u8 gUnknown_3004FFC[MAX_BATTLERS_COUNT]; + +static const struct ScanlineEffectParams sIntroScanlineParams16Bit = +{ + ®_BG3HOFS, SCANLINE_EFFECT_DMACNT_16BIT, 1 +}; + +const struct SpriteTemplate gUnknown_824EFF0 = +{ + .tileTag = 0, + .paletteTag = 0, + .oam = &gDummyOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = sub_80111EC, +}; + +static const u8 sText_ShedinjaJpnName[] = _("ヌケニン"); // Nukenin + +const struct OamData gOamData_824F010 = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_NORMAL, + .objMode = ST_OAM_OBJ_NORMAL, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(64x64), + .x = 0, + .size = SPRITE_SIZE(64x64), + .tileNum = 0, + .priority = 2, + .paletteNum = 0, + .affineParam = 0, +}; + +const struct OamData gOamData_824F018 = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_NORMAL, + .objMode = ST_OAM_OBJ_NORMAL, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(64x64), + .x = 0, + .size = SPRITE_SIZE(64x64), + .tileNum = 0, + .priority = 2, + .paletteNum = 2, + .affineParam = 0, +}; + +// not used +static const union AnimCmd gUnknown_824F020[] = +{ + ANIMCMD_FRAME(0, 5), + ANIMCMD_JUMP(0), +}; + +// not used +static const union AnimCmd *const gUnknown_824F028[] = +{ + gUnknown_824F020, +}; + +// not used +static const union AffineAnimCmd gUnknown_824F02C[] = +{ + AFFINEANIMCMD_FRAME(-0x10, 0x0, 0, 4), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 0x3C), + AFFINEANIMCMD_JUMP(1), +}; + +// not used +static const union AffineAnimCmd *const gUnknown_824F044[] = +{ + gUnknown_824F02C, +}; + +static const s8 gUnknown_824F048[] = { -32, -16, -16, -32, -32, 0, 0, 0 }; + +// format: attacking type, defending type, damage multiplier +// the multiplier is a (decimal) fixed-point number: +// 20 is ×2.0 TYPE_MUL_SUPER_EFFECTIVE +// 10 is ×1.0 TYPE_MUL_NORMAL +// 05 is ×0.5 TYPE_MUL_NOT_EFFECTIVE +// 00 is ×0.0 TYPE_MUL_NO_EFFECT +const u8 gTypeEffectiveness[336] = +{ + TYPE_NORMAL, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE, + TYPE_NORMAL, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIRE, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIRE, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIRE, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIRE, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIRE, TYPE_BUG, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIRE, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIRE, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIRE, TYPE_STEEL, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_WATER, TYPE_FIRE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_WATER, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE, + TYPE_WATER, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE, + TYPE_WATER, TYPE_GROUND, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_WATER, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_WATER, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ELECTRIC, TYPE_WATER, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ELECTRIC, TYPE_ELECTRIC, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ELECTRIC, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ELECTRIC, TYPE_GROUND, TYPE_MUL_NO_EFFECT, + TYPE_ELECTRIC, TYPE_FLYING, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ELECTRIC, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_WATER, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GRASS, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_GROUND, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GRASS, TYPE_FLYING, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_BUG, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GRASS, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GRASS, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ICE, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ICE, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ICE, TYPE_ICE, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ICE, TYPE_GROUND, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ICE, TYPE_FLYING, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ICE, TYPE_DRAGON, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ICE, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ICE, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIGHTING, TYPE_NORMAL, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIGHTING, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIGHTING, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIGHTING, TYPE_FLYING, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIGHTING, TYPE_PSYCHIC, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIGHTING, TYPE_BUG, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FIGHTING, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIGHTING, TYPE_DARK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FIGHTING, TYPE_STEEL, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_POISON, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_POISON, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_POISON, TYPE_GROUND, TYPE_MUL_NOT_EFFECTIVE, + TYPE_POISON, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE, + TYPE_POISON, TYPE_GHOST, TYPE_MUL_NOT_EFFECTIVE, + TYPE_POISON, TYPE_STEEL, TYPE_MUL_NO_EFFECT, + TYPE_GROUND, TYPE_FIRE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GROUND, TYPE_ELECTRIC, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GROUND, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GROUND, TYPE_POISON, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GROUND, TYPE_FLYING, TYPE_MUL_NO_EFFECT, + TYPE_GROUND, TYPE_BUG, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GROUND, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GROUND, TYPE_STEEL, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FLYING, TYPE_ELECTRIC, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FLYING, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FLYING, TYPE_FIGHTING, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FLYING, TYPE_BUG, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_FLYING, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FLYING, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_PSYCHIC, TYPE_FIGHTING, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_PSYCHIC, TYPE_POISON, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_PSYCHIC, TYPE_PSYCHIC, TYPE_MUL_NOT_EFFECTIVE, + TYPE_PSYCHIC, TYPE_DARK, TYPE_MUL_NO_EFFECT, + TYPE_PSYCHIC, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_BUG, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE, + TYPE_BUG, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_BUG, TYPE_FIGHTING, TYPE_MUL_NOT_EFFECTIVE, + TYPE_BUG, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE, + TYPE_BUG, TYPE_FLYING, TYPE_MUL_NOT_EFFECTIVE, + TYPE_BUG, TYPE_PSYCHIC, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_BUG, TYPE_GHOST, TYPE_MUL_NOT_EFFECTIVE, + TYPE_BUG, TYPE_DARK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_BUG, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ROCK, TYPE_FIRE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ROCK, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ROCK, TYPE_FIGHTING, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ROCK, TYPE_GROUND, TYPE_MUL_NOT_EFFECTIVE, + TYPE_ROCK, TYPE_FLYING, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ROCK, TYPE_BUG, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_ROCK, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GHOST, TYPE_NORMAL, TYPE_MUL_NO_EFFECT, + TYPE_GHOST, TYPE_PSYCHIC, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_GHOST, TYPE_DARK, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GHOST, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_GHOST, TYPE_GHOST, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_DRAGON, TYPE_DRAGON, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_DRAGON, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_DARK, TYPE_FIGHTING, TYPE_MUL_NOT_EFFECTIVE, + TYPE_DARK, TYPE_PSYCHIC, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_DARK, TYPE_GHOST, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_DARK, TYPE_DARK, TYPE_MUL_NOT_EFFECTIVE, + TYPE_DARK, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_STEEL, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE, + TYPE_STEEL, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE, + TYPE_STEEL, TYPE_ELECTRIC, TYPE_MUL_NOT_EFFECTIVE, + TYPE_STEEL, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_STEEL, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE, + TYPE_STEEL, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE, + TYPE_FORESIGHT, TYPE_FORESIGHT, TYPE_MUL_NO_EFFECT, + TYPE_NORMAL, TYPE_GHOST, TYPE_MUL_NO_EFFECT, + TYPE_FIGHTING, TYPE_GHOST, TYPE_MUL_NO_EFFECT, + TYPE_ENDTABLE, TYPE_ENDTABLE, TYPE_MUL_NO_EFFECT +}; + +const u8 gTypeNames[][TYPE_NAME_LENGTH + 1] = +{ + _("NORMAL"), + _("FIGHT"), + _("FLYING"), + _("POISON"), + _("GROUND"), + _("ROCK"), + _("BUG"), + _("GHOST"), + _("STEEL"), + _("???"), + _("FIRE"), + _("WATER"), + _("GRASS"), + _("ELECTR"), + _("PSYCHC"), + _("ICE"), + _("DRAGON"), + _("DARK"), +}; + +// This is a factor in how much money you get for beating a trainer. +const struct TrainerMoney gTrainerMoneyTable[] = +{ + { CLASS_LEADER_2, 25 }, + { CLASS_ELITE_FOUR_2, 25 }, + { CLASS_PKMN_PROF, 25 }, + { CLASS_RIVAL, 4 }, + { CLASS_RIVAL_2, 9 }, + { CLASS_CHAMPION_2, 25 }, + { CLASS_YOUNGSTER_2, 4 }, + { CLASS_BUG_CATCHER_2, 3 }, + { CLASS_HIKER_2, 9 }, + { CLASS_BIRD_KEEPER_2, 6 }, + { CLASS_PICNICKER_2, 5 }, + { CLASS_SUPER_NERD, 6 }, + { CLASS_FISHERMAN_2, 9 }, + { CLASS_TEAM_ROCKET, 8 }, + { CLASS_LASS_2, 4 }, + { CLASS_BEAUTY_2, 18 }, + { CLASS_BLACK_BELT_2, 6 }, + { CLASS_CUE_BALL, 6 }, + { CLASS_CHANNELER, 8 }, + { CLASS_ROCKER, 6 }, + { CLASS_GENTLEMAN_2, 18 }, + { CLASS_BURGLAR, 22 }, + { CLASS_SWIMMER_MALE_2, 1 }, + { CLASS_ENGINEER, 12 }, + { CLASS_JUGGLER, 10 }, + { CLASS_SAILOR_2, 8 }, + { CLASS_COOLTRAINER_2, 9 }, + { CLASS_POKEMANIAC_2, 12 }, + { CLASS_TAMER, 10 }, + { CLASS_CAMPER_2, 5 }, + { CLASS_PSYCHIC_2, 5 }, + { CLASS_BIKER, 5 }, + { CLASS_GAMER, 18 }, + { CLASS_SCIENTIST, 12 }, + { CLASS_CRUSH_GIRL, 6 }, + { CLASS_TUBER_3, 1 }, + { CLASS_PKMN_BREEDER_2, 7 }, + { CLASS_PKMN_RANGER_2, 9 }, + { CLASS_AROMA_LADY_2, 7 }, + { CLASS_RUIN_MANIAC_2, 12 }, + { CLASS_LADY_2, 50 }, + { CLASS_PAINTER, 4 }, + { CLASS_TWINS_2, 3 }, + { CLASS_YOUNG_COUPLE_2, 7 }, + { CLASS_SIS_AND_BRO_2, 1 }, + { CLASS_COOL_COUPLE, 6 }, + { CLASS_CRUSH_KIN, 6 }, + { CLASS_SWIMMER_FEMALE_2, 1 }, + { CLASS_PLAYER, 1 }, + { CLASS_LEADER, 25 }, + { CLASS_ELITE_FOUR, 25 }, + { CLASS_LASS, 4 }, + { CLASS_YOUNGSTER, 4 }, + { CLASS_PKMN_TRAINER_3, 15 }, + { CLASS_HIKER, 10 }, + { CLASS_BEAUTY, 20 }, + { CLASS_FISHERMAN, 10 }, + { CLASS_LADY, 50 }, + { CLASS_TRIATHLETE, 10 }, + { CLASS_TEAM_AQUA, 5 }, + { CLASS_TWINS, 3 }, + { CLASS_SWIMMER_FEMALE, 2 }, + { CLASS_BUG_CATCHER, 4 }, + { CLASS_SCHOOL_KID, 5 }, + { CLASS_RICH_BOY, 50 }, + { CLASS_SR_AND_JR, 4 }, + { CLASS_BLACK_BELT, 8 }, + { CLASS_TUBER, 1 }, + { CLASS_HEX_MANIAC, 6 }, + { CLASS_PKMN_BREEDER, 10 }, + { CLASS_TEAM_MAGMA, 5 }, + { CLASS_INTERVIEWER, 12 }, + { CLASS_TUBER_2, 1 }, + { CLASS_YOUNG_COUPLE, 8 }, + { CLASS_GUITARIST, 8 }, + { CLASS_GENTLEMAN, 20 }, + { CLASS_CHAMPION, 50 }, + { CLASS_MAGMA_LEADER, 20 }, + { CLASS_BATTLE_GIRL, 6 }, + { CLASS_SWIMMER_MALE, 2 }, + { CLASS_POKEFAN, 20 }, + { CLASS_EXPERT, 10 }, + { CLASS_DRAGON_TAMER, 12 }, + { CLASS_BIRD_KEEPER, 8 }, + { CLASS_NINJA_BOY, 3 }, + { CLASS_PARASOL_LADY, 10 }, + { CLASS_BUG_MANIAC, 15 }, + { CLASS_SAILOR, 8 }, + { CLASS_COLLECTOR, 15 }, + { CLASS_PKMN_RANGER, 12 }, + { CLASS_MAGMA_ADMIN, 10 }, + { CLASS_AROMA_LADY, 10 }, + { CLASS_RUIN_MANIAC, 15 }, + { CLASS_COOLTRAINER, 12 }, + { CLASS_POKEMANIAC, 15 }, + { CLASS_KINDLER, 8 }, + { CLASS_CAMPER, 4 }, + { CLASS_PICNICKER, 4 }, + { CLASS_PSYCHIC, 6 }, + { CLASS_SIS_AND_BRO, 3 }, + { CLASS_OLD_COUPLE, 10 }, + { CLASS_AQUA_ADMIN, 10 }, + { CLASS_AQUA_LEADER, 20 }, + { CLASS_BOSS, 25 }, + { 0xFF, 5 }, +}; + +#include "data/text/abilities.h" + +static void (*const sTurnActionsFuncsTable[])(void) = +{ + [B_ACTION_USE_MOVE] = HandleAction_UseMove, + [B_ACTION_USE_ITEM] = HandleAction_UseItem, + [B_ACTION_SWITCH] = HandleAction_Switch, + [B_ACTION_RUN] = HandleAction_Run, + [B_ACTION_SAFARI_WATCH_CAREFULLY] = HandleAction_WatchesCarefully, + [B_ACTION_SAFARI_BALL] = HandleAction_SafariZoneBallThrow, + [B_ACTION_SAFARI_POKEBLOCK] = HandleAction_ThrowPokeblock, + [B_ACTION_SAFARI_GO_NEAR] = HandleAction_GoNear, + [B_ACTION_SAFARI_RUN] = HandleAction_SafariZoneRun, + [B_ACTION_OLDMAN_THROW] = HandleAction_OldManBallThrow, + [B_ACTION_EXEC_SCRIPT] = HandleAction_RunBattleScript, + [B_ACTION_TRY_FINISH] = HandleAction_TryFinish, + [B_ACTION_FINISHED] = HandleAction_ActionFinished, + [B_ACTION_NOTHING_FAINTED] = HandleAction_NothingIsFainted, +}; + +static void (*const sEndTurnFuncsTable[])(void) = +{ + [0] = HandleEndTurn_ContinueBattle, //B_OUTCOME_NONE? + [B_OUTCOME_WON] = HandleEndTurn_BattleWon, + [B_OUTCOME_LOST] = HandleEndTurn_BattleLost, + [B_OUTCOME_DREW] = HandleEndTurn_BattleLost, + [B_OUTCOME_RAN] = HandleEndTurn_RanFromBattle, + [B_OUTCOME_PLAYER_TELEPORTED] = HandleEndTurn_FinishBattle, + [B_OUTCOME_MON_FLED] = HandleEndTurn_MonFled, + [B_OUTCOME_CAUGHT] = HandleEndTurn_FinishBattle, + [B_OUTCOME_NO_SAFARI_BALLS] = HandleEndTurn_FinishBattle, +}; + +const u8 gStatusConditionString_PoisonJpn[8] = _("どく$$$$$"); +const u8 gStatusConditionString_SleepJpn[8] = _("ねむり$$$$"); +const u8 gStatusConditionString_ParalysisJpn[8] = _("まひ$$$$$"); +const u8 gStatusConditionString_BurnJpn[8] = _("やけど$$$$"); +const u8 gStatusConditionString_IceJpn[8] = _("こおり$$$$"); +const u8 gStatusConditionString_ConfusionJpn[8] = _("こんらん$$$"); +const u8 gStatusConditionString_LoveJpn[8] = _("メロメロ$$$"); + +const u8 *const gStatusConditionStringsTable[7][2] = +{ + { gStatusConditionString_PoisonJpn, gText_Poison }, + { gStatusConditionString_SleepJpn, gText_Sleep }, + { gStatusConditionString_ParalysisJpn, gText_Paralysis }, + { gStatusConditionString_BurnJpn, gText_Burn }, + { gStatusConditionString_IceJpn, gText_Ice }, + { gStatusConditionString_ConfusionJpn, gText_Confusion }, + { gStatusConditionString_LoveJpn, gText_Love } +}; + +void CB2_InitBattle(void) +{ + MoveSaveBlocks_ResetHeap(); + AllocateBattleResources(); + AllocateBattleSpritesData(); + AllocateMonSpritesGfx(); + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + HandleLinkBattleSetup(); + SetMainCallback2(CB2_PreInitMultiBattle); + gBattleCommunication[MULTIUSE_STATE] = 0; + } + else + { + CB2_InitBattleInternal(); + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + HelpSystem_SetSomeVariable2(0x19); + else + HelpSystem_SetSomeVariable2(0x18); + } + else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + { + HelpSystem_SetSomeVariable2(0x1A); + } + else + { + HelpSystem_SetSomeVariable2(0x17); + } + } + } +} + +static void CB2_InitBattleInternal(void) +{ + s32 i; + + SetHBlankCallback(NULL); + SetVBlankCallback(NULL); + CpuFill32(0, (void *)VRAM, VRAM_SIZE); + SetGpuReg(REG_OFFSET_MOSAIC, 0); + SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(0, 0xF0)); + SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(0x50, 0x51)); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + gBattle_WIN0H = WIN_RANGE(0, 0xF0); + gBattle_WIN0V = WIN_RANGE(0x50, 0x51); + ScanlineEffect_Clear(); + for (i = 0; i < 80; ++i) + { + gScanlineEffectRegBuffers[0][i] = 0xF0; + gScanlineEffectRegBuffers[1][i] = 0xF0; + } + for (; i < 160; ++i) + { + gScanlineEffectRegBuffers[0][i] = 0xFF10; + gScanlineEffectRegBuffers[1][i] = 0xFF10; + } + ScanlineEffect_SetParams(sIntroScanlineParams16Bit); + ResetPaletteFade(); + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + gBattle_BG3_X = 0; + gBattle_BG3_Y = 0; + gBattleTerrain = BattleSetup_GetTerrainId(); + sub_800F34C(); + LoadBattleTextboxAndBackground(); + ResetSpriteData(); + ResetTasks(); + DrawBattleEntryBackground(); + FreeAllSpritePalettes(); + gReservedSpritePaletteCount = 4; + SetVBlankCallback(VBlankCB_Battle); + SetUpBattleVars(); + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + SetMainCallback2(CB2_HandleStartMultiBattle); + else + SetMainCallback2(CB2_HandleStartBattle); + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A); + SetWildMonHeldItem(); + } + gMain.inBattle = TRUE; + for (i = 0; i < PARTY_SIZE; ++i) + AdjustFriendship(&gPlayerParty[i], 3); + gBattleCommunication[MULTIUSE_STATE] = 0; +} + +static void sub_800FFEC(void) +{ + u16 r6 = 0; + u16 species = SPECIES_NONE; + u16 hp = 0; + u32 status = 0; + s32 i; + + for (i = 0; i < PARTY_SIZE; ++i) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp != 0 && status == 0) + r6 |= 1 << i * 2; + if (species == SPECIES_NONE) + continue; + if (hp != 0 && (species == SPECIES_EGG || status != 0)) + r6 |= 2 << i * 2; + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp == 0) + r6 |= 3 << i * 2; + } + gBattleStruct->field_186 = r6; + *(&gBattleStruct->field_187) = r6 >> 8; +} + +static void SetPlayerBerryDataInBattleStruct(void) +{ + s32 i; + struct BattleStruct *battleStruct = gBattleStruct; + struct BattleEnigmaBerry *battleBerry = &battleStruct->battleEnigmaBerry; + + if (IsEnigmaBerryValid() == TRUE) + { + for (i = 0; i < BERRY_NAME_LENGTH; ++i) + battleBerry->name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i]; + battleBerry->name[i] = EOS; + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; ++i) + battleBerry->itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i]; + battleBerry->holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + battleBerry->holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam; + } + else + { + const struct Berry *berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY)); + + for (i = 0; i < BERRY_NAME_LENGTH; ++i) + battleBerry->name[i] = berryData->name[i]; + battleBerry->name[i] = EOS; + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; ++i) + battleBerry->itemEffect[i] = 0; + battleBerry->holdEffect = HOLD_EFFECT_NONE; + battleBerry->holdEffectParam = 0; + } +} + +static void SetAllPlayersBerryData(void) +{ + s32 i, j; + + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + if (IsEnigmaBerryValid() == TRUE) + { + for (i = 0; i < BERRY_NAME_LENGTH; ++i) + { + gEnigmaBerries[0].name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i]; + gEnigmaBerries[2].name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i]; + } + gEnigmaBerries[0].name[i] = EOS; + gEnigmaBerries[2].name[i] = EOS; + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; ++i) + { + gEnigmaBerries[0].itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i]; + gEnigmaBerries[2].itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i]; + } + gEnigmaBerries[0].holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + gEnigmaBerries[2].holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + gEnigmaBerries[0].holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam; + gEnigmaBerries[2].holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam; + } + else + { + const struct Berry *berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY)); + + for (i = 0; i < BERRY_NAME_LENGTH; ++i) + { + gEnigmaBerries[0].name[i] = berryData->name[i]; + gEnigmaBerries[2].name[i] = berryData->name[i]; + } + gEnigmaBerries[0].name[i] = EOS; + gEnigmaBerries[2].name[i] = EOS; + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; ++i) + { + gEnigmaBerries[0].itemEffect[i] = 0; + gEnigmaBerries[2].itemEffect[i] = 0; + } + gEnigmaBerries[0].holdEffect = HOLD_EFFECT_NONE; + gEnigmaBerries[2].holdEffect = HOLD_EFFECT_NONE; + gEnigmaBerries[0].holdEffectParam = 0; + gEnigmaBerries[2].holdEffectParam = 0; + } + } + else + { + s32 numPlayers; + struct BattleEnigmaBerry *src; + u8 battlerId; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + for (i = 0; i < 4; ++i) + { + src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2); + battlerId = gLinkPlayers[i].id; + for (j = 0; j < BERRY_NAME_LENGTH; ++j) + gEnigmaBerries[battlerId].name[j] = src->name[j]; + gEnigmaBerries[battlerId].name[j] = EOS; + for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; ++j) + gEnigmaBerries[battlerId].itemEffect[j] = src->itemEffect[j]; + gEnigmaBerries[battlerId].holdEffect = src->holdEffect; + gEnigmaBerries[battlerId].holdEffectParam = src->holdEffectParam; + } + } + else + { + for (i = 0; i < 2; ++i) + { + src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2); + for (j = 0; j < BERRY_NAME_LENGTH; ++j) + { + gEnigmaBerries[i].name[j] = src->name[j]; + gEnigmaBerries[i + 2].name[j] = src->name[j]; + } + gEnigmaBerries[i].name[j] = EOS; + gEnigmaBerries[i + 2].name[j] = EOS; + for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; ++j) + { + gEnigmaBerries[i].itemEffect[j] = src->itemEffect[j]; + gEnigmaBerries[i + 2].itemEffect[j] = src->itemEffect[j]; + } + gEnigmaBerries[i].holdEffect = src->holdEffect; + gEnigmaBerries[i + 2].holdEffect = src->holdEffect; + gEnigmaBerries[i].holdEffectParam = src->holdEffectParam; + gEnigmaBerries[i + 2].holdEffectParam = src->holdEffectParam; + } + } + } +} + +static void sub_8010414(u8 arg0, u8 arg1) +{ + u8 var = 0; + + if (gBlockRecvBuffer[0][0] == 256) + { + if (arg1 == 0) + gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER; + else + gBattleTypeFlags |= BATTLE_TYPE_TRAINER; + ++var; + } + if (var == 0) + { + s32 i; + + for (i = 0; i < arg0; ++i) + if (gBlockRecvBuffer[0][0] != gBlockRecvBuffer[i][0]) + break; + if (i == arg0) + { + if (arg1 == 0) + gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER; + else + gBattleTypeFlags |= BATTLE_TYPE_TRAINER; + ++var; + } + if (var == 0) + { + for (i = 0; i < arg0; ++i) + { + if (gBlockRecvBuffer[i][0] == 0x201) + if (i != arg1 && i < arg1) + break; + if (gBlockRecvBuffer[i][0] > 0x201 && i != arg1) + break; + } + if (i == arg0) + gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER; + else + gBattleTypeFlags |= BATTLE_TYPE_TRAINER; + } + } +} + +static void CB2_HandleStartBattle(void) +{ + u8 playerMultiplayerId; + u8 enemyMultiplayerId; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + playerMultiplayerId = GetMultiplayerId(); + gBattleStruct->multiplayerId = playerMultiplayerId; + enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE; + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (!IsDma3ManagerBusyWithBgCopy()) + { + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + sub_80357C8(); + gBattleCommunication[MULTIUSE_STATE] = 1; + } + if (gWirelessCommType) + LoadWirelessStatusIndicatorSpriteGfx(); + break; + case 1: + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + if (gReceivedRemoteLinkPlayers != 0) + { + if (IsLinkTaskFinished()) + { + *(&gBattleStruct->field_184) = 1; + *(&gBattleStruct->field_185) = 2; + sub_800FFEC(); + SetPlayerBerryDataInBattleStruct(); + SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_184, 32); + gBattleCommunication[MULTIUSE_STATE] = 2; + } + if (gWirelessCommType != 0) + CreateWirelessStatusIndicatorSprite(0, 0); + } + } + else + { + gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER; + gBattleCommunication[MULTIUSE_STATE] = 15; + SetAllPlayersBerryData(); + } + break; + case 2: + if ((GetBlockReceivedStatus() & 3) == 3) + { + u8 taskId; + + ResetBlockReceivedFlags(); + sub_8010414(2, playerMultiplayerId); + SetAllPlayersBerryData(); + taskId = CreateTask(sub_800F6FC, 0); + gTasks[taskId].data[1] = 270; + gTasks[taskId].data[2] = 90; + gTasks[taskId].data[5] = 0; + gTasks[taskId].data[3] = gBattleStruct->field_186 | (gBattleStruct->field_187 << 8); + gTasks[taskId].data[4] = gBlockRecvBuffer[enemyMultiplayerId][1]; + SetDeoxysStats(); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 3: + if (IsLinkTaskFinished()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 4: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + memcpy(gEnemyParty, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 7: + if (IsLinkTaskFinished()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon) * 2); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 8: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + memcpy(gEnemyParty + 2, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 11: + if (IsLinkTaskFinished()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 4, sizeof(struct Pokemon) * 2); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 12: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + memcpy(gEnemyParty + 4, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + TryCorrectShedinjaLanguage(&gEnemyParty[0]); + TryCorrectShedinjaLanguage(&gEnemyParty[1]); + TryCorrectShedinjaLanguage(&gEnemyParty[2]); + TryCorrectShedinjaLanguage(&gEnemyParty[3]); + TryCorrectShedinjaLanguage(&gEnemyParty[4]); + TryCorrectShedinjaLanguage(&gEnemyParty[5]); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 15: + sub_800D30C(); + ++gBattleCommunication[MULTIUSE_STATE]; + gBattleCommunication[SPRITES_INIT_STATE1] = 0; + gBattleCommunication[SPRITES_INIT_STATE2] = 0; + break; + case 16: + if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2])) + { + gPreBattleCallback1 = gMain.callback1; + gMain.callback1 = BattleMainCB1; + SetMainCallback2(BattleMainCB2); + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleTypeFlags |= BATTLE_TYPE_20; + } + } + break; + case 5: + case 9: + case 13: + ++gBattleCommunication[MULTIUSE_STATE]; + gBattleCommunication[1] = 1; + case 6: + case 10: + case 14: + if (--gBattleCommunication[1] == 0) + ++gBattleCommunication[MULTIUSE_STATE]; + break; + } +} + +static void sub_80108C4(void) +{ + s32 i, j; + u8 *nick, *cur; + + for (i = 0; i < 3; ++i) + { + gUnknown_2022B58[i].species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES); + gUnknown_2022B58[i].heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + nick = gUnknown_2022B58[i].nickname; + GetMonData(&gPlayerParty[i], MON_DATA_NICKNAME, nick); + gUnknown_2022B58[i].level = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); + gUnknown_2022B58[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + gUnknown_2022B58[i].maxhp = GetMonData(&gPlayerParty[i], MON_DATA_MAX_HP); + gUnknown_2022B58[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + gUnknown_2022B58[i].personality = GetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY); + gUnknown_2022B58[i].gender = GetMonGender(&gPlayerParty[i]); + StripExtCtrlCodes(nick); + if (GetMonData(&gPlayerParty[i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE) + { + for (cur = nick, j = 0; cur[j] != EOS; ++j) + ; + while (j < 6) + cur[j++] = 0; + cur[j] = EOS; + } + } + memcpy(&gBattleStruct->field_184, gUnknown_2022B58, sizeof(gUnknown_2022B58)); +} + +static void CB2_PreInitMultiBattle(void) +{ + s32 i; + u8 playerMultiplierId; + u8 r4 = 0xF; + u16 *savedBattleTypeFlags; + void (**savedCallback)(void); + + playerMultiplierId = GetMultiplayerId(); + gBattleStruct->multiplayerId = playerMultiplierId; + savedCallback = &gBattleStruct->savedCallback; + savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (gReceivedRemoteLinkPlayers != 0 && IsLinkTaskFinished()) + { + sub_80108C4(); + SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_184, sizeof(gUnknown_2022B58)); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 1: + if ((GetBlockReceivedStatus() & r4) == r4) + { + ResetBlockReceivedFlags(); + for (i = 0; i < 4; ++i) + { + if (i == playerMultiplierId) + continue; + if ((!(gLinkPlayers[i].id & 1) && !(gLinkPlayers[playerMultiplierId].id & 1)) + || (gLinkPlayers[i].id & 1 && gLinkPlayers[playerMultiplierId].id & 1)) + memcpy(gUnknown_2022B58, gBlockRecvBuffer[i], sizeof(gUnknown_2022B58)); + } + ++gBattleCommunication[MULTIUSE_STATE]; + *savedCallback = gMain.savedCallback; + *savedBattleTypeFlags = gBattleTypeFlags; + gMain.savedCallback = CB2_PreInitMultiBattle; + sub_8128198(); + } + break; + case 2: + if (!gPaletteFade.active) + { + ++gBattleCommunication[MULTIUSE_STATE]; + if (gWirelessCommType) + sub_800AB9C(); + else + sub_800AAC0(); + } + break; + case 3: + if (gWirelessCommType) + { + if (IsLinkRfuTaskFinished()) + { + gBattleTypeFlags = *savedBattleTypeFlags; + gMain.savedCallback = *savedCallback; + SetMainCallback2(CB2_InitBattleInternal); + } + } + else if (gReceivedRemoteLinkPlayers == 0) + { + gBattleTypeFlags = *savedBattleTypeFlags; + gMain.savedCallback = *savedCallback; + SetMainCallback2(CB2_InitBattleInternal); + } + break; + } +} + +static void CB2_HandleStartMultiBattle(void) +{ + u8 playerMultiplayerId; + s32 id; + u8 taskId; + + playerMultiplayerId = GetMultiplayerId(); + gBattleStruct->multiplayerId = playerMultiplayerId; + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (!IsDma3ManagerBusyWithBgCopy()) + { + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + sub_80357C8(); + gBattleCommunication[MULTIUSE_STATE] = 1; + } + if (gWirelessCommType) + LoadWirelessStatusIndicatorSpriteGfx(); + break; + case 1: + if (gReceivedRemoteLinkPlayers != 0) + { + if (IsLinkTaskFinished()) + { + *(&gBattleStruct->field_184) = 1; + *(&gBattleStruct->field_185) = 2; + sub_800FFEC(); + SetPlayerBerryDataInBattleStruct(); + SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_184, 32); + ++gBattleCommunication[MULTIUSE_STATE]; + } + if (gWirelessCommType) + CreateWirelessStatusIndicatorSprite(0, 0); + } + break; + case 2: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + sub_8010414(4, playerMultiplayerId); + SetAllPlayersBerryData(); + SetDeoxysStats(); + memcpy(gDecompressionBuffer, gPlayerParty, sizeof(struct Pokemon) * 3); + taskId = CreateTask(sub_800F6FC, 0); + gTasks[taskId].data[1] = 270; + gTasks[taskId].data[2] = 90; + gTasks[taskId].data[5] = 0; + gTasks[taskId].data[3] = 0; + gTasks[taskId].data[4] = 0; + for (id = 0; id < MAX_LINK_PLAYERS; ++id) + { + switch (gLinkPlayers[id].id) + { + case 0: + gTasks[taskId].data[3] |= gBlockRecvBuffer[id][1] & 0x3F; + break; + case 1: + gTasks[taskId].data[4] |= gBlockRecvBuffer[id][1] & 0x3F; + break; + case 2: + gTasks[taskId].data[3] |= (gBlockRecvBuffer[id][1] & 0x3F) << 6; + break; + case 3: + gTasks[taskId].data[4] |= (gBlockRecvBuffer[id][1] & 0x3F) << 6; + break; + } + } + ZeroPlayerPartyMons(); + ZeroEnemyPartyMons(); + ++gBattleCommunication[MULTIUSE_STATE]; + } + else + { + break; + } + // fall through + case 3: + if (IsLinkTaskFinished()) + { + SendBlock(bitmask_all_link_players_but_self(), gDecompressionBuffer, sizeof(struct Pokemon) * 2); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 4: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + for (id = 0; id < MAX_LINK_PLAYERS; ++id) + { + if (id == playerMultiplayerId) + { + switch (gLinkPlayers[id].id) + { + case 0: + case 3: + memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + case 1: + case 2: + memcpy(gPlayerParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + } + } + else + { + if ((!(gLinkPlayers[id].id & 1) && !(gLinkPlayers[playerMultiplayerId].id & 1)) + || ((gLinkPlayers[id].id & 1) && (gLinkPlayers[playerMultiplayerId].id & 1))) + { + switch (gLinkPlayers[id].id) + { + case 0: + case 3: + memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + case 1: + case 2: + memcpy(gPlayerParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + } + } + else + { + switch (gLinkPlayers[id].id) + { + case 0: + case 3: + memcpy(gEnemyParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + case 1: + case 2: + memcpy(gEnemyParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + } + } + } + } + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 7: + if (IsLinkTaskFinished()) + { + SendBlock(bitmask_all_link_players_but_self(), gDecompressionBuffer + sizeof(struct Pokemon) * 2, sizeof(struct Pokemon)); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 8: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + for (id = 0; id < MAX_LINK_PLAYERS; ++id) + { + if (id == playerMultiplayerId) + { + switch (gLinkPlayers[id].id) + { + case 0: + case 3: + memcpy(gPlayerParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + case 1: + case 2: + memcpy(gPlayerParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + } + } + else + { + if ((!(gLinkPlayers[id].id & 1) && !(gLinkPlayers[playerMultiplayerId].id & 1)) + || ((gLinkPlayers[id].id & 1) && (gLinkPlayers[playerMultiplayerId].id & 1))) + { + switch (gLinkPlayers[id].id) + { + case 0: + case 3: + memcpy(gPlayerParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + case 1: + case 2: + memcpy(gPlayerParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + } + } + else + { + switch (gLinkPlayers[id].id) + { + case 0: + case 3: + memcpy(gEnemyParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + case 1: + case 2: + memcpy(gEnemyParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + } + } + } + } + TryCorrectShedinjaLanguage(&gPlayerParty[0]); + TryCorrectShedinjaLanguage(&gPlayerParty[1]); + TryCorrectShedinjaLanguage(&gPlayerParty[2]); + TryCorrectShedinjaLanguage(&gPlayerParty[3]); + TryCorrectShedinjaLanguage(&gPlayerParty[4]); + TryCorrectShedinjaLanguage(&gPlayerParty[5]); + TryCorrectShedinjaLanguage(&gEnemyParty[0]); + TryCorrectShedinjaLanguage(&gEnemyParty[1]); + TryCorrectShedinjaLanguage(&gEnemyParty[2]); + TryCorrectShedinjaLanguage(&gEnemyParty[3]); + TryCorrectShedinjaLanguage(&gEnemyParty[4]); + TryCorrectShedinjaLanguage(&gEnemyParty[5]); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 11: + sub_800D30C(); + ++gBattleCommunication[MULTIUSE_STATE]; + gBattleCommunication[SPRITES_INIT_STATE1] = 0; + gBattleCommunication[SPRITES_INIT_STATE2] = 0; + break; + case 12: + if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2])) + { + gPreBattleCallback1 = gMain.callback1; + gMain.callback1 = BattleMainCB1; + SetMainCallback2(BattleMainCB2); + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + gBattleTypeFlags |= BATTLE_TYPE_20; + } + break; + case 5: + case 9: + ++gBattleCommunication[0]; + gBattleCommunication[SPRITES_INIT_STATE1] = 1; + // fall through + case 6: + case 10: + if (--gBattleCommunication[SPRITES_INIT_STATE1] == 0) + ++gBattleCommunication[0]; + break; + } +} + +void BattleMainCB2(void) +{ + AnimateSprites(); + BuildOamBuffer(); + RunTextPrinters(); + UpdatePaletteFade(); + RunTasks(); + if (JOY_HELD(B_BUTTON) && gBattleTypeFlags & BATTLE_TYPE_POKEDUDE) + { + gSpecialVar_Result = gBattleOutcome = B_OUTCOME_DREW; + ResetPaletteFadeControl(); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK); + SetMainCallback2(CB2_QuitPokeDudeBattle); + } +} + +void FreeRestoreBattleData(void) +{ + gMain.callback1 = gPreBattleCallback1; + gScanlineEffect.state = 3; + gMain.inBattle = FALSE; + ZeroEnemyPartyMons(); + m4aSongNumStop(SE_HINSI); + FreeMonSpritesGfx(); + FreeBattleSpritesData(); + FreeBattleResources(); +} + +static void CB2_QuitPokeDudeBattle(void) +{ + UpdatePaletteFade(); + if (!gPaletteFade.active) + { + FreeRestoreBattleData(); + FreeAllWindowBuffers(); + SetMainCallback2(gMain.savedCallback); + } +} + +static void sub_80111EC(struct Sprite *sprite) +{ + sprite->data[0] = 0; + sprite->callback = sub_80111FC; +} + +static void sub_80111FC(struct Sprite *sprite) +{ + switch (sprite->data[0]) + { + case 0: + gUnknown_2022BC0 = AllocZeroed(0x1000); + ++sprite->data[0]; + sprite->data[1] = 0; + sprite->data[2] = 0x281; + sprite->data[3] = 0; + sprite->data[4] = 1; + // fall through + case 1: + if (--sprite->data[4] == 0) + { + s32 i, r2, r0; + + sprite->data[4] = 2; + r2 = sprite->data[1] + sprite->data[3] * 32; + r0 = sprite->data[2] - sprite->data[3] * 32; + for (i = 0; i <= 29; i += 2) + { + *(&gUnknown_2022BC0[r2] + i) = 0x3D; + *(&gUnknown_2022BC0[r0] + i) = 0x3D; + } + if (++sprite->data[3] == 21) + { + ++sprite->data[0]; + sprite->data[1] = 32; + } + } + break; + case 2: + if (--sprite->data[1] == 20) + { + if (gUnknown_2022BC0 != NULL) + { + memset(gUnknown_2022BC0, 0, 0x1000); + FREE_AND_SET_NULL(gUnknown_2022BC0); + } + SetMainCallback2(CB2_InitBattle); + } + break; + } +} + +static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum) +{ + u32 nameHash = 0; + u32 personalityValue; + u8 fixedIV; + s32 i, j; + + if (trainerNum == TRAINER_SECRET_BASE) + return 0; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER + && !(gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_TOWER))) + { + ZeroEnemyPartyMons(); + for (i = 0; i < gTrainers[trainerNum].partySize; ++i) + { + + if (gTrainers[trainerNum].doubleBattle == TRUE) + personalityValue = 0x80; + else if (gTrainers[trainerNum].encounterMusic_gender & 0x80) + personalityValue = 0x78; + else + personalityValue = 0x88; + for (j = 0; gTrainers[trainerNum].trainerName[j] != EOS; ++j) + nameHash += gTrainers[trainerNum].trainerName[j]; + switch (gTrainers[trainerNum].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; ++j) + nameHash += gSpeciesNames[partyData[i].species][j]; + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); + break; + } + case F_TRAINER_PARTY_CUSTOM_MOVESET: + { + const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; ++j) + nameHash += gSpeciesNames[partyData[i].species][j]; + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); + for (j = 0; j < MAX_MON_MOVES; ++j) + { + SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); + SetMonData(&party[i], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp); + } + break; + } + case F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; ++j) + nameHash += gSpeciesNames[partyData[i].species][j]; + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); + + SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); + break; + } + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; ++j) + nameHash += gSpeciesNames[partyData[i].species][j]; + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); + SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); + for (j = 0; j < MAX_MON_MOVES; ++j) + { + SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); + SetMonData(&party[i], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp); + } + break; + } + } + } + gBattleTypeFlags |= gTrainers[trainerNum].doubleBattle; + } + return gTrainers[trainerNum].partySize; +} + +// not used +static void sub_80116CC(void) +{ + if (REG_VCOUNT < 0xA0 && REG_VCOUNT >= 0x6F) + REG_BG0CNT = BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(24) | BGCNT_16COLOR | BGCNT_TXT256x512; +} + +void VBlankCB_Battle(void) +{ + // Change gRngSeed every vblank. + Random(); + SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X); + SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y); + SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X); + SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y); + SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X); + SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y); + SetGpuReg(REG_OFFSET_BG3HOFS, gBattle_BG3_X); + SetGpuReg(REG_OFFSET_BG3VOFS, gBattle_BG3_Y); + SetGpuReg(REG_OFFSET_WIN0H, gBattle_WIN0H); + SetGpuReg(REG_OFFSET_WIN0V, gBattle_WIN0V); + SetGpuReg(REG_OFFSET_WIN1H, gBattle_WIN1H); + SetGpuReg(REG_OFFSET_WIN1V, gBattle_WIN1V); + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); + ScanlineEffect_InitHBlankDmaTransfer(); +} + +void nullsub_9(struct Sprite *sprite) +{ +} + +static void sub_80117BC(struct Sprite *sprite) +{ + if (sprite->data[0] != 0) + sprite->pos1.x = sprite->data[1] + ((sprite->data[2] & 0xFF00) >> 8); + else + sprite->pos1.x = sprite->data[1] - ((sprite->data[2] & 0xFF00) >> 8); + sprite->data[2] += 0x180; + if (sprite->affineAnimEnded) + { + FreeSpriteTilesByTag(ANIM_SPRITES_START); + FreeSpritePaletteByTag(ANIM_SPRITES_START); + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); + } +} + +void sub_801182C(struct Sprite *sprite) +{ + StartSpriteAffineAnim(sprite, 1); + sprite->callback = sub_80117BC; + PlaySE(SE_BT_START); +} + +static void sub_801184C(u8 taskId) +{ + struct Pokemon *party1 = NULL; + struct Pokemon *party2 = NULL; + u8 multiplayerId = gBattleStruct->multiplayerId; + u32 r7; + s32 i; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + switch (gLinkPlayers[multiplayerId].id) + { + case 0: + case 2: + party1 = gPlayerParty; + party2 = gEnemyParty; + break; + case 1: + case 3: + party1 = gEnemyParty; + party2 = gPlayerParty; + break; + } + } + else + { + party1 = gPlayerParty; + party2 = gEnemyParty; + } + r7 = 0; + for (i = 0; i < PARTY_SIZE; ++i) + { + u16 species = GetMonData(&party1[i], MON_DATA_SPECIES2); + u16 hp = GetMonData(&party1[i], MON_DATA_HP); + u32 status = GetMonData(&party1[i], MON_DATA_STATUS); + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp != 0 && status == 0) + r7 |= 1 << i * 2; + + if (species == SPECIES_NONE) + continue; + if (hp != 0 && (species == SPECIES_EGG || status != 0)) + r7 |= 2 << i * 2; + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp == 0) + r7 |= 3 << i * 2; + } + gTasks[taskId].data[3] = r7; + r7 = 0; + for (i = 0; i < PARTY_SIZE; ++i) + { + u16 species = GetMonData(&party2[i], MON_DATA_SPECIES2); + u16 hp = GetMonData(&party2[i], MON_DATA_HP); + u32 status = GetMonData(&party2[i], MON_DATA_STATUS); + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp != 0 && status == 0) + r7 |= 1 << i * 2; + if (species == SPECIES_NONE) + continue; + if (hp != 0 && (species == SPECIES_EGG || status != 0)) + r7 |= 2 << i * 2; + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp == 0) + r7 |= 3 << i * 2; + } + gTasks[taskId].data[4] = r7; +} + +void sub_8011A1C(void) +{ + s32 i; + u8 taskId; + + SetHBlankCallback(NULL); + SetVBlankCallback(NULL); + CpuFill32(0, (void *)VRAM, VRAM_SIZE); + SetGpuReg(REG_OFFSET_MOSAIC, 0); + SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(0, 0xF0)); + SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(0x50, 0x51)); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + gBattle_WIN0H = WIN_RANGE(0, 0xF0); + gBattle_WIN0V = WIN_RANGE(0x50, 0x51); + ScanlineEffect_Clear(); + for (i = 0; i < 80; ++i) + { + gScanlineEffectRegBuffers[0][i] = 0xF0; + gScanlineEffectRegBuffers[1][i] = 0xF0; + } + + for (; i < 160; ++i) + { + gScanlineEffectRegBuffers[0][i] = 0xFF10; + gScanlineEffectRegBuffers[1][i] = 0xFF10; + } + ResetPaletteFade(); + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + gBattle_BG3_X = 0; + gBattle_BG3_Y = 0; + sub_800F34C(); + LoadCompressedPalette(gBattleTextboxPalette, 0, 64); + LoadBattleMenuWindowGfx(); + ResetSpriteData(); + ResetTasks(); + DrawBattleEntryBackground(); + SetGpuReg(REG_OFFSET_WINOUT, WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG2 | WININ_WIN0_OBJ | WININ_WIN0_CLR); + FreeAllSpritePalettes(); + gReservedSpritePaletteCount = 4; + SetVBlankCallback(VBlankCB_Battle); + taskId = CreateTask(sub_800F6FC, 0); + gTasks[taskId].data[1] = 270; + gTasks[taskId].data[2] = 90; + gTasks[taskId].data[5] = 1; + sub_801184C(taskId); + SetMainCallback2(sub_8011B94); + gBattleCommunication[MULTIUSE_STATE] = 0; +} + +static void sub_8011B94(void) +{ + sub_8011BB0(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); + RunTasks(); +} + +static void sub_8011BB0(void) +{ + s32 i; + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + ShowBg(0); + ShowBg(1); + ShowBg(2); + gBattleCommunication[1] = 0xFF; + ++gBattleCommunication[MULTIUSE_STATE]; + break; + case 1: + if (--gBattleCommunication[1] == 0) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK); + ++gBattleCommunication[MULTIUSE_STATE]; + } + break; + case 2: + if (!gPaletteFade.active) + { + SetMainCallback2(gMain.savedCallback); + sub_812C224(); + FreeMonSpritesGfx(); + FreeBattleSpritesData(); + FreeBattleResources(); + } + break; + } +} + +u32 sub_8011C44(u8 arrayId, u8 caseId) +{ + u32 ret = 0; + + switch (caseId) + { + case 0: + ret = gBattleBgTemplates[arrayId].bg; + break; + case 1: + ret = gBattleBgTemplates[arrayId].charBaseIndex; + break; + case 2: + ret = gBattleBgTemplates[arrayId].mapBaseIndex; + break; + case 3: + ret = gBattleBgTemplates[arrayId].screenSize; + break; + case 4: + ret = gBattleBgTemplates[arrayId].paletteMode; + break; + case 5: + ret = gBattleBgTemplates[arrayId].priority; + break; + case 6: + ret = gBattleBgTemplates[arrayId].baseTile; + break; + } + return ret; +} + +static void TryCorrectShedinjaLanguage(struct Pokemon *mon) +{ + u8 nickname[POKEMON_NAME_LENGTH + 1]; + u8 language = LANGUAGE_JAPANESE; + + if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_SHEDINJA + && GetMonData(mon, MON_DATA_LANGUAGE) != language) + { + GetMonData(mon, MON_DATA_NICKNAME, nickname); + if (StringCompareWithoutExtCtrlCodes(nickname, sText_ShedinjaJpnName) == 0) + SetMonData(mon, MON_DATA_LANGUAGE, &language); + } +} + +#define sBattler data[0] +#define sSpeciesId data[2] + +void SpriteCB_WildMon(struct Sprite *sprite) +{ + sprite->callback = SpriteCB_MoveWildMonToRight; + StartSpriteAnimIfDifferent(sprite, 0); + BeginNormalPaletteFade(0x20000, 0, 10, 10, RGB(8, 8, 8)); +} + +static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite) +{ + if ((gIntroSlideFlags & 1) == 0) + { + sprite->pos2.x += 2; + if (sprite->pos2.x == 0) + { + sprite->callback = SpriteCB_WildMonShowHealthbox; + PlayCry1(sprite->data[2], 25); + } + } +} + +static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite) +{ + if (sprite->animEnded) + { + sub_804BD94(sprite->sBattler); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[sprite->sBattler]); + sprite->callback = SpriteCallbackDummy2; + StartSpriteAnimIfDifferent(sprite, 0); + BeginNormalPaletteFade(0x20000, 0, 10, 0, RGB(8, 8, 8)); + } +} + +void SpriteCallbackDummy2(struct Sprite *sprite) +{ +} + +// not used +static void sub_8011E28(struct Sprite *sprite) +{ + sprite->data[3] = 6; + sprite->data[4] = 1; + sprite->callback = sub_8011E3C; +} + +// not used +static void sub_8011E3C(struct Sprite *sprite) +{ + --sprite->data[4]; + if (sprite->data[4] == 0) + { + sprite->data[4] = 8; + sprite->invisible ^= 1; + --sprite->data[3]; + if (sprite->data[3] == 0) + { + sprite->invisible = FALSE; + sprite->callback = SpriteCallbackDummy2; + gUnknown_2022AE8[0] = 0; + } + } +} + +void SpriteCB_FaintOpponentMon(struct Sprite *sprite) +{ + u8 battler = sprite->sBattler; + u16 species; + u8 yOffset; + + if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies != 0) + species = gBattleSpritesDataPtr->battlerData[battler].transformSpecies; + else + species = sprite->sSpeciesId; + GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); // Unused return value. + if (species == SPECIES_UNOWN) + { + u32 personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); + u16 unownForm = ((((personalityValue & 0x3000000) >> 18) | ((personalityValue & 0x30000) >> 12) | ((personalityValue & 0x300) >> 6) | (personalityValue & 3)) % 0x1C); + u16 unownSpecies; + + if (unownForm == 0) + unownSpecies = SPECIES_UNOWN; // Use the A Unown form. + else + unownSpecies = NUM_SPECIES + unownForm; // Use one of the other Unown letters. + yOffset = gMonFrontPicCoords[unownSpecies].y_offset; + } + else if (species == SPECIES_CASTFORM) + { + yOffset = gCastformFrontSpriteCoords[gBattleMonForms[battler]].y_offset; + } + else if (species > NUM_SPECIES) + { + yOffset = gMonFrontPicCoords[SPECIES_NONE].y_offset; + } + else + { + yOffset = gMonFrontPicCoords[species].y_offset; + } + sprite->data[3] = 8 - yOffset / 8; + sprite->data[4] = 1; + sprite->callback = SpriteCB_AnimFaintOpponent; +} + +static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite) +{ + s32 i; + + if (--sprite->data[4] == 0) + { + sprite->data[4] = 2; + sprite->pos2.y += 8; // Move the sprite down. + if (--sprite->data[3] < 0) + { + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); + } + else // Erase bottom part of the sprite to create a smooth illusion of mon falling down. + { + u8 *dst = (u8 *)gMonSpritesGfxPtr->sprites[GetBattlerPosition(sprite->sBattler)] + (gBattleMonForms[sprite->sBattler] << 11) + (sprite->data[3] << 8); + + for (i = 0; i < 0x100; ++i) + *(dst++) = 0; + StartSpriteAnim(sprite, gBattleMonForms[sprite->sBattler]); + } + } +} + +void sub_8012044(struct Sprite *sprite) +{ + sprite->data[3] = 8; + sprite->data[4] = sprite->invisible; + sprite->callback = sub_8012060; +} + +static void sub_8012060(struct Sprite *sprite) +{ + --sprite->data[3]; + if (sprite->data[3] == 0) + { + sprite->invisible ^= 1; + sprite->data[3] = 8; + } +} + +void sub_8012098(struct Sprite *sprite) +{ + sprite->invisible = sprite->data[4]; + sprite->data[4] = FALSE; + sprite->callback = SpriteCallbackDummy2; +} + +void sub_80120C4(struct Sprite *sprite) +{ + sprite->callback = oac_poke_ally_; +} + +static void oac_poke_ally_(struct Sprite *sprite) +{ + if (!(gIntroSlideFlags & 1)) + { + sprite->pos2.x -= 2; + if (sprite->pos2.x == 0) + { + sprite->callback = SpriteCallbackDummy3; + sprite->data[1] = 0; + } + } +} + +void sub_8012100(struct Sprite *sprite) +{ + sprite->callback = SpriteCallbackDummy3; +} + +static void SpriteCallbackDummy3(struct Sprite *sprite) +{ +} + +void sub_8012110(struct Sprite *sprite) +{ + if (!(gIntroSlideFlags & 1)) + { + sprite->pos2.x += sprite->data[1]; + sprite->pos2.y += sprite->data[2]; + } +} + +#define sSinIndex data[0] +#define sDelta data[1] +#define sAmplitude data[2] +#define sBouncerSpriteId data[3] +#define sWhich data[4] + +void DoBounceEffect(u8 battler, u8 which, s8 delta, s8 amplitude) +{ + u8 invisibleSpriteId; + u8 bouncerSpriteId; + + switch (which) + { + case BOUNCE_HEALTHBOX: + default: + if (gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing) + return; + break; + case BOUNCE_MON: + if (gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing) + return; + break; + } + invisibleSpriteId = CreateInvisibleSpriteWithCallback(SpriteCB_BounceEffect); + if (which == BOUNCE_HEALTHBOX) + { + bouncerSpriteId = gHealthboxSpriteIds[battler]; + gBattleSpritesDataPtr->healthBoxesData[battler].healthboxBounceSpriteId = invisibleSpriteId; + gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing = 1; + gSprites[invisibleSpriteId].sSinIndex = 128; // 0 + } + else + { + bouncerSpriteId = gBattlerSpriteIds[battler]; + gBattleSpritesDataPtr->healthBoxesData[battler].battlerBounceSpriteId = invisibleSpriteId; + gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing = 1; + gSprites[invisibleSpriteId].sSinIndex = 192; // -1 + } + gSprites[invisibleSpriteId].sDelta = delta; + gSprites[invisibleSpriteId].sAmplitude = amplitude; + gSprites[invisibleSpriteId].sBouncerSpriteId = bouncerSpriteId; + gSprites[invisibleSpriteId].sWhich = which; + gSprites[bouncerSpriteId].pos2.x = 0; + gSprites[bouncerSpriteId].pos2.y = 0; +} + +void EndBounceEffect(u8 battler, u8 which) +{ + u8 bouncerSpriteId; + + if (which == BOUNCE_HEALTHBOX) + { + if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing) + return; + + bouncerSpriteId = gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].healthboxBounceSpriteId].sBouncerSpriteId; + DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].healthboxBounceSpriteId]); + gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing = 0; + } + else + { + if (!gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing) + return; + + bouncerSpriteId = gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].battlerBounceSpriteId].sBouncerSpriteId; + DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].battlerBounceSpriteId]); + gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing = 0; + } + gSprites[bouncerSpriteId].pos2.x = 0; + gSprites[bouncerSpriteId].pos2.y = 0; +} + +static void SpriteCB_BounceEffect(struct Sprite *sprite) +{ + u8 bouncerSpriteId = sprite->sBouncerSpriteId; + s32 index; + + if (sprite->sWhich == BOUNCE_HEALTHBOX) + index = sprite->sSinIndex; + else + index = sprite->sSinIndex; + gSprites[bouncerSpriteId].pos2.y = Sin(index, sprite->sAmplitude) + sprite->sAmplitude; + sprite->sSinIndex = (sprite->sSinIndex + sprite->sDelta) & 0xFF; +} + +void sub_8012354(struct Sprite *sprite) +{ + StartSpriteAnim(sprite, 1); + sprite->callback = sub_8012398; +} + +void sub_801236C(struct Sprite *sprite) +{ + if (sprite->animDelayCounter == 0) + sprite->centerToCornerVecX = gUnknown_824F048[sprite->animCmdIndex]; +} + +static void sub_8012398(struct Sprite *sprite) +{ + sub_801236C(sprite); + if (sprite->animEnded) + sprite->callback = SpriteCallbackDummy3; +} + +void nullsub_12(void) +{ +} + +void BeginBattleIntro(void) +{ + BattleStartClearSetData(); + gBattleCommunication[1] = 0; + gBattleMainFunc = BattleIntroGetMonsData; +} + +static void BattleMainCB1(void) +{ + gBattleMainFunc(); + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + gBattlerControllerFuncs[gActiveBattler](); +} + +static void BattleStartClearSetData(void) +{ + s32 i; + u32 j; + u8 *dataPtr; + + TurnValuesCleanUp(FALSE); + SpecialStatusesClear(); + for (i = 0; i < MAX_BATTLERS_COUNT; ++i) + { + gStatuses3[i] = 0; + dataPtr = (u8 *)&gDisableStructs[i]; + for (j = 0; j < sizeof(struct DisableStruct); ++j) + dataPtr[j] = 0; + gDisableStructs[i].isFirstTurn = 2; + gUnknown_2023DD4[i] = 0; + gLastMoves[i] = MOVE_NONE; + gLastLandedMoves[i] = MOVE_NONE; + gLastHitByType[i] = 0; + gLastResultingMoves[i] = MOVE_NONE; + gLastHitBy[i] = 0xFF; + gLockedMoves[i] = MOVE_NONE; + gLastPrintedMoves[i] = MOVE_NONE; + gBattleResources->flags->flags[i] = 0; + } + for (i = 0; i < 2; ++i) + { + gSideStatuses[i] = 0; + dataPtr = (u8 *)&gSideTimers[i]; + for (j = 0; j < sizeof(struct SideTimer); ++j) + dataPtr[j] = 0; + } + gBattlerAttacker = 0; + gBattlerTarget = 0; + gBattleWeather = 0; + dataPtr = (u8 *)&gWishFutureKnock; + for (i = 0; i < sizeof(struct WishFutureKnock); ++i) + dataPtr[i] = 0; + gHitMarker = 0; + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_POKEDUDE)) && gSaveBlock2Ptr->optionsBattleSceneOff) + gHitMarker |= HITMARKER_NO_ANIMATIONS; + gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; + gMultiHitCounter = 0; + gBattleOutcome = 0; + gBattleControllerExecFlags = 0; + gPaydayMoney = 0; + gBattleResources->battleScriptsStack->size = 0; + gBattleResources->battleCallbackStack->size = 0; + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; ++i) + gBattleCommunication[i] = 0; + gPauseCounterBattle = 0; + gBattleMoveDamage = 0; + gIntroSlideFlags = 0; + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gLeveledUpInBattle = 0; + gAbsentBattlerFlags = 0; + gBattleStruct->runTries = 0; + gBattleStruct->safariGoNearCounter = 0; + gBattleStruct->safariPkblThrowCounter = 0; + *(&gBattleStruct->safariCatchFactor) = gBaseStats[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].catchRate * 100 / 1275; + *(&gBattleStruct->safariEscapeFactor) = gBaseStats[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].safariZoneFleeRate * 100 / 1275; + if (gBattleStruct->safariEscapeFactor <= 1) + gBattleStruct->safariEscapeFactor = 2; + gBattleStruct->wildVictorySong = 0; + gBattleStruct->moneyMultiplier = 1; + for (i = 0; i < 8; ++i) + { + *((u8 *)gBattleStruct->lastTakenMove + i) = MOVE_NONE; + *((u8 *)gBattleStruct->usedHeldItems + i) = ITEM_NONE; + *((u8 *)gBattleStruct->choicedMove + i) = MOVE_NONE; + *((u8 *)gBattleStruct->changedItems + i) = ITEM_NONE; + *(i + 0 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(i + 1 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(i + 2 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(i + 3 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + } + *(gBattleStruct->AI_monToSwitchIntoId + 0) = PARTY_SIZE; + *(gBattleStruct->AI_monToSwitchIntoId + 1) = PARTY_SIZE; + *(&gBattleStruct->givenExpMons) = 0; + for (i = 0; i < 11; ++i) + gBattleResults.catchAttempts[i] = 0; + gBattleResults.battleTurnCounter = 0; + gBattleResults.playerFaintCounter = 0; + gBattleResults.opponentFaintCounter = 0; + gBattleResults.playerSwitchesCounter = 0; + gBattleResults.numHealingItemsUsed = 0; + gBattleResults.numRevivesUsed = 0; + gBattleResults.playerMonWasDamaged = FALSE; + gBattleResults.usedMasterBall = FALSE; + gBattleResults.lastOpponentSpecies = SPECIES_NONE; + gBattleResults.lastUsedMovePlayer = MOVE_NONE; + gBattleResults.lastUsedMoveOpponent = MOVE_NONE; + gBattleResults.playerMon1Species = SPECIES_NONE; + gBattleResults.playerMon2Species = SPECIES_NONE; + gBattleResults.caughtMonSpecies = SPECIES_NONE; + for (i = 0; i < POKEMON_NAME_LENGTH; ++i) + { + gBattleResults.playerMon1Name[i] = 0; + gBattleResults.playerMon2Name[i] = 0; + gBattleResults.caughtMonNick[i] = 0; + } +} + +void SwitchInClearSetData(void) +{ + struct DisableStruct disableStructCopy = gDisableStructs[gActiveBattler]; + s32 i; + u8 *ptr; + + if (gBattleMoves[gCurrentMove].effect != EFFECT_BATON_PASS) + { + for (i = 0; i < NUM_BATTLE_STATS; ++i) + gBattleMons[gActiveBattler].statStages[i] = 6; + for (i = 0; i < gBattlersCount; ++i) + { + if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == gActiveBattler) + gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; + if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].battlerWithSureHit == gActiveBattler) + { + gStatuses3[i] &= ~STATUS3_ALWAYS_HITS; + gDisableStructs[i].battlerWithSureHit = 0; + } + } + } + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + gBattleMons[gActiveBattler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED); + gStatuses3[gActiveBattler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED | STATUS3_MUDSPORT | STATUS3_WATERSPORT); + for (i = 0; i < gBattlersCount; ++i) + { + if (GetBattlerSide(gActiveBattler) != GetBattlerSide(i) + && (gStatuses3[i] & STATUS3_ALWAYS_HITS) != 0 + && (gDisableStructs[i].battlerWithSureHit == gActiveBattler)) + { + gStatuses3[i] &= ~(STATUS3_ALWAYS_HITS); + gStatuses3[i] |= 0x10; + } + } + } + else + { + gBattleMons[gActiveBattler].status2 = 0; + gStatuses3[gActiveBattler] = 0; + } + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBattler)) + gBattleMons[i].status2 &= ~(STATUS2_INFATUATED_WITH(gActiveBattler)); + if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBattler) + gBattleMons[i].status2 &= ~(STATUS2_WRAPPED); + } + gActionSelectionCursor[gActiveBattler] = 0; + gMoveSelectionCursor[gActiveBattler] = 0; + ptr = (u8 *)&gDisableStructs[gActiveBattler]; + for (i = 0; i < sizeof(struct DisableStruct); ++i) + ptr[i] = 0; + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + gDisableStructs[gActiveBattler].substituteHP = disableStructCopy.substituteHP; + gDisableStructs[gActiveBattler].battlerWithSureHit = disableStructCopy.battlerWithSureHit; + gDisableStructs[gActiveBattler].perishSongTimer = disableStructCopy.perishSongTimer; + gDisableStructs[gActiveBattler].perishSongTimerStartValue = disableStructCopy.perishSongTimerStartValue; + gDisableStructs[gActiveBattler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape; + } + gMoveResultFlags = 0; + gDisableStructs[gActiveBattler].isFirstTurn = 2; + gLastMoves[gActiveBattler] = MOVE_NONE; + gLastLandedMoves[gActiveBattler] = MOVE_NONE; + gLastHitByType[gActiveBattler] = 0; + gLastResultingMoves[gActiveBattler] = MOVE_NONE; + gLastPrintedMoves[gActiveBattler] = MOVE_NONE; + gLastHitBy[gActiveBattler] = 0xFF; + *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 0) = MOVE_NONE; + *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 1) = MOVE_NONE; + *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + for (i = 0; i < gBattlersCount; ++i) + { + if (i != gActiveBattler) + { + *(gBattleStruct->lastTakenMove + i * 2 + 0) = MOVE_NONE; + *(gBattleStruct->lastTakenMove + i * 2 + 1) = MOVE_NONE; + } + *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + } + *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 0) = MOVE_NONE; + *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 1) = MOVE_NONE; + gBattleResources->flags->flags[gActiveBattler] = 0; + gCurrentMove = MOVE_NONE; +} + +void FaintClearSetData(void) +{ + s32 i; + u8 *ptr; + + for (i = 0; i < NUM_BATTLE_STATS; ++i) + gBattleMons[gActiveBattler].statStages[i] = 6; + gBattleMons[gActiveBattler].status2 = 0; + gStatuses3[gActiveBattler] = 0; + for (i = 0; i < gBattlersCount; ++i) + { + if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == gActiveBattler) + gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; + if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBattler)) + gBattleMons[i].status2 &= ~(STATUS2_INFATUATED_WITH(gActiveBattler)); + if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBattler) + gBattleMons[i].status2 &= ~(STATUS2_WRAPPED); + } + gActionSelectionCursor[gActiveBattler] = 0; + gMoveSelectionCursor[gActiveBattler] = 0; + ptr = (u8 *)&gDisableStructs[gActiveBattler]; + for (i = 0; i < sizeof(struct DisableStruct); ++i) + ptr[i] = 0; + gProtectStructs[gActiveBattler].protected = FALSE; + gProtectStructs[gActiveBattler].endured = FALSE; + gProtectStructs[gActiveBattler].noValidMoves = FALSE; + gProtectStructs[gActiveBattler].helpingHand = FALSE; + gProtectStructs[gActiveBattler].bounceMove = FALSE; + gProtectStructs[gActiveBattler].stealMove = FALSE; + gProtectStructs[gActiveBattler].flag0Unknown = FALSE; + gProtectStructs[gActiveBattler].prlzImmobility = FALSE; + gProtectStructs[gActiveBattler].confusionSelfDmg = FALSE; + gProtectStructs[gActiveBattler].targetNotAffected = FALSE; + gProtectStructs[gActiveBattler].chargingTurn = FALSE; + gProtectStructs[gActiveBattler].fleeFlag = 0; + gProtectStructs[gActiveBattler].usedImprisonedMove = FALSE; + gProtectStructs[gActiveBattler].loveImmobility = FALSE; + gProtectStructs[gActiveBattler].usedDisabledMove = FALSE; + gProtectStructs[gActiveBattler].usedTauntedMove = FALSE; + gProtectStructs[gActiveBattler].flag2Unknown = FALSE; + gProtectStructs[gActiveBattler].flinchImmobility = FALSE; + gProtectStructs[gActiveBattler].notFirstStrike = FALSE; + gDisableStructs[gActiveBattler].isFirstTurn = 2; + gLastMoves[gActiveBattler] = MOVE_NONE; + gLastLandedMoves[gActiveBattler] = MOVE_NONE; + gLastHitByType[gActiveBattler] = MOVE_NONE; + gLastResultingMoves[gActiveBattler] = MOVE_NONE; + gLastPrintedMoves[gActiveBattler] = MOVE_NONE; + gLastHitBy[gActiveBattler] = 0xFF; + *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 0) = MOVE_NONE; + *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 1) = MOVE_NONE; + *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 0) = MOVE_NONE; + *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 1) = MOVE_NONE; + *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + for (i = 0; i < gBattlersCount; ++i) + { + if (i != gActiveBattler) + { + *(gBattleStruct->lastTakenMove + i * 2 + 0) = MOVE_NONE; + *(gBattleStruct->lastTakenMove + i * 2 + 1) = MOVE_NONE; + } + *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + } + gBattleResources->flags->flags[gActiveBattler] = 0; + gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1; + gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2; +} + +static void BattleIntroGetMonsData(void) +{ + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + gActiveBattler = gBattleCommunication[1]; + BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); + MarkBattlerForControllerExec(gActiveBattler); + ++gBattleCommunication[MULTIUSE_STATE]; + break; + case 1: + if (gBattleControllerExecFlags == 0) + { + ++gBattleCommunication[1]; + if (gBattleCommunication[1] == gBattlersCount) + gBattleMainFunc = BattleIntroPrepareBackgroundSlide; + else + gBattleCommunication[MULTIUSE_STATE] = 0; + } + break; + } +} + +static void BattleIntroPrepareBackgroundSlide(void) +{ + if (gBattleControllerExecFlags == 0) + { + gActiveBattler = GetBattlerAtPosition(0); + BtlController_EmitIntroSlide(0, gBattleTerrain); + MarkBattlerForControllerExec(gActiveBattler); + gBattleMainFunc = BattleIntroDrawTrainersOrMonsSprites; + gBattleCommunication[MULTIUSE_STATE] = 0; + gBattleCommunication[SPRITES_INIT_STATE1] = 0; + } +} + +static void BattleIntroDrawTrainersOrMonsSprites(void) +{ + u8 *ptr; + s32 i; + + if (!gBattleControllerExecFlags) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) + && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { + ptr = (u8 *)&gBattleMons[gActiveBattler]; + for (i = 0; i < sizeof(struct BattlePokemon); ++i) + ptr[i] = 0; + } + else + { + u16 *hpOnSwitchout; + + ptr = (u8 *)&gBattleMons[gActiveBattler]; + for (i = 0; i < sizeof(struct BattlePokemon); ++i) + ptr[i] = gBattleBufferB[gActiveBattler][4 + i]; + gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1; + gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2; + gBattleMons[gActiveBattler].ability = GetAbilityBySpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].abilityNum); + hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(gActiveBattler)]; + *hpOnSwitchout = gBattleMons[gActiveBattler].hp; + for (i = 0; i < NUM_BATTLE_STATS; ++i) + gBattleMons[gActiveBattler].statStages[i] = 6; + gBattleMons[gActiveBattler].status2 = 0; + } + if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_LEFT) + { + BtlController_EmitDrawTrainerPic(0); + MarkBattlerForControllerExec(gActiveBattler); + } + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_LEFT) + { + BtlController_EmitDrawTrainerPic(0); + MarkBattlerForControllerExec(gActiveBattler); + } + if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_POKEDUDE + | BATTLE_TYPE_LINK + | BATTLE_TYPE_GHOST + | BATTLE_TYPE_OLD_MAN_TUTORIAL + | BATTLE_TYPE_LEGENDARY))) + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality); + } + else + { + if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) + { + if (gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_LEGENDARY)) + { + if ((gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_LEGENDARY)) != BATTLE_TYPE_GHOST) + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality); + } + else if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_POKEDUDE + | BATTLE_TYPE_LINK + | BATTLE_TYPE_GHOST + | BATTLE_TYPE_OLD_MAN_TUTORIAL + | BATTLE_TYPE_LEGENDARY))) + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality); + } + BtlController_EmitLoadMonSprite(0); + MarkBattlerForControllerExec(gActiveBattler); + } + } + if (gBattleTypeFlags & BATTLE_TYPE_MULTI + && (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT || GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT)) + { + BtlController_EmitDrawTrainerPic(0); + MarkBattlerForControllerExec(gActiveBattler); + } + } + gBattleMainFunc = BattleIntroDrawPartySummaryScreens; + } +} + +static void BattleIntroDrawPartySummaryScreens(void) +{ + s32 i; + struct HpAndStatus hpStatus[PARTY_SIZE]; + + if (!gBattleControllerExecFlags) + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + for (i = 0; i < PARTY_SIZE; ++i) + { + if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatus[i].hp = 0xFFFF; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS); + } + } + gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + BtlController_EmitDrawPartyStatusSummary(0, hpStatus, 0x80); + MarkBattlerForControllerExec(gActiveBattler); + for (i = 0; i < PARTY_SIZE; ++i) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatus[i].hp = 0xFFFF; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + } + } + gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + BtlController_EmitDrawPartyStatusSummary(0, hpStatus, 0x80); + MarkBattlerForControllerExec(gActiveBattler); + + gBattleMainFunc = BattleIntroPrintTrainerWantsToBattle; + } + else + { + // The struct gets set here, but nothing is ever done with it since + // wild battles don't show the party summary. + // Still, there's no point in having dead code. + for (i = 0; i < PARTY_SIZE; ++i) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatus[i].hp = 0xFFFF; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + } + } + gBattleMainFunc = BattleIntroPrintWildMonAttacked; + } + } +} + +static void BattleIntroPrintTrainerWantsToBattle(void) +{ + if (!gBattleControllerExecFlags) + { + gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + PrepareStringBattle(STRINGID_INTROMSG, gActiveBattler); + gBattleMainFunc = BattleIntroPrintOpponentSendsOut; + } +} + +static void BattleIntroPrintWildMonAttacked(void) +{ + if (!gBattleControllerExecFlags) + { + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; + PrepareStringBattle(STRINGID_INTROMSG, 0); + if ((gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_GHOST)) == (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_GHOST)) + { + gBattleScripting.battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + BattleScriptExecute(gUnknown_81D91A1); + } + } +} + +static void BattleIntroPrintOpponentSendsOut(void) +{ + if (!gBattleControllerExecFlags) + { + PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); + gBattleMainFunc = BattleIntroOpponentSendsOutMonAnimation; + } +} + +static void BattleIntroOpponentSendsOutMonAnimation(void) +{ + if (!gBattleControllerExecFlags) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_LEFT) + { + BtlController_EmitIntroTrainerBallThrow(0); + MarkBattlerForControllerExec(gActiveBattler); + } + if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT) + { + BtlController_EmitIntroTrainerBallThrow(0); + MarkBattlerForControllerExec(gActiveBattler); + } + } + gBattleMainFunc = BattleIntroRecordMonsToDex; + } +} + +static void BattleIntroRecordMonsToDex(void) +{ + if (!gBattleControllerExecFlags) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_POKEDUDE + | BATTLE_TYPE_LINK + | BATTLE_TYPE_GHOST + | BATTLE_TYPE_OLD_MAN_TUTORIAL + | BATTLE_TYPE_LEGENDARY))) + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality); + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; + } +} + +// not used +static void sub_80136C4(void) +{ + if (!gBattleControllerExecFlags) + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; +} + +void BattleIntroPrintPlayerSendsOut(void) +{ + if (!gBattleControllerExecFlags) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) + PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); + gBattleMainFunc = BattleIntroPlayerSendsOutMonAnimation; + } +} + +static void BattleIntroPlayerSendsOutMonAnimation(void) +{ + u32 position; + + if (!gBattleControllerExecFlags) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_LEFT) + { + BtlController_EmitIntroTrainerBallThrow(0); + MarkBattlerForControllerExec(gActiveBattler); + } + if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT) + { + BtlController_EmitIntroTrainerBallThrow(0); + MarkBattlerForControllerExec(gActiveBattler); + } + } + gBattleStruct->switchInAbilitiesCounter = 0; + gBattleStruct->switchInItemsCounter = 0; + gBattleStruct->overworldWeatherDone = FALSE; + gBattleMainFunc = TryDoEventsBeforeFirstTurn; + } +} + +// not used +static void sub_80137D0(void) +{ + if (!gBattleControllerExecFlags) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { + BtlController_EmitSwitchInAnim(0, gBattlerPartyIndexes[gActiveBattler], FALSE); + MarkBattlerForControllerExec(gActiveBattler); + } + } + gBattleStruct->switchInAbilitiesCounter = 0; + gBattleStruct->switchInItemsCounter = 0; + gBattleStruct->overworldWeatherDone = FALSE; + gBattleMainFunc = TryDoEventsBeforeFirstTurn; + } +} + +static void TryDoEventsBeforeFirstTurn(void) +{ + s32 i, j; + u8 effect = 0; + + if (!gBattleControllerExecFlags) + { + + if (gBattleStruct->switchInAbilitiesCounter == 0) + { + for (i = 0; i < gBattlersCount; ++i) + gBattlerByTurnOrder[i] = i; + for (i = 0; i < gBattlersCount - 1; ++i) + for (j = i + 1; j < gBattlersCount; ++j) + if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) != 0) + SwapTurnOrder(i, j); + } + if (!gBattleStruct->overworldWeatherDone + && AbilityBattleEffects(0, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0) + { + gBattleStruct->overworldWeatherDone = TRUE; + return; + } + // Check all switch in abilities happening from the fastest mon to slowest. + while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount) + { + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter], 0, 0, 0) != 0) + ++effect; + ++gBattleStruct->switchInAbilitiesCounter; + if (effect) + return; + } + if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) != 0) + return; + if (AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) != 0) + return; + // Check all switch in items having effect from the fastest mon to slowest. + while (gBattleStruct->switchInItemsCounter < gBattlersCount) + { + if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInItemsCounter], FALSE)) + ++effect; + ++gBattleStruct->switchInItemsCounter; + if (effect) + return; + } + for (i = 0; i < gBattlersCount; ++i) // pointless, ruby leftover + ; + for (i = 0; i < MAX_BATTLERS_COUNT; ++i) + { + *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; + gChosenActionByBattler[i] = B_ACTION_NONE; + gChosenMoveByBattler[i] = MOVE_NONE; + } + TurnValuesCleanUp(FALSE); + SpecialStatusesClear(); + *(&gBattleStruct->field_91) = gAbsentBattlerFlags; + gBattleMainFunc = HandleTurnActionSelectionState; + ResetSentPokesToOpponentValue(); + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; ++i) + gBattleCommunication[i] = 0; + for (i = 0; i < gBattlersCount; ++i) + gBattleMons[i].status2 &= ~(STATUS2_FLINCHED); + *(&gBattleStruct->turnEffectsTracker) = 0; + *(&gBattleStruct->turnEffectsBattlerId) = 0; + *(&gBattleStruct->wishPerishSongState) = 0; + *(&gBattleStruct->wishPerishSongBattlerId) = 0; + gBattleScripting.atk49_state = 0; + gBattleStruct->faintedActionsState = 0; + gBattleStruct->turnCountersTracker = 0; + gMoveResultFlags = 0; + gRandomTurnNumber = Random(); + } +} + +static void HandleEndTurn_ContinueBattle(void) +{ + s32 i; + + if (!gBattleControllerExecFlags) + { + gBattleMainFunc = BattleTurnPassed; + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; ++i) + gBattleCommunication[i] = 0; + for (i = 0; i < gBattlersCount; ++i) + { + gBattleMons[i].status2 &= ~(STATUS2_FLINCHED); + if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS)) + CancelMultiTurnMoves(i); + } + gBattleStruct->turnEffectsTracker = 0; + gBattleStruct->turnEffectsBattlerId = 0; + gBattleStruct->wishPerishSongState = 0; + gBattleStruct->wishPerishSongBattlerId = 0; + gBattleStruct->turnCountersTracker = 0; + gMoveResultFlags = 0; + } +} + +void BattleTurnPassed(void) +{ + s32 i; + + TurnValuesCleanUp(TRUE); + if (gBattleOutcome == 0) + { + if (DoFieldEndTurnEffects()) + return; + if (DoBattlerEndTurnEffects()) + return; + } + if (HandleFaintedMonActions()) + return; + gBattleStruct->faintedActionsState = 0; + if (HandleWishPerishSongOnTurnEnd()) + return; + TurnValuesCleanUp(FALSE); + gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING); + gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE); + gHitMarker &= ~(HITMARKER_x400000); + gHitMarker &= ~(HITMARKER_x100000); + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gBattleScripting.atk49_state = 0; + gBattleMoveDamage = 0; + gMoveResultFlags = 0; + for (i = 0; i < 5; ++i) + gBattleCommunication[i] = 0; + if (gBattleOutcome != 0) + { + gCurrentActionFuncId = B_ACTION_FINISHED; + gBattleMainFunc = RunTurnActionsFunctions; + return; + } + if (gBattleResults.battleTurnCounter < 0xFF) + ++gBattleResults.battleTurnCounter; + for (i = 0; i < gBattlersCount; ++i) + { + gChosenActionByBattler[i] = B_ACTION_NONE; + gChosenMoveByBattler[i] = MOVE_NONE; + } + for (i = 0; i < MAX_BATTLERS_COUNT; ++i) + *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; + *(&gBattleStruct->field_91) = gAbsentBattlerFlags; + gBattleMainFunc = HandleTurnActionSelectionState; + gRandomTurnNumber = Random(); +} + +u8 IsRunningFromBattleImpossible(void) +{ + u8 holdEffect; + u8 side; + s32 i; + + if (gBattleMons[gActiveBattler].item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[gActiveBattler].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(gBattleMons[gActiveBattler].item); + gPotentialItemEffectBattler = gActiveBattler; + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN + || (gBattleTypeFlags & BATTLE_TYPE_LINK) + || gBattleMons[gActiveBattler].ability == ABILITY_RUN_AWAY) + return BATTLE_RUN_SUCCESS; + side = GetBattlerSide(gActiveBattler); + for (i = 0; i < gBattlersCount; ++i) + { + if (side != GetBattlerSide(i) + && gBattleMons[i].ability == ABILITY_SHADOW_TAG) + { + gBattleScripting.battler = i; + gLastUsedAbility = gBattleMons[i].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + return BATTLE_RUN_FAILURE; + } + if (side != GetBattlerSide(i) + && gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE + && !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING) + && gBattleMons[i].ability == ABILITY_ARENA_TRAP) + { + gBattleScripting.battler = i; + gLastUsedAbility = gBattleMons[i].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + return BATTLE_RUN_FAILURE; + } + } + i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0); + if (i != 0 && IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL)) + { + gBattleScripting.battler = i - 1; + gLastUsedAbility = gBattleMons[i - 1].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + return BATTLE_RUN_FAILURE; + } + if ((gBattleMons[gActiveBattler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED)) + || (gStatuses3[gActiveBattler] & STATUS3_ROOTED)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + return BATTLE_RUN_FORBIDDEN; + } + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + return BATTLE_RUN_FORBIDDEN; + } + return BATTLE_RUN_SUCCESS; +} + +void sub_8013F6C(u8 battler) +{ + s32 i; + u8 r4, r1; + + for (i = 0; i < 3; ++i) + gUnknown_203B0DC[i] = *(battler * 3 + i + (u8 *)(gBattleStruct->field_60)); + r4 = pokemon_order_func(gBattlerPartyIndexes[battler]); + r1 = pokemon_order_func(*(gBattleStruct->monToSwitchIntoId + battler)); + sub_8127FF4(r4, r1); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + for (i = 0; i < 3; ++i) + { + *(battler * 3 + i + (u8 *)(gBattleStruct->field_60)) = gUnknown_203B0DC[i]; + *(BATTLE_PARTNER(battler) * 3 + i + (u8 *)(gBattleStruct->field_60)) = gUnknown_203B0DC[i]; + } + } + else + { + for (i = 0; i < 3; ++i) + *(battler * 3 + i + (u8 *)(gBattleStruct->field_60)) = gUnknown_203B0DC[i]; + } +} + +enum +{ + STATE_BEFORE_ACTION_CHOSEN, + STATE_WAIT_ACTION_CHOSEN, + STATE_WAIT_ACTION_CASE_CHOSEN, + STATE_WAIT_ACTION_CONFIRMED_STANDBY, + STATE_WAIT_ACTION_CONFIRMED, + STATE_SELECTION_SCRIPT, + STATE_WAIT_SET_BEFORE_ACTION, +}; + +static void HandleTurnActionSelectionState(void) +{ + s32 i; + + gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0; + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + u8 position = GetBattlerPosition(gActiveBattler); + + switch (gBattleCommunication[gActiveBattler]) + { + case STATE_BEFORE_ACTION_CHOSEN: // Choose an action. + *(gBattleStruct->monToSwitchIntoId + gActiveBattler) = PARTY_SIZE; + if (gBattleTypeFlags & BATTLE_TYPE_MULTI + || (position & BIT_FLANK) == B_FLANK_LEFT + || gBattleStruct->field_91 & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(position))] + || gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED) + { + if (gBattleStruct->field_91 & gBitTable[gActiveBattler]) + { + gChosenActionByBattler[gActiveBattler] = B_ACTION_NOTHING_FAINTED; + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED; + else + gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + } + else + { + if (gBattleMons[gActiveBattler].status2 & STATUS2_MULTIPLETURNS + || gBattleMons[gActiveBattler].status2 & STATUS2_RECHARGE) + { + gChosenActionByBattler[gActiveBattler] = B_ACTION_USE_MOVE; + gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + } + else + { + BtlController_EmitChooseAction(0, gChosenActionByBattler[0], gBattleBufferB[0][1] | (gBattleBufferB[0][2] << 8)); + MarkBattlerForControllerExec(gActiveBattler); + ++gBattleCommunication[gActiveBattler]; + } + } + } + break; + case STATE_WAIT_ACTION_CHOSEN: // Try to perform an action. + if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC)))) + { + gChosenActionByBattler[gActiveBattler] = gBattleBufferB[gActiveBattler][1]; + switch (gBattleBufferB[gActiveBattler][1]) + { + case B_ACTION_USE_MOVE: + if (AreAllMovesUnusable()) + { + gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + *(gBattleStruct->moveTarget + gActiveBattler) = gBattleBufferB[gActiveBattler][3]; + return; + } + else if (gDisableStructs[gActiveBattler].encoredMove != MOVE_NONE) + { + gChosenMoveByBattler[gActiveBattler] = gDisableStructs[gActiveBattler].encoredMove; + *(gBattleStruct->chosenMovePositions + gActiveBattler) = gDisableStructs[gActiveBattler].encoredMovePos; + gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + return; + } + else + { + struct ChooseMoveStruct moveInfo; + + moveInfo.species = gBattleMons[gActiveBattler].species; + moveInfo.monType1 = gBattleMons[gActiveBattler].type1; + moveInfo.monType2 = gBattleMons[gActiveBattler].type2; + for (i = 0; i < MAX_MON_MOVES; ++i) + { + moveInfo.moves[i] = gBattleMons[gActiveBattler].moves[i]; + moveInfo.currentPp[i] = gBattleMons[gActiveBattler].pp[i]; + moveInfo.maxPp[i] = CalculatePPWithBonus(gBattleMons[gActiveBattler].moves[i], + gBattleMons[gActiveBattler].ppBonuses, + i); + } + BtlController_EmitChooseMove(0, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo); + MarkBattlerForControllerExec(gActiveBattler); + } + break; + case B_ACTION_USE_ITEM: + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER)) + { + gSelectionBattleScripts[gActiveBattler] = BattleScript_ActionSelectionItemsCantBeUsed; + gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + else + { + BtlController_EmitChooseItem(0, gBattleStruct->field_60[gActiveBattler]); + MarkBattlerForControllerExec(gActiveBattler); + } + break; + case B_ACTION_SWITCH: + *(gBattleStruct->field_58 + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler]; + if (gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION) || gStatuses3[gActiveBattler] & STATUS3_ROOTED) + { + BtlController_EmitChoosePokemon(0, PARTY_CANT_SWITCH, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]); + } + else if ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_SHADOW_TAG)) + || ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_ARENA_TRAP)) + && !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING) + && gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE) + || ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0)) + && IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL))) + { + BtlController_EmitChoosePokemon(0, ((i - 1) << 4) | PARTY_ABILITY_PREVENTS, 6, gLastUsedAbility, gBattleStruct->field_60[gActiveBattler]); + } + else + { + if (gActiveBattler == 2 && gChosenActionByBattler[0] == B_ACTION_SWITCH) + BtlController_EmitChoosePokemon(0, PARTY_CHOOSE_MON, *(gBattleStruct->monToSwitchIntoId + 0), ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]); + else if (gActiveBattler == 3 && gChosenActionByBattler[1] == B_ACTION_SWITCH) + BtlController_EmitChoosePokemon(0, PARTY_CHOOSE_MON, *(gBattleStruct->monToSwitchIntoId + 1), ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]); + else + BtlController_EmitChoosePokemon(0, PARTY_CHOOSE_MON, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]); + } + MarkBattlerForControllerExec(gActiveBattler); + break; + case B_ACTION_SAFARI_BALL: + if (IsPlayerPartyAndPokemonStorageFull()) + { + gSelectionBattleScripts[gActiveBattler] = BattleScript_PrintFullBox; + gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + break; + case B_ACTION_CANCEL_PARTNER: + gBattleCommunication[gActiveBattler] = STATE_WAIT_SET_BEFORE_ACTION; + gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))] = STATE_BEFORE_ACTION_CHOSEN; + BtlController_EmitEndBounceEffect(0); + MarkBattlerForControllerExec(gActiveBattler); + return; + } + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER + && !(gBattleTypeFlags & BATTLE_TYPE_LINK) + && gBattleBufferB[gActiveBattler][1] == B_ACTION_RUN) + { + BattleScriptExecute(BattleScript_PrintCantRunFromTrainer); + gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN; + } + else if (IsRunningFromBattleImpossible() != BATTLE_RUN_SUCCESS + && gBattleBufferB[gActiveBattler][1] == B_ACTION_RUN) + { + gSelectionBattleScripts[gActiveBattler] = BattleScript_PrintCantEscapeFromBattle; + gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + else + { + ++gBattleCommunication[gActiveBattler]; + } + } + break; + case STATE_WAIT_ACTION_CASE_CHOSEN: + if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC)))) + { + switch (gChosenActionByBattler[gActiveBattler]) + { + case B_ACTION_USE_MOVE: + switch (gBattleBufferB[gActiveBattler][1]) + { + case 3 ... 9: + gChosenActionByBattler[gActiveBattler] = gBattleBufferB[gActiveBattler][1]; + return; + default: + if ((gBattleBufferB[gActiveBattler][2] | (gBattleBufferB[gActiveBattler][3] << 8)) == 0xFFFF) + { + gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN; + } + else if (TrySetCantSelectMoveBattleScript()) + { + gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE; + gBattleBufferB[gActiveBattler][1] = 0; + *(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_WAIT_ACTION_CHOSEN; + return; + } + else + { + *(gBattleStruct->chosenMovePositions + gActiveBattler) = gBattleBufferB[gActiveBattler][2]; + gChosenMoveByBattler[gActiveBattler] = gBattleMons[gActiveBattler].moves[*(gBattleStruct->chosenMovePositions + gActiveBattler)]; + *(gBattleStruct->moveTarget + gActiveBattler) = gBattleBufferB[gActiveBattler][3]; + ++gBattleCommunication[gActiveBattler]; + } + break; + } + break; + case B_ACTION_USE_ITEM: + if ((gBattleBufferB[gActiveBattler][1] | (gBattleBufferB[gActiveBattler][2] << 8)) == 0) + { + gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN; + } + else + { + gLastUsedItem = (gBattleBufferB[gActiveBattler][1] | (gBattleBufferB[gActiveBattler][2] << 8)); + ++gBattleCommunication[gActiveBattler]; + } + break; + case B_ACTION_SWITCH: + if (gBattleBufferB[gActiveBattler][1] == PARTY_SIZE) + { + gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN; + } + else + { + *(gBattleStruct->monToSwitchIntoId + gActiveBattler) = gBattleBufferB[gActiveBattler][1]; + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + *(gActiveBattler * 3 + (u8 *)(gBattleStruct->field_60) + 0) &= 0xF; + *(gActiveBattler * 3 + (u8 *)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBattler][2] & 0xF0); + *(gActiveBattler * 3 + (u8 *)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBattler][3]; + *((gActiveBattler ^ BIT_FLANK) * 3 + (u8 *)(gBattleStruct->field_60) + 0) &= (0xF0); + *((gActiveBattler ^ BIT_FLANK) * 3 + (u8 *)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBattler][2] & 0xF0) >> 4; + *((gActiveBattler ^ BIT_FLANK) * 3 + (u8 *)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBattler][3]; + } + ++gBattleCommunication[gActiveBattler]; + } + break; + case B_ACTION_RUN: + gHitMarker |= HITMARKER_RUN; + ++gBattleCommunication[gActiveBattler]; + break; + case B_ACTION_SAFARI_WATCH_CAREFULLY: + ++gBattleCommunication[gActiveBattler]; + break; + case B_ACTION_SAFARI_BALL: + ++gBattleCommunication[gActiveBattler]; + break; + case B_ACTION_SAFARI_POKEBLOCK: + case B_ACTION_SAFARI_GO_NEAR: + ++gBattleCommunication[gActiveBattler]; + break; + case B_ACTION_SAFARI_RUN: + gHitMarker |= HITMARKER_RUN; + ++gBattleCommunication[gActiveBattler]; + break; + case B_ACTION_OLDMAN_THROW: + ++gBattleCommunication[gActiveBattler]; + break; + } + } + break; + case STATE_WAIT_ACTION_CONFIRMED_STANDBY: + if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC)))) + { + if (((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_DOUBLE)) != BATTLE_TYPE_DOUBLE) + || (position & BIT_FLANK) != B_FLANK_LEFT + || (*(&gBattleStruct->field_91) & gBitTable[GetBattlerAtPosition(position ^ BIT_FLANK)])) + BtlController_EmitLinkStandbyMsg(0, 0); + else + BtlController_EmitLinkStandbyMsg(0, 1); + MarkBattlerForControllerExec(gActiveBattler); + ++gBattleCommunication[gActiveBattler]; + } + break; + case STATE_WAIT_ACTION_CONFIRMED: + if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC)))) + ++gBattleCommunication[ACTIONS_CONFIRMED_COUNT]; + break; + case STATE_SELECTION_SCRIPT: + if (*(gBattleStruct->selectionScriptFinished + gActiveBattler)) + { + gBattleCommunication[gActiveBattler] = *(gBattleStruct->stateIdAfterSelScript + gActiveBattler); + } + else + { + gBattlerAttacker = gActiveBattler; + gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBattler]; + if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC)))) + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + gSelectionBattleScripts[gActiveBattler] = gBattlescriptCurrInstr; + } + break; + case STATE_WAIT_SET_BEFORE_ACTION: + if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC)))) + gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN; + break; + } + } + // Check if everyone chose actions. + if (gBattleCommunication[ACTIONS_CONFIRMED_COUNT] == gBattlersCount) + gBattleMainFunc = SetActionsAndBattlersTurnOrder; +} + +void SwapTurnOrder(u8 id1, u8 id2) +{ + u32 temp; + + SWAP(gActionsByTurnOrder[id1], gActionsByTurnOrder[id2], temp); + SWAP(gBattlerByTurnOrder[id1], gBattlerByTurnOrder[id2], temp); +} + +u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves) +{ + u8 strikesFirst = 0; + u8 speedMultiplierBattler1 = 0, speedMultiplierBattler2 = 0; + u32 speedBattler1 = 0, speedBattler2 = 0; + u8 holdEffect = 0; + u8 holdEffectParam = 0; + u16 moveBattler1 = 0, moveBattler2 = 0; + + if (WEATHER_HAS_EFFECT) + { + if ((gBattleMons[battler1].ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY) + || (gBattleMons[battler1].ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY)) + speedMultiplierBattler1 = 2; + else + speedMultiplierBattler1 = 1; + if ((gBattleMons[battler2].ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY) + || (gBattleMons[battler2].ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY)) + speedMultiplierBattler2 = 2; + else + speedMultiplierBattler2 = 1; + } + else + { + speedMultiplierBattler1 = 1; + speedMultiplierBattler2 = 1; + } + speedBattler1 = (gBattleMons[battler1].speed * speedMultiplierBattler1) + * (gStatStageRatios[gBattleMons[battler1].statStages[STAT_SPEED]][0]) + / (gStatStageRatios[gBattleMons[battler1].statStages[STAT_SPEED]][1]); + if (gBattleMons[battler1].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[battler1].holdEffect; + holdEffectParam = gEnigmaBerries[battler1].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[battler1].item); + holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[battler1].item); + } + // badge boost + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) + && FlagGet(FLAG_BADGE03_GET) + && GetBattlerSide(battler1) == B_SIDE_PLAYER) + speedBattler1 = (speedBattler1 * 110) / 100; + if (holdEffect == HOLD_EFFECT_MACHO_BRACE) + speedBattler1 /= 2; + if (gBattleMons[battler1].status1 & STATUS1_PARALYSIS) + speedBattler1 /= 4; + if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100) + speedBattler1 = UINT_MAX; + // check second battlerId's speed + speedBattler2 = (gBattleMons[battler2].speed * speedMultiplierBattler2) + * (gStatStageRatios[gBattleMons[battler2].statStages[STAT_SPEED]][0]) + / (gStatStageRatios[gBattleMons[battler2].statStages[STAT_SPEED]][1]); + if (gBattleMons[battler2].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[battler2].holdEffect; + holdEffectParam = gEnigmaBerries[battler2].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[battler2].item); + holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[battler2].item); + } + // badge boost + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) + && FlagGet(FLAG_BADGE03_GET) + && GetBattlerSide(battler2) == B_SIDE_PLAYER) + speedBattler2 = (speedBattler2 * 110) / 100; + if (holdEffect == HOLD_EFFECT_MACHO_BRACE) + speedBattler2 /= 2; + if (gBattleMons[battler2].status1 & STATUS1_PARALYSIS) + speedBattler2 /= 4; + if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100) + speedBattler2 = UINT_MAX; + if (ignoreChosenMoves) + { + moveBattler1 = MOVE_NONE; + moveBattler2 = MOVE_NONE; + } + else + { + if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE) + { + if (gProtectStructs[battler1].noValidMoves) + moveBattler1 = MOVE_STRUGGLE; + else + moveBattler1 = gBattleMons[battler1].moves[*(gBattleStruct->chosenMovePositions + battler1)]; + } + else + moveBattler1 = MOVE_NONE; + if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE) + { + if (gProtectStructs[battler2].noValidMoves) + moveBattler2 = MOVE_STRUGGLE; + else + moveBattler2 = gBattleMons[battler2].moves[*(gBattleStruct->chosenMovePositions + battler2)]; + } + else + moveBattler2 = MOVE_NONE; + } + // both move priorities are different than 0 + if (gBattleMoves[moveBattler1].priority != 0 || gBattleMoves[moveBattler2].priority != 0) + { + // both priorities are the same + if (gBattleMoves[moveBattler1].priority == gBattleMoves[moveBattler2].priority) + { + if (speedBattler1 == speedBattler2 && Random() & 1) + strikesFirst = 2; // same speeds, same priorities + else if (speedBattler1 < speedBattler2) + strikesFirst = 1; // battler2 has more speed + // else battler1 has more speed + } + else if (gBattleMoves[moveBattler1].priority < gBattleMoves[moveBattler2].priority) + strikesFirst = 1; // battler2's move has greater priority + // else battler1's move has greater priority + } + // both priorities are equal to 0 + else + { + if (speedBattler1 == speedBattler2 && Random() & 1) + strikesFirst = 2; // same speeds, same priorities + else if (speedBattler1 < speedBattler2) + strikesFirst = 1; // battler2 has more speed + // else battler1 has more speed + } + return strikesFirst; +} + +static void SetActionsAndBattlersTurnOrder(void) +{ + s32 turnOrderId = 0; + s32 i, j; + + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; + gBattlerByTurnOrder[turnOrderId] = gActiveBattler; + ++turnOrderId; + } + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_RUN) + { + turnOrderId = 5; + break; + } + } + } + else if (gChosenActionByBattler[0] == B_ACTION_RUN) + { + gActiveBattler = 0; + turnOrderId = 5; + } + if (turnOrderId == 5) // One of battlers wants to run. + { + gActionsByTurnOrder[0] = gChosenActionByBattler[gActiveBattler]; + gBattlerByTurnOrder[0] = gActiveBattler; + turnOrderId = 1; + for (i = 0; i < gBattlersCount; ++i) + { + if (i != gActiveBattler) + { + gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[i]; + gBattlerByTurnOrder[turnOrderId] = i; + ++turnOrderId; + } + } + gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts; + gBattleStruct->focusPunchBattlerId = 0; + return; + } + else + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_USE_ITEM || gChosenActionByBattler[gActiveBattler] == B_ACTION_SWITCH) + { + gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; + gBattlerByTurnOrder[turnOrderId] = gActiveBattler; + ++turnOrderId; + } + } + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH) + { + gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; + gBattlerByTurnOrder[turnOrderId] = gActiveBattler; + ++turnOrderId; + } + } + for (i = 0; i < gBattlersCount - 1; ++i) + { + for (j = i + 1; j < gBattlersCount; ++j) + { + u8 battler1 = gBattlerByTurnOrder[i]; + u8 battler2 = gBattlerByTurnOrder[j]; + + if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM + && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM + && gActionsByTurnOrder[i] != B_ACTION_SWITCH + && gActionsByTurnOrder[j] != B_ACTION_SWITCH) + if (GetWhoStrikesFirst(battler1, battler2, FALSE)) + SwapTurnOrder(i, j); + } + } + } + } + gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts; + gBattleStruct->focusPunchBattlerId = 0; +} + +static void TurnValuesCleanUp(bool8 var0) +{ + s32 i; + u8 *dataPtr; + + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (var0) + { + gProtectStructs[gActiveBattler].protected = FALSE; + gProtectStructs[gActiveBattler].endured = FALSE; + } + else + { + dataPtr = (u8 *)(&gProtectStructs[gActiveBattler]); + for (i = 0; i < sizeof(struct ProtectStruct); ++i) + dataPtr[i] = 0; + if (gDisableStructs[gActiveBattler].isFirstTurn) + --gDisableStructs[gActiveBattler].isFirstTurn; + if (gDisableStructs[gActiveBattler].rechargeTimer) + { + --gDisableStructs[gActiveBattler].rechargeTimer; + if (gDisableStructs[gActiveBattler].rechargeTimer == 0) + gBattleMons[gActiveBattler].status2 &= ~(STATUS2_RECHARGE); + } + } + + if (gDisableStructs[gActiveBattler].substituteHP == 0) + gBattleMons[gActiveBattler].status2 &= ~(STATUS2_SUBSTITUTE); + } + gSideTimers[0].followmeTimer = 0; + gSideTimers[1].followmeTimer = 0; +} + +static void SpecialStatusesClear(void) +{ + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + s32 i; + u8 *dataPtr = (u8 *)(&gSpecialStatuses[gActiveBattler]); + + for (i = 0; i < sizeof(struct SpecialStatus); ++i) + dataPtr[i] = 0; + } +} + +static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) +{ + if (!(gHitMarker & HITMARKER_RUN)) + { + while (gBattleStruct->focusPunchBattlerId < gBattlersCount) + { + gActiveBattler = gBattlerAttacker = gBattleStruct->focusPunchBattlerId; + ++gBattleStruct->focusPunchBattlerId; + if (gChosenMoveByBattler[gActiveBattler] == MOVE_FOCUS_PUNCH + && !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP) + && !(gDisableStructs[gBattlerAttacker].truantCounter) + && !(gProtectStructs[gActiveBattler].noValidMoves)) + { + BattleScriptExecute(BattleScript_FocusPunchSetUp); + return; + } + } + } + TryClearRageStatuses(); + gCurrentTurnActionNumber = 0; + { + // something stupid needed to match + u8 zero; + + gCurrentActionFuncId = gActionsByTurnOrder[(zero = 0)]; + } + gDynamicBasePower = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleMainFunc = RunTurnActionsFunctions; + gBattleCommunication[3] = 0; + gBattleCommunication[4] = 0; + gBattleScripting.multihitMoveEffect = 0; + gBattleResources->battleScriptsStack->size = 0; +} + +static void RunTurnActionsFunctions(void) +{ + if (gBattleOutcome != 0) + gCurrentActionFuncId = B_ACTION_FINISHED; + *(&gBattleStruct->savedTurnActionNumber) = gCurrentTurnActionNumber; + sTurnActionsFuncsTable[gCurrentActionFuncId](); + + if (gCurrentTurnActionNumber >= gBattlersCount) // everyone did their actions, turn finished + { + gHitMarker &= ~(HITMARKER_x100000); + gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F]; + } + else + { + if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battlerId + { + gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING); + gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE); + } + } +} + +static void HandleEndTurn_BattleWon(void) +{ + gCurrentActionFuncId = 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleTextBuff1[0] = gBattleOutcome; + gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost; + gBattleOutcome &= ~(B_OUTCOME_LINK_BATTLE_RAN); + } + else if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_BATTLE_TOWER)) + { + BattleStopLowHpSound(); + PlayBGM(MUS_WIN_TRE); + gBattlescriptCurrInstr = gUnknown_81D88D7; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + BattleStopLowHpSound(); + gBattlescriptCurrInstr = BattleScript_LocalTrainerBattleWon; + switch (gTrainers[gTrainerBattleOpponent_A].trainerClass) + { + case CLASS_LEADER_2: + case CLASS_CHAMPION_2: + PlayBGM(MUS_WIN_GYM); + break; + case CLASS_BOSS: + case CLASS_TEAM_ROCKET: + case CLASS_COOLTRAINER_2: + case CLASS_ELITE_FOUR_2: + case CLASS_GENTLEMAN_2: + default: + PlayBGM(MUS_WIN_TRE); + break; + } + } + else + { + gBattlescriptCurrInstr = BattleScript_PayDayMoneyAndPickUpItems; + } + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_BattleLost(void) +{ + gCurrentActionFuncId = 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleTextBuff1[0] = gBattleOutcome; + gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost; + gBattleOutcome &= ~(B_OUTCOME_LINK_BATTLE_RAN); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && ScrSpecial_GetTrainerBattleMode() == 9) + { + if (sub_80803D8() & 1) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattlerAttacker = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr = BattleScript_LocalBattleLost; + } + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_RanFromBattle(void) +{ + gCurrentActionFuncId = 0; + switch (gProtectStructs[gBattlerAttacker].fleeFlag) + { + default: + gBattlescriptCurrInstr = BattleScript_GotAwaySafely; + break; + case 1: + gBattlescriptCurrInstr = BattleScript_SmokeBallEscape; + break; + case 2: + gBattlescriptCurrInstr = BattleScript_RanAwayUsingMonAbility; + break; + } + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_MonFled(void) +{ + gCurrentActionFuncId = 0; + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]); + gBattlescriptCurrInstr = BattleScript_WildMonFled; + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_FinishBattle(void) +{ + if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED) + { + if (!(gBattleTypeFlags & (BATTLE_TYPE_TRAINER_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_SAFARI | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_LINK))) + { + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { + if (gBattleResults.playerMon1Species == SPECIES_NONE) + { + gBattleResults.playerMon1Species = gBattleMons[gActiveBattler].species; + StringCopy(gBattleResults.playerMon1Name, gBattleMons[gActiveBattler].nickname); + } + else + { + gBattleResults.playerMon2Species = gBattleMons[gActiveBattler].species; + StringCopy(gBattleResults.playerMon2Name, gBattleMons[gActiveBattler].nickname); + } + } + } + } + sub_812BFDC(); + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + sub_810CB90(); + BeginFastPaletteFade(3); + FadeOutMapMusic(5); + gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions; + gCB2_AfterEvolution = BattleMainCB2; + } + else if (!gBattleControllerExecFlags) + { + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + } +} + +static void FreeResetData_ReturnToOvOrDoEvolutions(void) +{ + if (!gPaletteFade.active) + { + ResetSpriteData(); + if (gLeveledUpInBattle == 0 || gBattleOutcome != B_OUTCOME_WON) + gBattleMainFunc = ReturnFromBattleToOverworld; + else + gBattleMainFunc = TryEvolvePokemon; + FreeAllWindowBuffers(); + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + FreeMonSpritesGfx(); + FreeBattleSpritesData(); + FreeBattleResources(); + } + } +} + +static void TryEvolvePokemon(void) +{ + s32 i; + + while (gLeveledUpInBattle != 0) + { + for (i = 0; i < PARTY_SIZE; ++i) + { + if (gLeveledUpInBattle & gBitTable[i]) + { + u16 species; + u8 levelUpBits = gLeveledUpInBattle; + + levelUpBits &= ~(gBitTable[i]); + gLeveledUpInBattle = levelUpBits; + species = GetEvolutionTargetSpecies(&gPlayerParty[i], 0, levelUpBits); + if (species != SPECIES_NONE) + { + gBattleMainFunc = WaitForEvoSceneToFinish; + EvolutionScene(&gPlayerParty[i], species, 0x81, i); + return; + } + } + } + } + gBattleMainFunc = ReturnFromBattleToOverworld; +} + +static void WaitForEvoSceneToFinish(void) +{ + if (gMain.callback2 == BattleMainCB2) + gBattleMainFunc = TryEvolvePokemon; +} + +static void ReturnFromBattleToOverworld(void) +{ + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + RandomlyGivePartyPokerus(gPlayerParty); + PartySpreadPokerus(gPlayerParty); + } + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) || gReceivedRemoteLinkPlayers == 0) + { + gSpecialVar_Result = gBattleOutcome; + gMain.inBattle = FALSE; + gMain.callback1 = gPreBattleCallback1; + if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) + { + UpdateRoamerHPStatus(&gEnemyParty[0]); + if ((gBattleOutcome & B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) + SetRoamerInactive(); + } + m4aSongNumStop(SE_HINSI); + SetMainCallback2(gMain.savedCallback); + } +} + +void RunBattleScriptCommands_PopCallbacksStack(void) +{ + if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED) + { + if (gBattleResources->battleCallbackStack->size != 0) + --gBattleResources->battleCallbackStack->size; + gBattleMainFunc = gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size]; + } + else + { + if (!gBattleControllerExecFlags) + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + } +} + +void RunBattleScriptCommands(void) +{ + if (!gBattleControllerExecFlags) + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); +} + +static void HandleAction_UseMove(void) +{ + u8 side; + u8 var = 4; + + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + if (*(&gBattleStruct->field_91) & gBitTable[gBattlerAttacker]) + { + gCurrentActionFuncId = B_ACTION_FINISHED; + return; + } + gCritMultiplier = 1; + gBattleScripting.dmgMultiplier = 1; + gBattleStruct->atkCancellerTracker = 0; + gMoveResultFlags = 0; + gMultiHitCounter = 0; + gBattleCommunication[6] = 0; + gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker); + // choose move + if (gProtectStructs[gBattlerAttacker].noValidMoves) + { + gProtectStructs[gBattlerAttacker].noValidMoves = 0; + gCurrentMove = gChosenMove = MOVE_STRUGGLE; + gHitMarker |= HITMARKER_NO_PPDEDUCT; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(MOVE_STRUGGLE, 0); + } + else if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + { + gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker]; + } + // encore forces you to use the same move + else if (gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBattlerAttacker].encoredMove == gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) + { + gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove; + gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, 0); + } + // check if the encored move wasn't overwritten + else if (gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBattlerAttacker].encoredMove != gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) + { + gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + gDisableStructs[gBattlerAttacker].encoredMove = MOVE_NONE; + gDisableStructs[gBattlerAttacker].encoredMovePos = 0; + gDisableStructs[gBattlerAttacker].encoreTimer = 0; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, 0); + } + else if (gBattleMons[gBattlerAttacker].moves[gCurrMovePos] != gChosenMoveByBattler[gBattlerAttacker]) + { + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, 0); + } + else + { + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + } + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + gBattleResults.lastUsedMovePlayer = gCurrentMove; + else + gBattleResults.lastUsedMoveOpponent = gCurrentMove; + // choose target + side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; + if (gSideTimers[side].followmeTimer != 0 + && gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget) + && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + { + gBattlerTarget = gSideTimers[side].followmeTarget; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + && gSideTimers[side].followmeTimer == 0 + && (gBattleMoves[gCurrentMove].power != 0 + || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER) + && gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_LIGHTNING_ROD + && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + { + side = GetBattlerSide(gBattlerAttacker); + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + if (side != GetBattlerSide(gActiveBattler) + && *(gBattleStruct->moveTarget + gBattlerAttacker) != gActiveBattler + && gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD + && GetBattlerTurnOrderNum(gActiveBattler) < var) + var = GetBattlerTurnOrderNum(gActiveBattler); + if (var == 4) + { + if (gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + } + else + { + gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + } + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + { + if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + else + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_SIDE); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + } + } + else + { + gActiveBattler = gBattlerByTurnOrder[var]; + RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability); + gSpecialStatuses[gActiveBattler].lightningRodRedirected = 1; + gBattlerTarget = gActiveBattler; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget] + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + else + { + gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + { + if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + else + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_SIDE); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + } + } + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_Switch(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gActionSelectionCursor[gBattlerAttacker] = 0; + gMoveSelectionCursor[gBattlerAttacker] = 0; + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, *(gBattleStruct->field_58 + gBattlerAttacker)); + gBattleScripting.battler = gBattlerAttacker; + gBattlescriptCurrInstr = BattleScript_ActionSwitch; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + if (gBattleResults.playerSwitchesCounter < 255) + ++gBattleResults.playerSwitchesCounter; +} + +static void HandleAction_UseItem(void) +{ + gBattlerAttacker = gBattlerTarget = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + ClearFuryCutterDestinyBondGrudge(gBattlerAttacker); + gLastUsedItem = gBattleBufferB[gBattlerAttacker][1] | (gBattleBufferB[gBattlerAttacker][2] << 8); + if (gLastUsedItem <= ITEM_PREMIER_BALL) // is ball + { + gBattlescriptCurrInstr = gBattlescriptsForBallThrow[gLastUsedItem]; + } + else if (gLastUsedItem == ITEM_POKE_DOLL || gLastUsedItem == ITEM_FLUFFY_TAIL) + { + gBattlescriptCurrInstr = gBattlescriptsForRunningByItem[0]; + } + else if (gLastUsedItem == ITEM_POKE_FLUTE) + { + gBattlescriptCurrInstr = gBattlescriptsForRunningByItem[1]; + } + else if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + gBattlescriptCurrInstr = gBattlescriptsForUsingItem[0]; + } + else + { + gBattleScripting.battler = gBattlerAttacker; + switch (*(gBattleStruct->AI_itemType + (gBattlerAttacker >> 1))) + { + case AI_ITEM_FULL_RESTORE: + case AI_ITEM_HEAL_HP: + break; + case AI_ITEM_CURE_CONDITION: + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + if (*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 1) + { + if (*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 0x3E) + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + while (!(*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 1)) + { + *(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) >>= 1; + ++gBattleCommunication[MULTISTRING_CHOOSER]; + } + } + break; + case AI_ITEM_X_STAT: + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + if (*(gBattleStruct->AI_itemFlags + (gBattlerAttacker >> 1)) & 0x80) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK); + PREPARE_STRING_BUFFER(gBattleTextBuff2, CHAR_X); + while (!((*(gBattleStruct->AI_itemFlags + (gBattlerAttacker >> 1))) & 1)) + { + *(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) >>= 1; + ++gBattleTextBuff1[2]; + } + gBattleScripting.animArg1 = gBattleTextBuff1[2] + 14; + gBattleScripting.animArg2 = 0; + } + break; + case AI_ITEM_GUARD_SPECS: + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + break; + } + + gBattlescriptCurrInstr = gBattlescriptsForUsingItem[*(gBattleStruct->AI_itemType + gBattlerAttacker / 2)]; + } + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +bool8 TryRunFromBattle(u8 battler) +{ + bool8 effect = FALSE; + u8 holdEffect; + u8 pyramidMultiplier; + u8 speedVar; + + if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[battler].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(gBattleMons[battler].item); + gPotentialItemEffectBattler = battler; + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + { + gLastUsedItem = gBattleMons[battler].item; + gProtectStructs[battler].fleeFlag = 1; + ++effect; + } + else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) + { + gLastUsedAbility = ABILITY_RUN_AWAY; + gProtectStructs[battler].fleeFlag = 2; + ++effect; + } + else if ((gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_GHOST)) == BATTLE_TYPE_GHOST) + { + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + ++effect; + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed) + { + speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + ++effect; + } + else // same speed or faster + { + ++effect; + } + } + + ++gBattleStruct->runTries; + } + if (effect) + { + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_RAN; + } + return effect; +} + +static void HandleAction_Run(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gCurrentTurnActionNumber = gBattlersCount; + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; ++gActiveBattler) + { + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_RUN) + gBattleOutcome |= B_OUTCOME_LOST; + } + else + { + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_RUN) + gBattleOutcome |= B_OUTCOME_WON; + } + } + gBattleOutcome |= B_OUTCOME_LINK_BATTLE_RAN; + } + else + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (!TryRunFromBattle(gBattlerAttacker)) // failed to run away + { + ClearFuryCutterDestinyBondGrudge(gBattlerAttacker); + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + } + } + else + { + if (gBattleMons[gBattlerAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + } + else + { + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_MON_FLED; + } + } + } +} + +static void HandleAction_WatchesCarefully(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + if (gBattleStruct->safariGoNearCounter != 0) + { + --gBattleStruct->safariGoNearCounter; + if (gBattleStruct->safariGoNearCounter == 0) + { + *(&gBattleStruct->safariCatchFactor) = gBaseStats[GetMonData(gEnemyParty, MON_DATA_SPECIES)].catchRate * 100 / 1275; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + } + else + { + if (gBattleStruct->safariPkblThrowCounter != 0) + { + --gBattleStruct->safariPkblThrowCounter; + if (gBattleStruct->safariPkblThrowCounter == 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[5] = 2; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + } + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[0]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_SafariZoneBallThrow(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + --gNumSafariBalls; + gLastUsedItem = ITEM_SAFARI_BALL; + gBattlescriptCurrInstr = gBattlescriptsForBallThrow[ITEM_SAFARI_BALL]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_ThrowPokeblock(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattleStruct->safariPkblThrowCounter += Random() % 5 + 2; + if (gBattleStruct->safariPkblThrowCounter > 6) + gBattleStruct->safariPkblThrowCounter = 6; + gBattleStruct->safariGoNearCounter = 0; + gBattleStruct->safariCatchFactor >>= 1; + if (gBattleStruct->safariCatchFactor <= 2) + gBattleStruct->safariCatchFactor = 3; + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[2]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_GoNear(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattleStruct->safariGoNearCounter += Random() % 5 + 2; + if (gBattleStruct->safariGoNearCounter > 6) + gBattleStruct->safariGoNearCounter = 6; + gBattleStruct->safariPkblThrowCounter = 0; + gBattleStruct->safariCatchFactor <<= 1; + if (gBattleStruct->safariCatchFactor > 20) + gBattleStruct->safariCatchFactor = 20; + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[1]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_SafariZoneRun(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + PlaySE(SE_NIGERU); + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_RAN; +} + +static void HandleAction_OldManBallThrow(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]) + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[3]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + gActionsByTurnOrder[1] = B_ACTION_FINISHED; +} + +static void HandleAction_TryFinish(void) +{ + if (!HandleFaintedMonActions()) + { + gBattleStruct->faintedActionsState = 0; + gCurrentActionFuncId = B_ACTION_FINISHED; + } +} + +static void HandleAction_NothingIsFainted(void) +{ + ++gCurrentTurnActionNumber; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR + | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000 + | HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_CHARGING | HITMARKER_x4000000); +} + +static void HandleAction_ActionFinished(void) +{ + ++gCurrentTurnActionNumber; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + SpecialStatusesClear(); + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR + | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000 + | HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_CHARGING | HITMARKER_x4000000); + gCurrentMove = MOVE_NONE; + gBattleMoveDamage = 0; + gMoveResultFlags = 0; + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gLastLandedMoves[gBattlerAttacker] = 0; + gLastHitByType[gBattlerAttacker] = 0; + gBattleStruct->dynamicMoveType = 0; + gDynamicBasePower = 0; + gBattleScripting.atk49_state = 0; + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0; + gBattleScripting.multihitMoveEffect = 0; + gBattleResources->battleScriptsStack->size = 0; +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 3de2a6dea..a7d8cb6fa 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -48,6 +48,7 @@ #include "constants/abilities.h" #include "constants/pokemon.h" #include "constants/trainers.h" +#include "constants/map_types.h" #define DEFENDER_IS_PROTECTED ((gProtectStructs[gBattlerTarget].protected) && (gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) @@ -1222,7 +1223,7 @@ static void atk04_critcalc(void) critChance = NELEMS(sCriticalHitChance) - 1; if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR) && !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT) - && !(gBattleTypeFlags & BATTLE_TYPE_OLDMAN_TUTORIAL) + && !(gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL) && !(Random() % sCriticalHitChance[critChance]) && (!(gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) || sub_80EB2E0(1)) && !(gBattleTypeFlags & BATTLE_TYPE_POKEDUDE)) @@ -4414,7 +4415,7 @@ static void atk4E_switchinanim(void) && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_LEGENDARY - | BATTLE_TYPE_OLDMAN_TUTORIAL + | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_POKEDUDE | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_GHOST))) @@ -9436,7 +9437,7 @@ static void atkEF_handleballthrow(void) MarkBattlerForControllerExec(gActiveBattler); gBattlescriptCurrInstr = BattleScript_TrainerBallBlock; } - else if (gBattleTypeFlags & (BATTLE_TYPE_POKEDUDE | BATTLE_TYPE_OLDMAN_TUTORIAL)) + else if (gBattleTypeFlags & (BATTLE_TYPE_POKEDUDE | BATTLE_TYPE_OLD_MAN_TUTORIAL)) { BtlController_EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS); MarkBattlerForControllerExec(gActiveBattler); @@ -9451,7 +9452,6 @@ static void atkEF_handleballthrow(void) catchRate = gBattleStruct->safariCatchFactor * 1275 / 100; else catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate; - if (gLastUsedItem > ITEM_SAFARI_BALL) { switch (gLastUsedItem) @@ -9515,7 +9515,7 @@ static void atkEF_handleballthrow(void) else { if (gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL] < 0xFF) - gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]++; + ++gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]; } } if (odds > 254) // mon caught diff --git a/src/battle_setup.c b/src/battle_setup.c new file mode 100644 index 000000000..98437e279 --- /dev/null +++ b/src/battle_setup.c @@ -0,0 +1,1060 @@ +#include "global.h" +#include "task.h" +#include "help_system.h" +#include "overworld.h" +#include "item.h" +#include "sound.h" +#include "pokemon.h" +#include "load_save.h" +#include "safari_zone.h" +#include "quest_log.h" +#include "script.h" +#include "script_pokemon_util_80A0058.h" +#include "strings.h" +#include "string_util.h" +#include "event_data.h" +#include "unk_8159F40.h" +#include "map_obj_80688E4.h" +#include "metatile_behavior.h" +#include "event_scripts.h" +#include "fldeff.h" +#include "fieldmap.h" +#include "field_control_avatar.h" +#include "field_player_avatar.h" +#include "field_screen_effect.h" +#include "field_message_box.h" +#include "field_map_obj.h" +#include "vs_seeker.h" +#include "battle.h" +#include "battle_setup.h" +#include "battle_transition.h" +#include "constants/battle_setup.h" +#include "constants/flags.h" +#include "constants/items.h" +#include "constants/maps.h" +#include "constants/songs.h" +#include "constants/species.h" +#include "constants/pokemon.h" +#include "constants/trainers.h" +#include "constants/trainer_classes.h" +#include "constants/map_types.h" + +enum +{ + TRAINER_PARAM_LOAD_VAL_8BIT, + TRAINER_PARAM_LOAD_VAL_16BIT, + TRAINER_PARAM_LOAD_VAL_32BIT, + TRAINER_PARAM_CLEAR_VAL_8BIT, + TRAINER_PARAM_CLEAR_VAL_16BIT, + TRAINER_PARAM_CLEAR_VAL_32BIT, + TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR, +}; + +struct TrainerBattleParameter +{ + void *varPtr; + u8 ptrType; +}; + +static void DoSafariBattle(void); +static void DoGhostBattle(void); +static void DoStandardWildBattle(void); +static void CB2_EndWildBattle(void); +static u8 GetWildBattleTransition(void); +static u8 GetTrainerBattleTransition(void); +static void CB2_EndScriptedWildBattle(void); +static void CB2_EndMarowakBattle(void); +static bool32 IsPlayerDefeated(u32 battleOutcome); +static void CB2_EndTrainerBattle(void); +static const u8 *GetIntroSpeechOfApproachingTrainer(void); +static const u8 *GetTrainerCantBattleSpeech(void); + +static EWRAM_DATA u16 sTrainerBattleMode = 0; +EWRAM_DATA u16 gTrainerBattleOpponent_A = 0; +static EWRAM_DATA u16 sTrainerEventObjectLocalId = 0; +static EWRAM_DATA u8 *sTrainerAIntroSpeech = NULL; +static EWRAM_DATA u8 *sTrainerADefeatSpeech = NULL; +static EWRAM_DATA u8 *sTrainerVictorySpeech = NULL; +static EWRAM_DATA u8 *sTrainerCannotBattleSpeech = NULL; +static EWRAM_DATA u8 *sTrainerBattleEndScript = NULL; +static EWRAM_DATA u8 *sTrainerABattleScriptRetAddr = NULL; +static EWRAM_DATA u16 gUnknown_20386CC = 0; + +static const u8 sBattleTransitionTable_Wild[][2] = +{ + B_TRANSITION_SLICED_SCREEN, B_TRANSITION_WHITEFADE_IN_STRIPES, + B_TRANSITION_CLOCKWISE_BLACKFADE, B_TRANSITION_GRID_SQUARES, + B_TRANSITION_BLUR, B_TRANSITION_GRID_SQUARES, + B_TRANSITION_BLACK_WAVE_TO_RIGHT, B_TRANSITION_FULLSCREEN_WAVE, +}; + +static const u8 sBattleTransitionTable_Trainer[][2] = +{ + B_TRANSITION_SLIDING_POKEBALLS, B_TRANSITION_BLACK_DOODLES, + B_TRANSITION_HORIZONTAL_CORRUGATE, B_TRANSITION_BIG_POKEBALL, + B_TRANSITION_BLUR, B_TRANSITION_GRID_SQUARES, + B_TRANSITION_DISTORTED_WAVE, B_TRANSITION_FULLSCREEN_WAVE, +}; + +static const struct TrainerBattleParameter sOrdinaryBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerEventObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sContinueScriptBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerEventObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sDoubleBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerEventObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sOrdinaryNoIntroBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerEventObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sTutorialBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&gUnknown_20386CC, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sContinueScriptDoubleBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerEventObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + + +#define tState data[0] +#define tTransition data[1] + +static void Task_BattleStart(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + switch (tState) + { + case 0: + if (!FldEffPoison_IsActive()) + { + HelpSystem_Disable(); + BT_StartOnField(tTransition); + ++tState; + } + break; + case 1: + if (BT_IsDone() == TRUE) + { + HelpSystem_Enable(); + CleanupOverworldWindowsAndTilemaps(); + SetMainCallback2(CB2_InitBattle); + RestartWildEncounterImmunitySteps(); + ClearPoisonStepCounter(); + DestroyTask(taskId); + } + break; + } +} + +static void CreateBattleStartTask(u8 transition, u16 song) // song == 0 means default music for current map +{ + u8 taskId = CreateTask(Task_BattleStart, 1); + + gTasks[taskId].tTransition = transition; + PlayMapChosenOrBattleBGM(song); +} + +static bool8 CheckSilphScopeInPokemonTower(u16 mapGroup, u16 mapNum) +{ + if (mapGroup == MAP_GROUP(POKEMON_TOWER_1F) + && ((u16)(mapNum - MAP_NUM(POKEMON_TOWER_1F)) <= 6) + && !(CheckBagHasItem(ITEM_SILPH_SCOPE, 1))) + return TRUE; + else + return FALSE; +} + +void BattleSetup_StartWildBattle(void) +{ + if (GetSafariZoneFlag()) + DoSafariBattle(); + else if (CheckSilphScopeInPokemonTower(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum)) + DoGhostBattle(); + else + DoStandardWildBattle(); +} + +static void DoStandardWildBattle(void) +{ + ScriptContext2_Enable(); + FreezeEventObjects(); + sub_805C780(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = 0; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +void BattleSetup_StartRoamerBattle(void) +{ + ScriptContext2_Enable(); + FreezeEventObjects(); + sub_805C780(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = BATTLE_TYPE_ROAMER; + CreateBattleStartTask(GetWildBattleTransition(), MUS_VS_DEN); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +static void DoSafariBattle(void) +{ + ScriptContext2_Enable(); + FreezeEventObjects(); + sub_805C780(); + gMain.savedCallback = CB2_EndSafariBattle; + gBattleTypeFlags = BATTLE_TYPE_SAFARI; + CreateBattleStartTask(GetWildBattleTransition(), 0); +} + +static void DoGhostBattle(void) +{ + ScriptContext2_Enable(); + FreezeEventObjects(); + sub_805C780(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = BATTLE_TYPE_GHOST; + CreateBattleStartTask(GetWildBattleTransition(), 0); + SetMonData(&gEnemyParty[0], MON_DATA_NICKNAME, gUnknown_841D148); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +static void DoTrainerBattle(void) +{ + CreateBattleStartTask(GetTrainerBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_TRAINER_BATTLES); +} + +void ScrSpecial_StartOldManTutorialBattle(void) +{ + CreateMaleMon(&gEnemyParty[0], SPECIES_WEEDLE, 5); + ScriptContext2_Enable(); + gMain.savedCallback = CB2_ReturnToFieldContinueScriptPlayMapMusic; + gBattleTypeFlags = BATTLE_TYPE_OLD_MAN_TUTORIAL; + CreateBattleStartTask(B_TRANSITION_SLICED_SCREEN, 0); +} + +void BattleSetup_StartScriptedWildBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_PALACE; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +void ScrSpecial_StartMarowakBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndMarowakBattle; + if (CheckBagHasItem(ITEM_SILPH_SCOPE, 1)) + { + gBattleTypeFlags = BATTLE_TYPE_GHOST | BATTLE_TYPE_LEGENDARY; + CreateMonWithGenderNatureLetter(gEnemyParty, SPECIES_MAROWAK, 30, 31, MON_FEMALE, NATURE_SERIOUS, 0); + } + else + { + gBattleTypeFlags = BATTLE_TYPE_GHOST; + } + CreateBattleStartTask(GetWildBattleTransition(), 0); + SetMonData(&gEnemyParty[0], MON_DATA_NICKNAME, gUnknown_841D148); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +void ScrSpecial_StartSouthernIslandBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +void Special_StartLegendaryBattle(void) +{ + u16 species; + + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_ARENA; + species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES); + switch (species) + { + case SPECIES_MEWTWO: + CreateBattleStartTask(B_TRANSITION_BLUR, MUS_VS_MYU2); + break; + case SPECIES_DEOXYS: + CreateBattleStartTask(B_TRANSITION_BLUR, MUS_VS_DEO); + break; + case SPECIES_MOLTRES: + case SPECIES_ARTICUNO: + case SPECIES_ZAPDOS: + case SPECIES_HO_OH: + case SPECIES_LUGIA: + CreateBattleStartTask(B_TRANSITION_BLUR, MUS_VS_DEN); + break; + default: + CreateBattleStartTask(B_TRANSITION_BLUR, MUS_BATTLE20); + break; + } + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +void Special_StartGroudonKyogreBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_KYOGRE_GROUDON; + if (gGameVersion == VERSION_FIRE_RED) + CreateBattleStartTask(B_TRANSITION_BLACK_DOODLES, MUS_BATTLE20); + else // pointless, exactly the same + CreateBattleStartTask(B_TRANSITION_BLACK_DOODLES, MUS_BATTLE20); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +void Special_StartRegiBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_REGI; + CreateBattleStartTask(B_TRANSITION_BLUR, MUS_BATTLE20); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); +} + +// not used +static void sub_807FAF8(void) +{ + LoadPlayerParty(); + CB2_EndWildBattle(); +} + +// not used +static void sub_807FB08(void) +{ + ScriptContext2_Enable(); + FreezeEventObjects(); + sub_805C780(); + gMain.savedCallback = sub_807FAF8; + SavePlayerParty(); + InitPokedudePartyAndOpponent(); + CreateBattleStartTask(GetWildBattleTransition(), 0); +} + +static void CB2_EndWildBattle(void) +{ + CpuFill16(0, (void *)BG_PLTT, BG_PLTT_SIZE); + ResetOamRange(0, 128); + if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(CB2_ReturnToField); + gFieldCallback = sub_807E3EC; + } +} + +static void CB2_EndScriptedWildBattle(void) +{ + CpuFill16(0, (void *)BG_PLTT, BG_PLTT_SIZE); + ResetOamRange(0, 128); + if (IsPlayerDefeated(gBattleOutcome) == TRUE) + SetMainCallback2(CB2_WhiteOut); + else + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); +} + +static void CB2_EndMarowakBattle(void) +{ + CpuFill16(0, (void *)BG_PLTT, BG_PLTT_SIZE); + ResetOamRange(0, 128); + if (IsPlayerDefeated(gBattleOutcome)) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + if (gBattleOutcome == B_OUTCOME_WON) + gSpecialVar_Result = 0; + else + gSpecialVar_Result = 1; + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + } +} + +u8 BattleSetup_GetTerrainId(void) +{ + u16 tileBehavior; + s16 x, y; + + PlayerGetDestCoords(&x, &y); + tileBehavior = MapGridGetMetatileBehaviorAt(x, y); + if (MetatileBehavior_IsTallGrass_2(tileBehavior)) + return BATTLE_TERRAIN_GRASS; + if (MetatileBehavior_IsLongGrass(tileBehavior)) + return BATTLE_TERRAIN_LONG_GRASS; + if (MetatileBehavior_IsSandOrDeepSand(tileBehavior)) + return BATTLE_TERRAIN_SAND; + switch (gMapHeader.mapType) + { + case MAP_TYPE_TOWN: + case MAP_TYPE_CITY: + case MAP_TYPE_ROUTE: + break; + case MAP_TYPE_UNDERGROUND: + if (MetatileBehavior_IsIndoorEncounter(tileBehavior)) + return BATTLE_TERRAIN_BUILDING; + if (MetatileBehavior_IsSurfable(tileBehavior)) + return BATTLE_TERRAIN_POND; + return BATTLE_TERRAIN_CAVE; + case MAP_TYPE_INDOOR: + case MAP_TYPE_SECRET_BASE: + return BATTLE_TERRAIN_BUILDING; + case MAP_TYPE_UNDERWATER: + return BATTLE_TERRAIN_UNDERWATER; + case MAP_TYPE_OCEAN_ROUTE: + if (MetatileBehavior_IsSurfable(tileBehavior)) + return BATTLE_TERRAIN_WATER; + return BATTLE_TERRAIN_PLAIN; + } + if (MetatileBehavior_IsDeepSemiDeepOrSplashingWater(tileBehavior)) + return BATTLE_TERRAIN_WATER; + if (MetatileBehavior_IsSurfable(tileBehavior)) + return BATTLE_TERRAIN_POND; + if (MetatileBehavior_IsMountain(tileBehavior)) + return BATTLE_TERRAIN_MOUNTAIN; + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) + { + if (MetatileBehavior_GetBridgeType(tileBehavior)) + return BATTLE_TERRAIN_POND; + if (MetatileBehavior_IsBridge(tileBehavior) == TRUE) + return BATTLE_TERRAIN_WATER; + } + return BATTLE_TERRAIN_PLAIN; +} + +static u8 GetBattleTransitionTypeByMap(void) +{ + u16 tileBehavior; + s16 x, y; + + PlayerGetDestCoords(&x, &y); + tileBehavior = MapGridGetMetatileBehaviorAt(x, y); + if (Overworld_GetFlashLevel()) + return B_TRANSITION_HORIZONTAL_CORRUGATE; + if (!MetatileBehavior_IsSurfable(tileBehavior)) + { + switch (gMapHeader.mapType) + { + case MAP_TYPE_UNDERGROUND: + return B_TRANSITION_DISTORTED_WAVE; + case MAP_TYPE_UNDERWATER: + return B_TRANSITION_BIG_POKEBALL; + default: + return B_TRANSITION_BLUR; + } + } + return B_TRANSITION_BIG_POKEBALL; +} + +static u16 GetSumOfPlayerPartyLevel(u8 numMons) +{ + u8 sum = 0; + s32 i; + + for (i = 0; i < PARTY_SIZE; ++i) + { + u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + + if (species != SPECIES_EGG && species != SPECIES_NONE && GetMonData(&gPlayerParty[i], MON_DATA_HP) != 0) + { + sum += GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); + if (--numMons == 0) + break; + } + } + return sum; +} + +static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons) +{ + u8 i; + u8 sum; + u32 count = numMons; + + if (gTrainers[opponentId].partySize < count) + count = gTrainers[opponentId].partySize; + sum = 0; + switch (gTrainers[opponentId].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *party; + + party = gTrainers[opponentId].party.NoItemDefaultMoves; + for (i = 0; i < count; ++i) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_CUSTOM_MOVESET: + { + const struct TrainerMonNoItemCustomMoves *party; + + party = gTrainers[opponentId].party.NoItemCustomMoves; + for (i = 0; i < count; ++i) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemDefaultMoves *party; + + party = gTrainers[opponentId].party.ItemDefaultMoves; + for (i = 0; i < count; ++i) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemCustomMoves *party; + + party = gTrainers[opponentId].party.ItemCustomMoves; + for (i = 0; i < count; ++i) + sum += party[i].lvl; + } + break; + } + return sum; +} + +static u8 GetWildBattleTransition(void) +{ + u8 transitionType = GetBattleTransitionTypeByMap(); + u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u8 playerLevel = GetSumOfPlayerPartyLevel(1); + + if (enemyLevel < playerLevel) + return sBattleTransitionTable_Wild[transitionType][0]; + else + return sBattleTransitionTable_Wild[transitionType][1]; +} + +static u8 GetTrainerBattleTransition(void) +{ + u8 minPartyCount; + u8 transitionType; + u8 enemyLevel; + u8 playerLevel; + + if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE) + return B_TRANSITION_BLUE; + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_ELITE_FOUR_2) + { + if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LORELEI || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LORELEI_2) + return B_TRANSITION_LORELEI; + if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_BRUNO || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_BRUNO_2) + return B_TRANSITION_BRUNO; + if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_AGATHA || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_AGATHA_2) + return B_TRANSITION_AGATHA; + if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LANCE || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LANCE_2) + return B_TRANSITION_LANCE; + return B_TRANSITION_BLUE; + } + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_CHAMPION_2) + return B_TRANSITION_BLUE; + if (gTrainers[gTrainerBattleOpponent_A].doubleBattle == TRUE) + minPartyCount = 2; // double battles always at least have 2 pokemon. + else + minPartyCount = 1; + transitionType = GetBattleTransitionTypeByMap(); + enemyLevel = GetSumOfEnemyPartyLevel(gTrainerBattleOpponent_A, minPartyCount); + playerLevel = GetSumOfPlayerPartyLevel(minPartyCount); + if (enemyLevel < playerLevel) + return sBattleTransitionTable_Trainer[transitionType][0]; + else + return sBattleTransitionTable_Trainer[transitionType][1]; +} + +u8 sub_8080060(void) +{ + u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u8 playerLevel = GetSumOfPlayerPartyLevel(1); + + if (enemyLevel < playerLevel) + return 4; + else + return 3; +} + +static u32 TrainerBattleLoadArg32(const u8 *ptr) +{ + return T1_READ_32(ptr); +} + +static u16 TrainerBattleLoadArg16(const u8 *ptr) +{ + return T1_READ_16(ptr); +} + +static u8 TrainerBattleLoadArg8(const u8 *ptr) +{ + return T1_READ_8(ptr); +} + +static u16 GetTrainerAFlag(void) +{ + return FLAG_TRAINER_FLAG_START + gTrainerBattleOpponent_A; +} + +static bool32 IsPlayerDefeated(u32 battleOutcome) +{ + switch (battleOutcome) + { + case B_OUTCOME_LOST: + case B_OUTCOME_DREW: + return TRUE; + case B_OUTCOME_WON: + case B_OUTCOME_RAN: + case B_OUTCOME_PLAYER_TELEPORTED: + case B_OUTCOME_MON_FLED: + case B_OUTCOME_CAUGHT: + return FALSE; + default: + return FALSE; + } +} + +static void InitTrainerBattleVariables(void) +{ + sTrainerBattleMode = 0; + gTrainerBattleOpponent_A = 0; + sTrainerEventObjectLocalId = 0; + sTrainerAIntroSpeech = NULL; + sTrainerADefeatSpeech = NULL; + sTrainerVictorySpeech = NULL; + sTrainerCannotBattleSpeech = NULL; + sTrainerBattleEndScript = NULL; + sTrainerABattleScriptRetAddr = NULL; + gUnknown_20386CC = 0; +} + +static inline void SetU8(void *ptr, u8 value) +{ + *(u8 *)(ptr) = value; +} + +static inline void SetU16(void *ptr, u16 value) +{ + *(u16 *)(ptr) = value; +} + +static inline void SetU32(void *ptr, u32 value) +{ + *(u32 *)(ptr) = value; +} + +static inline void SetPtr(const void *ptr, const void *value) +{ + *(const void **)(ptr) = value; +} + +static void TrainerBattleLoadArgs(const struct TrainerBattleParameter *specs, const u8 *data) +{ + while (1) + { + switch (specs->ptrType) + { + case TRAINER_PARAM_LOAD_VAL_8BIT: + SetU8(specs->varPtr, TrainerBattleLoadArg8(data)); + data += 1; + break; + case TRAINER_PARAM_LOAD_VAL_16BIT: + SetU16(specs->varPtr, TrainerBattleLoadArg16(data)); + data += 2; + break; + case TRAINER_PARAM_LOAD_VAL_32BIT: + SetU32(specs->varPtr, TrainerBattleLoadArg32(data)); + data += 4; + break; + case TRAINER_PARAM_CLEAR_VAL_8BIT: + SetU8(specs->varPtr, 0); + break; + case TRAINER_PARAM_CLEAR_VAL_16BIT: + SetU16(specs->varPtr, 0); + break; + case TRAINER_PARAM_CLEAR_VAL_32BIT: + SetU32(specs->varPtr, 0); + break; + case TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR: + SetPtr(specs->varPtr, data); + return; + } + ++specs; + } +} + +static void SetMapVarsToTrainer(void) +{ + if (sTrainerEventObjectLocalId != 0) + { + gSpecialVar_LastTalked = sTrainerEventObjectLocalId; + gSelectedEventObject = GetFieldObjectIdByLocalIdAndMap(sTrainerEventObjectLocalId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + } +} + +const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data) +{ + InitTrainerBattleVariables(); + sTrainerBattleMode = TrainerBattleLoadArg8(data); + switch (sTrainerBattleMode) + { + case TRAINER_BATTLE_SINGLE_NO_INTRO_TEXT: + TrainerBattleLoadArgs(sOrdinaryNoIntroBattleParams, data); + return EventScript_DoTrainerBattle; + case TRAINER_BATTLE_DOUBLE: + TrainerBattleLoadArgs(sDoubleBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoDoubleTrainerBattle; + case TRAINER_BATTLE_CONTINUE_SCRIPT: + case TRAINER_BATTLE_CONTINUE_SCRIPT_NO_MUSIC: + TrainerBattleLoadArgs(sContinueScriptBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoNormalTrainerBattle; + case TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE: + case TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC: + TrainerBattleLoadArgs(sContinueScriptDoubleBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoDoubleTrainerBattle; + case TRAINER_BATTLE_REMATCH_DOUBLE: + sub_811231C(); + TrainerBattleLoadArgs(sDoubleBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A); + return EventScript_TryDoDoubleRematchBattle; + case TRAINER_BATTLE_REMATCH: + sub_811231C(); + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A); + return EventScript_TryDoRematchBattle; + case TRAINER_BATTLE_TUTORIAL: + TrainerBattleLoadArgs(sTutorialBattleParams, data); + return EventScript_DoTrainerBattle; + default: + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoNormalTrainerBattle; + } +} + +void ConfigureAndSetUpOneTrainerBattle(u8 trainerEventObjId, const u8 *trainerScript) +{ + gSelectedEventObject = trainerEventObjId; + gSpecialVar_LastTalked = gMapObjects[trainerEventObjId].localId; + BattleSetup_ConfigureTrainerBattle(trainerScript + 1); + ScriptContext1_SetupScript(gUnknown_81A4EB4); + ScriptContext2_Enable(); +} + +bool32 GetTrainerFlagFromScriptPointer(const u8 *data) +{ + u32 flag = TrainerBattleLoadArg16(data + 2); + + return FlagGet(FLAG_TRAINER_FLAG_START + flag); +} + +void SetUpTrainerMovement(void) +{ + struct MapObject *eventObject = &gMapObjects[gSelectedEventObject]; + + SetTrainerMovementType(eventObject, GetTrainerFacingDirectionMovementType(eventObject->facingDirection)); +} + +u8 ScrSpecial_GetTrainerBattleMode(void) +{ + return sTrainerBattleMode; +} + +u16 sub_80803D8(void) +{ + return gUnknown_20386CC; +} + +u16 ScrSpecial_HasTrainerBeenFought(void) +{ + return FlagGet(GetTrainerAFlag()); +} + +void SetBattledTrainerFlag(void) +{ + FlagSet(GetTrainerAFlag()); +} + +// not used +static void SetBattledTrainerFlag2(void) +{ + FlagSet(GetTrainerAFlag()); +} + +bool8 HasTrainerBeenFought(u16 trainerId) +{ + return FlagGet(FLAG_TRAINER_FLAG_START + trainerId); +} + +void SetTrainerFlag(u16 trainerId) +{ + FlagSet(FLAG_TRAINER_FLAG_START + trainerId); +} + +void ClearTrainerFlag(u16 trainerId) +{ + FlagClear(FLAG_TRAINER_FLAG_START + trainerId); +} + +void BattleSetup_StartTrainerBattle(void) +{ + gBattleTypeFlags = BATTLE_TYPE_TRAINER; + if (ScrSpecial_GetTrainerBattleMode() == TRAINER_BATTLE_TUTORIAL + && sub_80803D8() & 3) + gBattleTypeFlags |= BATTLE_TYPE_FIRST_BATTLE; + gMain.savedCallback = CB2_EndTrainerBattle; + DoTrainerBattle(); + ScriptContext1_Stop(); +} + +static void CB2_EndTrainerBattle(void) +{ + if (sTrainerBattleMode == TRAINER_BATTLE_TUTORIAL) + { + if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + gSpecialVar_Result = 1; + if (gUnknown_20386CC & 1) + { + sp000_heal_pokemon(); + } + else + { + SetMainCallback2(CB2_WhiteOut); + return; + } + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + SetBattledTrainerFlag(); + sub_81139BC(); + } + else + { + gSpecialVar_Result = 0; + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + SetBattledTrainerFlag(); + sub_81139BC(); + } + + } + else + { + if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE) + { + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + } + else if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + SetBattledTrainerFlag(); + sub_81139BC(); + } + } +} + +static void CB2_EndRematchBattle(void) +{ + if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE) + { + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + } + else if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + SetBattledTrainerFlag(); + sub_810CDE8(); + sub_81138F8(); + } +} + +void ScrSpecial_StartTrainerEyeRematch(void) +{ + gBattleTypeFlags = BATTLE_TYPE_TRAINER; + gMain.savedCallback = CB2_EndRematchBattle; + DoTrainerBattle(); + ScriptContext1_Stop(); +} + +void ScrSpecial_ShowTrainerIntroSpeech(void) +{ + ShowFieldMessage(GetIntroSpeechOfApproachingTrainer()); +} + +const u8 *BattleSetup_GetScriptAddrAfterBattle(void) +{ + if (sTrainerBattleEndScript != NULL) + return sTrainerBattleEndScript; + else + return EventScript_1C555B; +} + +const u8 *BattleSetup_GetTrainerPostBattleScript(void) +{ + if (sTrainerABattleScriptRetAddr != NULL) + return sTrainerABattleScriptRetAddr; + else + return EventScript_1C555B; +} + +void ScrSpecial_ShowTrainerNonBattlingSpeech(void) +{ + ShowFieldMessage(GetTrainerCantBattleSpeech()); +} + +void PlayTrainerEncounterMusic(void) +{ + u16 music; + + if (gUnknown_203ADFA != 2 + && gUnknown_203ADFA != 3 + && sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_NO_MUSIC + && sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC) + { + switch (GetTrainerEncounterMusicId(gTrainerBattleOpponent_A)) + { + case TRAINER_ENCOUNTER_MUSIC_FEMALE: + case TRAINER_ENCOUNTER_MUSIC_GIRL: + case TRAINER_ENCOUNTER_MUSIC_TWINS: + music = MUS_SHOUJO; + break; + case TRAINER_ENCOUNTER_MUSIC_MALE: + case TRAINER_ENCOUNTER_MUSIC_INTENSE: + case TRAINER_ENCOUNTER_MUSIC_COOL: + case TRAINER_ENCOUNTER_MUSIC_SWIMMER: + case TRAINER_ENCOUNTER_MUSIC_ELITE_FOUR: + case TRAINER_ENCOUNTER_MUSIC_HIKER: + case TRAINER_ENCOUNTER_MUSIC_INTERVIEWER: + case TRAINER_ENCOUNTER_MUSIC_RICH: + music = MUS_SHOUNEN; + break; + default: + music = MUS_ROCKET; + break; + } + PlayNewMapMusic(music); + } +} + +static const u8 *ReturnEmptyStringIfNull(const u8 *string) +{ + if (string == NULL) + return gString_Dummy; + else + return string; +} + +static const u8 *GetIntroSpeechOfApproachingTrainer(void) +{ + return ReturnEmptyStringIfNull(sTrainerAIntroSpeech); +} + +const u8 *GetTrainerALoseText(void) +{ + const u8 *string = sTrainerADefeatSpeech; + + StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(string)); + return gStringVar4; +} + +const u8 *GetTrainerWonSpeech(void) +{ + StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(sTrainerVictorySpeech)); + return gStringVar4; +} + +static const u8 *GetTrainerCantBattleSpeech(void) +{ + return ReturnEmptyStringIfNull(sTrainerCannotBattleSpeech); +} diff --git a/src/battle_transition.c b/src/battle_transition.c index 19d76fed1..1dbfe3aed 100644 --- a/src/battle_transition.c +++ b/src/battle_transition.c @@ -27,7 +27,7 @@ struct TransitionData u16 winOut; u16 win0H; u16 win0V; - u16 unused_A; + u16 win1H; // not used u16 win1V; u16 bldCnt; u16 bldAlpha; @@ -3175,7 +3175,7 @@ static bool8 BT_Phase2WhiteFadeInStripes_Stop(struct Task *task) DmaStop(0); SetVBlankCallback(NULL); SetHBlankCallback(NULL); - sTransitionStructPtr->win0H = 240; + sTransitionStructPtr->win0H = WIN_RANGE(0, 240); sTransitionStructPtr->bldY = 0; sTransitionStructPtr->bldCnt = BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD | BLDCNT_EFFECT_DARKEN; sTransitionStructPtr->winIn = WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WININ_WIN0_CLR; diff --git a/src/battle_util2.c b/src/battle_util2.c index d940d8508..a3a748767 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -1,6 +1,7 @@ #include "global.h" #include "bg.h" #include "battle.h" +#include "battle_anim.h" #include "pokemon.h" #include "malloc.h" #include "trainer_tower.h" diff --git a/src/berry.c b/src/berry.c index 91d83f40c..d349109d2 100644 --- a/src/berry.c +++ b/src/berry.c @@ -134,7 +134,7 @@ bool32 IsEnigmaBerryValid(void) return TRUE; } -const struct Berry * sub_809C8A0(u8 berryIdx) +const struct Berry * GetBerryInfo(u8 berryIdx) { if (berryIdx == ITEM_TO_BERRY(ITEM_ENIGMA_BERRY) && IsEnigmaBerryValid()) return (struct Berry *)&gSaveBlock1Ptr->enigmaBerry.berry; @@ -163,7 +163,7 @@ u16 BerryTypeToItemId(u16 berryType) void GetBerryNameByBerryType(u8 berryType, u8 * dest) { - const struct Berry * berry = sub_809C8A0(berryType); + const struct Berry * berry = GetBerryInfo(berryType); memcpy(dest, berry->name, 6); dest[6] = EOS; } diff --git a/src/dark.c b/src/dark.c index cb34b991e..b6d13afe3 100644 --- a/src/dark.c +++ b/src/dark.c @@ -613,7 +613,7 @@ static void sub_80B82C0(u8 taskId) { case 0: task->data[5] += 8; - if (task->data[5] >= task->data[7]) + if (task->data[5] >= task->data[7]) task->data[5] = task->data[7]; sub_80B843C(task); if (task->data[5] == task->data[7]) diff --git a/src/data/text/abilities.h b/src/data/text/abilities.h new file mode 100644 index 000000000..c2002bed7 --- /dev/null +++ b/src/data/text/abilities.h @@ -0,0 +1,242 @@ +static const u8 sNoneDescription[] = _("No special ability."); +static const u8 sStenchDescription[] = _("Helps repel wild POKéMON."); +static const u8 sDrizzleDescription[] = _("Summons rain in battle."); +static const u8 sSpeedBoostDescription[] = _("Gradually boosts SPEED."); +static const u8 sBattleArmorDescription[] = _("Blocks critical hits."); +static const u8 sSturdyDescription[] = _("Negates 1-hit KO attacks."); +static const u8 sDampDescription[] = _("Prevents self-destruction."); +static const u8 sLimberDescription[] = _("Prevents paralysis."); +static const u8 sSandVeilDescription[] = _("Ups evasion in a sandstorm."); +static const u8 sStaticDescription[] = _("Paralyzes on contact."); +static const u8 sVoltAbsorbDescription[] = _("Turns electricity into HP."); +static const u8 sWaterAbsorbDescription[] = _("Changes water into HP."); +static const u8 sObliviousDescription[] = _("Prevents attraction."); +static const u8 sCloudNineDescription[] = _("Negates weather effects."); +static const u8 sCompoundEyesDescription[] = _("Raises accuracy."); +static const u8 sInsomniaDescription[] = _("Prevents sleep."); +static const u8 sColorChangeDescription[] = _("Changes type to foe's move."); +static const u8 sImmunityDescription[] = _("Prevents poisoning."); +static const u8 sFlashFireDescription[] = _("Powers up if hit by fire."); +static const u8 sShieldDustDescription[] = _("Prevents added effects."); +static const u8 sOwnTempoDescription[] = _("Prevents confusion."); +static const u8 sSuctionCupsDescription[] = _("Firmly anchors the body."); +static const u8 sIntimidateDescription[] = _("Lowers the foe's ATTACK."); +static const u8 sShadowTagDescription[] = _("Prevents the foe's escape."); +static const u8 sRoughSkinDescription[] = _("Hurts to touch."); +static const u8 sWonderGuardDescription[] = _("“Super effective” hits."); +static const u8 sLevitateDescription[] = _("Not hit by GROUND attacks."); +static const u8 sEffectSporeDescription[] = _("Leaves spores on contact."); +static const u8 sSynchronizeDescription[] = _("Passes on status problems."); +static const u8 sClearBodyDescription[] = _("Prevents ability reduction."); +static const u8 sNaturalCureDescription[] = _("Heals upon switching out."); +static const u8 sLightningRodDescription[] = _("Draws electrical moves."); +static const u8 sSereneGraceDescription[] = _("Promotes added effects."); +static const u8 sSwiftSwimDescription[] = _("Raises SPEED in rain."); +static const u8 sChlorophyllDescription[] = _("Raises SPEED in sunshine."); +static const u8 sIlluminateDescription[] = _("Encounter rate increases."); +static const u8 sTraceDescription[] = _("Copies special ability."); +static const u8 sHugePowerDescription[] = _("Raises ATTACK."); +static const u8 sPoisonPointDescription[] = _("Poisons foe on contact."); +static const u8 sInnerFocusDescription[] = _("Prevents flinching."); +static const u8 sMagmaArmorDescription[] = _("Prevents freezing."); +static const u8 sWaterVeilDescription[] = _("Prevents burns."); +static const u8 sMagnetPullDescription[] = _("Traps STEEL-type POKéMON."); +static const u8 sSoundproofDescription[] = _("Avoids sound-based moves."); +static const u8 sRainDishDescription[] = _("Slight HP recovery in rain."); +static const u8 sSandStreamDescription[] = _("Summons a sandstorm."); +static const u8 sPressureDescription[] = _("Raises foe's PP usage."); +static const u8 sThickFatDescription[] = _("Heat-and-cold protection."); +static const u8 sEarlyBirdDescription[] = _("Awakens quickly from sleep."); +static const u8 sFlameBodyDescription[] = _("Burns the foe on contact."); +static const u8 sRunAwayDescription[] = _("Makes escaping easier."); +static const u8 sKeenEyeDescription[] = _("Prevents loss of accuracy."); +static const u8 sHyperCutterDescription[] = _("Prevents ATTACK reduction."); +static const u8 sPickupDescription[] = _("May pick up items."); +static const u8 sTruantDescription[] = _("Moves only every two turns."); +static const u8 sHustleDescription[] = _("Trades accuracy for power."); +static const u8 sCuteCharmDescription[] = _("Infatuates on contact."); +static const u8 sPlusDescription[] = _("Powers up with MINUS."); +static const u8 sMinusDescription[] = _("Powers up with PLUS."); +static const u8 sForecastDescription[] = _("Changes with the weather."); +static const u8 sStickyHoldDescription[] = _("Prevents item theft."); +static const u8 sShedSkinDescription[] = _("Heals the body by shedding."); +static const u8 sGutsDescription[] = _("Ups ATTACK if suffering."); +static const u8 sMarvelScaleDescription[] = _("Ups DEFENSE if suffering."); +static const u8 sLiquidOozeDescription[] = _("Draining causes injury."); +static const u8 sOvergrowDescription[] = _("Ups GRASS moves in a pinch."); +static const u8 sBlazeDescription[] = _("Ups FIRE moves in a pinch."); +static const u8 sTorrentDescription[] = _("Ups WATER moves in a pinch."); +static const u8 sSwarmDescription[] = _("Ups BUG moves in a pinch."); +static const u8 sRockHeadDescription[] = _("Prevents recoil damage."); +static const u8 sDroughtDescription[] = _("Summons sunlight in battle."); +static const u8 sArenaTrapDescription[] = _("Prevents fleeing."); +static const u8 sVitalSpiritDescription[] = _("Prevents sleep."); +static const u8 sWhiteSmokeDescription[] = _("Prevents ability reduction."); +static const u8 sPurePowerDescription[] = _("Raises ATTACK."); +static const u8 sShellArmorDescription[] = _("Blocks critical hits."); +static const u8 sCacophonyDescription[] = _("Avoids sound-based moves."); +static const u8 sAirLockDescription[] = _("Negates weather effects."); + +const u8 *const gAbilityDescriptionPointers[ABILITIES_COUNT] = +{ + [ABILITY_NONE] = sNoneDescription, + [ABILITY_STENCH] = sStenchDescription, + [ABILITY_DRIZZLE] = sDrizzleDescription, + [ABILITY_SPEED_BOOST] = sSpeedBoostDescription, + [ABILITY_BATTLE_ARMOR] = sBattleArmorDescription, + [ABILITY_STURDY] = sSturdyDescription, + [ABILITY_DAMP] = sDampDescription, + [ABILITY_LIMBER] = sLimberDescription, + [ABILITY_SAND_VEIL] = sSandVeilDescription, + [ABILITY_STATIC] = sStaticDescription, + [ABILITY_VOLT_ABSORB] = sVoltAbsorbDescription, + [ABILITY_WATER_ABSORB] = sWaterAbsorbDescription, + [ABILITY_OBLIVIOUS] = sObliviousDescription, + [ABILITY_CLOUD_NINE] = sCloudNineDescription, + [ABILITY_COMPOUND_EYES] = sCompoundEyesDescription, + [ABILITY_INSOMNIA] = sInsomniaDescription, + [ABILITY_COLOR_CHANGE] = sColorChangeDescription, + [ABILITY_IMMUNITY] = sImmunityDescription, + [ABILITY_FLASH_FIRE] = sFlashFireDescription, + [ABILITY_SHIELD_DUST] = sShieldDustDescription, + [ABILITY_OWN_TEMPO] = sOwnTempoDescription, + [ABILITY_SUCTION_CUPS] = sSuctionCupsDescription, + [ABILITY_INTIMIDATE] = sIntimidateDescription, + [ABILITY_SHADOW_TAG] = sShadowTagDescription, + [ABILITY_ROUGH_SKIN] = sRoughSkinDescription, + [ABILITY_WONDER_GUARD] = sWonderGuardDescription, + [ABILITY_LEVITATE] = sLevitateDescription, + [ABILITY_EFFECT_SPORE] = sEffectSporeDescription, + [ABILITY_SYNCHRONIZE] = sSynchronizeDescription, + [ABILITY_CLEAR_BODY] = sClearBodyDescription, + [ABILITY_NATURAL_CURE] = sNaturalCureDescription, + [ABILITY_LIGHTNING_ROD] = sLightningRodDescription, + [ABILITY_SERENE_GRACE] = sSereneGraceDescription, + [ABILITY_SWIFT_SWIM] = sSwiftSwimDescription, + [ABILITY_CHLOROPHYLL] = sChlorophyllDescription, + [ABILITY_ILLUMINATE] = sIlluminateDescription, + [ABILITY_TRACE] = sTraceDescription, + [ABILITY_HUGE_POWER] = sHugePowerDescription, + [ABILITY_POISON_POINT] = sPoisonPointDescription, + [ABILITY_INNER_FOCUS] = sInnerFocusDescription, + [ABILITY_MAGMA_ARMOR] = sMagmaArmorDescription, + [ABILITY_WATER_VEIL] = sWaterVeilDescription, + [ABILITY_MAGNET_PULL] = sMagnetPullDescription, + [ABILITY_SOUNDPROOF] = sSoundproofDescription, + [ABILITY_RAIN_DISH] = sRainDishDescription, + [ABILITY_SAND_STREAM] = sSandStreamDescription, + [ABILITY_PRESSURE] = sPressureDescription, + [ABILITY_THICK_FAT] = sThickFatDescription, + [ABILITY_EARLY_BIRD] = sEarlyBirdDescription, + [ABILITY_FLAME_BODY] = sFlameBodyDescription, + [ABILITY_RUN_AWAY] = sRunAwayDescription, + [ABILITY_KEEN_EYE] = sKeenEyeDescription, + [ABILITY_HYPER_CUTTER] = sHyperCutterDescription, + [ABILITY_PICKUP] = sPickupDescription, + [ABILITY_TRUANT] = sTruantDescription, + [ABILITY_HUSTLE] = sHustleDescription, + [ABILITY_CUTE_CHARM] = sCuteCharmDescription, + [ABILITY_PLUS] = sPlusDescription, + [ABILITY_MINUS] = sMinusDescription, + [ABILITY_FORECAST] = sForecastDescription, + [ABILITY_STICKY_HOLD] = sStickyHoldDescription, + [ABILITY_SHED_SKIN] = sShedSkinDescription, + [ABILITY_GUTS] = sGutsDescription, + [ABILITY_MARVEL_SCALE] = sMarvelScaleDescription, + [ABILITY_LIQUID_OOZE] = sLiquidOozeDescription, + [ABILITY_OVERGROW] = sOvergrowDescription, + [ABILITY_BLAZE] = sBlazeDescription, + [ABILITY_TORRENT] = sTorrentDescription, + [ABILITY_SWARM] = sSwarmDescription, + [ABILITY_ROCK_HEAD] = sRockHeadDescription, + [ABILITY_DROUGHT] = sDroughtDescription, + [ABILITY_ARENA_TRAP] = sArenaTrapDescription, + [ABILITY_VITAL_SPIRIT] = sVitalSpiritDescription, + [ABILITY_WHITE_SMOKE] = sWhiteSmokeDescription, + [ABILITY_PURE_POWER] = sPurePowerDescription, + [ABILITY_SHELL_ARMOR] = sShellArmorDescription, + [ABILITY_CACOPHONY] = sCacophonyDescription, + [ABILITY_AIR_LOCK] = sAirLockDescription, +}; + +const u8 gAbilityNames[ABILITIES_COUNT][ABILITY_NAME_LENGTH + 1] = +{ + [ABILITY_NONE] = _("-------"), + [ABILITY_STENCH] = _("STENCH"), + [ABILITY_DRIZZLE] = _("DRIZZLE"), + [ABILITY_SPEED_BOOST] = _("SPEED BOOST"), + [ABILITY_BATTLE_ARMOR] = _("BATTLE ARMOR"), + [ABILITY_STURDY] = _("STURDY"), + [ABILITY_DAMP] = _("DAMP"), + [ABILITY_LIMBER] = _("LIMBER"), + [ABILITY_SAND_VEIL] = _("SAND VEIL"), + [ABILITY_STATIC] = _("STATIC"), + [ABILITY_VOLT_ABSORB] = _("VOLT ABSORB"), + [ABILITY_WATER_ABSORB] = _("WATER ABSORB"), + [ABILITY_OBLIVIOUS] = _("OBLIVIOUS"), + [ABILITY_CLOUD_NINE] = _("CLOUD NINE"), + [ABILITY_COMPOUND_EYES] = _("COMPOUNDEYES"), + [ABILITY_INSOMNIA] = _("INSOMNIA"), + [ABILITY_COLOR_CHANGE] = _("COLOR CHANGE"), + [ABILITY_IMMUNITY] = _("IMMUNITY"), + [ABILITY_FLASH_FIRE] = _("FLASH FIRE"), + [ABILITY_SHIELD_DUST] = _("SHIELD DUST"), + [ABILITY_OWN_TEMPO] = _("OWN TEMPO"), + [ABILITY_SUCTION_CUPS] = _("SUCTION CUPS"), + [ABILITY_INTIMIDATE] = _("INTIMIDATE"), + [ABILITY_SHADOW_TAG] = _("SHADOW TAG"), + [ABILITY_ROUGH_SKIN] = _("ROUGH SKIN"), + [ABILITY_WONDER_GUARD] = _("WONDER GUARD"), + [ABILITY_LEVITATE] = _("LEVITATE"), + [ABILITY_EFFECT_SPORE] = _("EFFECT SPORE"), + [ABILITY_SYNCHRONIZE] = _("SYNCHRONIZE"), + [ABILITY_CLEAR_BODY] = _("CLEAR BODY"), + [ABILITY_NATURAL_CURE] = _("NATURAL CURE"), + [ABILITY_LIGHTNING_ROD] = _("LIGHTNINGROD"), + [ABILITY_SERENE_GRACE] = _("SERENE GRACE"), + [ABILITY_SWIFT_SWIM] = _("SWIFT SWIM"), + [ABILITY_CHLOROPHYLL] = _("CHLOROPHYLL"), + [ABILITY_ILLUMINATE] = _("ILLUMINATE"), + [ABILITY_TRACE] = _("TRACE"), + [ABILITY_HUGE_POWER] = _("HUGE POWER"), + [ABILITY_POISON_POINT] = _("POISON POINT"), + [ABILITY_INNER_FOCUS] = _("INNER FOCUS"), + [ABILITY_MAGMA_ARMOR] = _("MAGMA ARMOR"), + [ABILITY_WATER_VEIL] = _("WATER VEIL"), + [ABILITY_MAGNET_PULL] = _("MAGNET PULL"), + [ABILITY_SOUNDPROOF] = _("SOUNDPROOF"), + [ABILITY_RAIN_DISH] = _("RAIN DISH"), + [ABILITY_SAND_STREAM] = _("SAND STREAM"), + [ABILITY_PRESSURE] = _("PRESSURE"), + [ABILITY_THICK_FAT] = _("THICK FAT"), + [ABILITY_EARLY_BIRD] = _("EARLY BIRD"), + [ABILITY_FLAME_BODY] = _("FLAME BODY"), + [ABILITY_RUN_AWAY] = _("RUN AWAY"), + [ABILITY_KEEN_EYE] = _("KEEN EYE"), + [ABILITY_HYPER_CUTTER] = _("HYPER CUTTER"), + [ABILITY_PICKUP] = _("PICKUP"), + [ABILITY_TRUANT] = _("TRUANT"), + [ABILITY_HUSTLE] = _("HUSTLE"), + [ABILITY_CUTE_CHARM] = _("CUTE CHARM"), + [ABILITY_PLUS] = _("PLUS"), + [ABILITY_MINUS] = _("MINUS"), + [ABILITY_FORECAST] = _("FORECAST"), + [ABILITY_STICKY_HOLD] = _("STICKY HOLD"), + [ABILITY_SHED_SKIN] = _("SHED SKIN"), + [ABILITY_GUTS] = _("GUTS"), + [ABILITY_MARVEL_SCALE] = _("MARVEL SCALE"), + [ABILITY_LIQUID_OOZE] = _("LIQUID OOZE"), + [ABILITY_OVERGROW] = _("OVERGROW"), + [ABILITY_BLAZE] = _("BLAZE"), + [ABILITY_TORRENT] = _("TORRENT"), + [ABILITY_SWARM] = _("SWARM"), + [ABILITY_ROCK_HEAD] = _("ROCK HEAD"), + [ABILITY_DROUGHT] = _("DROUGHT"), + [ABILITY_ARENA_TRAP] = _("ARENA TRAP"), + [ABILITY_VITAL_SPIRIT] = _("VITAL SPIRIT"), + [ABILITY_WHITE_SMOKE] = _("WHITE SMOKE"), + [ABILITY_PURE_POWER] = _("PURE POWER"), + [ABILITY_SHELL_ARMOR] = _("SHELL ARMOR"), + [ABILITY_CACOPHONY] = _("CACOPHONY"), + [ABILITY_AIR_LOCK] = _("AIR LOCK"), +}; diff --git a/src/fame_checker.c b/src/fame_checker.c index e803a9700..50a8aa0bc 100644 --- a/src/fame_checker.c +++ b/src/fame_checker.c @@ -26,6 +26,7 @@ #include "menu_indicators.h" #include "text_window.h" #include "fame_checker.h" +#include "constants/trainers.h" #define SPRITETAG_SELECTOR_CURSOR 1000 #define SPRITETAG_QUESTION_MARK 1001 @@ -878,7 +879,7 @@ static void FC_DestroyWindow(u8 windowId) static u8 AdjustGiovanniIndexIfBeatenInGym(u8 a0) { - if (HasTrainerAlreadyBeenFought(0x15e) == TRUE) + if (HasTrainerBeenFought(TRAINER_LEADER_GIOVANNI) == TRUE) { if (a0 == 9) return FAMECHECKER_GIOVANNI; diff --git a/src/field_fadetransition.c b/src/field_fadetransition.c index de9f09ff0..58caad509 100644 --- a/src/field_fadetransition.c +++ b/src/field_fadetransition.c @@ -323,14 +323,14 @@ static void sub_807DFBC(u8 taskId) { case 0: // Never reached sub_807DCB0(0); - player_bitmagic(); + FreezeEventObjects(); PlayerGetDestCoords(x, y); FieldSetDoorOpened(*x, *y); task->data[0] = 1; break; case 5: sub_807DCB0(0); - player_bitmagic(); + FreezeEventObjects(); sub_807F114(); sub_807DBAC(); task->data[0] = 6; @@ -408,7 +408,7 @@ static void task_map_chg_seq_0807E20C(u8 taskId) { case 0: sub_807DCB0(0); - player_bitmagic(); + FreezeEventObjects(); PlayerGetDestCoords(x, y); task->data[0] = 1; break; @@ -439,7 +439,7 @@ static void task_map_chg_seq_0807E2CC(u8 taskId) switch (gTasks[taskId].data[0]) { case 0: - player_bitmagic(); + FreezeEventObjects(); ScriptContext2_Enable(); gTasks[taskId].data[0]++; break; @@ -459,7 +459,7 @@ static void sub_807E31C(u8 taskId) switch (gTasks[taskId].data[0]) { case 0: - player_bitmagic(); + FreezeEventObjects(); ScriptContext2_Enable(); sub_805DC04(); gTasks[taskId].data[0]++; @@ -689,7 +689,7 @@ static void sub_807E718(u8 taskId) switch (task->data[0]) { case 0: - player_bitmagic(); + FreezeEventObjects(); ScriptContext2_Enable(); task->data[0]++; break; @@ -711,7 +711,7 @@ static void sub_807E784(u8 taskId) switch (task->data[0]) { case 0: - player_bitmagic(); + FreezeEventObjects(); ScriptContext2_Enable(); PlaySE(SE_TK_WARPIN); sub_805DAB0(); @@ -744,7 +744,7 @@ static void sub_807E80C(u8 taskId) switch (task->data[0]) { case 0: - player_bitmagic(); + FreezeEventObjects(); PlayerGetDestCoords(xp, yp); PlaySE(GetDoorSoundEffect(*xp, *yp - 1)); task->data[1] = FieldAnimateDoorOpen(*xp, *yp - 1); @@ -798,7 +798,7 @@ static void sub_807E980(u8 taskId) { case 0: ScriptContext2_Enable(); - player_bitmagic(); + FreezeEventObjects(); CameraObjectReset2(); data[0]++; break; diff --git a/src/fldeff_rocksmash.c b/src/fldeff_rocksmash.c index 56a607fff..90abda81f 100644 --- a/src/fldeff_rocksmash.c +++ b/src/fldeff_rocksmash.c @@ -16,6 +16,7 @@ #include "field_map_obj.h" #include "constants/songs.h" #include "constants/map_objects.h" +#include "constants/map_types.h" static void task08_080C9820(u8 taskId); static void sub_80C98FC(u8 taskId); diff --git a/src/ground.c b/src/ground.c index 4ae4d8370..97f42e5c5 100644 --- a/src/ground.c +++ b/src/ground.c @@ -416,8 +416,7 @@ static void sub_80B91B0(u8 taskId) task->data[12] = gBattle_BG1_X; else task->data[12] = gBattle_BG2_X; - - var0 = GetBattlerYCoordWithElevation(gBattleAnimAttacker); + var0 = GetBattlerYCoordWithElevation(gBattleAnimAttacker); task->data[14] = var0 - 32; task->data[15] = var0 + 32; ++task->data[0]; diff --git a/src/item.c b/src/item.c index e76cb10d3..677c13ad7 100644 --- a/src/item.c +++ b/src/item.c @@ -73,7 +73,7 @@ void CopyItemName(u16 itemId, u8 * dest) { if (itemId == ITEM_ENIGMA_BERRY) { - StringCopy(dest, sub_809C8A0(43)->name); + StringCopy(dest, GetBerryInfo(ITEM_TO_BERRY(ITEM_ENIGMA_BERRY))->name); StringAppend(dest, gUnknown_84162BD); } else diff --git a/src/item_use.c b/src/item_use.c index 679a3b8cc..873ce4ab4 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -42,6 +42,7 @@ #include "constants/maps.h" #include "constants/moves.h" #include "constants/songs.h" +#include "constants/map_types.h" EWRAM_DATA void (*sItemUseOnFieldCB)(u8 taskId) = NULL; @@ -162,7 +163,7 @@ void sub_80A1184(void) bool8 sub_80A1194(void) { - player_bitmagic(); + FreezeEventObjects(); ScriptContext2_Enable(); sub_807DC00(); CreateTask(sub_80A11C0, 10); @@ -259,7 +260,7 @@ bool8 ItemUseCheckFunc_Rod(void) { if (MetatileBehavior_IsSurfable(behavior) && !MapGridIsImpassableAt(x, y)) return TRUE; - if (MetatileBehavior_ReturnFalse_6(behavior) == TRUE) + if (MetatileBehavior_IsBridge(behavior) == TRUE) return TRUE; } return FALSE; diff --git a/src/link.c b/src/link.c index c8c7932df..ac9cf9cfe 100644 --- a/src/link.c +++ b/src/link.c @@ -1025,7 +1025,7 @@ bool8 IsLinkTaskFinished(void) { if (gWirelessCommType == 1) { - return IsRfuTaskFinished(); + return IsLinkRfuTaskFinished(); } return gLinkCallback == NULL; } diff --git a/src/map_obj_lock.c b/src/map_obj_lock.c index f89819647..e28872fd4 100644 --- a/src/map_obj_lock.c +++ b/src/map_obj_lock.c @@ -38,7 +38,7 @@ bool8 sub_8069590(void) void ScriptFreezeMapObjects(void) { - player_bitmagic(); + FreezeEventObjects(); CreateTask(sub_8069570, 80); } diff --git a/src/metatile_behavior.c b/src/metatile_behavior.c index 62a102a09..bca99d38f 100644 --- a/src/metatile_behavior.c +++ b/src/metatile_behavior.c @@ -69,7 +69,7 @@ bool8 MetatileBehavior_IsMB21OrSand(u8 metatileBehavior) return FALSE; } -bool8 MetatileBehavior_IsMB21OrWaterfallBottom(u8 metatileBehavior) +bool8 MetatileBehavior_IsSandOrDeepSand(u8 metatileBehavior) { if(metatileBehavior == MB_21 || metatileBehavior == MB_WATERFALL_BOTTOM) return TRUE; @@ -428,11 +428,11 @@ bool8 MetatileBehavior_IsTallGrass_2(u8 metatileBehavior) return FALSE; } -bool8 MetatileBehavior_ReturnFalse_3(u8 metatileBehavior) { return FALSE; } +bool8 MetatileBehavior_IsLongGrass(u8 metatileBehavior) { return FALSE; } bool8 MetatileBehavior_ReturnFalse_4(u8 metatileBehavior) { return FALSE; } bool8 MetatileBehavior_ReturnFalse_5(u8 metatileBehavior) { return FALSE; } -bool8 MetatileBehavior_ReturnFalse_6(u8 metatileBehavior) { return FALSE; } -bool8 MetatileBehavior_ReturnFalse_7(u8 metatileBehavior) { return FALSE; } +bool8 MetatileBehavior_IsBridge(u8 metatileBehavior) { return FALSE; } +bool8 MetatileBehavior_GetBridgeType(u8 metatileBehavior) { return FALSE; } bool8 MetatileBehavior_UnusedIsMB_01(u8 metatileBehavior) { @@ -450,7 +450,7 @@ bool8 MetatileBehavior_UnusedIsTallGrass(u8 metatileBehavior) return FALSE; } -bool8 MetatileBehavior_IsMB0B(u8 metatileBehavior) +bool8 MetatileBehavior_IsIndoorEncounter(u8 metatileBehavior) { if(metatileBehavior == MB_0B) return TRUE; @@ -458,7 +458,7 @@ bool8 MetatileBehavior_IsMB0B(u8 metatileBehavior) return FALSE; } -bool8 MetatileBehavior_IsMB0C(u8 metatileBehavior) +bool8 MetatileBehavior_IsMountain(u8 metatileBehavior) { if(metatileBehavior == MB_0C) return TRUE; diff --git a/src/mystery_gift_menu.c b/src/mystery_gift_menu.c index f76d70c04..13a6d37e2 100644 --- a/src/mystery_gift_menu.c +++ b/src/mystery_gift_menu.c @@ -1374,7 +1374,7 @@ void task00_mystery_gift(u8 taskId) } break; case 13: - if (IsRfuTaskFinished()) + if (IsLinkRfuTaskFinished()) { DestroyWirelessStatusIndicatorSprite(); data->state = 14; @@ -1650,7 +1650,7 @@ void task00_mystery_gift(u8 taskId) data->state = 34; break; case 34: - if (IsRfuTaskFinished()) + if (IsLinkRfuTaskFinished()) { DestroyWirelessStatusIndicatorSprite(); data->state = 35; diff --git a/src/pokemon.c b/src/pokemon.c index f9fe72007..17f28c7a6 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -8,7 +8,7 @@ #include "data.h" #include "string_util.h" #include "battle.h" -#include "battle_main.h" +#include "battle_anim.h" #include "item.h" #include "event_data.h" #include "util.h" @@ -1467,7 +1467,7 @@ const struct SpriteTemplate gUnknown_825DEF0[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gUnknown_8234698, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1476,16 +1476,16 @@ const struct SpriteTemplate gUnknown_825DEF0[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F010, + .oam = &gOamData_824F010, .anims = NULL, .images = gUnknown_82346B8, .affineAnims = gSpriteAffineAnimTable_8234944, - .callback = oac_poke_opponent, + .callback = SpriteCB_WildMon, }, { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gUnknown_82346D8, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1494,11 +1494,11 @@ const struct SpriteTemplate gUnknown_825DEF0[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F010, + .oam = &gOamData_824F010, .anims = NULL, .images = gUnknown_82346F8, .affineAnims = gSpriteAffineAnimTable_8234944, - .callback = oac_poke_opponent, + .callback = SpriteCB_WildMon, }, }; @@ -1507,7 +1507,7 @@ const struct SpriteTemplate gUnknown_825DF50[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gTrainerBackPicTable_Red, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1516,7 +1516,7 @@ const struct SpriteTemplate gUnknown_825DF50[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gTrainerBackPicTable_Leaf, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1525,7 +1525,7 @@ const struct SpriteTemplate gUnknown_825DF50[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gTrainerBackPicTable_RSBrendan, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1534,7 +1534,7 @@ const struct SpriteTemplate gUnknown_825DF50[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gTrainerBackPicTable_RSMay, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1543,7 +1543,7 @@ const struct SpriteTemplate gUnknown_825DF50[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gTrainerBackPicTable_PokeDude, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -1552,7 +1552,7 @@ const struct SpriteTemplate gUnknown_825DF50[] = { .tileTag = SPRITE_INVALID_TAG, .paletteTag = 0, - .oam = &gUnknown_824F018, + .oam = &gOamData_824F018, .anims = NULL, .images = gTrainerBackPicTable_OldMan, .affineAnims = gSpriteAffineAnimTable_82348C8, @@ -4652,8 +4652,7 @@ bool8 PokemonUseItemEffects2(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mo sp18 = itemEffect[r10]; r10++; break; - case 7:\ - + case 7: if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 200 && retVal == FALSE && sp18 == 0) @@ -5406,7 +5405,7 @@ u16 GetMonEVCount(struct Pokemon *mon) return count; } -void sub_8043A68(void) +void RandomlyGivePartyPokerus(struct Pokemon *party) { u8 foo[4]; // huh? } @@ -5472,7 +5471,7 @@ static void sub_8043B38(void) u8 foo[4]; // huh? } -void sub_8043B40(void) +void PartySpreadPokerus(struct Pokemon *party) { u8 foo[4]; // huh? } diff --git a/src/psychic.c b/src/psychic.c index 662320a2b..a8108c55a 100644 --- a/src/psychic.c +++ b/src/psychic.c @@ -47,7 +47,7 @@ const struct SpriteTemplate gUnknown_83E6DF8 = .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gUnknown_83E6DF4, - .callback = sub_8075D9C, + .callback = AnimSpriteOnMonPos, }; const struct SpriteTemplate gUnknown_83E6E10 = @@ -376,7 +376,7 @@ const struct SpriteTemplate gUnknown_83E7148 = .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gUnknown_83E7144, - .callback = sub_8075D9C, + .callback = AnimSpriteOnMonPos, }; static const union AffineAnimCmd gUnknown_83E7160[] = diff --git a/src/quest_log.c b/src/quest_log.c index ffced87ee..e3ff53417 100644 --- a/src/quest_log.c +++ b/src/quest_log.c @@ -1513,7 +1513,7 @@ static void sub_8111F8C(u8 taskId) if (ScriptContext2_IsEnabled() != TRUE) { - player_bitmagic(); + FreezeEventObjects(); sub_805C270(); sub_805C780(); ScriptContext2_Enable(); @@ -1536,7 +1536,7 @@ static void sub_8111FCC(u8 taskId) task->data[0] = 0; task->data[1] = 0; task->func = sub_8112044; - player_bitmagic(); + FreezeEventObjects(); ScriptContext2_Enable(); } } diff --git a/src/quest_log_8150454.c b/src/quest_log_8150454.c index 3d61dee72..fbd3b4487 100644 --- a/src/quest_log_8150454.c +++ b/src/quest_log_8150454.c @@ -88,7 +88,7 @@ void sub_8150530(void) else { sub_81507BC(mapObject, sub_805C808(4)); - StartSpriteAnim(sprite, sub_80634F0(mapObject->mapobj_unk_18)); + StartSpriteAnim(sprite, sub_80634F0(mapObject->facingDirection)); } } @@ -103,7 +103,7 @@ void sub_81505C4(u8 taskId) FieldObjectClearAnimIfSpecialAnimActive(mapObject); mapObject->mapobj_bit_11 = TRUE; sub_81507BC(mapObject, sub_805C808(4)); - StartSpriteAnim(sprite, sub_80634F0(mapObject->mapobj_unk_18)); + StartSpriteAnim(sprite, sub_80634F0(mapObject->facingDirection)); gTasks[taskId].data[0]++; gTasks[taskId].data[1] = 0; break; diff --git a/src/quest_log_battle.c b/src/quest_log_battle.c index 2687e4ea5..efe866dea 100644 --- a/src/quest_log_battle.c +++ b/src/quest_log_battle.c @@ -2,6 +2,7 @@ #include "constants/species.h" #include "malloc.h" #include "battle.h" +#include "battle_anim.h" #include "link.h" #include "overworld.h" #include "quest_log.h" @@ -22,11 +23,11 @@ struct QuestLogStruct_WildBattleRecord u8 v4; }; -void sub_812C334(s32 *, s32 *); +static void sub_812C334(s32 *, s32 *); void sub_812BFDC(void) { - if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_OLDMAN_TUTORIAL | BATTLE_TYPE_POKEDUDE)) && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_POKEDUDE)) && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { struct QuestLogStruct_TrainerBattleRecord * questLogTrainerBattleRecord = Alloc(sizeof(struct QuestLogStruct_TrainerBattleRecord)); struct QuestLogStruct_WildBattleRecord * questLogWildBattleRecord = Alloc(sizeof(struct QuestLogStruct_WildBattleRecord)); @@ -38,18 +39,18 @@ void sub_812BFDC(void) { switch (gTrainers[gTrainerBattleOpponent_A].trainerClass) { - case 0x54: - questLogMessageType = 30; - break; - case 0x5a: - questLogMessageType = 33; - break; - case 0x57: - questLogMessageType = 32; - break; - default: - questLogMessageType = 34; - break; + case 0x54: + questLogMessageType = 30; + break; + case 0x5a: + questLogMessageType = 33; + break; + case 0x57: + questLogMessageType = 32; + break; + default: + questLogMessageType = 34; + break; } questLogTrainerBattleRecord->v0 = gTrainerBattleOpponent_A; if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) @@ -141,7 +142,7 @@ void sub_812C224(void) } for (r3 = 0; r3 < 7; r3++) { - r5->v1[0][r3] = gLinkPlayers[gBattleStruct->field_B5 ^ 1].name[r3]; + r5->v1[0][r3] = gLinkPlayers[gBattleStruct->multiplayerId ^ 1].name[r3]; } } sub_8113550(r8, (const u16 *)r5); @@ -149,16 +150,16 @@ void sub_812C224(void) } } -void sub_812C334(s32 * a0, s32 * a1) +static void sub_812C334(s32 * a0, s32 * a1) { s32 r5; s32 _optimized_out = 0; - u8 r2 = gLinkPlayers[gBattleStruct->field_B5].id ^ 2; + u8 r2 = gLinkPlayers[gBattleStruct->multiplayerId].id ^ 2; for (r5 = 0; r5 < 4; r5++) { if (r2 == gLinkPlayers[r5].id) a0[0] = r5; - else if (r5 != gBattleStruct->field_B5) + else if (r5 != gBattleStruct->multiplayerId) a1[_optimized_out++] = r5; } } diff --git a/src/reshow_battle_screen.c b/src/reshow_battle_screen.c index 6dd743176..5ab38e461 100644 --- a/src/reshow_battle_screen.c +++ b/src/reshow_battle_screen.c @@ -211,7 +211,7 @@ static bool8 LoadBattlerSpriteGfx(u8 battler) } else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && battler == B_POSITION_PLAYER_LEFT) // Should be checking position, not battler. DecompressTrainerBackPalette(gSaveBlock2Ptr->playerGender, battler); - else if (gBattleTypeFlags & BATTLE_TYPE_OLDMAN_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) // Should be checking position, not battler. + else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) // Should be checking position, not battler. DecompressTrainerBackPalette(5, battler); else if (!gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battler]], battler); @@ -256,7 +256,7 @@ static void CreateBattlerSprite(u8 battler) gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy; gSprites[gBattlerSpriteIds[battler]].data[0] = battler; } - else if (gBattleTypeFlags & BATTLE_TYPE_OLDMAN_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) + else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) { SetMultiuseSpriteTemplateToTrainerBack(5, GetBattlerPosition(0)); gBattlerSpriteIds[battler] = CreateSprite(&gMultiuseSpriteTemplate, 0x50, @@ -292,7 +292,7 @@ static void CreateHealthboxSprite(u8 battler) if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && battler == B_POSITION_PLAYER_LEFT) healthboxSpriteId = CreateSafariPlayerHealthboxSprites(); - else if (gBattleTypeFlags & BATTLE_TYPE_OLDMAN_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) + else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) return; else healthboxSpriteId = CreateBattlerHealthboxSprites(battler); diff --git a/src/scrcmd.c b/src/scrcmd.c index 7a70d09c7..b59f97420 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -1916,7 +1916,7 @@ bool8 ScrCmd_checktrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - ctx->comparisonResult = HasTrainerAlreadyBeenFought(index); + ctx->comparisonResult = HasTrainerBeenFought(index); return FALSE; } diff --git a/src/start_menu.c b/src/start_menu.c index 221ae1f1f..dddb5f44e 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -392,7 +392,7 @@ void ShowStartMenu(void) { if (!IsUpdateLinkStateCBActive()) { - player_bitmagic(); + FreezeEventObjects(); sub_805C270(); sub_805C780(); } diff --git a/src/teachy_tv.c b/src/teachy_tv.c index c1d6dc6c8..e33cb9d2e 100644 --- a/src/teachy_tv.c +++ b/src/teachy_tv.c @@ -1214,7 +1214,7 @@ static void TeachyTvPreBattleAnimAndSetBattleCallback(u8 taskId) case 1: if (BT_IsDone()) { - SetMainCallback2(sub_800FD9C); + SetMainCallback2(CB2_InitBattle); DestroyTask(taskId); } break; diff --git a/src/trainer_tower.c b/src/trainer_tower.c index 5acac299f..cd796bf3a 100644 --- a/src/trainer_tower.c +++ b/src/trainer_tower.c @@ -940,7 +940,7 @@ static void sub_815E124(u8 taskId) { gMain.savedCallback = sub_815E114; CleanupOverworldWindowsAndTilemaps(); - SetMainCallback2(sub_800FD9C); + SetMainCallback2(CB2_InitBattle); DestroyTask(taskId); } } diff --git a/src/unk_8159F40.c b/src/unk_8159F40.c index f2cb1764f..ef21d19d0 100644 --- a/src/unk_8159F40.c +++ b/src/unk_8159F40.c @@ -177,7 +177,7 @@ void sub_815A008(struct QuestLog * questLog) questLog->unk_008[i].mapobj_bit_24 = gMapObjects[i].mapobj_bit_24; questLog->unk_008[i].mapobj_bit_25 = gMapObjects[i].mapobj_bit_25; questLog->unk_008[i].mapobj_bit_26 = gMapObjects[i].mapobj_bit_26; - questLog->unk_008[i].mapobj_unk_18 = gMapObjects[i].mapobj_unk_18; + questLog->unk_008[i].mapobj_unk_18 = gMapObjects[i].facingDirection; questLog->unk_008[i].mapobj_unk_0B_0 = gMapObjects[i].mapobj_unk_0B_0; questLog->unk_008[i].elevation = gMapObjects[i].elevation; questLog->unk_008[i].graphicsId = gMapObjects[i].graphicsId; @@ -222,7 +222,7 @@ void sub_815A1F8(const struct QuestLog * questLog, const struct MapObjectTemplat gMapObjects[i].mapobj_bit_24 = questLogMapObjects[i].mapobj_bit_24; gMapObjects[i].mapobj_bit_25 = questLogMapObjects[i].mapobj_bit_25; gMapObjects[i].mapobj_bit_26 = questLogMapObjects[i].mapobj_bit_26; - gMapObjects[i].mapobj_unk_18 = questLogMapObjects[i].mapobj_unk_18; + gMapObjects[i].facingDirection = questLogMapObjects[i].mapobj_unk_18; gMapObjects[i].mapobj_unk_0B_0 = questLogMapObjects[i].mapobj_unk_0B_0; gMapObjects[i].elevation = questLogMapObjects[i].elevation; gMapObjects[i].graphicsId = questLogMapObjects[i].graphicsId; diff --git a/src/vs_seeker.c b/src/vs_seeker.c index 6ae92236f..9a8ff5dd6 100644 --- a/src/vs_seeker.c +++ b/src/vs_seeker.c @@ -628,7 +628,7 @@ void sub_810C444(void) mapObject = &gMapObjects[sp0]; if (sub_810CF04(sp0) == TRUE) { - npc_set_running_behaviour_etc(mapObject, r6); + SetTrainerMovementType(mapObject, r6); } templates[i].movementType = r6; } @@ -766,7 +766,7 @@ static void sub_810C594(void) { gSprites[mapObject->spriteId].pos2.x = 0; gSprites[mapObject->spriteId].pos2.y = 0; - npc_set_running_behaviour_etc(mapObject, r3); + SetTrainerMovementType(mapObject, r3); } } } @@ -931,7 +931,7 @@ static u8 GetVsSeekerResponseInArea(const VsSeekerData * a0) if (IsTrainerVisibleOnScreen(&sVsSeeker->trainerInfo[vsSeekerIdx]) == 1) { r8 = sVsSeeker->trainerInfo[vsSeekerIdx].trainerIdx; - if (!HasTrainerAlreadyBeenFought(r8)) + if (!HasTrainerBeenFought(r8)) { StartTrainerObjectMovementScript(&sVsSeeker->trainerInfo[vsSeekerIdx], gUnknown_8453F60); sVsSeeker->trainerHasNotYetBeenFought = 1; @@ -1027,7 +1027,7 @@ static u8 GetVsSeekerResponseInArea(const VsSeekerData * a0) "\tadds r0, r5\n" "\tldrh r0, [r0, 0x4]\n" "\tmov r8, r0\n" - "\tbl HasTrainerAlreadyBeenFought\n" + "\tbl HasTrainerBeenFought\n" "\tlsls r0, 24\n" "\tcmp r0, 0\n" "\tbne _0810CA20\n" @@ -1239,10 +1239,10 @@ void sub_810CB90(void) TryGetFieldObjectIdByLocalIdAndMap(r4[r8].localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &sp0); r4_2 = &gMapObjects[sp0]; sub_810CF54(&r4[r8]); // You are using this function incorrectly. Please consult the manual. - sub_805FE7C(r4_2, gUnknown_8453F67[r4_2->mapobj_unk_18]); + sub_805FE7C(r4_2, gUnknown_8453F67[r4_2->facingDirection]); gSaveBlock1Ptr->trainerRematches[r4[r8].localId] = 0; if (gSelectedEventObject == sp0) - r4_2->animPattern = gUnknown_8453F67[r4_2->mapobj_unk_18]; + r4_2->animPattern = gUnknown_8453F67[r4_2->facingDirection]; else r4_2->animPattern = 0x08; } @@ -1319,7 +1319,7 @@ static bool8 HasRematchTrainerAlreadyBeenFought(const VsSeekerData *vsSeekerData if (rematchIdx == -1) return FALSE; - if (!HasTrainerAlreadyBeenFought(vsSeekerData[rematchIdx].trainerIdxs[0])) + if (!HasTrainerBeenFought(vsSeekerData[rematchIdx].trainerIdxs[0])) return FALSE; return TRUE; } @@ -1327,7 +1327,7 @@ static bool8 HasRematchTrainerAlreadyBeenFought(const VsSeekerData *vsSeekerData void sub_810CDE8(void) { gSaveBlock1Ptr->trainerRematches[gSpecialVar_LastTalked] = 0; - sub_80803FC(); + SetBattledTrainerFlag(); } static s32 sub_810CE10(const VsSeekerData * a0, u16 a1) @@ -1353,7 +1353,7 @@ static s32 sub_810CE10(const VsSeekerData * a0, u16 a1) return -1; } -s32 sub_810CE64(u16 a0) +s32 GetRematchTrainerId(u16 a0) { u8 i; u8 j; @@ -1529,7 +1529,7 @@ static u8 GetNextAvailableRematchTrainer(const VsSeekerData * vsSeekerData, u16 return j - 1; if (vsSeekerData[i].trainerIdxs[j] == 0xffff) continue; - if (HasTrainerAlreadyBeenFought(vsSeekerData[i].trainerIdxs[j])) + if (HasTrainerBeenFought(vsSeekerData[i].trainerIdxs[j])) continue; return j; } @@ -1550,7 +1550,7 @@ static u8 GetRematchableTrainerLocalId(void) { if (IsTrainerVisibleOnScreen(&sVsSeeker->trainerInfo[i]) == 1) { - if (HasTrainerAlreadyBeenFought(sVsSeeker->trainerInfo[i].trainerIdx) != 1 || GetNextAvailableRematchTrainer(sVsSeekerData, sVsSeeker->trainerInfo[i].trainerIdx, &idx)) + if (HasTrainerBeenFought(sVsSeeker->trainerInfo[i].trainerIdx) != 1 || GetNextAvailableRematchTrainer(sVsSeekerData, sVsSeeker->trainerInfo[i].trainerIdx, &idx)) return sVsSeeker->trainerInfo[i].localId; } } @@ -1599,7 +1599,7 @@ static void StartAllRespondantIdleMovements(void) struct MapObject *r4 = &gMapObjects[sVsSeeker->trainerInfo[j].fieldObjectId]; if (sub_810CF04(sVsSeeker->trainerInfo[j].fieldObjectId) == 1) - npc_set_running_behaviour_etc(r4, sVsSeeker->runningBehaviourEtcArray[i]); + SetTrainerMovementType(r4, sVsSeeker->runningBehaviourEtcArray[i]); sub_805FE7C(r4, sVsSeeker->runningBehaviourEtcArray[i]); gSaveBlock1Ptr->trainerRematches[sVsSeeker->trainerInfo[j].localId] = GetNextAvailableRematchTrainer(sVsSeekerData, sVsSeeker->trainerInfo[j].trainerIdx, &dummy); } |