summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle_2.c39
-rw-r--r--src/battle_ai_switch_items.c18
-rw-r--r--src/battle_anim.c20
-rw-r--r--src/battle_controller_linkopponent.c143
-rw-r--r--src/battle_controller_opponent.c146
-rw-r--r--src/battle_controller_player.c3160
-rw-r--r--src/battle_controller_player_partner.c1970
-rw-r--r--src/battle_controller_recorded_player.c1854
-rw-r--r--src/battle_controller_safari.c723
-rw-r--r--src/battle_controller_wally.c147
-rw-r--r--src/battle_controllers.c116
-rw-r--r--src/battle_interface.c59
-rw-r--r--src/battle_message.c2
-rw-r--r--src/battle_script_commands.c106
-rw-r--r--src/pokemon_2.c7
-rw-r--r--src/pokemon_3.c2
-rw-r--r--src/reshow_battle_screen.c4
17 files changed, 8317 insertions, 199 deletions
diff --git a/src/battle_2.c b/src/battle_2.c
index 16c07114a..fd1b88b48 100644
--- a/src/battle_2.c
+++ b/src/battle_2.c
@@ -238,7 +238,6 @@ static void sub_8038F34(void);
static void sub_80392A8(void);
static void sub_803937C(void);
static void sub_803939C(void);
-void oac_poke_opponent(struct Sprite *sprite);
static void sub_803980C(struct Sprite *sprite);
static void sub_8039838(struct Sprite *sprite);
static void sub_8039894(struct Sprite *sprite);
@@ -2121,7 +2120,7 @@ static void sub_8038F34(void)
if (sub_800A520() == TRUE)
{
sub_800ADF8();
- sub_814F9EC(gText_LinkStandby3, 0);
+ BattleHandleAddTextPrinter(gText_LinkStandby3, 0);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@@ -2247,17 +2246,17 @@ static void sub_803939C(void)
case 3:
if (!gPaletteFade.active)
{
- sub_814F9EC(gText_RecordBattleToPass, 0);
+ BattleHandleAddTextPrinter(gText_RecordBattleToPass, 0);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if (!IsTextPrinterActive(0))
{
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 0);
- sub_814F9EC(gText_BattleYesNoChoice, 0xC);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
gBattleCommunication[CURSOR_POSITION] = 1;
- BattleCreateCursorAt(1);
+ BattleCreateYesNoCursorAt(1);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@@ -2267,9 +2266,9 @@ static void sub_803939C(void)
if (gBattleCommunication[CURSOR_POSITION] != 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
}
}
else if (gMain.newKeys & DPAD_DOWN)
@@ -2277,9 +2276,9 @@ static void sub_803939C(void)
if (gBattleCommunication[CURSOR_POSITION] == 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 1;
- BattleCreateCursorAt(1);
+ BattleCreateYesNoCursorAt(1);
}
}
else if (gMain.newKeys & A_BUTTON)
@@ -2287,7 +2286,7 @@ static void sub_803939C(void)
PlaySE(SE_SELECT);
if (gBattleCommunication[CURSOR_POSITION] == 0)
{
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
gBattleCommunication[1] = MoveRecordedBattleToSaveData();
gBattleCommunication[MULTIUSE_STATE] = 10;
}
@@ -2305,11 +2304,11 @@ static void sub_803939C(void)
case 6:
if (sub_800A520() == TRUE)
{
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
if (gMain.field_439_x4)
{
sub_800ADF8();
- sub_814F9EC(gText_LinkStandby3, 0);
+ BattleHandleAddTextPrinter(gText_LinkStandby3, 0);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
@@ -2340,14 +2339,14 @@ static void sub_803939C(void)
{
PlaySE(SE_SAVE);
BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordedOnPass);
- sub_814F9EC(gDisplayedStringBattle, 0);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
gBattleCommunication[1] = 0x80;
gBattleCommunication[MULTIUSE_STATE]++;
}
else
{
BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordCouldntBeSaved);
- sub_814F9EC(gDisplayedStringBattle, 0);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
gBattleCommunication[1] = 0x80;
gBattleCommunication[MULTIUSE_STATE]++;
}
@@ -2358,7 +2357,7 @@ static void sub_803939C(void)
if (gMain.field_439_x4)
{
sub_800ADF8();
- sub_814F9EC(gText_LinkStandby3, 0);
+ BattleHandleAddTextPrinter(gText_LinkStandby3, 0);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
@@ -3690,7 +3689,7 @@ static void TryDoEventsBeforeFirstTurn(void)
TurnValuesCleanUp(FALSE);
SpecialStatusesClear();
*(&gBattleStruct->field_91) = gAbsentBankFlags;
- sub_814F9EC(gText_EmptyString3, 0);
+ BattleHandleAddTextPrinter(gText_EmptyString3, 0);
gBattleMainFunc = HandleTurnActionSelectionState;
ResetSentPokesToOpponentValue();
@@ -3797,7 +3796,7 @@ void BattleTurnPassed(void)
*(gBattleStruct->field_5C + i) = 6;
*(&gBattleStruct->field_91) = gAbsentBankFlags;
- sub_814F9EC(gText_EmptyString3, 0);
+ BattleHandleAddTextPrinter(gText_EmptyString3, 0);
gBattleMainFunc = HandleTurnActionSelectionState;
gRandomTurnNumber = Random();
@@ -4025,7 +4024,7 @@ static void HandleTurnActionSelectionState(void)
}
else
{
- EmitOpenBag(0, gBattleStruct->field_60[gActiveBank]);
+ EmitChooseItem(0, gBattleStruct->field_60[gActiveBank]);
MarkBufferBankForExecution(gActiveBank);
}
break;
@@ -4070,7 +4069,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case ACTION_POKEBLOCK_CASE:
- EmitOpenBag(0, gBattleStruct->field_60[gActiveBank]);
+ EmitChooseItem(0, gBattleStruct->field_60[gActiveBank]);
MarkBufferBankForExecution(gActiveBank);
break;
case ACTION_CANCEL_PARTNER:
diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c
index d86be6fad..de440054c 100644
--- a/src/battle_ai_switch_items.c
+++ b/src/battle_ai_switch_items.c
@@ -39,7 +39,7 @@ static bool8 ShouldSwitchIfPerishSong(void)
&& gDisableStructs[gActiveBank].perishSong1 == 0)
{
*(gBattleStruct->field_294 + gActiveBank) = 6;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
@@ -121,7 +121,7 @@ static bool8 ShouldSwitchIfWonderGuard(void)
{
// we found a mon
*(gBattleStruct->field_294 + gActiveBank) = i;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
}
@@ -221,7 +221,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void)
{
// we found a mon
*(gBattleStruct->field_294 + gActiveBank) = i;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
}
@@ -241,13 +241,13 @@ static bool8 ShouldSwitchIfNaturalCure(void)
if ((gUnknown_02024250[gActiveBank] == 0 || gUnknown_02024250[gActiveBank] == 0xFFFF) && Random() & 1)
{
*(gBattleStruct->field_294 + gActiveBank) = 6;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
else if (gBattleMoves[gUnknown_02024250[gActiveBank]].power == 0 && Random() & 1)
{
*(gBattleStruct->field_294 + gActiveBank) = 6;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
@@ -258,7 +258,7 @@ static bool8 ShouldSwitchIfNaturalCure(void)
if (Random() & 1)
{
*(gBattleStruct->field_294 + gActiveBank) = 6;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
@@ -426,7 +426,7 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent)
if (moveFlags & MOVESTATUS_SUPEREFFECTIVE && Random() % moduloPercent == 0)
{
*(gBattleStruct->field_294 + gActiveBank) = i;
- EmitCmd33(1, 2, 0);
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
return TRUE;
}
}
@@ -611,7 +611,7 @@ void AI_TrySwitchOrUseItem(void)
}
}
- EmitCmd33(1, 0, (gActiveBank ^ BIT_SIDE) << 8);
+ EmitTwoReturnValues(1, ACTION_USE_MOVE, (gActiveBank ^ BIT_SIDE) << 8);
}
#define TYPE_FORESIGHT 0xFE
@@ -940,7 +940,7 @@ static bool8 ShouldUseItem(void)
if (shouldUse)
{
- EmitCmd33(1, 1, 0);
+ EmitTwoReturnValues(1, ACTION_USE_ITEM, 0);
*(gBattleStruct->field_C0 + (gActiveBank / 2) * 2) = item;
gBattleResources->battleHistory->trainerItems[i] = 0;
return shouldUse;
diff --git a/src/battle_anim.c b/src/battle_anim.c
index 023272017..d41dc77c4 100644
--- a/src/battle_anim.c
+++ b/src/battle_anim.c
@@ -47,18 +47,6 @@ extern const struct CompressedSpriteSheet gBattleAnimPicTable[];
extern const struct CompressedSpritePalette gBattleAnimPaletteTable[];
extern const struct BattleAnimBackground gBattleAnimBackgroundTable[];
-extern void sub_80A8278(void); // rom_80A5C6C.s
-extern void sub_80A6B30(struct UnknownAnimStruct2*); // rom_80A5C6C.s
-extern void sub_80A6B90(struct UnknownAnimStruct2*, u32 arg1); // rom_80A5C6C.s
-extern u8 sub_80A82E4(u8 bank); // rom_80A5C6C.s
-extern u8 sub_80A5C6C(u8 bank, u8 attributeId); // rom_80A5C6C.s
-extern bool8 AnimBankSpriteExists(u8 bank); // rom_80A5C6C.s
-extern void sub_80A6C68(u8 arg0); // rom_80A5C6C.s
-extern u8 GetAnimBankSpriteId(u8 wantedBank); // rom_80A5C6C.s
-extern u8 sub_80A6D94(void);
-extern u8 sub_80A8364(u8);
-extern bool8 IsDoubleBattle(void);
-
// this file's functions
static void ScriptCmd_loadspritegfx(void);
static void ScriptCmd_unloadspritegfx(void);
@@ -234,10 +222,10 @@ void DoMoveAnim(u16 move)
{
gAnimBankAttacker = gBankAttacker;
gAnimBankTarget = gBankTarget;
- DoBattleAnim(gBattleAnims_Moves, move, TRUE);
+ LaunchBattleAnimation(gBattleAnims_Moves, move, TRUE);
}
-void DoBattleAnim(const u8 *const animsTable[], u16 tableId, bool8 isMoveAnim)
+void LaunchBattleAnimation(const u8 *const animsTable[], u16 tableId, bool8 isMoveAnim)
{
s32 i;
@@ -1281,7 +1269,7 @@ static void ScriptCmd_changebg(void)
s8 BattleAnimAdjustPanning(s8 pan)
{
- if (!IsContest() && gBattleSpritesDataPtr->healthBoxesData[gAnimBankAttacker].flag_x10)
+ if (!IsContest() && gBattleSpritesDataPtr->healthBoxesData[gAnimBankAttacker].statusAnimActive)
{
if (GetBankSide(gAnimBankAttacker) != SIDE_PLAYER)
pan = PAN_SIDE_OPPONENT;
@@ -1323,7 +1311,7 @@ s8 BattleAnimAdjustPanning(s8 pan)
s8 BattleAnimAdjustPanning2(s8 pan)
{
- if (!IsContest() && gBattleSpritesDataPtr->healthBoxesData[gAnimBankAttacker].flag_x10)
+ if (!IsContest() && gBattleSpritesDataPtr->healthBoxesData[gAnimBankAttacker].statusAnimActive)
{
if (GetBankSide(gAnimBankAttacker) != SIDE_PLAYER)
pan = PAN_SIDE_OPPONENT;
diff --git a/src/battle_controller_linkopponent.c b/src/battle_controller_linkopponent.c
new file mode 100644
index 000000000..fb21865ca
--- /dev/null
+++ b/src/battle_controller_linkopponent.c
@@ -0,0 +1,143 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "link.h"
+
+extern u8 gActiveBank;
+extern bool8 gDoingBattleAnim;
+extern u8 gUnknown_020244CC;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+
+// this file's functions
+void LinkOpponentHandleGetMonData(void);
+void LinkOpponentHandleGetRawMonData(void);
+void LinkOpponentHandleSetMonData(void);
+void LinkOpponentHandleSetRawMonData(void);
+void LinkOpponentHandleLoadMonSprite(void);
+void LinkOpponentHandleSwitchInAnim(void);
+void LinkOpponentHandleReturnMonToBall(void);
+void LinkOpponentHandleDrawTrainerPic(void);
+void LinkOpponentHandleTrainerSlide(void);
+void LinkOpponentHandleTrainerSlideBack(void);
+void LinkOpponentHandleFaintAnimation(void);
+void LinkOpponentHandleCmd11(void);
+void LinkOpponentHandleCmd12(void);
+void LinkOpponentHandleBallThrow(void);
+void LinkOpponentHandlePause(void);
+void LinkOpponentHandleMoveAnimation(void);
+void LinkOpponentHandlePrintString(void);
+void LinkOpponentHandlePrintStringPlayerOnly(void);
+void LinkOpponentHandleChooseAction(void);
+void LinkOpponentHandleCmd19(void);
+void LinkOpponentHandleChooseMove(void);
+void LinkOpponentHandleOpenBag(void);
+void LinkOpponentHandleChoosePokemon(void);
+void LinkOpponentHandleCmd23(void);
+void LinkOpponentHandleHealthBarUpdate(void);
+void LinkOpponentHandleExpUpdate(void);
+void LinkOpponentHandleStatusIconUpdate(void);
+void LinkOpponentHandleStatusAnimation(void);
+void LinkOpponentHandleStatusXor(void);
+void LinkOpponentHandleDataTransfer(void);
+void LinkOpponentHandleDMA3Transfer(void);
+void LinkOpponentHandlePlayBGM(void);
+void LinkOpponentHandleCmd32(void);
+void LinkOpponentHandleCmd33(void);
+void LinkOpponentHandleCmd34(void);
+void LinkOpponentHandleCmd35(void);
+void LinkOpponentHandleCmd36(void);
+void LinkOpponentHandleCmd37(void);
+void LinkOpponentHandleCmd38(void);
+void LinkOpponentHandleCmd39(void);
+void LinkOpponentHandleCmd40(void);
+void LinkOpponentHandleHitAnimation(void);
+void LinkOpponentHandleCmd42(void);
+void LinkOpponentHandleEffectivenessSound(void);
+void LinkOpponentHandlePlayFanfareOrBGM(void);
+void LinkOpponentHandleFaintingCry(void);
+void LinkOpponentHandleIntroSlide(void);
+void LinkOpponentHandleIntroTrainerBallThrow(void);
+void LinkOpponentHandleDrawPartyStatusSummary(void);
+void LinkOpponentHandleCmd49(void);
+void LinkOpponentHandleCmd50(void);
+void LinkOpponentHandleSpriteInvisibility(void);
+void LinkOpponentHandleBattleAnimation(void);
+void LinkOpponentHandleLinkStandbyMsg(void);
+void LinkOpponentHandleResetActionMoveSelection(void);
+void LinkOpponentHandleCmd55(void);
+void nullsub_92(void);
+
+void LinkOpponentBufferRunCommand(void);
+
+void (*const gLinkOpponentBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ LinkOpponentHandleGetMonData,
+ LinkOpponentHandleGetRawMonData,
+ LinkOpponentHandleSetMonData,
+ LinkOpponentHandleSetRawMonData,
+ LinkOpponentHandleLoadMonSprite,
+ LinkOpponentHandleSwitchInAnim,
+ LinkOpponentHandleReturnMonToBall,
+ LinkOpponentHandleDrawTrainerPic,
+ LinkOpponentHandleTrainerSlide,
+ LinkOpponentHandleTrainerSlideBack,
+ LinkOpponentHandleFaintAnimation,
+ LinkOpponentHandleCmd11,
+ LinkOpponentHandleCmd12,
+ LinkOpponentHandleBallThrow,
+ LinkOpponentHandlePause,
+ LinkOpponentHandleMoveAnimation,
+ LinkOpponentHandlePrintString,
+ LinkOpponentHandlePrintStringPlayerOnly,
+ LinkOpponentHandleChooseAction,
+ LinkOpponentHandleCmd19,
+ LinkOpponentHandleChooseMove,
+ LinkOpponentHandleOpenBag,
+ LinkOpponentHandleChoosePokemon,
+ LinkOpponentHandleCmd23,
+ LinkOpponentHandleHealthBarUpdate,
+ LinkOpponentHandleExpUpdate,
+ LinkOpponentHandleStatusIconUpdate,
+ LinkOpponentHandleStatusAnimation,
+ LinkOpponentHandleStatusXor,
+ LinkOpponentHandleDataTransfer,
+ LinkOpponentHandleDMA3Transfer,
+ LinkOpponentHandlePlayBGM,
+ LinkOpponentHandleCmd32,
+ LinkOpponentHandleCmd33,
+ LinkOpponentHandleCmd34,
+ LinkOpponentHandleCmd35,
+ LinkOpponentHandleCmd36,
+ LinkOpponentHandleCmd37,
+ LinkOpponentHandleCmd38,
+ LinkOpponentHandleCmd39,
+ LinkOpponentHandleCmd40,
+ LinkOpponentHandleHitAnimation,
+ LinkOpponentHandleCmd42,
+ LinkOpponentHandleEffectivenessSound,
+ LinkOpponentHandlePlayFanfareOrBGM,
+ LinkOpponentHandleFaintingCry,
+ LinkOpponentHandleIntroSlide,
+ LinkOpponentHandleIntroTrainerBallThrow,
+ LinkOpponentHandleDrawPartyStatusSummary,
+ LinkOpponentHandleCmd49,
+ LinkOpponentHandleCmd50,
+ LinkOpponentHandleSpriteInvisibility,
+ LinkOpponentHandleBattleAnimation,
+ LinkOpponentHandleLinkStandbyMsg,
+ LinkOpponentHandleResetActionMoveSelection,
+ LinkOpponentHandleCmd55,
+ nullsub_92
+};
+
+void nullsub_28(void)
+{
+}
+
+void SetBankFuncToLinkOpponentBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = LinkOpponentBufferRunCommand;
+}
diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c
new file mode 100644
index 000000000..e55d78912
--- /dev/null
+++ b/src/battle_controller_opponent.c
@@ -0,0 +1,146 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "link.h"
+
+extern u8 gActiveBank;
+extern bool8 gDoingBattleAnim;
+extern u8 gUnknown_020244CC;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+
+// this file's functions
+void OpponentHandleGetMonData(void);
+void OpponentHandleGetRawMonData(void);
+void OpponentHandleSetMonData(void);
+void OpponentHandleSetRawMonData(void);
+void OpponentHandleLoadMonSprite(void);
+void OpponentHandleSwitchInAnim(void);
+void OpponentHandleReturnMonToBall(void);
+void OpponentHandleDrawTrainerPic(void);
+void OpponentHandleTrainerSlide(void);
+void OpponentHandleTrainerSlideBack(void);
+void OpponentHandleFaintAnimation(void);
+void OpponentHandleCmd11(void);
+void OpponentHandleCmd12(void);
+void OpponentHandleBallThrow(void);
+void OpponentHandlePause(void);
+void OpponentHandleMoveAnimation(void);
+void OpponentHandlePrintString(void);
+void OpponentHandlePrintStringPlayerOnly(void);
+void OpponentHandleChooseAction(void);
+void OpponentHandleCmd19(void);
+void OpponentHandleChooseMove(void);
+void OpponentHandleOpenBag(void);
+void OpponentHandleChoosePokemon(void);
+void OpponentHandleCmd23(void);
+void OpponentHandleHealthBarUpdate(void);
+void OpponentHandleExpUpdate(void);
+void OpponentHandleStatusIconUpdate(void);
+void OpponentHandleStatusAnimation(void);
+void OpponentHandleStatusXor(void);
+void OpponentHandleDataTransfer(void);
+void OpponentHandleDMA3Transfer(void);
+void OpponentHandlePlayBGM(void);
+void OpponentHandleCmd32(void);
+void OpponentHandleCmd33(void);
+void OpponentHandleCmd34(void);
+void OpponentHandleCmd35(void);
+void OpponentHandleCmd36(void);
+void OpponentHandleCmd37(void);
+void OpponentHandleCmd38(void);
+void OpponentHandleCmd39(void);
+void OpponentHandleCmd40(void);
+void OpponentHandleHitAnimation(void);
+void OpponentHandleCmd42(void);
+void OpponentHandleEffectivenessSound(void);
+void OpponentHandlePlayFanfareOrBGM(void);
+void OpponentHandleFaintingCry(void);
+void OpponentHandleIntroSlide(void);
+void OpponentHandleIntroTrainerBallThrow(void);
+void OpponentHandleDrawPartyStatusSummary(void);
+void OpponentHandleCmd49(void);
+void OpponentHandleCmd50(void);
+void OpponentHandleSpriteInvisibility(void);
+void OpponentHandleBattleAnimation(void);
+void OpponentHandleLinkStandbyMsg(void);
+void OpponentHandleResetActionMoveSelection(void);
+void OpponentHandleCmd55(void);
+void nullsub_91(void);
+
+void OpponentBufferRunCommand(void);
+
+void (*const gOpponentBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ OpponentHandleGetMonData,
+ OpponentHandleGetRawMonData,
+ OpponentHandleSetMonData,
+ OpponentHandleSetRawMonData,
+ OpponentHandleLoadMonSprite,
+ OpponentHandleSwitchInAnim,
+ OpponentHandleReturnMonToBall,
+ OpponentHandleDrawTrainerPic,
+ OpponentHandleTrainerSlide,
+ OpponentHandleTrainerSlideBack,
+ OpponentHandleFaintAnimation,
+ OpponentHandleCmd11,
+ OpponentHandleCmd12,
+ OpponentHandleBallThrow,
+ OpponentHandlePause,
+ OpponentHandleMoveAnimation,
+ OpponentHandlePrintString,
+ OpponentHandlePrintStringPlayerOnly,
+ OpponentHandleChooseAction,
+ OpponentHandleCmd19,
+ OpponentHandleChooseMove,
+ OpponentHandleOpenBag,
+ OpponentHandleChoosePokemon,
+ OpponentHandleCmd23,
+ OpponentHandleHealthBarUpdate,
+ OpponentHandleExpUpdate,
+ OpponentHandleStatusIconUpdate,
+ OpponentHandleStatusAnimation,
+ OpponentHandleStatusXor,
+ OpponentHandleDataTransfer,
+ OpponentHandleDMA3Transfer,
+ OpponentHandlePlayBGM,
+ OpponentHandleCmd32,
+ OpponentHandleCmd33,
+ OpponentHandleCmd34,
+ OpponentHandleCmd35,
+ OpponentHandleCmd36,
+ OpponentHandleCmd37,
+ OpponentHandleCmd38,
+ OpponentHandleCmd39,
+ OpponentHandleCmd40,
+ OpponentHandleHitAnimation,
+ OpponentHandleCmd42,
+ OpponentHandleEffectivenessSound,
+ OpponentHandlePlayFanfareOrBGM,
+ OpponentHandleFaintingCry,
+ OpponentHandleIntroSlide,
+ OpponentHandleIntroTrainerBallThrow,
+ OpponentHandleDrawPartyStatusSummary,
+ OpponentHandleCmd49,
+ OpponentHandleCmd50,
+ OpponentHandleSpriteInvisibility,
+ OpponentHandleBattleAnimation,
+ OpponentHandleLinkStandbyMsg,
+ OpponentHandleResetActionMoveSelection,
+ OpponentHandleCmd55,
+ nullsub_91
+};
+
+// unknown unused data
+static const u8 gUnknown_0831C7AC[] = {0xB0, 0xB0, 0xC8, 0x98, 0x28, 0x28, 0x28, 0x20};
+
+void nullsub_26(void)
+{
+}
+
+void SetBankFuncToOpponentBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = OpponentBufferRunCommand;
+}
diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c
new file mode 100644
index 000000000..b022d3f87
--- /dev/null
+++ b/src/battle_controller_player.c
@@ -0,0 +1,3160 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "battle_link_817C95C.h"
+#include "pokemon.h"
+#include "link.h"
+#include "util.h"
+#include "main.h"
+#include "item.h"
+#include "items.h"
+#include "songs.h"
+#include "sound.h"
+#include "moves.h"
+#include "window.h"
+#include "m4a.h"
+#include "palette.h"
+#include "task.h"
+#include "text.h"
+#include "string_util.h"
+#include "bg.h"
+#include "reshow_battle_screen.h"
+#include "rng.h"
+#include "pokeball.h"
+
+extern u32 gBattleExecBuffer;
+extern u8 gActiveBank;
+extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
+extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT];
+extern u8 gMoveSelectionCursor[BATTLE_BANKS_COUNT];
+extern u8 gAbsentBankFlags;
+extern u8 gNoOfAllBanks;
+extern bool8 gDoingBattleAnim;
+extern u8 gUnknown_020244CC;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+extern void (*gPreBattleCallback1)(void);
+extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
+extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
+extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
+extern u8 gMultiUsePlayerCursor;
+extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
+extern struct MusicPlayerInfo gMPlay_BGM;
+extern u16 gPartnerTrainerId;
+extern struct SpriteTemplate gUnknown_0202499C;
+extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
+extern u16 gScriptItemId;
+extern u8 gUnknown_0203CEE8;
+extern u8 gUnknown_0203CEE9;
+extern u8 gUnknown_0203CF00[];
+extern u8 gUnknown_03005D7C[BATTLE_BANKS_COUNT];
+extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
+extern u8 gBattleOutcome;
+extern u8 gNumberOfMovesToChoose;
+extern u16 gBattle_BG0_X;
+extern u16 gBattle_BG0_Y;
+extern s32 gUnknown_0203CD70;
+extern u8 gBankInMenu;
+extern u32 gBattlePalaceMoveSelectionRngValue;
+extern u32 gTransformedPersonalities[BATTLE_BANKS_COUNT];
+extern u8 gUnknown_020244B4[];
+extern u16 gUnknown_020243FC;
+extern struct UnusedControllerStruct gUnknown_02022D0C;
+
+extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
+extern const struct CompressedSpritePalette gTrainerBackPicPaletteTable[];
+extern const u8 gTypeNames[][7];
+extern const struct BattleMove gBattleMoves[];
+
+extern const u8 gText_BattleSwitchWhich[];
+extern const u8 gText_MoveInterfacePP[];
+extern const u8 gText_MoveInterfaceType[];
+extern const u8 gText_LinkStandby[];
+extern const u8 gText_BattleMenu[];
+extern const u8 gText_WhatWillPkmnDo[];
+extern const u8 gText_BattleYesNoChoice[];
+
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_81B89AC(u8 arg0);
+extern void sub_81AABB0(void);
+extern void sub_806A068(u16, u8);
+extern void sub_81A57E4(u8 bank, u16 stringId);
+extern void sub_81851A8(u8 *);
+
+// this file's functions
+static void PlayerHandleGetMonData(void);
+void PlayerHandleGetRawMonData(void);
+static void PlayerHandleSetMonData(void);
+static void PlayerHandleSetRawMonData(void);
+static void PlayerHandleLoadMonSprite(void);
+static void PlayerHandleSwitchInAnim(void);
+static void PlayerHandleReturnMonToBall(void);
+static void PlayerHandleDrawTrainerPic(void);
+static void PlayerHandleTrainerSlide(void);
+static void PlayerHandleTrainerSlideBack(void);
+static void PlayerHandleFaintAnimation(void);
+static void PlayerHandlePaletteFade(void);
+static void PlayerHandleSuccessBallThrowAnim(void);
+static void PlayerHandleBallThrowAnim(void);
+static void PlayerHandlePause(void);
+static void PlayerHandleMoveAnimation(void);
+static void PlayerHandlePrintString(void);
+static void PlayerHandlePrintStringPlayerOnly(void);
+static void PlayerHandleChooseAction(void);
+static void PlayerHandleUnknownYesNoBox(void);
+static void PlayerHandleChooseMove(void);
+static void PlayerHandleChooseItem(void);
+static void PlayerHandleChoosePokemon(void);
+static void PlayerHandleCmd23(void);
+static void PlayerHandleHealthBarUpdate(void);
+static void PlayerHandleExpUpdate(void);
+static void PlayerHandleStatusIconUpdate(void);
+static void PlayerHandleStatusAnimation(void);
+static void PlayerHandleStatusXor(void);
+static void PlayerHandleDataTransfer(void);
+static void PlayerHandleDMA3Transfer(void);
+static void PlayerHandlePlayBGM(void);
+static void PlayerHandleCmd32(void);
+static void PlayerHandleTwoReturnValues(void);
+static void PlayerHandleChosenMonReturnValue(void);
+static void PlayerHandleOneReturnValue(void);
+static void PlayerHandleOneReturnValue_Duplicate(void);
+static void PlayerHandleCmd37(void);
+static void PlayerHandleCmd38(void);
+static void PlayerHandleCmd39(void);
+static void PlayerHandleCmd40(void);
+static void PlayerHandleHitAnimation(void);
+static void PlayerHandleCmd42(void);
+static void PlayerHandleEffectivenessSound(void);
+static void PlayerHandlePlayFanfareOrBGM(void);
+static void PlayerHandleFaintingCry(void);
+static void PlayerHandleIntroSlide(void);
+static void PlayerHandleIntroTrainerBallThrow(void);
+static void PlayerHandleDrawPartyStatusSummary(void);
+static void PlayerHandleCmd49(void);
+static void PlayerHandleCmd50(void);
+static void PlayerHandleSpriteInvisibility(void);
+static void PlayerHandleBattleAnimation(void);
+static void PlayerHandleLinkStandbyMsg(void);
+static void PlayerHandleResetActionMoveSelection(void);
+static void PlayerHandleCmd55(void);
+static void nullsub_22(void);
+
+static void PlayerBufferRunCommand(void);
+static void HandleInputChooseTarget(void);
+static void HandleInputChooseMove(void);
+static void MoveSelectionCreateCursorAt(u8 cursorPos, u8 arg1);
+static void MoveSelectionDestroyCursorAt(u8 cursorPos);
+static void MoveSelectionDisplayPpNumber(void);
+static void MoveSelectionDisplayPpString(void);
+static void MoveSelectionDisplayMoveType(void);
+static void MoveSelectionDisplayMoveNames(void);
+static void HandleMoveSwitchting(void);
+static void sub_8058FC0(void);
+static void sub_8059828(void);
+static void CompleteWhenChoseItem(void);
+static void sub_8059544(u8 taskId);
+static void Task_PrepareToGiveExpWithExpBar(u8 taskId);
+static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId);
+static void sub_8059400(u8 taskId);
+static void sub_80595A4(u8 taskId);
+static void PrintLinkStandbyMsg(void);
+static u32 CopyPlayerMonData(u8 monId, u8 *dst);
+static void SetPlayerMonData(u8 monId);
+static void sub_805B258(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void PlayerDoMoveAnimation(void);
+static void task05_08033660(u8 taskId);
+static void sub_805CE38(void);
+
+static void (*const gPlayerBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ PlayerHandleGetMonData,
+ PlayerHandleGetRawMonData,
+ PlayerHandleSetMonData,
+ PlayerHandleSetRawMonData,
+ PlayerHandleLoadMonSprite,
+ PlayerHandleSwitchInAnim,
+ PlayerHandleReturnMonToBall,
+ PlayerHandleDrawTrainerPic,
+ PlayerHandleTrainerSlide,
+ PlayerHandleTrainerSlideBack,
+ PlayerHandleFaintAnimation,
+ PlayerHandlePaletteFade,
+ PlayerHandleSuccessBallThrowAnim,
+ PlayerHandleBallThrowAnim,
+ PlayerHandlePause,
+ PlayerHandleMoveAnimation,
+ PlayerHandlePrintString,
+ PlayerHandlePrintStringPlayerOnly,
+ PlayerHandleChooseAction,
+ PlayerHandleUnknownYesNoBox,
+ PlayerHandleChooseMove,
+ PlayerHandleChooseItem,
+ PlayerHandleChoosePokemon,
+ PlayerHandleCmd23,
+ PlayerHandleHealthBarUpdate,
+ PlayerHandleExpUpdate,
+ PlayerHandleStatusIconUpdate,
+ PlayerHandleStatusAnimation,
+ PlayerHandleStatusXor,
+ PlayerHandleDataTransfer,
+ PlayerHandleDMA3Transfer,
+ PlayerHandlePlayBGM,
+ PlayerHandleCmd32,
+ PlayerHandleTwoReturnValues,
+ PlayerHandleChosenMonReturnValue,
+ PlayerHandleOneReturnValue,
+ PlayerHandleOneReturnValue_Duplicate,
+ PlayerHandleCmd37,
+ PlayerHandleCmd38,
+ PlayerHandleCmd39,
+ PlayerHandleCmd40,
+ PlayerHandleHitAnimation,
+ PlayerHandleCmd42,
+ PlayerHandleEffectivenessSound,
+ PlayerHandlePlayFanfareOrBGM,
+ PlayerHandleFaintingCry,
+ PlayerHandleIntroSlide,
+ PlayerHandleIntroTrainerBallThrow,
+ PlayerHandleDrawPartyStatusSummary,
+ PlayerHandleCmd49,
+ PlayerHandleCmd50,
+ PlayerHandleSpriteInvisibility,
+ PlayerHandleBattleAnimation,
+ PlayerHandleLinkStandbyMsg,
+ PlayerHandleResetActionMoveSelection,
+ PlayerHandleCmd55,
+ nullsub_22
+};
+
+static const u8 sTargetIdentities[] = {IDENTITY_PLAYER_MON1, IDENTITY_PLAYER_MON2, IDENTITY_OPPONENT_MON2, IDENTITY_OPPONENT_MON1};
+
+// unknown unused data
+static const u8 gUnknown_0831C5FC[] = {0x48, 0x48, 0x20, 0x5a, 0x50, 0x50, 0x50, 0x58};
+
+void nullsub_21(void)
+{
+}
+
+void SetBankFuncToPlayerBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerBufferRunCommand;
+ gDoingBattleAnim = FALSE;
+ gUnknown_020244CC = 0;
+}
+
+static void PlayerBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTOLLER_CMDS_COUNT - 1;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void PlayerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(gPlayerBufferCommands))
+ gPlayerBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpritePosX_0(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0)
+ PlayerBufferExecCompleted();
+}
+
+static void HandleInputChooseAction(void)
+{
+ u16 itemId = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ dp11b_obj_instanciate(gActiveBank, 1, 7, 1);
+ dp11b_obj_instanciate(gActiveBank, 0, 7, 1);
+
+ if (gMain.newAndRepeatedKeys & DPAD_ANY && gSaveBlock2Ptr->optionsButtonMode == 2)
+ gUnknown_020244CC++;
+ else
+ gUnknown_020244CC = 0;
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+
+ switch (gActionSelectionCursor[gActiveBank])
+ {
+ case 0:
+ EmitTwoReturnValues(1, ACTION_USE_MOVE, 0);
+ break;
+ case 1:
+ EmitTwoReturnValues(1, ACTION_USE_ITEM, 0);
+ break;
+ case 2:
+ EmitTwoReturnValues(1, ACTION_SWITCH, 0);
+ break;
+ case 3:
+ EmitTwoReturnValues(1, ACTION_RUN, 0);
+ break;
+ }
+ PlayerBufferExecCompleted();
+ }
+ else if (gMain.newKeys & DPAD_LEFT)
+ {
+ if (gActionSelectionCursor[gActiveBank] & 1) // if is ACTION_USE_ITEM or ACTION_RUN
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 1;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_RIGHT)
+ {
+ if (!(gActionSelectionCursor[gActiveBank] & 1)) // if is ACTION_USE_MOVE or ACTION_SWITCH
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 1;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_UP)
+ {
+ if (gActionSelectionCursor[gActiveBank] & 2) // if is ACTION_SWITCH or ACTION_RUN
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 2;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (!(gActionSelectionCursor[gActiveBank] & 2)) // if is ACTION_USE_MOVE or ACTION_USE_ITEM
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 2;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & B_BUTTON || gUnknown_020244CC > 59)
+ {
+ if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
+ && GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON2
+ && !(gAbsentBankFlags & gBitTable[GetBankByIdentity(IDENTITY_PLAYER_MON1)])
+ && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ if (gBattleBufferA[gActiveBank][1] == 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);
+ EmitTwoReturnValues(1, ACTION_CANCEL_PARTNER, 0);
+ PlayerBufferExecCompleted();
+ }
+ }
+ else if (gMain.newKeys & START_BUTTON)
+ {
+ SwapHpBarsWithHpText();
+ }
+}
+
+static void sub_80577F0(void) // unused
+{
+ dp11b_obj_free(gActiveBank, 1);
+ dp11b_obj_free(gActiveBank, 0);
+ gBattleBankFunc[gActiveBank] = HandleInputChooseTarget;
+}
+
+static void HandleInputChooseTarget(void)
+{
+ s32 i;
+ u8 identities[4];
+ memcpy(identities, sTargetIdentities, ARRAY_COUNT(sTargetIdentities));
+
+ dp11b_obj_instanciate(gMultiUsePlayerCursor, 1, 0xF, 1);
+
+ // what a weird loop
+ i = 0;
+ if (gNoOfAllBanks != 0)
+ {
+ do
+ {
+ if (i != gMultiUsePlayerCursor)
+ dp11b_obj_free(i, 1);
+ i++;
+ } while (i < gNoOfAllBanks);
+ }
+
+ if (gMain.heldKeys & DPAD_ANY && gSaveBlock2Ptr->optionsButtonMode == 2)
+ gUnknown_020244CC++;
+ else
+ gUnknown_020244CC = 0;
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039B2C;
+ EmitTwoReturnValues(1, 10, gMoveSelectionCursor[gActiveBank] | (gMultiUsePlayerCursor << 8));
+ dp11b_obj_free(gMultiUsePlayerCursor, 1);
+ PlayerBufferExecCompleted();
+ }
+ else if (gMain.newKeys & B_BUTTON || gUnknown_020244CC > 59)
+ {
+ PlaySE(SE_SELECT);
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039B2C;
+ gBattleBankFunc[gActiveBank] = HandleInputChooseMove;
+ dp11b_obj_instanciate(gActiveBank, 1, 7, 1);
+ dp11b_obj_instanciate(gActiveBank, 0, 7, 1);
+ dp11b_obj_free(gMultiUsePlayerCursor, 1);
+ }
+ else if (gMain.newKeys & (DPAD_LEFT | DPAD_UP))
+ {
+ PlaySE(SE_SELECT);
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039B2C;
+
+ do
+ {
+ u8 currSelIdentity = GetBankIdentity(gMultiUsePlayerCursor);
+
+ for (i = 0; i < BATTLE_BANKS_COUNT; i++)
+ {
+ if (currSelIdentity == identities[i])
+ break;
+ }
+ do
+ {
+ if (--i < 0)
+ i = 4; // UB: array out of range
+ gMultiUsePlayerCursor = GetBankByIdentity(identities[i]);
+ } while (gMultiUsePlayerCursor == gNoOfAllBanks);
+
+ i = 0;
+ switch (GetBankIdentity(gMultiUsePlayerCursor))
+ {
+ case IDENTITY_PLAYER_MON1:
+ case IDENTITY_PLAYER_MON2:
+ if (gActiveBank != gMultiUsePlayerCursor)
+ i++;
+ else if (gBattleMoves[GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBank])].target & MOVE_TARGET_USER)
+ i++;
+ break;
+ case IDENTITY_OPPONENT_MON1:
+ case IDENTITY_OPPONENT_MON2:
+ i++;
+ break;
+ }
+
+ if (gAbsentBankFlags & gBitTable[gMultiUsePlayerCursor])
+ i = 0;
+ } while (i == 0);
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039AD8;
+ }
+ else if (gMain.newKeys & (DPAD_RIGHT | DPAD_DOWN))
+ {
+ PlaySE(SE_SELECT);
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039B2C;
+
+ do
+ {
+ u8 currSelIdentity = GetBankIdentity(gMultiUsePlayerCursor);
+
+ for (i = 0; i < BATTLE_BANKS_COUNT; i++)
+ {
+ if (currSelIdentity == identities[i])
+ break;
+ }
+ do
+ {
+ if (++i > 3)
+ i = 0;
+ gMultiUsePlayerCursor = GetBankByIdentity(identities[i]);
+ } while (gMultiUsePlayerCursor == gNoOfAllBanks);
+
+ i = 0;
+ switch (GetBankIdentity(gMultiUsePlayerCursor))
+ {
+ case IDENTITY_PLAYER_MON1:
+ case IDENTITY_PLAYER_MON2:
+ if (gActiveBank != gMultiUsePlayerCursor)
+ i++;
+ else if (gBattleMoves[GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBank])].target & MOVE_TARGET_USER)
+ i++;
+ break;
+ case IDENTITY_OPPONENT_MON1:
+ case IDENTITY_OPPONENT_MON2:
+ i++;
+ break;
+ }
+
+ if (gAbsentBankFlags & gBitTable[gMultiUsePlayerCursor])
+ i = 0;
+ } while (i == 0);
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039AD8;
+ }
+}
+
+static void HandleInputChooseMove(void)
+{
+ bool32 canSelectTarget = FALSE;
+ struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+
+ if (gMain.heldKeys & DPAD_ANY && gSaveBlock2Ptr->optionsButtonMode == 2)
+ gUnknown_020244CC++;
+ else
+ gUnknown_020244CC = 0;
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ u8 moveTarget;
+
+ PlaySE(SE_SELECT);
+ if (moveInfo->moves[gMoveSelectionCursor[gActiveBank]] == MOVE_CURSE)
+ {
+ if (moveInfo->monType1 != TYPE_GHOST && moveInfo->monType2 != TYPE_GHOST)
+ moveTarget = MOVE_TARGET_x10;
+ else
+ moveTarget = MOVE_TARGET_SELECTED;
+ }
+ else
+ {
+ moveTarget = gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBank]]].target;
+ }
+
+ if (moveTarget & MOVE_TARGET_x10)
+ gMultiUsePlayerCursor = gActiveBank;
+ else
+ gMultiUsePlayerCursor = GetBankByIdentity((GetBankIdentity(gActiveBank) & BIT_SIDE) ^ BIT_SIDE);
+
+ if (!gBattleBufferA[gActiveBank][1]) // not a double battle
+ {
+ if (moveTarget & MOVE_TARGET_USER && !gBattleBufferA[gActiveBank][2])
+ canSelectTarget++;
+ }
+ else // double battle
+ {
+ if (!(moveTarget & (MOVE_TARGET_RANDOM | MOVE_TARGET_BOTH | MOVE_TARGET_DEPENDS | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_x10)))
+ canSelectTarget++; // either selected or user
+
+ if (moveInfo->currentPp[gMoveSelectionCursor[gActiveBank]] == 0)
+ {
+ canSelectTarget = FALSE;
+ }
+ else if (!(moveTarget & (MOVE_TARGET_x10 | MOVE_TARGET_USER)) && CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_ACTIVE) <= 1)
+ {
+ gMultiUsePlayerCursor = GetDefaultMoveTarget(gActiveBank);
+ canSelectTarget = FALSE;
+ }
+ }
+
+ if (!canSelectTarget)
+ {
+ EmitTwoReturnValues(1, 10, gMoveSelectionCursor[gActiveBank] | (gMultiUsePlayerCursor << 8));
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleBankFunc[gActiveBank] = HandleInputChooseTarget;
+
+ if (moveTarget & (MOVE_TARGET_x10 | MOVE_TARGET_USER))
+ gMultiUsePlayerCursor = gActiveBank;
+ else if (gAbsentBankFlags & gBitTable[GetBankByIdentity(IDENTITY_OPPONENT_MON1)])
+ gMultiUsePlayerCursor = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
+ else
+ gMultiUsePlayerCursor = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
+
+ gSprites[gBankSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039AD8;
+ }
+ }
+ else if (gMain.newKeys & B_BUTTON || gUnknown_020244CC > 59)
+ {
+ PlaySE(SE_SELECT);
+ EmitTwoReturnValues(1, 10, 0xFFFF);
+ PlayerBufferExecCompleted();
+ }
+ else if (gMain.newKeys & DPAD_LEFT)
+ {
+ if (gMoveSelectionCursor[gActiveBank] & 1)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 1;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+ }
+ }
+ else if (gMain.newKeys & DPAD_RIGHT)
+ {
+ if (!(gMoveSelectionCursor[gActiveBank] & 1)
+ && (gMoveSelectionCursor[gActiveBank] ^ 1) < gNumberOfMovesToChoose)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 1;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+ }
+ }
+ else if (gMain.newKeys & DPAD_UP)
+ {
+ if (gMoveSelectionCursor[gActiveBank] & 2)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 2;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+ }
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (!(gMoveSelectionCursor[gActiveBank] & 2)
+ && (gMoveSelectionCursor[gActiveBank] ^ 2) < gNumberOfMovesToChoose)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 2;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+ }
+ }
+ else if (gMain.newKeys & SELECT_BUTTON)
+ {
+ if (gNumberOfMovesToChoose > 1 && !(gBattleTypeFlags & BATTLE_TYPE_LINK))
+ {
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 29);
+
+ if (gMoveSelectionCursor[gActiveBank] != 0)
+ gMultiUsePlayerCursor = 0;
+ else
+ gMultiUsePlayerCursor = gMoveSelectionCursor[gActiveBank] + 1;
+
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
+ BattleHandleAddTextPrinter(gText_BattleSwitchWhich, 0xB);
+ gBattleBankFunc[gActiveBank] = HandleMoveSwitchting;
+ }
+ }
+}
+
+u32 sub_8057FBC(void) // unused
+{
+ u32 var = 0;
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ var = 1;
+ }
+ if (gMain.newKeys & B_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0x140;
+ var = 0xFF;
+ }
+ if (gMain.newKeys & DPAD_LEFT && gMoveSelectionCursor[gActiveBank] & 1)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 1;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ }
+ if (gMain.newKeys & DPAD_RIGHT && !(gMoveSelectionCursor[gActiveBank] & 1)
+ && (gMoveSelectionCursor[gActiveBank] ^ 1) < gNumberOfMovesToChoose)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 1;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ }
+ if (gMain.newKeys & DPAD_UP && gMoveSelectionCursor[gActiveBank] & 2)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 2;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ }
+ if (gMain.newKeys & DPAD_DOWN && !(gMoveSelectionCursor[gActiveBank] & 2)
+ && (gMoveSelectionCursor[gActiveBank] ^ 2) < gNumberOfMovesToChoose)
+ {
+ MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBank]);
+ gMoveSelectionCursor[gActiveBank] ^= 2;
+ PlaySE(SE_SELECT);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ }
+
+ return var;
+}
+
+static void HandleMoveSwitchting(void)
+{
+ u8 perMovePPBonuses[4];
+ struct ChooseMoveStruct moveStruct;
+ u8 totalPPBonuses;
+
+ if (gMain.newKeys & (A_BUTTON | SELECT_BUTTON))
+ {
+ PlaySE(SE_SELECT);
+
+ if (gMoveSelectionCursor[gActiveBank] != gMultiUsePlayerCursor)
+ {
+ struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+ s32 i;
+
+ // swap moves and pp
+ i = moveInfo->moves[gMoveSelectionCursor[gActiveBank]];
+ moveInfo->moves[gMoveSelectionCursor[gActiveBank]] = moveInfo->moves[gMultiUsePlayerCursor];
+ moveInfo->moves[gMultiUsePlayerCursor] = i;
+
+ i = moveInfo->currentPp[gMoveSelectionCursor[gActiveBank]];
+ moveInfo->currentPp[gMoveSelectionCursor[gActiveBank]] = moveInfo->currentPp[gMultiUsePlayerCursor];
+ moveInfo->currentPp[gMultiUsePlayerCursor] = i;
+
+ i = moveInfo->maxPp[gMoveSelectionCursor[gActiveBank]];
+ moveInfo->maxPp[gMoveSelectionCursor[gActiveBank]] = moveInfo->maxPp[gMultiUsePlayerCursor];
+ moveInfo->maxPp[gMultiUsePlayerCursor] = i;
+
+ if (gDisableStructs[gActiveBank].unk18_b & gBitTable[gMoveSelectionCursor[gActiveBank]])
+ {
+ gDisableStructs[gActiveBank].unk18_b &= (~gBitTable[gMoveSelectionCursor[gActiveBank]]);
+ gDisableStructs[gActiveBank].unk18_b |= gBitTable[gMultiUsePlayerCursor];
+ }
+
+ MoveSelectionDisplayMoveNames();
+
+ for (i = 0; i < 4; i++)
+ perMovePPBonuses[i] = (gBattleMons[gActiveBank].ppBonuses & (3 << (i * 2))) >> (i * 2);
+
+ totalPPBonuses = perMovePPBonuses[gMoveSelectionCursor[gActiveBank]];
+ perMovePPBonuses[gMoveSelectionCursor[gActiveBank]] = perMovePPBonuses[gMultiUsePlayerCursor];
+ perMovePPBonuses[gMultiUsePlayerCursor] = totalPPBonuses;
+
+ totalPPBonuses = 0;
+ for (i = 0; i < 4; i++)
+ totalPPBonuses |= perMovePPBonuses[i] << (i * 2);
+
+ gBattleMons[gActiveBank].ppBonuses = totalPPBonuses;
+
+ for (i = 0; i < 4; i++)
+ {
+ gBattleMons[gActiveBank].moves[i] = moveInfo->moves[i];
+ gBattleMons[gActiveBank].pp[i] = moveInfo->currentPp[i];
+ }
+
+ if (!(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED))
+ {
+ for (i = 0; i < 4; i++)
+ {
+ moveStruct.moves[i] = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MOVE1 + i);
+ moveStruct.currentPp[i] = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_PP1 + i);
+ }
+
+ totalPPBonuses = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_PP_BONUSES);
+ for (i = 0; i < 4; i++)
+ perMovePPBonuses[i] = (totalPPBonuses & (3 << (i * 2))) >> (i * 2);
+
+ i = moveStruct.moves[gMoveSelectionCursor[gActiveBank]];
+ moveStruct.moves[gMoveSelectionCursor[gActiveBank]] = moveStruct.moves[gMultiUsePlayerCursor];
+ moveStruct.moves[gMultiUsePlayerCursor] = i;
+
+ i = moveStruct.currentPp[gMoveSelectionCursor[gActiveBank]];
+ moveStruct.currentPp[gMoveSelectionCursor[gActiveBank]] = moveStruct.currentPp[gMultiUsePlayerCursor];
+ moveStruct.currentPp[gMultiUsePlayerCursor] = i;
+
+ totalPPBonuses = perMovePPBonuses[gMoveSelectionCursor[gActiveBank]];
+ perMovePPBonuses[gMoveSelectionCursor[gActiveBank]] = perMovePPBonuses[gMultiUsePlayerCursor];
+ perMovePPBonuses[gMultiUsePlayerCursor] = totalPPBonuses;
+
+ totalPPBonuses = 0;
+ for (i = 0; i < 4; i++)
+ totalPPBonuses |= perMovePPBonuses[i] << (i * 2);
+
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MOVE1 + i, &moveStruct.moves[i]);
+ SetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_PP1 + i, &moveStruct.currentPp[i]);
+ }
+
+ SetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_PP_BONUSES, &totalPPBonuses);
+ }
+ }
+
+ gBattleBankFunc[gActiveBank] = HandleInputChooseMove;
+ gMoveSelectionCursor[gActiveBank] = gMultiUsePlayerCursor;
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ MoveSelectionDisplayPpString();
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+ }
+ else if (gMain.newKeys & (B_BUTTON | SELECT_BUTTON))
+ {
+ PlaySE(SE_SELECT);
+ MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ gBattleBankFunc[gActiveBank] = HandleInputChooseMove;
+ MoveSelectionDisplayPpString();
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+ }
+ else if (gMain.newKeys & DPAD_LEFT)
+ {
+ if (gMultiUsePlayerCursor & 1)
+ {
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 29);
+ else
+ MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
+
+ gMultiUsePlayerCursor ^= 1;
+ PlaySE(SE_SELECT);
+
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
+ else
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
+ }
+ }
+ else if (gMain.newKeys & DPAD_RIGHT)
+ {
+ if (!(gMultiUsePlayerCursor & 1) && (gMultiUsePlayerCursor ^ 1) < gNumberOfMovesToChoose)
+ {
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 29);
+ else
+ MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
+
+ gMultiUsePlayerCursor ^= 1;
+ PlaySE(SE_SELECT);
+
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
+ else
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
+ }
+ }
+ else if (gMain.newKeys & DPAD_UP)
+ {
+ if (gMultiUsePlayerCursor & 2)
+ {
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 29);
+ else
+ MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
+
+ gMultiUsePlayerCursor ^= 2;
+ PlaySE(SE_SELECT);
+
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
+ else
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
+ }
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (!(gMultiUsePlayerCursor & 2) && (gMultiUsePlayerCursor ^ 2) < gNumberOfMovesToChoose)
+ {
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 29);
+ else
+ MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
+
+ gMultiUsePlayerCursor ^= 2;
+ PlaySE(SE_SELECT);
+
+ if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBank])
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
+ else
+ MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
+ }
+ }
+}
+
+static void sub_80586F8(void)
+{
+ if (gLinkVSyncDisabled == 0)
+ {
+ if (gReceivedRemoteLinkPlayers == 0)
+ {
+ m4aSongNumStop(SE_HINSI);
+ gMain.inBattle = 0;
+ gMain.callback1 = gPreBattleCallback1;
+ SetMainCallback2(sub_8038D64);
+ if (gBattleOutcome == BATTLE_WON)
+ sub_817E3F4();
+ FreeAllWindowBuffers();
+ }
+ }
+ else
+ {
+ if (sub_800A520())
+ {
+ m4aSongNumStop(SE_HINSI);
+ gMain.inBattle = 0;
+ gMain.callback1 = gPreBattleCallback1;
+ SetMainCallback2(sub_8038D64);
+ if (gBattleOutcome == BATTLE_WON)
+ sub_817E3F4();
+ FreeAllWindowBuffers();
+ }
+ }
+}
+
+void sub_80587B0(void)
+{
+ if (!gPaletteFade.active)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ if (sub_800A520())
+ {
+ if (gLinkVSyncDisabled == 0)
+ sub_800AC34();
+ else
+ sub_800ADF8();
+
+ gBattleBankFunc[gActiveBank] = sub_80586F8;
+ }
+ }
+ else
+ {
+ m4aSongNumStop(SE_HINSI);
+ gMain.inBattle = 0;
+ gMain.callback1 = gPreBattleCallback1;
+ SetMainCallback2(gMain.savedCallback);
+ }
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ PlayerBufferExecCompleted();
+}
+
+static void CompleteOnBankSpriteCallbackDummy2(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ PlayerBufferExecCompleted();
+}
+
+static void sub_80588B4(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ nullsub_25(gSaveBlock2Ptr->playerGender);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void sub_8058924(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void sub_805896C(void)
+{
+ bool8 var = FALSE;
+
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ var = TRUE;
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ var = TRUE;
+ }
+
+ if (var && gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1
+ && gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1 = 0;
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+
+ if (IsDoubleBattle())
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]], gActiveBank ^ BIT_MON);
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_8058924;
+ }
+}
+
+static void sub_8058B40(void)
+{
+ bool32 r9 = FALSE;
+ bool32 r8 = FALSE;
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ sub_8172EF0(gActiveBank, &gPlayerParty[gBattlePartyID[gActiveBank]]);
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8)
+ sub_8172EF0(gActiveBank ^ BIT_MON, &gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]]);
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8)
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80)
+ {
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank ^ BIT_MON], &gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank ^ BIT_MON);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank ^ BIT_MON]);
+ }
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 1;
+ }
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x40
+ && gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x40
+ && !IsCryPlayingOrClearCrySongs())
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
+ m4aMPlayContinue(&gMPlay_BGM);
+ else
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 1;
+ r9 = TRUE;
+ }
+
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ r8 = TRUE;
+ }
+ }
+ else
+ {
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gUnknown_03005D7C[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ {
+ r8 = TRUE;
+ }
+ }
+
+ if (r9 && r8)
+ {
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank ^ BIT_MON]]);
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 0;
+
+ gBattleBankFunc[gActiveBank] = sub_805896C;
+ }
+}
+
+static void sub_8058EDC(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ SetBattleSpriteInvisibilityBitToSpriteInvisibility(gActiveBank);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+
+ gBattleBankFunc[gActiveBank] = sub_8058FC0;
+ }
+}
+
+static void sub_8058FC0(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive
+ && !IsCryPlayingOrClearCrySongs())
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void sub_805902C(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ sub_8172EF0(gActiveBank, &gPlayerParty[gBattlePartyID[gActiveBank]]);
+ }
+
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ gBattleBankFunc[gActiveBank] = sub_8058EDC;
+ }
+}
+
+void c3_0802FDF4(u8 taskId)
+{
+ if (!IsCryPlayingOrClearCrySongs())
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ DestroyTask(taskId);
+ }
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], 0, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ PlayerBufferExecCompleted();
+}
+
+#define tExpTask_monId data[0]
+#define tExpTask_gainedExp data[1]
+#define tExpTask_bank data[2]
+#define tExpTask_frames data[10]
+
+static void Task_GiveExpToMon(u8 taskId)
+{
+ u32 monId = (u8)(gTasks[taskId].tExpTask_monId);
+ u8 bank = gTasks[taskId].tExpTask_bank;
+ s16 gainedExp = gTasks[taskId].tExpTask_gainedExp;
+
+ if (IsDoubleBattle() == TRUE || monId != gBattlePartyID[bank]) // give exp without 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 savedActiveBank;
+
+ SetMonData(mon, MON_DATA_EXP, &nextLvlExp);
+ CalculateMonStats(mon);
+ gainedExp -= nextLvlExp - currExp;
+ savedActiveBank = gActiveBank;
+ gActiveBank = bank;
+ EmitTwoReturnValues(1, RET_VALUE_LEVELLED_UP, gainedExp);
+ gActiveBank = savedActiveBank;
+
+ if (IsDoubleBattle() == TRUE
+ && ((u16)(monId) == gBattlePartyID[bank] || (u16)(monId) == gBattlePartyID[bank ^ BIT_MON]))
+ gTasks[taskId].func = sub_8059544;
+ else
+ gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter;
+ }
+ else
+ {
+ currExp += gainedExp;
+ SetMonData(mon, MON_DATA_EXP, &currExp);
+ gBattleBankFunc[bank] = CompleteOnInactiveTextPrinter;
+ 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 bank = gTasks[taskId].tExpTask_bank;
+ 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(bank, gHealthBoxesIds[bank], expToNextLvl, exp, -gainedExp);
+ PlaySE(SE_EXP);
+ gTasks[taskId].func = sub_8059400;
+}
+
+static void sub_8059400(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 bank = gTasks[taskId].tExpTask_bank;
+ s16 r4;
+
+ r4 = sub_8074AA0(bank, gHealthBoxesIds[bank], EXP_BAR, 0);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[bank]);
+ if (r4 == -1)
+ {
+ 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 savedActiveBank;
+
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl);
+ CalculateMonStats(&gPlayerParty[monId]);
+ gainedExp -= expOnNextLvl - currExp;
+ savedActiveBank = gActiveBank;
+ gActiveBank = bank;
+ EmitTwoReturnValues(1, RET_VALUE_LEVELLED_UP, gainedExp);
+ gActiveBank = savedActiveBank;
+ gTasks[taskId].func = sub_8059544;
+ }
+ else
+ {
+ currExp += gainedExp;
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp);
+ gBattleBankFunc[bank] = CompleteOnInactiveTextPrinter;
+ DestroyTask(taskId);
+ }
+ }
+ }
+}
+
+static void sub_8059544(u8 taskId)
+{
+ u8 bank = gTasks[taskId].tExpTask_bank;
+ u8 monIndex = gTasks[taskId].tExpTask_monId;
+
+ if (IsDoubleBattle() == TRUE && monIndex == gBattlePartyID[bank ^ BIT_MON])
+ bank ^= BIT_MON;
+
+ DoSpecialBattleAnimation(bank, bank, bank, B_ANIM_LVL_UP);
+ gTasks[taskId].func = sub_80595A4;
+}
+
+static void sub_80595A4(u8 taskId)
+{
+ u8 bank = gTasks[taskId].tExpTask_bank;
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[bank].specialAnimActive)
+ {
+ u8 monIndex = gTasks[taskId].tExpTask_monId;
+
+ GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value
+
+ if (IsDoubleBattle() == TRUE && monIndex == gBattlePartyID[bank ^ BIT_MON])
+ UpdateHealthboxAttribute(gHealthBoxesIds[bank ^ BIT_MON], &gPlayerParty[monIndex], HEALTHBOX_ALL);
+ else
+ UpdateHealthboxAttribute(gHealthBoxesIds[bank], &gPlayerParty[monIndex], HEALTHBOX_ALL);
+
+ gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter;
+ }
+}
+
+static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId)
+{
+ u8 monIndex;
+ u8 bank;
+
+ monIndex = gTasks[taskId].tExpTask_monId;
+ GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value
+ bank = gTasks[taskId].tExpTask_bank;
+ gBattleBankFunc[bank] = CompleteOnInactiveTextPrinter;
+ DestroyTask(taskId);
+}
+
+static void sub_80596A8(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].pos1.y + gSprites[gBankSpriteIds[gActiveBank]].pos2.y > DISPLAY_HEIGHT)
+ {
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ nullsub_24(species);
+ FreeOamMatrix(gSprites[gBankSpriteIds[gActiveBank]].oam.matrixNum);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void sub_8059744(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter2(void)
+{
+ if (!IsTextPrinterActive(0))
+ PlayerBufferExecCompleted();
+}
+
+static void sub_80597CC(void)
+{
+ if (!gPaletteFade.active)
+ {
+ u8 r4;
+
+ gBattleBankFunc[gActiveBank] = sub_8059828;
+ r4 = gTasks[gUnknown_03005D7C[gActiveBank]].data[0];
+ DestroyTask(gUnknown_03005D7C[gActiveBank]);
+ FreeAllWindowBuffers();
+ sub_81B89AC(r4);
+ }
+}
+
+static void sub_8059828(void)
+{
+ if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
+ {
+ if (gUnknown_0203CEE8 == 1)
+ EmitChosenMonReturnValue(1, gUnknown_0203CEE9, gUnknown_0203CF00);
+ else
+ EmitChosenMonReturnValue(1, 6, NULL);
+
+ if ((gBattleBufferA[gActiveBank][1] & 0xF) == 1)
+ PrintLinkStandbyMsg();
+
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void OpenBagAndChooseItem(void)
+{
+ if (!gPaletteFade.active)
+ {
+ gBattleBankFunc[gActiveBank] = CompleteWhenChoseItem;
+ nullsub_35();
+ FreeAllWindowBuffers();
+ sub_81AABB0();
+ }
+}
+
+static void CompleteWhenChoseItem(void)
+{
+ if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
+ {
+ EmitOneReturnValue(1, gScriptItemId);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnSpecialAnimDone(void)
+{
+ if (!gDoingBattleAnim || !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ PlayerBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void PlayerHandleUnknownYesNoInput(void)
+{
+ if (gMain.newKeys & DPAD_UP && gMultiUsePlayerCursor != 0)
+ {
+ PlaySE(SE_SELECT);
+ BattleDestroyYesNoCursorAt(gMultiUsePlayerCursor);
+ gMultiUsePlayerCursor = 0;
+ BattleCreateYesNoCursorAt(0);
+ }
+ if (gMain.newKeys & DPAD_DOWN && gMultiUsePlayerCursor == 0)
+ {
+ PlaySE(SE_SELECT);
+ BattleDestroyYesNoCursorAt(gMultiUsePlayerCursor);
+ gMultiUsePlayerCursor = 1;
+ BattleCreateYesNoCursorAt(1);
+ }
+ if (gMain.newKeys & A_BUTTON)
+ {
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
+ PlaySE(SE_SELECT);
+
+ if (gMultiUsePlayerCursor != 0)
+ EmitTwoReturnValues(1, 0xE, 0);
+ else
+ EmitTwoReturnValues(1, 0xD, 0);
+
+ PlayerBufferExecCompleted();
+ }
+ if (gMain.newKeys & B_BUTTON)
+ {
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
+ PlaySE(SE_SELECT);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void MoveSelectionDisplayMoveNames(void)
+{
+ s32 i;
+ struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+ gNumberOfMovesToChoose = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ MoveSelectionDestroyCursorAt(i);
+ StringCopy(gDisplayedStringBattle, gMoveNames[moveInfo->moves[i]]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, i + 3);
+ if (moveInfo->moves[i] != MOVE_NONE)
+ gNumberOfMovesToChoose++;
+ }
+}
+
+static void MoveSelectionDisplayPpString(void)
+{
+ StringCopy(gDisplayedStringBattle, gText_MoveInterfacePP);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 7);
+}
+
+static void MoveSelectionDisplayPpNumber(void)
+{
+ u8 *txtPtr;
+ struct ChooseMoveStruct *moveInfo;
+
+ if (gBattleBufferA[gActiveBank][2] == TRUE) // check if we didn't want to display pp number
+ return;
+
+ SetPpNumbersPaletteInMoveSelection();
+ moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+ txtPtr = ConvertIntToDecimalStringN(gDisplayedStringBattle, moveInfo->currentPp[gMoveSelectionCursor[gActiveBank]], STR_CONV_MODE_RIGHT_ALIGN, 2);
+ txtPtr[0] = CHAR_SLASH;
+ txtPtr++;
+ ConvertIntToDecimalStringN(txtPtr, moveInfo->maxPp[gMoveSelectionCursor[gActiveBank]], STR_CONV_MODE_RIGHT_ALIGN, 2);
+
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 9);
+}
+
+static void MoveSelectionDisplayMoveType(void)
+{
+ u8 *txtPtr;
+ struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+
+ txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType);
+ txtPtr[0] = EXT_CTRL_CODE_BEGIN;
+ txtPtr++;
+ txtPtr[0] = 6;
+ txtPtr++;
+ txtPtr[0] = 1;
+ txtPtr++;
+
+ StringCopy(txtPtr, gTypeNames[gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBank]]].type]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 10);
+}
+
+static void MoveSelectionCreateCursorAt(u8 cursorPosition, u8 arg1)
+{
+ u16 src[2];
+ src[0] = arg1 + 1;
+ src[1] = arg1 + 2;
+
+ CopyToBgTilemapBufferRect_ChangePalette(0, src, 9 * (cursorPosition & 1) + 1, 55 + (cursorPosition & 2), 1, 2, 0x11);
+ CopyBgTilemapBufferToVram(0);
+}
+
+static void MoveSelectionDestroyCursorAt(u8 cursorPosition)
+{
+ u16 src[2];
+ src[0] = 0x1016;
+ src[1] = 0x1016;
+
+ CopyToBgTilemapBufferRect_ChangePalette(0, src, 9 * (cursorPosition & 1) + 1, 55 + (cursorPosition & 2), 1, 2, 0x11);
+ CopyBgTilemapBufferToVram(0);
+}
+
+void ActionSelectionCreateCursorAt(u8 cursorPosition, u8 arg1)
+{
+ u16 src[2];
+ src[0] = 1;
+ src[1] = 2;
+
+ CopyToBgTilemapBufferRect_ChangePalette(0, src, 7 * (cursorPosition & 1) + 16, 35 + (cursorPosition & 2), 1, 2, 0x11);
+ CopyBgTilemapBufferToVram(0);
+}
+
+void ActionSelectionDestroyCursorAt(u8 cursorPosition)
+{
+ u16 src[2];
+ src[0] = 0x1016;
+ src[1] = 0x1016;
+
+ CopyToBgTilemapBufferRect_ChangePalette(0, src, 7 * (cursorPosition & 1) + 16, 35 + (cursorPosition & 2), 1, 2, 0x11);
+ CopyBgTilemapBufferToVram(0);
+}
+
+void SetCB2ToReshowScreenAfterMenu(void)
+{
+ SetMainCallback2(ReshowBattleScreenAfterMenu);
+}
+
+void SetCB2ToReshowScreenAfterMenu2(void)
+{
+ SetMainCallback2(ReshowBattleScreenAfterMenu);
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ PlayerBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ PlayerBufferExecCompleted();
+}
+
+static void PrintLinkStandbyMsg(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ BattleHandleAddTextPrinter(gText_LinkStandby, 0);
+ }
+}
+
+static void PlayerHandleGetMonData(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 monsToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyPlayerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monsToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monsToCheck & 1)
+ size += CopyPlayerMonData(i, monData + size);
+ monsToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ PlayerBufferExecCompleted();
+}
+
+static u32 CopyPlayerMonData(u8 monId, u8 *dst)
+{
+ struct BattlePokemon battleMon;
+ struct MovePpInfo moveData;
+ u8 nickname[20];
+ u8 *src;
+ s16 data16;
+ u32 data32;
+ s32 size = 0;
+
+ switch (gBattleBufferA[gActiveBank][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 < 4; 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_SPD_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_SPD);
+ 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.altAbility = GetMonData(&gPlayerParty[monId], MON_DATA_ALT_ABILITY);
+ 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 < 4; 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[gActiveBank][1] - REQUEST_MOVE1_BATTLE);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ for (size = 0; size < 4; 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[gActiveBank][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_SPD_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_SPD_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_SPD_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_SPD);
+ 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;
+}
+
+void PlayerHandleGetRawMonData(void)
+{
+ struct BattlePokemon battleMon;
+ u8 *src = (u8 *)&gPlayerParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 *dst = (u8 *)&battleMon + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = src[i];
+
+ EmitDataTransfer(1, gBattleBufferA[gActiveBank][2], dst);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleSetMonData(void)
+{
+ u8 monsToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetPlayerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monsToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monsToCheck & 1)
+ SetPlayerMonData(i);
+ monsToCheck >>= 1;
+ }
+ }
+ PlayerBufferExecCompleted();
+}
+
+static void SetPlayerMonData(u8 monId)
+{
+ struct BattlePokemon *battlePokemon = (struct BattlePokemon *)&gBattleBufferA[gActiveBank][3];
+ struct MovePpInfo *moveData = (struct MovePpInfo *)&gBattleBufferA[gActiveBank][3];
+ s32 i;
+
+ switch (gBattleBufferA[gActiveBank][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 < 4; 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_SPD_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_SPD, &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[gActiveBank][3]);
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MOVES_PP_BATTLE:
+ for (i = 0; i < 4; 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[gActiveBank][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &gBattleBufferA[gActiveBank][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[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_OTID_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_EXP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_IV, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][7]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][8]);
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_STATUS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ }
+
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+}
+
+static void PlayerHandleSetRawMonData(void)
+{
+ u8 *dst = (u8 *)&gPlayerParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = gBattleBufferA[gActiveBank][3 + i];
+
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleLoadMonSprite(void)
+{
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpritePosX_0;
+}
+
+static void PlayerHandleSwitchInAnim(void)
+{
+ ClearTemporarySpeciesSpriteData(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ gActionSelectionCursor[gActiveBank] = 0;
+ gMoveSelectionCursor[gActiveBank] = 0;
+ sub_805B258(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_805902C;
+}
+
+static void sub_805B258(u8 bank, bool8 dontClearSubstituteBit)
+{
+ u16 species;
+
+ ClearTemporarySpeciesSpriteData(bank, dontClearSubstituteBit);
+ gBattlePartyID[bank] = gBattleBufferA[bank][1];
+ species = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES);
+ gUnknown_03005D7C[bank] = CreateInvisibleSpriteWithCallback(sub_805D714);
+ sub_806A068(species, GetBankIdentity(bank));
+
+ gBankSpriteIds[bank] = CreateSprite(
+ &gUnknown_0202499C,
+ sub_80A5C6C(bank, 2),
+ sub_80A6138(bank),
+ sub_80A82E4(bank));
+
+ gSprites[gUnknown_03005D7C[bank]].data1 = gBankSpriteIds[bank];
+ gSprites[gUnknown_03005D7C[bank]].data2 = bank;
+
+ gSprites[gBankSpriteIds[bank]].data0 = bank;
+ gSprites[gBankSpriteIds[bank]].data2 = species;
+ gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank;
+
+ StartSpriteAnim(&gSprites[gBankSpriteIds[bank]], gBattleMonForms[bank]);
+
+ gSprites[gBankSpriteIds[bank]].invisible = TRUE;
+ gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy;
+
+ gSprites[gUnknown_03005D7C[bank]].data0 = sub_80753E8(0, 0xFF);
+}
+
+static void PlayerHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = DoSwitchOutAnimation;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void DoSwitchOutAnimation(void)
+{
+ switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState)
+ {
+ case 0:
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 1;
+ break;
+ case 1:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SWITCH_OUT_MON);
+ gBattleBankFunc[gActiveBank] = sub_8059744;
+ }
+ break;
+ }
+}
+
+// todo: get rid of it once the struct is declared in a header
+struct MonCoords
+{
+ // This would use a bitfield, but sub_8079F44
+ // uses it as a u8 and casting won't match.
+ u8 coords; // u8 x:4, y:4;
+ u8 y_offset;
+};
+extern const struct MonCoords gTrainerBackPicCoords[];
+extern const struct MonCoords gTrainerFrontPicCoords[];
+
+// some explanation here
+// in emerald it's possible to have a tag battle in the battle frontier facilities with AI
+// which use the front sprite for both the player and the partner as opposed to any other battles (including the one with Steven) that use the back pic as well as animate it
+static void PlayerHandleDrawTrainerPic(void)
+{
+ s16 xPos, yPos;
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_FIRE_RED
+ || (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_LEAF_GREEN)
+ {
+ trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + BACK_PIC_RED;
+ }
+ else if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_RUBY
+ || (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_SAPPHIRE)
+ {
+ trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + BACK_PIC_RS_BRENDAN;
+ }
+ else
+ {
+ trainerPicId = gLinkPlayers[GetMultiplayerId()].gender;
+ }
+ }
+ else
+ {
+ trainerPicId = gSaveBlock2Ptr->playerGender;
+ }
+
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ if ((GetBankIdentity(gActiveBank) & BIT_MON) != 0) // second mon
+ xPos = 90;
+ else // first mon
+ xPos = 32;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != STEVEN_PARTNER_ID)
+ {
+ xPos = 90;
+ yPos = (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+ else
+ {
+ yPos = (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+
+ }
+ else
+ {
+ xPos = 80;
+ yPos = (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+
+ // Use front pic table for any tag battles unless your partner is Steven.
+ if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != STEVEN_PARTNER_ID)
+ {
+ trainerPicId = PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender);
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A1C0(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, yPos, sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.y = 48;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineMode = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].hFlip = 1;
+ }
+ // use the back pic in any other scenario
+ else
+ {
+ DecompressTrainerBackPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, yPos, sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void PlayerHandleTrainerSlide(void)
+{
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_FIRE_RED
+ || (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_LEAF_GREEN)
+ {
+ trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + BACK_PIC_RED;
+ }
+ else if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_RUBY
+ || (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_SAPPHIRE)
+ {
+ trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + BACK_PIC_RS_BRENDAN;
+ }
+ else
+ {
+ trainerPicId = gLinkPlayers[GetMultiplayerId()].gender;
+ }
+ }
+ else
+ {
+ trainerPicId = gSaveBlock2Ptr->playerGender;
+ }
+
+ DecompressTrainerBackPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, 80, (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80, 30);
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = -96;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy2;
+}
+
+static void PlayerHandleTrainerSlideBack(void)
+{
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 50;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = -40;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], SpriteCallbackDummy);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 1);
+ gBattleBankFunc[gActiveBank] = sub_80588B4;
+}
+
+static void PlayerHandleFaintAnimation(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState == 0)
+ {
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState++;
+ }
+ else
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ PlaySE12WithPanning(SE_POKE_DEAD, -64);
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 5;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039C00;
+ gBattleBankFunc[gActiveBank] = sub_80596A8;
+ }
+ }
+}
+
+static void PlayerHandlePaletteFade(void)
+{
+ BeginNormalPaletteFade(-1, 2, 0, 16, 0);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleSuccessBallThrowAnim(void)
+{
+ gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
+ gDoingBattleAnim = TRUE;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, GetBankByIdentity(IDENTITY_OPPONENT_MON1), B_ANIM_BALL_THROW);
+ gBattleBankFunc[gActiveBank] = CompleteOnSpecialAnimDone;
+}
+
+static void PlayerHandleBallThrowAnim(void)
+{
+ u8 ballThrowCaseId = gBattleBufferA[gActiveBank][1];
+
+ gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId;
+ gDoingBattleAnim = TRUE;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, GetBankByIdentity(IDENTITY_OPPONENT_MON1), B_ANIM_BALL_THROW);
+ gBattleBankFunc[gActiveBank] = CompleteOnSpecialAnimDone;
+}
+
+static void PlayerHandlePause(void)
+{
+ u8 var = gBattleBufferA[gActiveBank][1];
+
+ // WTF is this??
+ while (var != 0)
+ var--;
+
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleMoveAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+
+ gAnimMoveTurn = gBattleBufferA[gActiveBank][3];
+ gAnimMovePower = gBattleBufferA[gActiveBank][4] | (gBattleBufferA[gActiveBank][5] << 8);
+ gAnimMoveDmg = gBattleBufferA[gActiveBank][6] | (gBattleBufferA[gActiveBank][7] << 8) | (gBattleBufferA[gActiveBank][8] << 16) | (gBattleBufferA[gActiveBank][9] << 24);
+ gAnimFriendship = gBattleBufferA[gActiveBank][10];
+ gWeatherMoveAnim = gBattleBufferA[gActiveBank][12] | (gBattleBufferA[gActiveBank][13] << 8);
+ gAnimDisableStructPtr = (struct DisableStruct *)&gBattleBufferA[gActiveBank][16];
+ gTransformedPersonalities[gActiveBank] = gAnimDisableStructPtr->transformedMonPersonality;
+ if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
+ {
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = PlayerDoMoveAnimation;
+ sub_817E0FC(move, gWeatherMoveAnim, gAnimDisableStructPtr);
+ }
+ }
+}
+
+static void PlayerDoMoveAnimation(void)
+{
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+ u8 multihit = gBattleBufferA[gActiveBank][11];
+
+ switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState)
+ {
+ case 0:
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute
+ && !gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8)
+ {
+ gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8 = 1;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 1;
+ break;
+ case 1:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ sub_805EB9C(0);
+ DoMoveAnim(move);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 2;
+ }
+ break;
+ case 2:
+ gAnimScriptCallback();
+ if (!gAnimScriptActive)
+ {
+ sub_805EB9C(1);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute && multihit < 2)
+ {
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+ gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8 = 0;
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 3;
+ }
+ break;
+ case 3:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ sub_805E394();
+ TrySetBehindSubstituteSpriteBit(gActiveBank, gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ PlayerBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void PlayerHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter2;
+ sub_817C95C(*stringId);
+ sub_81A57E4(gActiveBank, *stringId);
+}
+
+static void PlayerHandlePrintStringPlayerOnly(void)
+{
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ PlayerHandlePrintString();
+ else
+ PlayerBufferExecCompleted();
+}
+
+static void HandleChooseActionAfterDma3(void)
+{
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 160;
+ gBattleBankFunc[gActiveBank] = HandleInputChooseAction;
+ }
+}
+
+static void PlayerHandleChooseAction(void)
+{
+ s32 i;
+
+ gBattleBankFunc[gActiveBank] = HandleChooseActionAfterDma3;
+ sub_817F2A8();
+ BattleHandleAddTextPrinter(gText_BattleMenu, 2);
+
+ for (i = 0; i < 4; i++)
+ ActionSelectionDestroyCursorAt(i);
+
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 1);
+}
+
+static void PlayerHandleUnknownYesNoBox(void)
+{
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 12);
+ gMultiUsePlayerCursor = 1;
+ BattleCreateYesNoCursorAt(1);
+ gBattleBankFunc[gActiveBank] = PlayerHandleUnknownYesNoInput;
+ }
+ else
+ {
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void HandleChooseMoveAfterDma3(void)
+{
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 320;
+ gBattleBankFunc[gActiveBank] = HandleInputChooseMove;
+ }
+}
+
+static void PlayerChooseMoveInBattlePalace(void)
+{
+ if (--*(gBattleStruct->field_298 + gActiveBank) == 0)
+ {
+ gBattlePalaceMoveSelectionRngValue = gRngValue;
+ EmitTwoReturnValues(1, 10, ChooseMoveAndTargetInBattlePalace());
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void PlayerHandleChooseMove(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
+ {
+ *(gBattleStruct->field_298 + gActiveBank) = 8;
+ gBattleBankFunc[gActiveBank] = PlayerChooseMoveInBattlePalace;
+ }
+ else
+ {
+ InitMoveSelectionsVarsAndStrings();
+ gBattleBankFunc[gActiveBank] = HandleChooseMoveAfterDma3;
+ }
+}
+
+void InitMoveSelectionsVarsAndStrings(void)
+{
+ MoveSelectionDisplayMoveNames();
+ gMultiUsePlayerCursor = 0xFF;
+ MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBank], 0);
+ MoveSelectionDisplayPpString();
+ MoveSelectionDisplayPpNumber();
+ MoveSelectionDisplayMoveType();
+}
+
+static void PlayerHandleChooseItem(void)
+{
+ s32 i;
+
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gBattleBankFunc[gActiveBank] = OpenBagAndChooseItem;
+ gBankInMenu = gActiveBank;
+
+ for (i = 0; i < 3; i++)
+ gUnknown_0203CF00[i] = gBattleBufferA[gActiveBank][1 + i];
+}
+
+static void PlayerHandleChoosePokemon(void)
+{
+ s32 i;
+
+ for (i = 0; i < 3; i++)
+ gUnknown_0203CF00[i] = gBattleBufferA[gActiveBank][4 + i];
+
+ if (gBattleTypeFlags & BATTLE_TYPE_ARENA && (gBattleBufferA[gActiveBank][1] & 0xF) != 2)
+ {
+ EmitChosenMonReturnValue(1, gBattlePartyID[gActiveBank] + 1, gUnknown_0203CF00);
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ gUnknown_03005D7C[gActiveBank] = CreateTask(TaskDummy, 0xFF);
+ gTasks[gUnknown_03005D7C[gActiveBank]].data[0] = gBattleBufferA[gActiveBank][1] & 0xF;
+ *(&gBattleStruct->field_49) = gBattleBufferA[gActiveBank][1] >> 4;
+ *(&gBattleStruct->field_8B) = gBattleBufferA[gActiveBank][2];
+ *(&gBattleStruct->field_B0) = gBattleBufferA[gActiveBank][3];
+ BeginNormalPaletteFade(-1, 0, 0, 16, 0);
+ gBattleBankFunc[gActiveBank] = sub_80597CC;
+ gBankInMenu = gActiveBank;
+ }
+}
+
+static void PlayerHandleCmd23(void)
+{
+ BattleMusicStop();
+ BeginNormalPaletteFade(-1, 2, 0, 16, 0);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleHealthBarUpdate(void)
+{
+ s16 hpVal;
+
+ LoadBattleBarGfx(0);
+ hpVal = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (hpVal > 0)
+ gUnknown_0203CD70 += hpVal;
+
+ if (hpVal != INSTANT_HP_BAR_DROP)
+ {
+ u32 maxHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+ u32 curHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, curHP, hpVal);
+ }
+ else
+ {
+ u32 maxHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, 0, hpVal);
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], 0, HP_CURRENT);
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthbarDone;
+}
+
+static void PlayerHandleExpUpdate(void)
+{
+ u8 monId = gBattleBufferA[gActiveBank][1];
+
+ if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_MON_LEVEL)
+ {
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ s16 expPointsToGive;
+ u8 taskId;
+
+ LoadBattleBarGfx(1);
+ GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); // unused return value
+ expPointsToGive = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+ taskId = CreateTask(Task_GiveExpToMon, 10);
+ gTasks[taskId].tExpTask_monId = monId;
+ gTasks[taskId].tExpTask_gainedExp = expPointsToGive;
+ gTasks[taskId].tExpTask_bank = gActiveBank;
+ gBattleBankFunc[gActiveBank] = nullsub_21;
+ }
+}
+
+#undef tExpTask_monId
+#undef tExpTask_gainedExp
+#undef tExpTask_bank
+#undef tExpTask_frames
+
+static void PlayerHandleStatusIconUpdate(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 bank;
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_STATUS_ICON);
+ bank = gActiveBank;
+ gBattleSpritesDataPtr->healthBoxesData[bank].statusAnimActive = 0;
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void PlayerHandleStatusAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ DoStatusAnimation(gBattleBufferA[gActiveBank][1],
+ gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8) | (gBattleBufferA[gActiveBank][4] << 16) | (gBattleBufferA[gActiveBank][5] << 24));
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void PlayerHandleStatusXor(void)
+{
+ u8 val = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_STATUS) ^ gBattleBufferA[gActiveBank][1];
+
+ SetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_STATUS, &val);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleDataTransfer(void)
+{
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleDMA3Transfer(void)
+{
+ u32 dstArg = gBattleBufferA[gActiveBank][1]
+ | (gBattleBufferA[gActiveBank][2] << 8)
+ | (gBattleBufferA[gActiveBank][3] << 16)
+ | (gBattleBufferA[gActiveBank][4] << 24);
+ u16 sizeArg = gBattleBufferA[gActiveBank][5] | (gBattleBufferA[gActiveBank][6] << 8);
+
+ const u8 *src = &gBattleBufferA[gActiveBank][7];
+ u8 *dst = (u8*)(dstArg);
+ u32 size = sizeArg;
+
+ while (1)
+ {
+ if (size <= 0x1000)
+ {
+ DmaCopy16(3, src, dst, size);
+ break;
+ }
+ DmaCopy16(3, src, dst, 0x1000);
+ src += 0x1000;
+ dst += 0x1000;
+ size -= 0x1000;
+ }
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandlePlayBGM(void)
+{
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd32(void)
+{
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleTwoReturnValues(void)
+{
+ EmitTwoReturnValues(1, 0, 0);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleChosenMonReturnValue(void)
+{
+ EmitChosenMonReturnValue(1, 0, NULL);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleOneReturnValue(void)
+{
+ EmitOneReturnValue(1, 0);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleOneReturnValue_Duplicate(void)
+{
+ EmitOneReturnValue_Duplicate(1, 0);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = 1;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void PlayerHandleCmd42(void)
+{
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleEffectivenessSound(void)
+{
+ s8 pan;
+
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ pan = PAN_SIDE_PLAYER;
+ else
+ pan = PAN_SIDE_OPPONENT;
+
+ PlaySE12WithPanning(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8), pan);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, -25, 5);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleIntroTrainerBallThrow(void)
+{
+ u8 paletteNum;
+ u8 taskId;
+
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 50;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = -40;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ gSprites[gBankSpriteIds[gActiveBank]].data5 = gActiveBank;
+
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], sub_805CC00);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 1);
+
+ paletteNum = AllocSpritePalette(0xD6F8);
+ LoadCompressedPalette(gTrainerBackPicPaletteTable[gSaveBlock2Ptr->playerGender].data, 0x100 + paletteNum * 16, 32);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = paletteNum;
+
+ taskId = CreateTask(task05_08033660, 5);
+ gTasks[taskId].data[0] = gActiveBank;
+
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 1;
+ gBattleBankFunc[gActiveBank] = nullsub_21;
+}
+
+void sub_805CC00(struct Sprite *sprite)
+{
+ u8 bank = sprite->data5;
+
+ FreeSpriteOamMatrix(sprite);
+ FreeSpritePaletteByTag(GetSpritePaletteTagByPaletteNum(sprite->oam.paletteNum));
+ DestroySprite(sprite);
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[bank]], bank);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[bank]], 0);
+}
+
+static void task05_08033660(u8 taskId)
+{
+ if (gTasks[taskId].data[1] < 31)
+ {
+ gTasks[taskId].data[1]++;
+ }
+ else
+ {
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_805B258(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_805B258(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_805B258(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_8058B40;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+ }
+}
+
+static void PlayerHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ PlayerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+ gUnknown_020244B4[gActiveBank] = CreatePartyStatusSummarySprites(gActiveBank, (struct HpAndStatus *)&gBattleBufferA[gActiveBank][4], gBattleBufferA[gActiveBank][1], gBattleBufferA[gActiveBank][2]);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+
+ if (gBattleBufferA[gActiveBank][2] != 0)
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0x5D;
+
+ gBattleBankFunc[gActiveBank] = sub_805CE38;
+ }
+}
+
+static void sub_805CE38(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ PlayerBufferExecCompleted();
+ }
+}
+
+static void PlayerHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd50(void)
+{
+ dp11b_obj_free(gActiveBank, 1);
+ dp11b_obj_free(gActiveBank, 0);
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleSpriteInvisibility(void)
+{
+ if (AnimBankSpriteExists(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ SetBattleSpriteInvisibilityBitToSpriteInvisibility(gActiveBank);
+ }
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleBattleAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 animationId = gBattleBufferA[gActiveBank][1];
+ u16 argument = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (DoBattleAnimationFromTable(gActiveBank, gActiveBank, gActiveBank, animationId, argument))
+ PlayerBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+
+ sub_817E32C(animationId);
+ }
+}
+
+static void PlayerHandleLinkStandbyMsg(void)
+{
+ sub_81851A8(&gBattleBufferA[gActiveBank][2]);
+ switch (gBattleBufferA[gActiveBank][1])
+ {
+ case 0:
+ PrintLinkStandbyMsg();
+ // fall through
+ case 1:
+ dp11b_obj_free(gActiveBank, 1);
+ dp11b_obj_free(gActiveBank, 0);
+ break;
+ case 2:
+ PrintLinkStandbyMsg();
+ break;
+ }
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleResetActionMoveSelection(void)
+{
+ switch (gBattleBufferA[gActiveBank][1])
+ {
+ case RESET_ACTION_MOVE_SELECTION:
+ gActionSelectionCursor[gActiveBank] = 0;
+ gMoveSelectionCursor[gActiveBank] = 0;
+ break;
+ case RESET_ACTION_SELECTION:
+ gActionSelectionCursor[gActiveBank] = 0;
+ break;
+ case RESET_MOVE_SELECTION:
+ gMoveSelectionCursor[gActiveBank] = 0;
+ break;
+ }
+ PlayerBufferExecCompleted();
+}
+
+static void PlayerHandleCmd55(void)
+{
+ sub_81851A8(&gBattleBufferA[gActiveBank][4]);
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ gSaveBlock2Ptr->field_CA9_b = gBattleBufferA[gActiveBank][2];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ PlayerBufferExecCompleted();
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_22(void)
+{
+}
diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c
new file mode 100644
index 000000000..25eaf773f
--- /dev/null
+++ b/src/battle_controller_player_partner.c
@@ -0,0 +1,1970 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "battle_ai_script_commands.h"
+#include "pokemon.h"
+#include "link.h"
+#include "util.h"
+#include "main.h"
+#include "songs.h"
+#include "sound.h"
+#include "window.h"
+#include "m4a.h"
+#include "palette.h"
+#include "task.h"
+#include "text.h"
+#include "string_util.h"
+#include "bg.h"
+#include "reshow_battle_screen.h"
+#include "pokeball.h"
+
+extern u32 gBattleExecBuffer;
+extern u8 gActiveBank;
+extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
+extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT];
+extern u8 gNoOfAllBanks;
+extern bool8 gDoingBattleAnim;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+extern void (*gPreBattleCallback1)(void);
+extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
+extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
+extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
+extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
+extern struct SpriteTemplate gUnknown_0202499C;
+extern u16 gScriptItemId;
+extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
+extern u8 gBattleOutcome;
+extern u16 gBattle_BG0_X;
+extern u16 gBattle_BG0_Y;
+extern u8 gBankInMenu;
+extern u16 gUnknown_020243FC;
+extern u8 gUnknown_03005D7C[BATTLE_BANKS_COUNT];
+extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
+extern u16 gPartnerTrainerId;
+extern u8 GetFrontierTrainerFrontSpriteId(u16 trainerId);
+extern u8 gBankTarget;
+extern u8 gAbsentBankFlags;
+extern u8 gUnknown_020244B4[];
+extern u32 gTransformedPersonalities[BATTLE_BANKS_COUNT];
+extern struct UnusedControllerStruct gUnknown_02022D0C;
+
+extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
+extern const struct CompressedSpritePalette gTrainerBackPicPaletteTable[];
+extern const struct BattleMove gBattleMoves[];
+
+extern void sub_81358F4(void);
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+
+// this file's functions
+static void PlayerPartnerHandleGetMonData(void);
+static void PlayerPartnerHandleGetRawMonData(void);
+static void PlayerPartnerHandleSetMonData(void);
+static void PlayerPartnerHandleSetRawMonData(void);
+static void PlayerPartnerHandleLoadMonSprite(void);
+static void PlayerPartnerHandleSwitchInAnim(void);
+static void PlayerPartnerHandleReturnMonToBall(void);
+static void PlayerPartnerHandleDrawTrainerPic(void);
+static void PlayerPartnerHandleTrainerSlide(void);
+static void PlayerPartnerHandleTrainerSlideBack(void);
+static void PlayerPartnerHandleFaintAnimation(void);
+static void PlayerPartnerHandlePaletteFade(void);
+static void PlayerPartnerHandleSuccessBallThrowAnim(void);
+static void PlayerPartnerHandleBallThrowAnim(void);
+static void PlayerPartnerHandlePause(void);
+static void PlayerPartnerHandleMoveAnimation(void);
+static void PlayerPartnerHandlePrintString(void);
+static void PlayerPartnerHandlePrintStringPlayerOnly(void);
+static void PlayerPartnerHandleChooseAction(void);
+static void PlayerPartnerHandleUnknownYesNoBox(void);
+static void PlayerPartnerHandleChooseMove(void);
+static void PlayerPartnerHandleChooseItem(void);
+static void PlayerPartnerHandleChoosePokemon(void);
+static void PlayerPartnerHandleCmd23(void);
+static void PlayerPartnerHandleHealthBarUpdate(void);
+static void PlayerPartnerHandleExpUpdate(void);
+static void PlayerPartnerHandleStatusIconUpdate(void);
+static void PlayerPartnerHandleStatusAnimation(void);
+static void PlayerPartnerHandleStatusXor(void);
+static void PlayerPartnerHandleDataTransfer(void);
+static void PlayerPartnerHandleDMA3Transfer(void);
+static void PlayerPartnerHandlePlayBGM(void);
+static void PlayerPartnerHandleCmd32(void);
+static void PlayerPartnerHandleTwoReturnValues(void);
+static void PlayerPartnerHandleChosenMonReturnValue(void);
+static void PlayerPartnerHandleOneReturnValue(void);
+static void PlayerPartnerHandleOneReturnValue_Duplicate(void);
+static void PlayerPartnerHandleCmd37(void);
+static void PlayerPartnerHandleCmd38(void);
+static void PlayerPartnerHandleCmd39(void);
+static void PlayerPartnerHandleCmd40(void);
+static void PlayerPartnerHandleHitAnimation(void);
+static void PlayerPartnerHandleCmd42(void);
+static void PlayerPartnerHandleEffectivenessSound(void);
+static void PlayerPartnerHandlePlayFanfareOrBGM(void);
+static void PlayerPartnerHandleFaintingCry(void);
+static void PlayerPartnerHandleIntroSlide(void);
+static void PlayerPartnerHandleIntroTrainerBallThrow(void);
+static void PlayerPartnerHandleDrawPartyStatusSummary(void);
+static void PlayerPartnerHandleCmd49(void);
+static void PlayerPartnerHandleCmd50(void);
+static void PlayerPartnerHandleSpriteInvisibility(void);
+static void PlayerPartnerHandleBattleAnimation(void);
+static void PlayerPartnerHandleLinkStandbyMsg(void);
+static void PlayerPartnerHandleResetActionMoveSelection(void);
+static void PlayerPartnerHandleCmd55(void);
+static void nullsub_128(void);
+
+static void PlayerPartnerBufferRunCommand(void);
+static void PlayerPartnerBufferExecCompleted(void);
+static void sub_81BB628(u8 taskId);
+static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId);
+static void Task_PrepareToGiveExpWithExpBar(u8 taskId);
+static void sub_81BB4E4(u8 taskId);
+static void sub_81BB628(u8 taskId);
+static void sub_81BB688(u8 taskId);
+static void sub_81BB9A0(void);
+static u32 CopyPlayerPartnerMonData(u8 monId, u8 *dst);
+static void SetPlayerPartnerMonData(u8 monId);
+static void sub_81BD0E4(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void PlayerPartnerDoMoveAnimation(void);
+static void sub_81BE2C8(u8 taskId);
+static void sub_81BE498(void);
+
+static void (*const gPlayerPartnerBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ PlayerPartnerHandleGetMonData,
+ PlayerPartnerHandleGetRawMonData,
+ PlayerPartnerHandleSetMonData,
+ PlayerPartnerHandleSetRawMonData,
+ PlayerPartnerHandleLoadMonSprite,
+ PlayerPartnerHandleSwitchInAnim,
+ PlayerPartnerHandleReturnMonToBall,
+ PlayerPartnerHandleDrawTrainerPic,
+ PlayerPartnerHandleTrainerSlide,
+ PlayerPartnerHandleTrainerSlideBack,
+ PlayerPartnerHandleFaintAnimation,
+ PlayerPartnerHandlePaletteFade,
+ PlayerPartnerHandleSuccessBallThrowAnim,
+ PlayerPartnerHandleBallThrowAnim,
+ PlayerPartnerHandlePause,
+ PlayerPartnerHandleMoveAnimation,
+ PlayerPartnerHandlePrintString,
+ PlayerPartnerHandlePrintStringPlayerOnly,
+ PlayerPartnerHandleChooseAction,
+ PlayerPartnerHandleUnknownYesNoBox,
+ PlayerPartnerHandleChooseMove,
+ PlayerPartnerHandleChooseItem,
+ PlayerPartnerHandleChoosePokemon,
+ PlayerPartnerHandleCmd23,
+ PlayerPartnerHandleHealthBarUpdate,
+ PlayerPartnerHandleExpUpdate,
+ PlayerPartnerHandleStatusIconUpdate,
+ PlayerPartnerHandleStatusAnimation,
+ PlayerPartnerHandleStatusXor,
+ PlayerPartnerHandleDataTransfer,
+ PlayerPartnerHandleDMA3Transfer,
+ PlayerPartnerHandlePlayBGM,
+ PlayerPartnerHandleCmd32,
+ PlayerPartnerHandleTwoReturnValues,
+ PlayerPartnerHandleChosenMonReturnValue,
+ PlayerPartnerHandleOneReturnValue,
+ PlayerPartnerHandleOneReturnValue_Duplicate,
+ PlayerPartnerHandleCmd37,
+ PlayerPartnerHandleCmd38,
+ PlayerPartnerHandleCmd39,
+ PlayerPartnerHandleCmd40,
+ PlayerPartnerHandleHitAnimation,
+ PlayerPartnerHandleCmd42,
+ PlayerPartnerHandleEffectivenessSound,
+ PlayerPartnerHandlePlayFanfareOrBGM,
+ PlayerPartnerHandleFaintingCry,
+ PlayerPartnerHandleIntroSlide,
+ PlayerPartnerHandleIntroTrainerBallThrow,
+ PlayerPartnerHandleDrawPartyStatusSummary,
+ PlayerPartnerHandleCmd49,
+ PlayerPartnerHandleCmd50,
+ PlayerPartnerHandleSpriteInvisibility,
+ PlayerPartnerHandleBattleAnimation,
+ PlayerPartnerHandleLinkStandbyMsg,
+ PlayerPartnerHandleResetActionMoveSelection,
+ PlayerPartnerHandleCmd55,
+ nullsub_128
+};
+
+// unknown unused data
+static const u8 gUnknown_08617254[] =
+{
+ 0x83, 0x4d, 0xf3, 0x5f, 0x6f, 0x4f, 0xeb, 0x3e,
+ 0x67, 0x2e, 0x10, 0x46, 0x8c, 0x3d, 0x28, 0x35,
+ 0xc5, 0x2c, 0x15, 0x7f, 0xb5, 0x56, 0x9d, 0x53,
+ 0x3b, 0x43, 0xda, 0x36, 0x79, 0x2a, 0x0e, 0x53,
+};
+
+static void nullsub_77(void)
+{
+}
+
+void SetBankFuncToPlayerPartnerBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerPartnerBufferRunCommand;
+}
+
+static void PlayerPartnerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(gPlayerPartnerBufferCommands))
+ gPlayerPartnerBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void sub_81BAE98(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ nullsub_25(0);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_81BAF00(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_81BAF48(void)
+{
+ bool32 r6 = FALSE;
+
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ r6 = TRUE;
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ {
+ r6 = TRUE;
+ }
+ }
+
+ if (IsCryPlayingOrClearCrySongs())
+ r6 = FALSE;
+
+ if (r6)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_81BAF00;
+ }
+}
+
+static void sub_81BB02C(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8
+ && gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy
+ && ++gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 != 1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank ^ BIT_MON]]);
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank ^ BIT_MON], &gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank ^ BIT_MON);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank ^ BIT_MON]);
+ }
+
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 0;
+
+ gBattleBankFunc[gActiveBank] = sub_81BAF48;
+ }
+}
+
+static void sub_81BB1D4(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].animEnded && gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0)
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], 0, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ PlayerPartnerBufferExecCompleted();
+}
+
+// the whole exp task is copied&pasted from player controller
+#define tExpTask_monId data[0]
+#define tExpTask_gainedExp data[1]
+#define tExpTask_bank data[2]
+#define tExpTask_frames data[10]
+
+static void Task_GiveExpToMon(u8 taskId)
+{
+ u32 monId = (u8)(gTasks[taskId].tExpTask_monId);
+ u8 bank = gTasks[taskId].tExpTask_bank;
+ s16 gainedExp = gTasks[taskId].tExpTask_gainedExp;
+
+ if (IsDoubleBattle() == TRUE || monId != gBattlePartyID[bank]) // give exp without 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 savedActiveBank;
+
+ SetMonData(mon, MON_DATA_EXP, &nextLvlExp);
+ CalculateMonStats(mon);
+ gainedExp -= nextLvlExp - currExp;
+ savedActiveBank = gActiveBank;
+ gActiveBank = bank;
+ EmitTwoReturnValues(1, RET_VALUE_LEVELLED_UP, gainedExp);
+ gActiveBank = savedActiveBank;
+
+ if (IsDoubleBattle() == TRUE
+ && ((u16)(monId) == gBattlePartyID[bank] || (u16)(monId) == gBattlePartyID[bank ^ BIT_MON]))
+ gTasks[taskId].func = sub_81BB628;
+ else
+ gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter;
+ }
+ else
+ {
+ currExp += gainedExp;
+ SetMonData(mon, MON_DATA_EXP, &currExp);
+ gBattleBankFunc[bank] = CompleteOnInactiveTextPrinter;
+ 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 bank = gTasks[taskId].tExpTask_bank;
+ 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(bank, gHealthBoxesIds[bank], expToNextLvl, exp, -gainedExp);
+ PlaySE(SE_EXP);
+ gTasks[taskId].func = sub_81BB4E4;
+}
+
+static void sub_81BB4E4(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 bank = gTasks[taskId].tExpTask_bank;
+ s16 r4;
+
+ r4 = sub_8074AA0(bank, gHealthBoxesIds[bank], EXP_BAR, 0);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[bank]);
+ if (r4 == -1)
+ {
+ 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 savedActiveBank;
+
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl);
+ CalculateMonStats(&gPlayerParty[monId]);
+ gainedExp -= expOnNextLvl - currExp;
+ savedActiveBank = gActiveBank;
+ gActiveBank = bank;
+ EmitTwoReturnValues(1, RET_VALUE_LEVELLED_UP, gainedExp);
+ gActiveBank = savedActiveBank;
+ gTasks[taskId].func = sub_81BB628;
+ }
+ else
+ {
+ currExp += gainedExp;
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp);
+ gBattleBankFunc[bank] = CompleteOnInactiveTextPrinter;
+ DestroyTask(taskId);
+ }
+ }
+ }
+}
+
+static void sub_81BB628(u8 taskId)
+{
+ u8 bank = gTasks[taskId].tExpTask_bank;
+ u8 monIndex = gTasks[taskId].tExpTask_monId;
+
+ if (IsDoubleBattle() == TRUE && monIndex == gBattlePartyID[bank ^ BIT_MON])
+ bank ^= BIT_MON;
+
+ DoSpecialBattleAnimation(bank, bank, bank, B_ANIM_LVL_UP);
+ gTasks[taskId].func = sub_81BB688;
+}
+
+static void sub_81BB688(u8 taskId)
+{
+ u8 bank = gTasks[taskId].tExpTask_bank;
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[bank].specialAnimActive)
+ {
+ u8 monIndex = gTasks[taskId].tExpTask_monId;
+
+ GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value
+
+ if (IsDoubleBattle() == TRUE && monIndex == gBattlePartyID[bank ^ BIT_MON])
+ UpdateHealthboxAttribute(gHealthBoxesIds[bank ^ BIT_MON], &gPlayerParty[monIndex], HEALTHBOX_ALL);
+ else
+ UpdateHealthboxAttribute(gHealthBoxesIds[bank], &gPlayerParty[monIndex], HEALTHBOX_ALL);
+
+ gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter;
+ }
+}
+
+static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId)
+{
+ u8 monIndex;
+ u8 bank;
+
+ monIndex = gTasks[taskId].tExpTask_monId;
+ GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value
+ bank = gTasks[taskId].tExpTask_bank;
+ gBattleBankFunc[bank] = CompleteOnInactiveTextPrinter;
+ DestroyTask(taskId);
+}
+
+static void sub_81BB78C(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].pos1.y + gSprites[gBankSpriteIds[gActiveBank]].pos2.y > DISPLAY_HEIGHT)
+ {
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ nullsub_24(species);
+ FreeOamMatrix(gSprites[gBankSpriteIds[gActiveBank]].oam.matrixNum);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_81BB828(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter2(void)
+{
+ if (!IsTextPrinterActive(0))
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ PlayerPartnerBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_81BB92C(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ SetBattleSpriteInvisibilityBitToSpriteInvisibility(gActiveBank);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+
+ gBattleBankFunc[gActiveBank] = sub_81BB9A0;
+ }
+}
+
+static void sub_81BB9A0(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_81BB9F4(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ CreateTask(c3_0802FDF4, 10);
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 0);
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ gBattleBankFunc[gActiveBank] = sub_81BB92C;
+ }
+}
+
+static void sub_81BBAE8(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ sub_8172EF0(gActiveBank, &gPlayerParty[gBattlePartyID[gActiveBank]]);
+ }
+
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ gBattleBankFunc[gActiveBank] = sub_81BB9F4;
+ }
+}
+
+static void PlayerPartnerBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerPartnerBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTOLLER_CMDS_COUNT - 1;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleGetMonData(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 monsToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyPlayerPartnerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monsToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monsToCheck & 1)
+ size += CopyPlayerPartnerMonData(i, monData + size);
+ monsToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ PlayerPartnerBufferExecCompleted();
+}
+
+static u32 CopyPlayerPartnerMonData(u8 monId, u8 *dst)
+{
+ struct BattlePokemon battleMon;
+ struct MovePpInfo moveData;
+ u8 nickname[20];
+ u8 *src;
+ s16 data16;
+ u32 data32;
+ s32 size = 0;
+
+ switch (gBattleBufferA[gActiveBank][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 < 4; 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_SPD_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_SPD);
+ 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.altAbility = GetMonData(&gPlayerParty[monId], MON_DATA_ALT_ABILITY);
+ 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 < 4; 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[gActiveBank][1] - REQUEST_MOVE1_BATTLE);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ for (size = 0; size < 4; 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[gActiveBank][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_SPD_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_SPD_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_SPD_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_SPD);
+ 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 PlayerPartnerHandleGetRawMonData(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleSetMonData(void)
+{
+ u8 monsToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetPlayerPartnerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monsToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monsToCheck & 1)
+ SetPlayerPartnerMonData(i);
+ monsToCheck >>= 1;
+ }
+ }
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void SetPlayerPartnerMonData(u8 monId)
+{
+ struct BattlePokemon *battlePokemon = (struct BattlePokemon *)&gBattleBufferA[gActiveBank][3];
+ struct MovePpInfo *moveData = (struct MovePpInfo *)&gBattleBufferA[gActiveBank][3];
+ s32 i;
+
+ switch (gBattleBufferA[gActiveBank][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 < 4; 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_SPD_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_SPD, &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[gActiveBank][3]);
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MOVES_PP_BATTLE:
+ for (i = 0; i < 4; 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[gActiveBank][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &gBattleBufferA[gActiveBank][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[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_OTID_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_EXP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_IV, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][7]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][8]);
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_STATUS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ }
+
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+}
+
+static void PlayerPartnerHandleSetRawMonData(void)
+{
+ u8 *dst = (u8 *)&gPlayerParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = gBattleBufferA[gActiveBank][3 + i];
+
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleLoadMonSprite(void)
+{
+ u16 species;
+
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+ sub_806A068(species, GetBankIdentity(gActiveBank));
+
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ sub_80A5C6C(gActiveBank, 2),
+ sub_80A6138(gActiveBank),
+ sub_80A82E4(gActiveBank));
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = -240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], gBattleMonForms[gActiveBank]);
+ gBattleBankFunc[gActiveBank] = sub_81BB1D4;
+}
+
+static void PlayerPartnerHandleSwitchInAnim(void)
+{
+ ClearTemporarySpeciesSpriteData(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_81BD0E4(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_81BBAE8;
+}
+
+static void sub_81BD0E4(u8 bank, bool8 dontClearSubstituteBit)
+{
+ u16 species;
+
+ ClearTemporarySpeciesSpriteData(bank, dontClearSubstituteBit);
+ gBattlePartyID[bank] = gBattleBufferA[bank][1];
+ species = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES);
+ gUnknown_03005D7C[bank] = CreateInvisibleSpriteWithCallback(sub_805D714);
+ sub_806A068(species, GetBankIdentity(bank));
+
+ gBankSpriteIds[bank] = CreateSprite(
+ &gUnknown_0202499C,
+ sub_80A5C6C(bank, 2),
+ sub_80A6138(bank),
+ sub_80A82E4(bank));
+
+ gSprites[gUnknown_03005D7C[bank]].data1 = gBankSpriteIds[bank];
+ gSprites[gUnknown_03005D7C[bank]].data2 = bank;
+
+ gSprites[gBankSpriteIds[bank]].data0 = bank;
+ gSprites[gBankSpriteIds[bank]].data2 = species;
+ gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank;
+
+ StartSpriteAnim(&gSprites[gBankSpriteIds[bank]], gBattleMonForms[bank]);
+
+ gSprites[gBankSpriteIds[bank]].invisible = TRUE;
+ gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy;
+
+ gSprites[gUnknown_03005D7C[bank]].data0 = sub_80753E8(0, 0xFF);
+}
+
+static void PlayerPartnerHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = DoSwitchOutAnimation;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void DoSwitchOutAnimation(void)
+{
+ switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState)
+ {
+ case 0:
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 1;
+ break;
+ case 1:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SWITCH_OUT_MON);
+ gBattleBankFunc[gActiveBank] = sub_81BB828;
+ }
+ break;
+ }
+}
+
+// todo: get rid of it once the struct is declared in a header
+struct MonCoords
+{
+ // This would use a bitfield, but sub_8079F44
+ // uses it as a u8 and casting won't match.
+ u8 coords; // u8 x:4, y:4;
+ u8 y_offset;
+};
+extern const struct MonCoords gTrainerBackPicCoords[];
+extern const struct MonCoords gTrainerFrontPicCoords[];
+
+// some explanation here
+// in emerald it's possible to have a tag battle in the battle frontier facilities with AI
+// which use the front sprite for both the player and the partner as opposed to any other battles (including the one with Steven) that use the back pic as well as animate it
+static void PlayerPartnerHandleDrawTrainerPic(void)
+{
+ s16 xPos, yPos;
+ u32 trainerPicId;
+
+ if (gPartnerTrainerId == STEVEN_PARTNER_ID)
+ {
+ trainerPicId = BACK_PIC_STEVEN;
+ xPos = 90;
+ yPos = (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+ else
+ {
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gPartnerTrainerId);
+ xPos = 32;
+ yPos = (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+
+ // Use back pic only if the partner is Steven
+ if (gPartnerTrainerId == STEVEN_PARTNER_ID)
+ {
+ DecompressTrainerBackPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, yPos, sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ }
+ else // otherwise use front sprite
+ {
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A1C0(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, yPos, sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.y = 48;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineMode = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].hFlip = 1;
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void PlayerPartnerHandleTrainerSlide(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleTrainerSlideBack(void)
+{
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = -40;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], SpriteCallbackDummy);
+ gBattleBankFunc[gActiveBank] = sub_81BAE98;
+}
+
+static void PlayerPartnerHandleFaintAnimation(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState == 0)
+ {
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState++;
+ }
+ else
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ PlaySE12WithPanning(SE_POKE_DEAD, -64);
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 5;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039C00;
+ gBattleBankFunc[gActiveBank] = sub_81BB78C;
+ }
+ }
+}
+
+static void PlayerPartnerHandlePaletteFade(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleSuccessBallThrowAnim(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleBallThrowAnim(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandlePause(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleMoveAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+
+ gAnimMoveTurn = gBattleBufferA[gActiveBank][3];
+ gAnimMovePower = gBattleBufferA[gActiveBank][4] | (gBattleBufferA[gActiveBank][5] << 8);
+ gAnimMoveDmg = gBattleBufferA[gActiveBank][6] | (gBattleBufferA[gActiveBank][7] << 8) | (gBattleBufferA[gActiveBank][8] << 16) | (gBattleBufferA[gActiveBank][9] << 24);
+ gAnimFriendship = gBattleBufferA[gActiveBank][10];
+ gWeatherMoveAnim = gBattleBufferA[gActiveBank][12] | (gBattleBufferA[gActiveBank][13] << 8);
+ gAnimDisableStructPtr = (struct DisableStruct *)&gBattleBufferA[gActiveBank][16];
+ gTransformedPersonalities[gActiveBank] = gAnimDisableStructPtr->transformedMonPersonality;
+ if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
+ {
+ PlayerPartnerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = PlayerPartnerDoMoveAnimation;
+ }
+ }
+}
+
+static void PlayerPartnerDoMoveAnimation(void)
+{
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+ u8 multihit = gBattleBufferA[gActiveBank][11];
+
+ switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState)
+ {
+ case 0:
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute
+ && !gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8)
+ {
+ gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8 = 1;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 1;
+ break;
+ case 1:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ sub_805EB9C(0);
+ DoMoveAnim(move);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 2;
+ }
+ break;
+ case 2:
+ gAnimScriptCallback();
+ if (!gAnimScriptActive)
+ {
+ sub_805EB9C(1);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute && multihit < 2)
+ {
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+ gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8 = 0;
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 3;
+ }
+ break;
+ case 3:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ sub_805E394();
+ TrySetBehindSubstituteSpriteBit(gActiveBank, gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ PlayerPartnerBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void PlayerPartnerHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter2;
+}
+
+static void PlayerPartnerHandlePrintStringPlayerOnly(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleChooseAction(void)
+{
+ AI_TrySwitchOrUseItem();
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleUnknownYesNoBox(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleChooseMove(void)
+{
+ u8 chosenMoveId;
+ struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+
+ BattleAI_SetupAIData(0xF);
+ chosenMoveId = BattleAI_ChooseMoveOrAction();
+
+ if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_x10 | MOVE_TARGET_USER))
+ gBankTarget = gActiveBank;
+ if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH)
+ {
+ gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
+ if (gAbsentBankFlags & gBitTable[gBankTarget])
+ gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
+ }
+
+ EmitTwoReturnValues(1, 10, chosenMoveId | (gBankTarget << 8));
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleChooseItem(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleChoosePokemon(void)
+{
+ s32 chosenMonId = GetMostSuitableMonToSwitchInto();
+
+ if (chosenMonId == 6) // just switch to the next mon
+ {
+ u8 playerMonIdentity = GetBankByIdentity(IDENTITY_PLAYER_MON1);
+ u8 selfIdentity = GetBankByIdentity(IDENTITY_PLAYER_MON2);
+
+ for (chosenMonId = 3; chosenMonId < 6; chosenMonId++)
+ {
+ if (GetMonData(&gPlayerParty[chosenMonId], MON_DATA_HP) != 0
+ && chosenMonId != gBattlePartyID[playerMonIdentity]
+ && chosenMonId != gBattlePartyID[selfIdentity])
+ {
+ break;
+ }
+ }
+ }
+
+ *(gBattleStruct->field_5C + gActiveBank) = chosenMonId;
+ EmitChosenMonReturnValue(1, chosenMonId, NULL);
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd23(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleHealthBarUpdate(void)
+{
+ s16 hpVal;
+
+ LoadBattleBarGfx(0);
+ hpVal = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (hpVal != INSTANT_HP_BAR_DROP)
+ {
+ u32 maxHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+ u32 curHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, curHP, hpVal);
+ }
+ else
+ {
+ u32 maxHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, 0, hpVal);
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthbarDone;
+}
+
+static void PlayerPartnerHandleExpUpdate(void)
+{
+ u8 monId = gBattleBufferA[gActiveBank][1];
+
+ if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_MON_LEVEL)
+ {
+ PlayerPartnerBufferExecCompleted();
+ }
+ else
+ {
+ s16 expPointsToGive;
+ u8 taskId;
+
+ LoadBattleBarGfx(1);
+ GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); // unused return value
+ expPointsToGive = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+ taskId = CreateTask(Task_GiveExpToMon, 10);
+ gTasks[taskId].tExpTask_monId = monId;
+ gTasks[taskId].tExpTask_gainedExp = expPointsToGive;
+ gTasks[taskId].tExpTask_bank = gActiveBank;
+ gBattleBankFunc[gActiveBank] = nullsub_21;
+ }
+}
+
+#undef tExpTask_monId
+#undef tExpTask_gainedExp
+#undef tExpTask_bank
+#undef tExpTask_frames
+
+static void PlayerPartnerHandleStatusIconUpdate(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 bank;
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_STATUS_ICON);
+ bank = gActiveBank;
+ gBattleSpritesDataPtr->healthBoxesData[bank].statusAnimActive = 0;
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void PlayerPartnerHandleStatusAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ DoStatusAnimation(gBattleBufferA[gActiveBank][1],
+ gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8) | (gBattleBufferA[gActiveBank][4] << 16) | (gBattleBufferA[gActiveBank][5] << 24));
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void PlayerPartnerHandleStatusXor(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleDataTransfer(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleDMA3Transfer(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandlePlayBGM(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd32(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleTwoReturnValues(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleChosenMonReturnValue(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleOneReturnValue(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleOneReturnValue_Duplicate(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ PlayerPartnerBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void PlayerPartnerHandleCmd42(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleEffectivenessSound(void)
+{
+ s8 pan;
+
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ pan = PAN_SIDE_PLAYER;
+ else
+ pan = PAN_SIDE_OPPONENT;
+
+ PlaySE12WithPanning(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8), pan);
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, -25, 5);
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleIntroTrainerBallThrow(void)
+{
+ u8 paletteNum;
+ u8 taskId;
+
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 50;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = -40;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ gSprites[gBankSpriteIds[gActiveBank]].data5 = gActiveBank;
+
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], sub_805CC00);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 1);
+
+ paletteNum = AllocSpritePalette(0xD6F9);
+ if (gPartnerTrainerId == STEVEN_PARTNER_ID)
+ {
+ u8 spriteId = BACK_PIC_STEVEN;
+ LoadCompressedPalette(gTrainerBackPicPaletteTable[spriteId].data, 0x100 + paletteNum * 16, 32);
+ }
+ else
+ {
+ u8 spriteId = GetFrontierTrainerFrontSpriteId(gPartnerTrainerId);
+ LoadCompressedPalette(gTrainerFrontPicPaletteTable[spriteId].data, 0x100 + paletteNum * 16, 32);
+ }
+
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = paletteNum;
+
+ taskId = CreateTask(sub_81BE2C8, 5);
+ gTasks[taskId].data[0] = gActiveBank;
+
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 1;
+ gBattleBankFunc[gActiveBank] = nullsub_77;
+}
+
+static void sub_81BE2C8(u8 taskId)
+{
+ if (gTasks[taskId].data[1] < 24)
+ {
+ gTasks[taskId].data[1]++;
+ }
+ else
+ {
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_81BD0E4(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_81BD0E4(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_81BD0E4(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_81BB02C;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+ }
+}
+
+static void PlayerPartnerHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ PlayerPartnerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+ gUnknown_020244B4[gActiveBank] = CreatePartyStatusSummarySprites(gActiveBank, (struct HpAndStatus *)&gBattleBufferA[gActiveBank][4], gBattleBufferA[gActiveBank][1], gBattleBufferA[gActiveBank][2]);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+
+ if (gBattleBufferA[gActiveBank][2] != 0)
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0x5D;
+
+ gBattleBankFunc[gActiveBank] = sub_81BE498;
+ }
+}
+
+static void sub_81BE498(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ PlayerPartnerBufferExecCompleted();
+ }
+}
+
+static void PlayerPartnerHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd50(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleSpriteInvisibility(void)
+{
+ if (AnimBankSpriteExists(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ SetBattleSpriteInvisibilityBitToSpriteInvisibility(gActiveBank);
+ }
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleBattleAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 animationId = gBattleBufferA[gActiveBank][1];
+ u16 argument = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (DoBattleAnimationFromTable(gActiveBank, gActiveBank, gActiveBank, animationId, argument))
+ PlayerPartnerBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+ }
+}
+
+static void PlayerPartnerHandleLinkStandbyMsg(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleResetActionMoveSelection(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleCmd55(void)
+{
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ PlayerPartnerBufferExecCompleted();
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_128(void)
+{
+}
diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c
new file mode 100644
index 000000000..efedf52b6
--- /dev/null
+++ b/src/battle_controller_recorded_player.c
@@ -0,0 +1,1854 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "battle_ai_script_commands.h"
+#include "recorded_battle.h"
+#include "pokemon.h"
+#include "link.h"
+#include "util.h"
+#include "main.h"
+#include "songs.h"
+#include "sound.h"
+#include "window.h"
+#include "m4a.h"
+#include "palette.h"
+#include "task.h"
+#include "text.h"
+#include "string_util.h"
+#include "bg.h"
+#include "reshow_battle_screen.h"
+#include "pokeball.h"
+
+extern u32 gBattleExecBuffer;
+extern u8 gActiveBank;
+extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
+extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT];
+extern u8 gNoOfAllBanks;
+extern bool8 gDoingBattleAnim;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+extern void (*gPreBattleCallback1)(void);
+extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
+extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
+extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
+extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
+extern struct SpriteTemplate gUnknown_0202499C;
+extern u16 gScriptItemId;
+extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
+extern u8 gBattleOutcome;
+extern u16 gBattle_BG0_X;
+extern u16 gBattle_BG0_Y;
+extern u8 gBankInMenu;
+extern u16 gUnknown_020243FC;
+extern u8 gUnknown_03005D7C[BATTLE_BANKS_COUNT];
+extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
+extern u16 gPartnerTrainerId;
+extern u8 GetFrontierTrainerFrontSpriteId(u16 trainerId);
+extern u8 gBankTarget;
+extern u8 gAbsentBankFlags;
+extern u8 gUnknown_020244B4[];
+extern u32 gTransformedPersonalities[BATTLE_BANKS_COUNT];
+extern u8 gBattleCommunication[];
+extern u8 gUnknown_0203C7B4;
+extern struct MusicPlayerInfo gMPlay_BGM;
+extern struct UnusedControllerStruct gUnknown_02022D0C;
+
+extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
+extern const struct CompressedSpritePalette gTrainerBackPicPaletteTable[];
+extern const struct BattleMove gBattleMoves[];
+
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+
+// this file's functions
+static void RecordedPlayerHandleGetMonData(void);
+static void RecordedPlayerHandleGetRawMonData(void);
+static void RecordedPlayerHandleSetMonData(void);
+static void RecordedPlayerHandleSetRawMonData(void);
+static void RecordedPlayerHandleLoadMonSprite(void);
+static void RecordedPlayerHandleSwitchInAnim(void);
+static void RecordedPlayerHandleReturnMonToBall(void);
+static void RecordedPlayerHandleDrawTrainerPic(void);
+static void RecordedPlayerHandleTrainerSlide(void);
+static void RecordedPlayerHandleTrainerSlideBack(void);
+static void RecordedPlayerHandleFaintAnimation(void);
+static void RecordedPlayerHandlePaletteFade(void);
+static void RecordedPlayerHandleSuccessBallThrowAnim(void);
+static void RecordedPlayerHandleBallThrowAnim(void);
+static void RecordedPlayerHandlePause(void);
+static void RecordedPlayerHandleMoveAnimation(void);
+static void RecordedPlayerHandlePrintString(void);
+static void RecordedPlayerHandlePrintStringPlayerOnly(void);
+static void RecordedPlayerHandleChooseAction(void);
+static void RecordedPlayerHandleUnknownYesNoBox(void);
+static void RecordedPlayerHandleChooseMove(void);
+static void RecordedPlayerHandleChooseItem(void);
+static void RecordedPlayerHandleChoosePokemon(void);
+static void RecordedPlayerHandleCmd23(void);
+static void RecordedPlayerHandleHealthBarUpdate(void);
+static void RecordedPlayerHandleExpUpdate(void);
+static void RecordedPlayerHandleStatusIconUpdate(void);
+static void RecordedPlayerHandleStatusAnimation(void);
+static void RecordedPlayerHandleStatusXor(void);
+static void RecordedPlayerHandleDataTransfer(void);
+static void RecordedPlayerHandleDMA3Transfer(void);
+static void RecordedPlayerHandlePlayBGM(void);
+static void RecordedPlayerHandleCmd32(void);
+static void RecordedPlayerHandleTwoReturnValues(void);
+static void RecordedPlayerHandleChosenMonReturnValue(void);
+static void RecordedPlayerHandleOneReturnValue(void);
+static void RecordedPlayerHandleOneReturnValue_Duplicate(void);
+static void RecordedPlayerHandleCmd37(void);
+static void RecordedPlayerHandleCmd38(void);
+static void RecordedPlayerHandleCmd39(void);
+static void RecordedPlayerHandleCmd40(void);
+static void RecordedPlayerHandleHitAnimation(void);
+static void RecordedPlayerHandleCmd42(void);
+static void RecordedPlayerHandleEffectivenessSound(void);
+static void RecordedPlayerHandlePlayFanfareOrBGM(void);
+static void RecordedPlayerHandleFaintingCry(void);
+static void RecordedPlayerHandleIntroSlide(void);
+static void RecordedPlayerHandleIntroTrainerBallThrow(void);
+static void RecordedPlayerHandleDrawPartyStatusSummary(void);
+static void RecordedPlayerHandleCmd49(void);
+static void RecordedPlayerHandleCmd50(void);
+static void RecordedPlayerHandleSpriteInvisibility(void);
+static void RecordedPlayerHandleBattleAnimation(void);
+static void RecordedPlayerHandleLinkStandbyMsg(void);
+static void RecordedPlayerHandleResetActionMoveSelection(void);
+static void RecordedPlayerHandleCmd55(void);
+static void nullsub_121(void);
+
+static void RecordedPlayerBufferRunCommand(void);
+static void RecordedPlayerBufferExecCompleted(void);
+static void sub_818A328(void);
+static u32 CopyRecordedPlayerMonData(u8 monId, u8 *dst);
+static void SetRecordedPlayerMonData(u8 monId);
+static void sub_818BA6C(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void RecordedPlayerDoMoveAnimation(void);
+static void sub_818CC24(u8 taskId);
+static void sub_818CDF4(void);
+
+static void (*const gRecordedPlayerBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ RecordedPlayerHandleGetMonData,
+ RecordedPlayerHandleGetRawMonData,
+ RecordedPlayerHandleSetMonData,
+ RecordedPlayerHandleSetRawMonData,
+ RecordedPlayerHandleLoadMonSprite,
+ RecordedPlayerHandleSwitchInAnim,
+ RecordedPlayerHandleReturnMonToBall,
+ RecordedPlayerHandleDrawTrainerPic,
+ RecordedPlayerHandleTrainerSlide,
+ RecordedPlayerHandleTrainerSlideBack,
+ RecordedPlayerHandleFaintAnimation,
+ RecordedPlayerHandlePaletteFade,
+ RecordedPlayerHandleSuccessBallThrowAnim,
+ RecordedPlayerHandleBallThrowAnim,
+ RecordedPlayerHandlePause,
+ RecordedPlayerHandleMoveAnimation,
+ RecordedPlayerHandlePrintString,
+ RecordedPlayerHandlePrintStringPlayerOnly,
+ RecordedPlayerHandleChooseAction,
+ RecordedPlayerHandleUnknownYesNoBox,
+ RecordedPlayerHandleChooseMove,
+ RecordedPlayerHandleChooseItem,
+ RecordedPlayerHandleChoosePokemon,
+ RecordedPlayerHandleCmd23,
+ RecordedPlayerHandleHealthBarUpdate,
+ RecordedPlayerHandleExpUpdate,
+ RecordedPlayerHandleStatusIconUpdate,
+ RecordedPlayerHandleStatusAnimation,
+ RecordedPlayerHandleStatusXor,
+ RecordedPlayerHandleDataTransfer,
+ RecordedPlayerHandleDMA3Transfer,
+ RecordedPlayerHandlePlayBGM,
+ RecordedPlayerHandleCmd32,
+ RecordedPlayerHandleTwoReturnValues,
+ RecordedPlayerHandleChosenMonReturnValue,
+ RecordedPlayerHandleOneReturnValue,
+ RecordedPlayerHandleOneReturnValue_Duplicate,
+ RecordedPlayerHandleCmd37,
+ RecordedPlayerHandleCmd38,
+ RecordedPlayerHandleCmd39,
+ RecordedPlayerHandleCmd40,
+ RecordedPlayerHandleHitAnimation,
+ RecordedPlayerHandleCmd42,
+ RecordedPlayerHandleEffectivenessSound,
+ RecordedPlayerHandlePlayFanfareOrBGM,
+ RecordedPlayerHandleFaintingCry,
+ RecordedPlayerHandleIntroSlide,
+ RecordedPlayerHandleIntroTrainerBallThrow,
+ RecordedPlayerHandleDrawPartyStatusSummary,
+ RecordedPlayerHandleCmd49,
+ RecordedPlayerHandleCmd50,
+ RecordedPlayerHandleSpriteInvisibility,
+ RecordedPlayerHandleBattleAnimation,
+ RecordedPlayerHandleLinkStandbyMsg,
+ RecordedPlayerHandleResetActionMoveSelection,
+ RecordedPlayerHandleCmd55,
+ nullsub_121
+};
+
+static void nullsub_120(void)
+{
+}
+
+void SetBankFuncToRecordedPlayerBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = RecordedPlayerBufferRunCommand;
+}
+
+static void RecordedPlayerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(gRecordedPlayerBufferCommands))
+ gRecordedPlayerBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void sub_81899F0(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ nullsub_25(0);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void sub_8189A58(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void sub_8189AA0(void)
+{
+ bool32 r6 = FALSE;
+
+ if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON1)
+ {
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ r6 = TRUE;
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ {
+ r6 = TRUE;
+ }
+ }
+
+ if (r6 && gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1
+ && gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1 = 0;
+
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ if (IsDoubleBattle())
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]], gActiveBank ^ BIT_MON);
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_8189A58;
+ }
+ }
+ else
+ {
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ r6 = TRUE;
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ {
+ r6 = TRUE;
+ }
+ }
+
+ if (IsCryPlayingOrClearCrySongs())
+ r6 = FALSE;
+
+ if (r6)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_8189A58;
+ }
+ }
+}
+
+static void sub_8189D40(void)
+{
+ bool32 r10 = FALSE;
+
+ if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON1)
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ sub_8172EF0(gActiveBank, &gPlayerParty[gBattlePartyID[gActiveBank]]);
+ }
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8)
+ {
+ sub_8172EF0(gActiveBank ^ BIT_MON, &gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]]);
+ }
+ }
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8)
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80)
+ {
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank ^ BIT_MON], &gPlayerParty[gBattlePartyID[gActiveBank ^ BIT_MON]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank ^ BIT_MON);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank ^ BIT_MON]);
+ }
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 1;
+ }
+
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x40
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x40
+ && !IsCryPlayingOrClearCrySongs())
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20)
+ {
+ if ((gBattleTypeFlags & BATTLE_TYPE_LINK) && (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON1)
+ m4aMPlayContinue(&gMPlay_BGM);
+ }
+ else
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ }
+
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 1;
+ r10 = TRUE;
+ }
+
+ if (r10 && gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank ^ BIT_MON]]);
+
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 0;
+ gBattleBankFunc[gActiveBank] = sub_8189AA0;
+ }
+}
+
+static void sub_818A064(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].animEnded && gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0)
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], 0, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void sub_818A114(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].pos1.y + gSprites[gBankSpriteIds[gActiveBank]].pos2.y > DISPLAY_HEIGHT)
+ {
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ nullsub_24(species);
+ FreeOamMatrix(gSprites[gBankSpriteIds[gActiveBank]].oam.matrixNum);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void sub_818A1B0(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ RecordedPlayerBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_818A2B4(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ SetBattleSpriteInvisibilityBitToSpriteInvisibility(gActiveBank);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+
+ gBattleBankFunc[gActiveBank] = sub_818A328;
+ }
+}
+
+static void sub_818A328(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void sub_818A37C(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ CreateTask(c3_0802FDF4, 10);
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 0);
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ gBattleBankFunc[gActiveBank] = sub_818A2B4;
+ }
+}
+
+static void sub_818A470(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ sub_8172EF0(gActiveBank, &gPlayerParty[gBattlePartyID[gActiveBank]]);
+ }
+
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ gBattleBankFunc[gActiveBank] = sub_818A37C;
+ }
+}
+
+static void RecordedPlayerBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = RecordedPlayerBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTOLLER_CMDS_COUNT - 1;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleGetMonData(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 monsToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyRecordedPlayerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monsToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monsToCheck & 1)
+ size += CopyRecordedPlayerMonData(i, monData + size);
+ monsToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ RecordedPlayerBufferExecCompleted();
+}
+
+static u32 CopyRecordedPlayerMonData(u8 monId, u8 *dst)
+{
+ struct BattlePokemon battleMon;
+ struct MovePpInfo moveData;
+ u8 nickname[20];
+ u8 *src;
+ s16 data16;
+ u32 data32;
+ s32 size = 0;
+
+ switch (gBattleBufferA[gActiveBank][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 < 4; 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_SPD_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_SPD);
+ 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.altAbility = GetMonData(&gPlayerParty[monId], MON_DATA_ALT_ABILITY);
+ 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 < 4; 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[gActiveBank][1] - REQUEST_MOVE1_BATTLE);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ for (size = 0; size < 4; 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[gActiveBank][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_SPD_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_SPD_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_SPD_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_SPD);
+ 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 RecordedPlayerHandleGetRawMonData(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleSetMonData(void)
+{
+ u8 monsToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetRecordedPlayerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monsToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monsToCheck & 1)
+ SetRecordedPlayerMonData(i);
+ monsToCheck >>= 1;
+ }
+ }
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void SetRecordedPlayerMonData(u8 monId)
+{
+ struct BattlePokemon *battlePokemon = (struct BattlePokemon *)&gBattleBufferA[gActiveBank][3];
+ struct MovePpInfo *moveData = (struct MovePpInfo *)&gBattleBufferA[gActiveBank][3];
+ s32 i;
+
+ switch (gBattleBufferA[gActiveBank][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 < 4; 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_SPD_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_SPD, &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[gActiveBank][3]);
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MOVES_PP_BATTLE:
+ for (i = 0; i < 4; 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[gActiveBank][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &gBattleBufferA[gActiveBank][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[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_OTID_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_EXP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_IV, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][7]);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][8]);
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_STATUS_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPD, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ }
+
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+}
+
+static void RecordedPlayerHandleSetRawMonData(void)
+{
+ u8 *dst = (u8 *)&gPlayerParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = gBattleBufferA[gActiveBank][3 + i];
+
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleLoadMonSprite(void)
+{
+ u16 species;
+
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+ sub_806A068(species, GetBankIdentity(gActiveBank));
+
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ sub_80A5C6C(gActiveBank, 2),
+ sub_80A6138(gActiveBank),
+ sub_80A82E4(gActiveBank));
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = -240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], gBattleMonForms[gActiveBank]);
+ gBattleBankFunc[gActiveBank] = sub_818A064;
+}
+
+static void RecordedPlayerHandleSwitchInAnim(void)
+{
+ ClearTemporarySpeciesSpriteData(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_818BA6C(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_818A470;
+}
+
+static void sub_818BA6C(u8 bank, bool8 dontClearSubstituteBit)
+{
+ u16 species;
+
+ ClearTemporarySpeciesSpriteData(bank, dontClearSubstituteBit);
+ gBattlePartyID[bank] = gBattleBufferA[bank][1];
+ species = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES);
+ gUnknown_03005D7C[bank] = CreateInvisibleSpriteWithCallback(sub_805D714);
+ sub_806A068(species, GetBankIdentity(bank));
+
+ gBankSpriteIds[bank] = CreateSprite(
+ &gUnknown_0202499C,
+ sub_80A5C6C(bank, 2),
+ sub_80A6138(bank),
+ sub_80A82E4(bank));
+
+ gSprites[gUnknown_03005D7C[bank]].data1 = gBankSpriteIds[bank];
+ gSprites[gUnknown_03005D7C[bank]].data2 = bank;
+
+ gSprites[gBankSpriteIds[bank]].data0 = bank;
+ gSprites[gBankSpriteIds[bank]].data2 = species;
+ gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank;
+
+ StartSpriteAnim(&gSprites[gBankSpriteIds[bank]], gBattleMonForms[bank]);
+
+ gSprites[gBankSpriteIds[bank]].invisible = TRUE;
+ gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy;
+
+ gSprites[gUnknown_03005D7C[bank]].data0 = sub_80753E8(0, 0xFF);
+}
+
+static void RecordedPlayerHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = DoSwitchOutAnimation;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void DoSwitchOutAnimation(void)
+{
+ switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState)
+ {
+ case 0:
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 1;
+ break;
+ case 1:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SWITCH_OUT_MON);
+ gBattleBankFunc[gActiveBank] = sub_818A1B0;
+ }
+ break;
+ }
+}
+
+// todo: get rid of it once the struct is declared in a header
+struct MonCoords
+{
+ // This would use a bitfield, but sub_8079F44
+ // uses it as a u8 and casting won't match.
+ u8 coords; // u8 x:4, y:4;
+ u8 y_offset;
+};
+extern const struct MonCoords gTrainerBackPicCoords[];
+extern const struct MonCoords gTrainerFrontPicCoords[];
+
+static void RecordedPlayerHandleDrawTrainerPic(void)
+{
+ s16 xPos, yPos;
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ trainerPicId = sub_8185F40();
+ else
+ trainerPicId = gLinkPlayers[gUnknown_0203C7B4].gender;
+ }
+ else
+ {
+ trainerPicId = gLinkPlayers[0].gender;
+ }
+
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ if ((GetBankIdentity(gActiveBank) & BIT_MON) != 0) // second mon
+ xPos = 90;
+ else // first mon
+ xPos = 32;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
+ {
+ xPos = 90;
+ yPos = (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+ else
+ {
+ yPos = (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+
+ }
+ else
+ {
+ xPos = 80;
+ yPos = (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80;
+ }
+
+ if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
+ {
+ trainerPicId = PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender);
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A1C0(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, yPos, sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.y = 48;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineMode = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].hFlip = 1;
+ }
+ else
+ {
+ DecompressTrainerBackPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, yPos, sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void RecordedPlayerHandleTrainerSlide(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleTrainerSlideBack(void)
+{
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = -40;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], SpriteCallbackDummy);
+ gBattleBankFunc[gActiveBank] = sub_81899F0;
+}
+
+static void RecordedPlayerHandleFaintAnimation(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState == 0)
+ {
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState++;
+ }
+ else
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ PlaySE12WithPanning(SE_POKE_DEAD, -64);
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 5;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039C00;
+ gBattleBankFunc[gActiveBank] = sub_818A114;
+ }
+ }
+}
+
+static void RecordedPlayerHandlePaletteFade(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleSuccessBallThrowAnim(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleBallThrowAnim(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandlePause(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleMoveAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+
+ gAnimMoveTurn = gBattleBufferA[gActiveBank][3];
+ gAnimMovePower = gBattleBufferA[gActiveBank][4] | (gBattleBufferA[gActiveBank][5] << 8);
+ gAnimMoveDmg = gBattleBufferA[gActiveBank][6] | (gBattleBufferA[gActiveBank][7] << 8) | (gBattleBufferA[gActiveBank][8] << 16) | (gBattleBufferA[gActiveBank][9] << 24);
+ gAnimFriendship = gBattleBufferA[gActiveBank][10];
+ gWeatherMoveAnim = gBattleBufferA[gActiveBank][12] | (gBattleBufferA[gActiveBank][13] << 8);
+ gAnimDisableStructPtr = (struct DisableStruct *)&gBattleBufferA[gActiveBank][16];
+ gTransformedPersonalities[gActiveBank] = gAnimDisableStructPtr->transformedMonPersonality;
+ if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
+ {
+ RecordedPlayerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = RecordedPlayerDoMoveAnimation;
+ }
+ }
+}
+
+static void RecordedPlayerDoMoveAnimation(void)
+{
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+ u8 multihit = gBattleBufferA[gActiveBank][11];
+
+ switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState)
+ {
+ case 0:
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute
+ && !gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8)
+ {
+ gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8 = 1;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SUBSTITUTE_TO_MON);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 1;
+ break;
+ case 1:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ sub_805EB9C(0);
+ DoMoveAnim(move);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 2;
+ }
+ break;
+ case 2:
+ gAnimScriptCallback();
+ if (!gAnimScriptActive)
+ {
+ sub_805EB9C(1);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute && multihit < 2)
+ {
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+ gBattleSpritesDataPtr->bankData[gActiveBank].flag_x8 = 0;
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 3;
+ }
+ break;
+ case 3:
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ sub_805E394();
+ TrySetBehindSubstituteSpriteBit(gActiveBank, gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ RecordedPlayerBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void RecordedPlayerHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter;
+}
+
+static void RecordedPlayerHandlePrintStringPlayerOnly(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void ChooseActionInBattlePalace(void)
+{
+ if (gBattleCommunication[4] >= gNoOfAllBanks / 2)
+ {
+ EmitTwoReturnValues(1, RecordedBattle_ReadBankAction(gActiveBank), 0);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void RecordedPlayerHandleChooseAction(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
+ {
+ gBattleBankFunc[gActiveBank] = ChooseActionInBattlePalace;
+ }
+ else
+ {
+ EmitTwoReturnValues(1, RecordedBattle_ReadBankAction(gActiveBank), 0);
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void RecordedPlayerHandleUnknownYesNoBox(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleChooseMove(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
+ {
+ EmitTwoReturnValues(1, 10, ChooseMoveAndTargetInBattlePalace());
+ }
+ else
+ {
+ u8 moveId = RecordedBattle_ReadBankAction(gActiveBank);
+ u8 target = RecordedBattle_ReadBankAction(gActiveBank);
+ EmitTwoReturnValues(1, 10, moveId | (target << 8));
+ }
+
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleChooseItem(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleChoosePokemon(void)
+{
+ *(gBattleStruct->field_5C + gActiveBank) = RecordedBattle_ReadBankAction(gActiveBank);
+ EmitChosenMonReturnValue(1, *(gBattleStruct->field_5C + gActiveBank), NULL);
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd23(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleHealthBarUpdate(void)
+{
+ s16 hpVal;
+
+ LoadBattleBarGfx(0);
+ hpVal = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (hpVal != INSTANT_HP_BAR_DROP)
+ {
+ u32 maxHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+ u32 curHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, curHP, hpVal);
+ }
+ else
+ {
+ u32 maxHP = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, 0, hpVal);
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], 0, HP_CURRENT);
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthbarDone;
+}
+
+static void RecordedPlayerHandleExpUpdate(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleStatusIconUpdate(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 bank;
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_STATUS_ICON);
+ bank = gActiveBank;
+ gBattleSpritesDataPtr->healthBoxesData[bank].statusAnimActive = 0;
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void RecordedPlayerHandleStatusAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ DoStatusAnimation(gBattleBufferA[gActiveBank][1],
+ gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8) | (gBattleBufferA[gActiveBank][4] << 16) | (gBattleBufferA[gActiveBank][5] << 24));
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void RecordedPlayerHandleStatusXor(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleDataTransfer(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleDMA3Transfer(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandlePlayBGM(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd32(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleTwoReturnValues(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleChosenMonReturnValue(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleOneReturnValue(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleOneReturnValue_Duplicate(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ RecordedPlayerBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void RecordedPlayerHandleCmd42(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleEffectivenessSound(void)
+{
+ s8 pan;
+
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ pan = PAN_SIDE_PLAYER;
+ else
+ pan = PAN_SIDE_OPPONENT;
+
+ PlaySE12WithPanning(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8), pan);
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, -25, 5);
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleIntroTrainerBallThrow(void)
+{
+ u8 paletteNum;
+ u8 taskId;
+ u32 trainerPicId;
+
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 50;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = -40;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ gSprites[gBankSpriteIds[gActiveBank]].data5 = gActiveBank;
+
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], sub_805CC00);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 1);
+
+ paletteNum = AllocSpritePalette(0xD6F9);
+ if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
+ trainerPicId = gLinkPlayers[sub_806D864(gActiveBank)].gender;
+ else
+ trainerPicId = gSaveBlock2Ptr->playerGender;
+
+ LoadCompressedPalette(gTrainerBackPicPaletteTable[trainerPicId].data, 0x100 + paletteNum * 16, 32);
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = paletteNum;
+
+ taskId = CreateTask(sub_818CC24, 5);
+ gTasks[taskId].data[0] = gActiveBank;
+
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 1;
+ gBattleBankFunc[gActiveBank] = nullsub_120;
+}
+
+static void sub_818CC24(u8 taskId)
+{
+ if (gTasks[taskId].data[1] < 24)
+ {
+ gTasks[taskId].data[1]++;
+ }
+ else
+ {
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_818BA6C(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_818BA6C(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_818BA6C(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_8189D40;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+ }
+}
+
+static void RecordedPlayerHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ RecordedPlayerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+ gUnknown_020244B4[gActiveBank] = CreatePartyStatusSummarySprites(gActiveBank, (struct HpAndStatus *)&gBattleBufferA[gActiveBank][4], gBattleBufferA[gActiveBank][1], gBattleBufferA[gActiveBank][2]);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+
+ if (gBattleBufferA[gActiveBank][2] != 0)
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0x5D;
+
+ gBattleBankFunc[gActiveBank] = sub_818CDF4;
+ }
+}
+
+static void sub_818CDF4(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ RecordedPlayerBufferExecCompleted();
+ }
+}
+
+static void RecordedPlayerHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd50(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleSpriteInvisibility(void)
+{
+ if (AnimBankSpriteExists(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ SetBattleSpriteInvisibilityBitToSpriteInvisibility(gActiveBank);
+ }
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleBattleAnimation(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 animationId = gBattleBufferA[gActiveBank][1];
+ u16 argument = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (DoBattleAnimationFromTable(gActiveBank, gActiveBank, gActiveBank, animationId, argument))
+ RecordedPlayerBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+ }
+}
+
+static void RecordedPlayerHandleLinkStandbyMsg(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleResetActionMoveSelection(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleCmd55(void)
+{
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ RecordedPlayerBufferExecCompleted();
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_121(void)
+{
+}
diff --git a/src/battle_controller_safari.c b/src/battle_controller_safari.c
new file mode 100644
index 000000000..74210e629
--- /dev/null
+++ b/src/battle_controller_safari.c
@@ -0,0 +1,723 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "pokemon.h"
+#include "link.h"
+#include "util.h"
+#include "main.h"
+#include "songs.h"
+#include "sound.h"
+#include "window.h"
+#include "m4a.h"
+#include "palette.h"
+#include "task.h"
+#include "text.h"
+#include "bg.h"
+#include "reshow_battle_screen.h"
+#include "pokeball.h"
+
+extern u32 gBattleExecBuffer;
+extern u8 gActiveBank;
+extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
+extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT];
+extern u8 gNoOfAllBanks;
+extern bool8 gDoingBattleAnim;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+extern void (*gPreBattleCallback1)(void);
+extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
+extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
+extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
+extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
+extern struct SpriteTemplate gUnknown_0202499C;
+extern u16 gScriptItemId;
+extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
+extern u8 gBattleOutcome;
+extern u16 gBattle_BG0_X;
+extern u16 gBattle_BG0_Y;
+extern u8 gBankInMenu;
+extern u16 gUnknown_020243FC;
+
+extern const struct CompressedSpritePalette gTrainerBackPicPaletteTable[];
+
+extern const u8 gText_SafariZoneMenu[];
+extern const u8 gText_WhatWillPkmnDo2[];
+
+extern void sub_81358F4(void);
+
+// this file's functions
+static void SafariHandleGetMonData(void);
+static void SafariHandleGetRawMonData(void);
+static void SafariHandleSetMonData(void);
+static void SafariHandleSetRawMonData(void);
+static void SafariHandleLoadMonSprite(void);
+static void SafariHandleSwitchInAnim(void);
+static void SafariHandleReturnMonToBall(void);
+static void SafariHandleDrawTrainerPic(void);
+static void SafariHandleTrainerSlide(void);
+static void SafariHandleTrainerSlideBack(void);
+static void SafariHandleFaintAnimation(void);
+static void SafariHandlePaletteFade(void);
+static void SafariHandleSuccessBallThrowAnim(void);
+static void SafariHandleBallThrowAnim(void);
+static void SafariHandlePause(void);
+static void SafariHandleMoveAnimation(void);
+static void SafariHandlePrintString(void);
+static void SafariHandlePrintStringPlayerOnly(void);
+static void SafariHandleChooseAction(void);
+static void SafariHandleUnknownYesNoBox(void);
+static void SafariHandleChooseMove(void);
+static void SafariHandleChooseItem(void);
+static void SafariHandleChoosePokemon(void);
+static void SafariHandleCmd23(void);
+static void SafariHandleHealthBarUpdate(void);
+static void SafariHandleExpUpdate(void);
+static void SafariHandleStatusIconUpdate(void);
+static void SafariHandleStatusAnimation(void);
+static void SafariHandleStatusXor(void);
+static void SafariHandleDataTransfer(void);
+static void SafariHandleDMA3Transfer(void);
+static void SafariHandlePlayBGM(void);
+static void SafariHandleCmd32(void);
+static void SafariHandleTwoReturnValues(void);
+static void SafariHandleChosenMonReturnValue(void);
+static void SafariHandleOneReturnValue(void);
+static void SafariHandleOneReturnValue_Duplicate(void);
+static void SafariHandleCmd37(void);
+static void SafariHandleCmd38(void);
+static void SafariHandleCmd39(void);
+static void SafariHandleCmd40(void);
+static void SafariHandleHitAnimation(void);
+static void SafariHandleCmd42(void);
+static void SafariHandleEffectivenessSound(void);
+static void SafariHandlePlayFanfareOrBGM(void);
+static void SafariHandleFaintingCry(void);
+static void SafariHandleIntroSlide(void);
+static void SafariHandleIntroTrainerBallThrow(void);
+static void SafariHandleDrawPartyStatusSummary(void);
+static void SafariHandleCmd49(void);
+static void SafariHandleCmd50(void);
+static void SafariHandleSpriteInvisibility(void);
+static void SafariHandleBattleAnimation(void);
+static void SafariHandleLinkStandbyMsg(void);
+static void SafariHandleResetActionMoveSelection(void);
+static void SafariHandleCmd55(void);
+static void nullsub_115(void);
+
+static void SafariBufferRunCommand(void);
+static void SafariBufferExecCompleted(void);
+static void CompleteWhenChosePokeblock(void);
+
+static void (*const gSafariBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ SafariHandleGetMonData,
+ SafariHandleGetRawMonData,
+ SafariHandleSetMonData,
+ SafariHandleSetRawMonData,
+ SafariHandleLoadMonSprite,
+ SafariHandleSwitchInAnim,
+ SafariHandleReturnMonToBall,
+ SafariHandleDrawTrainerPic,
+ SafariHandleTrainerSlide,
+ SafariHandleTrainerSlideBack,
+ SafariHandleFaintAnimation,
+ SafariHandlePaletteFade,
+ SafariHandleSuccessBallThrowAnim,
+ SafariHandleBallThrowAnim,
+ SafariHandlePause,
+ SafariHandleMoveAnimation,
+ SafariHandlePrintString,
+ SafariHandlePrintStringPlayerOnly,
+ SafariHandleChooseAction,
+ SafariHandleUnknownYesNoBox,
+ SafariHandleChooseMove,
+ SafariHandleChooseItem,
+ SafariHandleChoosePokemon,
+ SafariHandleCmd23,
+ SafariHandleHealthBarUpdate,
+ SafariHandleExpUpdate,
+ SafariHandleStatusIconUpdate,
+ SafariHandleStatusAnimation,
+ SafariHandleStatusXor,
+ SafariHandleDataTransfer,
+ SafariHandleDMA3Transfer,
+ SafariHandlePlayBGM,
+ SafariHandleCmd32,
+ SafariHandleTwoReturnValues,
+ SafariHandleChosenMonReturnValue,
+ SafariHandleOneReturnValue,
+ SafariHandleOneReturnValue_Duplicate,
+ SafariHandleCmd37,
+ SafariHandleCmd38,
+ SafariHandleCmd39,
+ SafariHandleCmd40,
+ SafariHandleHitAnimation,
+ SafariHandleCmd42,
+ SafariHandleEffectivenessSound,
+ SafariHandlePlayFanfareOrBGM,
+ SafariHandleFaintingCry,
+ SafariHandleIntroSlide,
+ SafariHandleIntroTrainerBallThrow,
+ SafariHandleDrawPartyStatusSummary,
+ SafariHandleCmd49,
+ SafariHandleCmd50,
+ SafariHandleSpriteInvisibility,
+ SafariHandleBattleAnimation,
+ SafariHandleLinkStandbyMsg,
+ SafariHandleResetActionMoveSelection,
+ SafariHandleCmd55,
+ nullsub_115
+};
+
+static void nullsub_114(void)
+{
+}
+
+void SetBankFuncToSafariBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = SafariBufferRunCommand;
+}
+
+static void SafariBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(gSafariBufferCommands))
+ gSafariBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ SafariBufferExecCompleted();
+ }
+}
+
+static void HandleInputChooseAction(void)
+{
+ if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+
+ switch (gActionSelectionCursor[gActiveBank])
+ {
+ case 0:
+ EmitTwoReturnValues(1, ACTION_SAFARI_ZONE_BALL, 0);
+ break;
+ case 1:
+ EmitTwoReturnValues(1, ACTION_POKEBLOCK_CASE, 0);
+ break;
+ case 2:
+ EmitTwoReturnValues(1, ACTION_GO_NEAR, 0);
+ break;
+ case 3:
+ EmitTwoReturnValues(1, ACTION_SAFARI_ZONE_RUN, 0);
+ break;
+ }
+ SafariBufferExecCompleted();
+ }
+ else if (gMain.newKeys & DPAD_LEFT)
+ {
+ if (gActionSelectionCursor[gActiveBank] & 1)
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 1;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_RIGHT)
+ {
+ if (!(gActionSelectionCursor[gActiveBank] & 1))
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 1;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_UP)
+ {
+ if (gActionSelectionCursor[gActiveBank] & 2)
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 2;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (!(gActionSelectionCursor[gActiveBank] & 2))
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBank]);
+ gActionSelectionCursor[gActiveBank] ^= 2;
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ }
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ SafariBufferExecCompleted();
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ SafariBufferExecCompleted();
+}
+
+static void CompleteOnHealthboxSpriteCallbackDummy(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ SafariBufferExecCompleted();
+}
+
+static void sub_81595E4(void)
+{
+ if (!gPaletteFade.active)
+ {
+ gMain.inBattle = FALSE;
+ gMain.callback1 = gPreBattleCallback1;
+ SetMainCallback2(gMain.savedCallback);
+ }
+}
+
+static void CompleteOnSpecialAnimDone(void)
+{
+ if (!gDoingBattleAnim || !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ SafariBufferExecCompleted();
+}
+
+static void OpenPokeblockCase(void)
+{
+ if (!gPaletteFade.active)
+ {
+ gBattleBankFunc[gActiveBank] = CompleteWhenChosePokeblock;
+ FreeAllWindowBuffers();
+ sub_81358F4();
+ }
+}
+
+static void CompleteWhenChosePokeblock(void)
+{
+ if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
+ {
+ EmitOneReturnValue(1, gScriptItemId);
+ SafariBufferExecCompleted();
+ }
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ SafariBufferExecCompleted();
+}
+
+static void SafariBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = SafariBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTOLLER_CMDS_COUNT - 1;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleGetMonData(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleGetRawMonData(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleSetMonData(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleSetRawMonData(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleLoadMonSprite(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleSwitchInAnim(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleReturnMonToBall(void)
+{
+ SafariBufferExecCompleted();
+}
+
+// todo: get rid of it once the struct is declared in a header
+struct MonCoords
+{
+ // This would use a bitfield, but sub_8079F44
+ // uses it as a u8 and casting won't match.
+ u8 coords; // u8 x:4, y:4;
+ u8 y_offset;
+};
+extern const struct MonCoords gTrainerBackPicCoords[];
+
+static void SafariHandleDrawTrainerPic(void)
+{
+ DecompressTrainerBackPic(gSaveBlock2Ptr->playerGender, gActiveBank);
+ sub_806A12C(gSaveBlock2Ptr->playerGender, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(
+ &gUnknown_0202499C,
+ 80,
+ (8 - gTrainerBackPicCoords[gSaveBlock2Ptr->playerGender].coords) * 4 + 80,
+ 30);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void SafariHandleTrainerSlide(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleTrainerSlideBack(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleFaintAnimation(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandlePaletteFade(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleSuccessBallThrowAnim(void)
+{
+ gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
+ gDoingBattleAnim = TRUE;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, GetBankByIdentity(IDENTITY_OPPONENT_MON1), B_ANIM_SAFARI_BALL_THROW);
+ gBattleBankFunc[gActiveBank] = CompleteOnSpecialAnimDone;
+}
+
+static void SafariHandleBallThrowAnim(void)
+{
+ u8 ballThrowCaseId = gBattleBufferA[gActiveBank][1];
+
+ gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId;
+ gDoingBattleAnim = TRUE;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, GetBankByIdentity(IDENTITY_OPPONENT_MON1), B_ANIM_SAFARI_BALL_THROW);
+ gBattleBankFunc[gActiveBank] = CompleteOnSpecialAnimDone;
+}
+
+static void SafariHandlePause(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleMoveAnimation(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter;
+}
+
+static void SafariHandlePrintStringPlayerOnly(void)
+{
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ SafariHandlePrintString();
+ else
+ SafariBufferExecCompleted();
+}
+
+static void HandleChooseActionAfterDma3(void)
+{
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 160;
+ gBattleBankFunc[gActiveBank] = HandleInputChooseAction;
+ }
+}
+
+static void SafariHandleChooseAction(void)
+{
+ s32 i;
+
+ gBattleBankFunc[gActiveBank] = HandleChooseActionAfterDma3;
+ BattleHandleAddTextPrinter(gText_SafariZoneMenu, 2);
+
+ for (i = 0; i < 4; i++)
+ ActionSelectionDestroyCursorAt(i);
+
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 1);
+}
+
+static void SafariHandleUnknownYesNoBox(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleChooseMove(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleChooseItem(void)
+{
+ s32 i;
+
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gBattleBankFunc[gActiveBank] = OpenPokeblockCase;
+ gBankInMenu = gActiveBank;
+}
+
+static void SafariHandleChoosePokemon(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd23(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleHealthBarUpdate(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleExpUpdate(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleStatusIconUpdate(void)
+{
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_SAFARI_BALLS_TEXT);
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleStatusAnimation(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleStatusXor(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleDataTransfer(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleDMA3Transfer(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandlePlayBGM(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd32(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleTwoReturnValues(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleChosenMonReturnValue(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleOneReturnValue(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleOneReturnValue_Duplicate(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd37(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd38(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd39(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd40(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleHitAnimation(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd42(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleEffectivenessSound(void)
+{
+ s8 pan;
+
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ pan = PAN_SIDE_PLAYER;
+ else
+ pan = PAN_SIDE_OPPONENT;
+
+ PlaySE12WithPanning(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8), pan);
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry1(species, 25);
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleIntroTrainerBallThrow(void)
+{
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gPlayerParty[gBattlePartyID[gActiveBank]], HEALTHBOX_SAFARI_ALL_TEXT);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthboxSpriteCallbackDummy;
+}
+
+static void SafariHandleDrawPartyStatusSummary(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd49(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd50(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleSpriteInvisibility(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleBattleAnimation(void)
+{
+ u8 animationId = gBattleBufferA[gActiveBank][1];
+ u16 argument = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (DoBattleAnimationFromTable(gActiveBank, gActiveBank, gActiveBank, animationId, argument))
+ SafariBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+}
+
+static void SafariHandleLinkStandbyMsg(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleResetActionMoveSelection(void)
+{
+ SafariBufferExecCompleted();
+}
+
+static void SafariHandleCmd55(void)
+{
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ SafariBufferExecCompleted();
+ if ((gBattleTypeFlags & BATTLE_TYPE_LINK) && !(gBattleTypeFlags & BATTLE_TYPE_WILD))
+ gBattleBankFunc[gActiveBank] = sub_81595E4;
+}
+
+static void nullsub_115(void)
+{
+}
diff --git a/src/battle_controller_wally.c b/src/battle_controller_wally.c
new file mode 100644
index 000000000..ce38ca882
--- /dev/null
+++ b/src/battle_controller_wally.c
@@ -0,0 +1,147 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_controllers.h"
+#include "battle_message.h"
+#include "battle_interface.h"
+#include "battle_anim.h"
+#include "link.h"
+
+extern u8 gActiveBank;
+extern bool8 gDoingBattleAnim;
+extern u8 gUnknown_020244CC;
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+
+// this file's functions
+void WallyHandleGetMonData(void);
+void WallyHandleGetRawMonData(void);
+void WallyHandleSetMonData(void);
+void WallyHandleSetRawMonData(void);
+void WallyHandleLoadMonSprite(void);
+void WallyHandleSwitchInAnim(void);
+void WallyHandleReturnMonToBall(void);
+void WallyHandleDrawTrainerPic(void);
+void WallyHandleTrainerSlide(void);
+void WallyHandleTrainerSlideBack(void);
+void WallyHandleFaintAnimation(void);
+void WallyHandleCmd11(void);
+void WallyHandleCmd12(void);
+void WallyHandleBallThrow(void);
+void WallyHandlePause(void);
+void WallyHandleMoveAnimation(void);
+void WallyHandlePrintString(void);
+void WallyHandlePrintStringPlayerOnly(void);
+void WallyHandleChooseAction(void);
+void WallyHandleCmd19(void);
+void WallyHandleChooseMove(void);
+void WallyHandleOpenBag(void);
+void WallyHandleChoosePokemon(void);
+void WallyHandleCmd23(void);
+void WallyHandleHealthBarUpdate(void);
+void WallyHandleExpUpdate(void);
+void WallyHandleStatusIconUpdate(void);
+void WallyHandleStatusAnimation(void);
+void WallyHandleStatusXor(void);
+void WallyHandleDataTransfer(void);
+void WallyHandleDMA3Transfer(void);
+void WallyHandlePlayBGM(void);
+void WallyHandleCmd32(void);
+void WallyHandleCmd33(void);
+void WallyHandleCmd34(void);
+void WallyHandleCmd35(void);
+void WallyHandleCmd36(void);
+void WallyHandleCmd37(void);
+void WallyHandleCmd38(void);
+void WallyHandleCmd39(void);
+void WallyHandleCmd40(void);
+void WallyHandleHitAnimation(void);
+void WallyHandleCmd42(void);
+void WallyHandleEffectivenessSound(void);
+void WallyHandlePlayFanfareOrBGM(void);
+void WallyHandleFaintingCry(void);
+void WallyHandleIntroSlide(void);
+void WallyHandleIntroTrainerBallThrow(void);
+void WallyHandleDrawPartyStatusSummary(void);
+void WallyHandleCmd49(void);
+void WallyHandleCmd50(void);
+void WallyHandleSpriteInvisibility(void);
+void WallyHandleBattleAnimation(void);
+void WallyHandleLinkStandbyMsg(void);
+void WallyHandleResetActionMoveSelection(void);
+void WallyHandleCmd55(void);
+void nullsub_118(void);
+
+void WallyBufferRunCommand(void);
+
+void (*const gWallyBufferCommands[CONTOLLER_CMDS_COUNT])(void) =
+{
+ WallyHandleGetMonData,
+ WallyHandleGetRawMonData,
+ WallyHandleSetMonData,
+ WallyHandleSetRawMonData,
+ WallyHandleLoadMonSprite,
+ WallyHandleSwitchInAnim,
+ WallyHandleReturnMonToBall,
+ WallyHandleDrawTrainerPic,
+ WallyHandleTrainerSlide,
+ WallyHandleTrainerSlideBack,
+ WallyHandleFaintAnimation,
+ WallyHandleCmd11,
+ WallyHandleCmd12,
+ WallyHandleBallThrow,
+ WallyHandlePause,
+ WallyHandleMoveAnimation,
+ WallyHandlePrintString,
+ WallyHandlePrintStringPlayerOnly,
+ WallyHandleChooseAction,
+ WallyHandleCmd19,
+ WallyHandleChooseMove,
+ WallyHandleOpenBag,
+ WallyHandleChoosePokemon,
+ WallyHandleCmd23,
+ WallyHandleHealthBarUpdate,
+ WallyHandleExpUpdate,
+ WallyHandleStatusIconUpdate,
+ WallyHandleStatusAnimation,
+ WallyHandleStatusXor,
+ WallyHandleDataTransfer,
+ WallyHandleDMA3Transfer,
+ WallyHandlePlayBGM,
+ WallyHandleCmd32,
+ WallyHandleCmd33,
+ WallyHandleCmd34,
+ WallyHandleCmd35,
+ WallyHandleCmd36,
+ WallyHandleCmd37,
+ WallyHandleCmd38,
+ WallyHandleCmd39,
+ WallyHandleCmd40,
+ WallyHandleHitAnimation,
+ WallyHandleCmd42,
+ WallyHandleEffectivenessSound,
+ WallyHandlePlayFanfareOrBGM,
+ WallyHandleFaintingCry,
+ WallyHandleIntroSlide,
+ WallyHandleIntroTrainerBallThrow,
+ WallyHandleDrawPartyStatusSummary,
+ WallyHandleCmd49,
+ WallyHandleCmd50,
+ WallyHandleSpriteInvisibility,
+ WallyHandleBattleAnimation,
+ WallyHandleLinkStandbyMsg,
+ WallyHandleResetActionMoveSelection,
+ WallyHandleCmd55,
+ nullsub_118
+};
+
+void nullsub_117(void)
+{
+}
+
+void SetBankFuncToWallyBufferRunCommand(void)
+{
+ gBattleBankFunc[gActiveBank] = WallyBufferRunCommand;
+ gBattleStruct->field_94 = 0;
+ gBattleStruct->field_95 = 0;
+ gBattleStruct->field_96 = 0;
+ gBattleStruct->field_97 = 0;
+}
diff --git a/src/battle_controllers.c b/src/battle_controllers.c
index 9ac18c72f..bf6962b1b 100644
--- a/src/battle_controllers.c
+++ b/src/battle_controllers.c
@@ -939,11 +939,11 @@ static void Task_HandleCopyReceivedLinkBuffersData(u8 taskId)
}
}
-void EmitGetMonData(u8 bufferId, u8 arg1, u8 arg2)
+void EmitGetMonData(u8 bufferId, u8 requestId, u8 monsToCheck)
{
gBattleBuffersTransferData[0] = CONTROLLER_GETMONDATA;
- gBattleBuffersTransferData[1] = arg1;
- gBattleBuffersTransferData[2] = arg2;
+ gBattleBuffersTransferData[1] = requestId;
+ gBattleBuffersTransferData[2] = monsToCheck;
gBattleBuffersTransferData[3] = 0;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -957,13 +957,13 @@ void EmitGetRawMonData(u8 bufferId, u8 monId, u8 bytes)
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitSetMonData(u8 bufferId, u8 request, u8 c, u8 bytes, void *data)
+void EmitSetMonData(u8 bufferId, u8 requestId, u8 monsToCheck, u8 bytes, void *data)
{
s32 i;
gBattleBuffersTransferData[0] = CONTROLLER_SETMONDATA;
- gBattleBuffersTransferData[1] = request;
- gBattleBuffersTransferData[2] = c;
+ gBattleBuffersTransferData[1] = requestId;
+ gBattleBuffersTransferData[2] = monsToCheck;
for (i = 0; i < bytes; i++)
gBattleBuffersTransferData[3 + i] = *(u8*)(data++);
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 3 + bytes);
@@ -984,9 +984,9 @@ void EmitSetRawMonData(u8 bufferId, u8 monId, u8 bytes, void *data)
void EmitLoadMonSprite(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_LOADMONSPRITE;
- gBattleBuffersTransferData[1] = 4;
- gBattleBuffersTransferData[2] = 4;
- gBattleBuffersTransferData[3] = 4;
+ gBattleBuffersTransferData[1] = CONTROLLER_LOADMONSPRITE;
+ gBattleBuffersTransferData[2] = CONTROLLER_LOADMONSPRITE;
+ gBattleBuffersTransferData[3] = CONTROLLER_LOADMONSPRITE;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1009,27 +1009,27 @@ void EmitReturnMonToBall(u8 bufferId, u8 arg1)
void EmitDrawTrainerPic(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_DRAWTRAINERPIC;
- gBattleBuffersTransferData[1] = 7;
- gBattleBuffersTransferData[2] = 7;
- gBattleBuffersTransferData[3] = 7;
+ gBattleBuffersTransferData[1] = CONTROLLER_DRAWTRAINERPIC;
+ gBattleBuffersTransferData[2] = CONTROLLER_DRAWTRAINERPIC;
+ gBattleBuffersTransferData[3] = CONTROLLER_DRAWTRAINERPIC;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
void EmitTrainerSlide(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_TRAINERSLIDE;
- gBattleBuffersTransferData[1] = 8;
- gBattleBuffersTransferData[2] = 8;
- gBattleBuffersTransferData[3] = 8;
+ gBattleBuffersTransferData[1] = CONTROLLER_TRAINERSLIDE;
+ gBattleBuffersTransferData[2] = CONTROLLER_TRAINERSLIDE;
+ gBattleBuffersTransferData[3] = CONTROLLER_TRAINERSLIDE;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
void EmitTrainerSlideBack(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_TRAINERSLIDEBACK;
- gBattleBuffersTransferData[1] = 9;
- gBattleBuffersTransferData[2] = 9;
- gBattleBuffersTransferData[3] = 9;
+ gBattleBuffersTransferData[1] = CONTROLLER_TRAINERSLIDEBACK;
+ gBattleBuffersTransferData[2] = CONTROLLER_TRAINERSLIDEBACK;
+ gBattleBuffersTransferData[3] = CONTROLLER_TRAINERSLIDEBACK;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1042,27 +1042,27 @@ void EmitFaintAnimation(u8 bufferId)
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitCmd11(u8 bufferId)
+void EmitPaletteFade(u8 bufferId)
{
- gBattleBuffersTransferData[0] = CONTROLLER_11;
- gBattleBuffersTransferData[1] = 11;
- gBattleBuffersTransferData[2] = 11;
- gBattleBuffersTransferData[3] = 11;
+ gBattleBuffersTransferData[0] = CONTROLLER_PALETTEFADE;
+ gBattleBuffersTransferData[1] = CONTROLLER_PALETTEFADE;
+ gBattleBuffersTransferData[2] = CONTROLLER_PALETTEFADE;
+ gBattleBuffersTransferData[3] = CONTROLLER_PALETTEFADE;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitCmd12(u8 bufferId)
+void EmitSuccessBallThrowAnim(u8 bufferId)
{
- gBattleBuffersTransferData[0] = CONTROLLER_12;
- gBattleBuffersTransferData[1] = 12;
- gBattleBuffersTransferData[2] = 12;
- gBattleBuffersTransferData[3] = 12;
+ gBattleBuffersTransferData[0] = CONTROLLER_SUCCESSBALLTHROWANIM;
+ gBattleBuffersTransferData[1] = CONTROLLER_SUCCESSBALLTHROWANIM;
+ gBattleBuffersTransferData[2] = CONTROLLER_SUCCESSBALLTHROWANIM;
+ gBattleBuffersTransferData[3] = CONTROLLER_SUCCESSBALLTHROWANIM;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitBallThrow(u8 bufferId, u8 caseId)
+void EmitBallThrowAnim(u8 bufferId, u8 caseId)
{
- gBattleBuffersTransferData[0] = CONTROLLER_BALLTHROW;
+ gBattleBuffersTransferData[0] = CONTROLLER_BALLTHROWANIM;
gBattleBuffersTransferData[1] = caseId;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2);
}
@@ -1178,12 +1178,12 @@ void EmitChooseAction(u8 bufferId, u8 arg1, u16 arg2)
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitCmd19(u8 bufferId)
+void EmitUnknownYesNoBox(u8 bufferId)
{
- gBattleBuffersTransferData[0] = CONTROLLER_19;
- gBattleBuffersTransferData[1] = 19;
- gBattleBuffersTransferData[2] = 19;
- gBattleBuffersTransferData[3] = 19;
+ gBattleBuffersTransferData[0] = CONTROLLER_UNKNOWNYESNOBOX;
+ gBattleBuffersTransferData[1] = CONTROLLER_UNKNOWNYESNOBOX;
+ gBattleBuffersTransferData[2] = CONTROLLER_UNKNOWNYESNOBOX;
+ gBattleBuffersTransferData[3] = CONTROLLER_UNKNOWNYESNOBOX;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1200,7 +1200,7 @@ void EmitChooseMove(u8 bufferId, bool8 isDoubleBattle, bool8 NoPpNumber, struct
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, sizeof(*movePpData) + 4);
}
-void EmitOpenBag(u8 bufferId, u8 *arg1)
+void EmitChooseItem(u8 bufferId, u8 *arg1)
{
s32 i;
@@ -1337,38 +1337,38 @@ void EmitCmd32(u8 bufferId, u16 size, void *data)
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, size + 3);
}
-void EmitCmd33(u8 bufferId, u8 arg1, u16 arg2)
+void EmitTwoReturnValues(u8 bufferId, u8 arg1, u16 arg2)
{
- gBattleBuffersTransferData[0] = CONTROLLER_33;
+ gBattleBuffersTransferData[0] = CONTROLLER_TWORETURNVALUES;
gBattleBuffersTransferData[1] = arg1;
gBattleBuffersTransferData[2] = arg2;
gBattleBuffersTransferData[3] = (arg2 & 0xFF00) >> 8;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitCmd34(u8 bufferId, u8 b, u8 *c)
+void EmitChosenMonReturnValue(u8 bufferId, u8 b, u8 *c)
{
s32 i;
- gBattleBuffersTransferData[0] = CONTROLLER_34;
+ gBattleBuffersTransferData[0] = CONTROLLER_CHOSENMONRETURNVALUE;
gBattleBuffersTransferData[1] = b;
for (i = 0; i < 3; i++)
gBattleBuffersTransferData[2 + i] = c[i];
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 5);
}
-void EmitCmd35(u8 bufferId, u16 b)
+void EmitOneReturnValue(u8 bufferId, u16 arg1)
{
- gBattleBuffersTransferData[0] = CONTROLLER_35;
- gBattleBuffersTransferData[1] = b;
- gBattleBuffersTransferData[2] = (b & 0xFF00) >> 8;
+ gBattleBuffersTransferData[0] = CONTROLLER_ONERETURNVALUE;
+ gBattleBuffersTransferData[1] = arg1;
+ gBattleBuffersTransferData[2] = (arg1 & 0xFF00) >> 8;
gBattleBuffersTransferData[3] = 0;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
-void EmitCmd36(u8 bufferId, u16 b)
+void EmitOneReturnValue_Duplicate(u8 bufferId, u16 b)
{
- gBattleBuffersTransferData[0] = CONTROLLER_36;
+ gBattleBuffersTransferData[0] = CONTROLLER_ONERETURNVALUE_DUPLICATE;
gBattleBuffersTransferData[1] = b;
gBattleBuffersTransferData[2] = (b & 0xFF00) >> 8;
gBattleBuffersTransferData[3] = 0;
@@ -1378,9 +1378,9 @@ void EmitCmd36(u8 bufferId, u16 b)
void EmitCmd37(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_37;
- gBattleBuffersTransferData[1] = 37;
- gBattleBuffersTransferData[2] = 37;
- gBattleBuffersTransferData[3] = 37;
+ gBattleBuffersTransferData[1] = CONTROLLER_37;
+ gBattleBuffersTransferData[2] = CONTROLLER_37;
+ gBattleBuffersTransferData[3] = CONTROLLER_37;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1394,27 +1394,27 @@ void EmitCmd38(u8 bufferId, u8 b)
void EmitCmd39(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_39;
- gBattleBuffersTransferData[1] = 39;
- gBattleBuffersTransferData[2] = 39;
- gBattleBuffersTransferData[3] = 39;
+ gBattleBuffersTransferData[1] = CONTROLLER_39;
+ gBattleBuffersTransferData[2] = CONTROLLER_39;
+ gBattleBuffersTransferData[3] = CONTROLLER_39;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
void EmitCmd40(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_40;
- gBattleBuffersTransferData[1] = 40;
- gBattleBuffersTransferData[2] = 40;
- gBattleBuffersTransferData[3] = 40;
+ gBattleBuffersTransferData[1] = CONTROLLER_40;
+ gBattleBuffersTransferData[2] = CONTROLLER_40;
+ gBattleBuffersTransferData[3] = CONTROLLER_40;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
void EmitHitAnimation(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_HITANIMATION;
- gBattleBuffersTransferData[1] = 41;
- gBattleBuffersTransferData[2] = 41;
- gBattleBuffersTransferData[3] = 41;
+ gBattleBuffersTransferData[1] = CONTROLLER_HITANIMATION;
+ gBattleBuffersTransferData[2] = CONTROLLER_HITANIMATION;
+ gBattleBuffersTransferData[3] = CONTROLLER_HITANIMATION;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
diff --git a/src/battle_interface.c b/src/battle_interface.c
index 9241db1d9..5f582a366 100644
--- a/src/battle_interface.c
+++ b/src/battle_interface.c
@@ -21,23 +21,11 @@
#include "safari_zone.h"
#include "battle_anim.h"
-enum
-{
- HEALTH_BAR,
- EXP_BAR
-};
-
-enum
-{
- HP_CURRENT,
- HP_MAX
-};
-
struct TestingBar
{
s32 maxValue;
s32 currValue;
- s32 field_8;
+ s32 receivedValue;
u32 unkC_0:5;
u32 unk10;
};
@@ -189,7 +177,6 @@ extern const u16 gBattleInterface_BallDisplayPal[];
extern const u8 gHealthboxElementsGfxTable[][32];
// functions
-extern bool8 IsDoubleBattle(void);
extern void AddTextPrinterParametrized2(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, struct TextColor *color, s8 speed, const u8 *str); // menu.h
extern void LoadBattleBarGfx(u8 arg0);
@@ -220,10 +207,10 @@ static void SpriteCB_StatusSummaryBallsOnBattleStart(struct Sprite *sprite);
static void SpriteCB_StatusSummaryBallsOnSwitchout(struct Sprite *sprite);
static u8 GetStatusIconForBankId(u8 statusElementId, u8 bank);
-static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4, u16 arg5);
-static u8 GetScaledExpFraction(s32 currValue, s32 arg1, s32 maxValue, u8 scale);
+static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 arg4, u16 arg5);
+static u8 GetScaledExpFraction(s32 currValue, s32 receivedValue, s32 maxValue, u8 scale);
static void sub_8074B9C(u8 bank, u8 whichBar);
-static u8 sub_8074E8C(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 *arg4, u8 arg5);
+static u8 sub_8074E8C(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 *arg4, u8 arg5);
static void sub_8074F88(struct TestingBar *barInfo, s32 *arg1, u16 *arg2);
// const rom data
@@ -1055,12 +1042,12 @@ static void sub_8072924(struct Sprite *sprite)
sprite->pos2.y = gSprites[otherSpriteId].pos2.y;
}
-void SetBattleBarStruct(u8 bank, u8 healthboxSpriteId, s32 maxVal, s32 currVal, s32 field_C)
+void SetBattleBarStruct(u8 bank, u8 healthboxSpriteId, s32 maxVal, s32 currVal, s32 receivedValue)
{
gBattleSpritesDataPtr->battleBars[bank].healthboxSpriteId = healthboxSpriteId;
gBattleSpritesDataPtr->battleBars[bank].maxValue = maxVal;
gBattleSpritesDataPtr->battleBars[bank].currentValue = currVal;
- gBattleSpritesDataPtr->battleBars[bank].field_C = field_C;
+ gBattleSpritesDataPtr->battleBars[bank].receivedValue = receivedValue;
gBattleSpritesDataPtr->battleBars[bank].field_10 = -32768;
}
@@ -2268,22 +2255,22 @@ s32 sub_8074AA0(u8 bank, u8 healthboxSpriteId, u8 whichBar, u8 arg3)
{
var = sub_8074DB8(gBattleSpritesDataPtr->battleBars[bank].maxValue,
gBattleSpritesDataPtr->battleBars[bank].currentValue,
- gBattleSpritesDataPtr->battleBars[bank].field_C,
+ gBattleSpritesDataPtr->battleBars[bank].receivedValue,
&gBattleSpritesDataPtr->battleBars[bank].field_10,
6, 1);
}
else // exp bar
{
u16 expFraction = GetScaledExpFraction(gBattleSpritesDataPtr->battleBars[bank].currentValue,
- gBattleSpritesDataPtr->battleBars[bank].field_C,
+ gBattleSpritesDataPtr->battleBars[bank].receivedValue,
gBattleSpritesDataPtr->battleBars[bank].maxValue, 8);
if (expFraction == 0)
expFraction = 1;
- expFraction = abs(gBattleSpritesDataPtr->battleBars[bank].field_C / expFraction);
+ expFraction = abs(gBattleSpritesDataPtr->battleBars[bank].receivedValue / expFraction);
var = sub_8074DB8(gBattleSpritesDataPtr->battleBars[bank].maxValue,
gBattleSpritesDataPtr->battleBars[bank].currentValue,
- gBattleSpritesDataPtr->battleBars[bank].field_C,
+ gBattleSpritesDataPtr->battleBars[bank].receivedValue,
&gBattleSpritesDataPtr->battleBars[bank].field_10,
8, expFraction);
}
@@ -2299,7 +2286,7 @@ s32 sub_8074AA0(u8 bank, u8 healthboxSpriteId, u8 whichBar, u8 arg3)
static void sub_8074B9C(u8 bank, u8 whichBar)
{
- u8 array[7];
+ u8 array[8];
u8 subRet, level;
u8 barElementId;
u8 i;
@@ -2309,7 +2296,7 @@ static void sub_8074B9C(u8 bank, u8 whichBar)
case HEALTH_BAR:
subRet = sub_8074E8C(gBattleSpritesDataPtr->battleBars[bank].maxValue,
gBattleSpritesDataPtr->battleBars[bank].currentValue,
- gBattleSpritesDataPtr->battleBars[bank].field_C,
+ gBattleSpritesDataPtr->battleBars[bank].receivedValue,
&gBattleSpritesDataPtr->battleBars[bank].field_10,
array, 6);
barElementId = 3;
@@ -2333,7 +2320,7 @@ static void sub_8074B9C(u8 bank, u8 whichBar)
case EXP_BAR:
sub_8074E8C(gBattleSpritesDataPtr->battleBars[bank].maxValue,
gBattleSpritesDataPtr->battleBars[bank].currentValue,
- gBattleSpritesDataPtr->battleBars[bank].field_C,
+ gBattleSpritesDataPtr->battleBars[bank].receivedValue,
&gBattleSpritesDataPtr->battleBars[bank].field_10,
array, 8);
level = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_LEVEL);
@@ -2355,7 +2342,7 @@ static void sub_8074B9C(u8 bank, u8 whichBar)
}
}
-static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4, u16 arg5)
+static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 arg4, u16 arg5)
{
s32 r6;
s32 ret;
@@ -2369,7 +2356,7 @@ static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4
*arg3 = currValue;
}
- currValue -= arg2;
+ currValue -= receivedValue;
if (currValue < 0)
currValue = 0;
else if (currValue > maxValue)
@@ -2394,7 +2381,7 @@ static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4
{
s32 var = (maxValue << 8) / arg4;
- if (arg2 < 0)
+ if (receivedValue < 0)
{
*arg3 = r6 + var;
ret = *arg3 >> 8;
@@ -2419,7 +2406,7 @@ static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4
}
else
{
- if (arg2 < 0)
+ if (receivedValue < 0)
{
*arg3 += arg5;
if (*arg3 > currValue)
@@ -2438,9 +2425,9 @@ static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4
return ret;
}
-static u8 sub_8074E8C(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 *arg4, u8 arg5)
+static u8 sub_8074E8C(s32 maxValue, s32 currValue, s32 receivedValue, s32 *arg3, u8 *arg4, u8 arg5)
{
- s32 r5 = currValue - arg2;
+ s32 r5 = currValue - receivedValue;
u8 ret;
u8 i;
u8 r2;
@@ -2493,7 +2480,7 @@ static s16 sub_8074F28(struct TestingBar *barInfo, s32 *arg1, u16 *arg2, s32 arg
ret = sub_8074DB8(barInfo->maxValue,
barInfo->currValue,
- barInfo->field_8,
+ barInfo->receivedValue,
arg1, 6, 1);
sub_8074F88(barInfo, arg1, arg2);
@@ -2514,7 +2501,7 @@ static void sub_8074F88(struct TestingBar *barInfo, s32 *arg1, u16 *arg2)
u8 i;
sub_8074E8C(barInfo->maxValue, barInfo->currValue,
- barInfo->field_8, arg1, sp8, 6);
+ barInfo->receivedValue, arg1, sp8, 6);
for (i = 0; i < 6; i++)
sp10[i] = (barInfo->unkC_0 << 12) | (barInfo->unk10 + sp8[i]);
@@ -2522,13 +2509,13 @@ static void sub_8074F88(struct TestingBar *barInfo, s32 *arg1, u16 *arg2)
CpuCopy16(sp10, arg2, sizeof(sp10));
}
-static u8 GetScaledExpFraction(s32 currValue, s32 arg1, s32 maxValue, u8 scale)
+static u8 GetScaledExpFraction(s32 currValue, s32 receivedValue, s32 maxValue, u8 scale)
{
s32 r5, result;
s8 r4, r0;
scale *= 8;
- r5 = currValue - arg1;
+ r5 = currValue - receivedValue;
if (r5 < 0)
r5 = 0;
diff --git a/src/battle_message.c b/src/battle_message.c
index aeff721d6..d0c7b118d 100644
--- a/src/battle_message.c
+++ b/src/battle_message.c
@@ -2209,7 +2209,7 @@ static void sub_814F950(u8* dst)
}
}
-void sub_814F9EC(const u8 *text, u8 arg1)
+void BattleHandleAddTextPrinter(const u8 *text, u8 arg1)
{
const u8 *r8 = gUnknown_085CD660[gBattleScripting.field_24];
bool32 r9;
diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c
index a1e5767ad..b2afd9837 100644
--- a/src/battle_script_commands.c
+++ b/src/battle_script_commands.c
@@ -3625,7 +3625,7 @@ static void atk23_getexp(void)
if (gBattleExecBuffer == 0)
{
gActiveBank = gBattleStruct->expGetterBank;
- if (gBattleBufferB[gActiveBank][0] == 0x21 && gBattleBufferB[gActiveBank][1] == 0xB)
+ if (gBattleBufferB[gActiveBank][0] == CONTROLLER_TWORETURNVALUES && gBattleBufferB[gActiveBank][1] == RET_VALUE_LEVELLED_UP)
{
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId)
sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
@@ -6114,33 +6114,33 @@ static void atk5A_yesnoboxlearnmove(void)
switch (gBattleScripting.learnMoveState)
{
case 0:
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 0);
- sub_814F9EC(gText_BattleYesNoChoice, 0xC);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
gBattleScripting.learnMoveState++;
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
break;
case 1:
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
}
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 1;
- BattleCreateCursorAt(1);
+ BattleCreateYesNoCursorAt(1);
}
if (gMain.newKeys & A_BUTTON)
{
PlaySE(SE_SELECT);
if (gBattleCommunication[1] == 0)
{
- sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
gBattleScripting.learnMoveState++;
}
@@ -6214,7 +6214,7 @@ static void atk5A_yesnoboxlearnmove(void)
}
break;
case 5:
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
gBattlescriptCurrInstr += 5;
break;
case 6:
@@ -6231,26 +6231,26 @@ static void atk5B_yesnoboxstoplearningmove(void)
switch (gBattleScripting.learnMoveState)
{
case 0:
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 0);
- sub_814F9EC(gText_BattleYesNoChoice, 0xC);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
gBattleScripting.learnMoveState++;
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
break;
case 1:
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
}
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 1;
- BattleCreateCursorAt(1);
+ BattleCreateYesNoCursorAt(1);
}
if (gMain.newKeys & A_BUTTON)
{
@@ -6261,13 +6261,13 @@ static void atk5B_yesnoboxstoplearningmove(void)
else
gBattlescriptCurrInstr += 5;
- sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
}
else if (gMain.newKeys & B_BUTTON)
{
PlaySE(SE_SELECT);
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
- sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
}
break;
}
@@ -6527,38 +6527,38 @@ static void atk67_yesnobox(void)
switch (gBattleCommunication[0])
{
case 0:
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 0);
- sub_814F9EC(gText_BattleYesNoChoice, 0xC);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
gBattleCommunication[0]++;
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
break;
case 1:
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
}
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 1;
- BattleCreateCursorAt(1);
+ BattleCreateYesNoCursorAt(1);
}
if (gMain.newKeys & B_BUTTON)
{
gBattleCommunication[CURSOR_POSITION] = 1;
PlaySE(SE_SELECT);
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
gBattlescriptCurrInstr++;
}
else if (gMain.newKeys & A_BUTTON)
{
PlaySE(SE_SELECT);
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
gBattlescriptCurrInstr++;
}
break;
@@ -6674,7 +6674,7 @@ static void atk6C_draw_lvlupbox(void)
SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 0);
ShowBg(0);
ShowBg(1);
- sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x80);
+ HandleBattleWindow(0x12, 7, 0x1D, 0x13, WINDOW_x80);
gBattleScripting.atk6C_state = 4;
break;
case 4:
@@ -6704,7 +6704,7 @@ static void atk6C_draw_lvlupbox(void)
if (gMain.newKeys != 0)
{
PlaySE(SE_SELECT);
- sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x81);
+ HandleBattleWindow(0x12, 7, 0x1D, 0x13, WINDOW_x80 | WINDOW_CLEAR);
gBattleScripting.atk6C_state++;
}
break;
@@ -7136,8 +7136,8 @@ static void atk76_various(void)
gDisableStructs[0].truantUnknownBit = 1;
gDisableStructs[1].truantUnknownBit = 1;
break;
- case 13:
- EmitCmd19(0);
+ case VARIOUS_EMIT_YESNOBOX:
+ EmitUnknownYesNoBox(0);
MarkBufferBankForExecution(gActiveBank);
break;
case 14:
@@ -7148,7 +7148,7 @@ static void atk76_various(void)
break;
case 16:
BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]);
- sub_814F9EC(gDisplayedStringBattle, 0x16);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0x16);
break;
case 17:
if (IsTextPrinterActive(0x16))
@@ -7255,7 +7255,7 @@ static void atk78_faintifabilitynotdamp(void)
{
gActiveBank = gBankAttacker;
gBattleMoveDamage = gBattleMons[gActiveBank].hp;
- EmitHealthBarUpdate(0, 0x7FFF);
+ EmitHealthBarUpdate(0, INSTANT_HP_BAR_DROP);
MarkBufferBankForExecution(gActiveBank);
gBattlescriptCurrInstr++;
@@ -8443,7 +8443,7 @@ static void atk9B_transformdataexecution(void)
gBattleMons[gBankAttacker].status2 |= STATUS2_TRANSFORMED;
gDisableStructs[gBankAttacker].disabledMove = 0;
gDisableStructs[gBankAttacker].disableTimer1 = 0;
- gDisableStructs[gBankAttacker].unk0 = gBattleMons[gBankTarget].personality;
+ gDisableStructs[gBankAttacker].transformedMonPersonality = gBattleMons[gBankTarget].personality;
gDisableStructs[gBankAttacker].unk18_b = 0;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].species)
@@ -9152,7 +9152,7 @@ static void atkA8_copymovepermanently(void) // sketch
for (i = 0; i < 4; i++)
{
- movePpData.move[i] = gBattleMons[gBankAttacker].moves[i];
+ movePpData.moves[i] = gBattleMons[gBankAttacker].moves[i];
movePpData.pp[i] = gBattleMons[gBankAttacker].pp[i];
}
movePpData.ppBonuses = gBattleMons[gBankAttacker].ppBonuses;
@@ -10184,7 +10184,7 @@ static void atkC9_jumpifattackandspecialattackcannotfall(void) // memento
{
gActiveBank = gBankAttacker;
gBattleMoveDamage = gBattleMons[gActiveBank].hp;
- EmitHealthBarUpdate(0, 0x7FFF);
+ EmitHealthBarUpdate(0, INSTANT_HP_BAR_DROP);
MarkBufferBankForExecution(gActiveBank);
gBattlescriptCurrInstr += 5;
}
@@ -11003,13 +11003,13 @@ static void atkEF_pokeball_catch_calculation(void)
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
- EmitBallThrow(0, BALL_TRAINER_BLOCK);
+ EmitBallThrowAnim(0, BALL_TRAINER_BLOCK);
MarkBufferBankForExecution(gActiveBank);
gBattlescriptCurrInstr = BattleScript_TrainerBallBlock;
}
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
{
- EmitBallThrow(0, BALL_3_SHAKES_SUCCESS);
+ EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS);
MarkBufferBankForExecution(gActiveBank);
gBattlescriptCurrInstr = BattleScript_WallyBallThrow;
}
@@ -11098,7 +11098,7 @@ static void atkEF_pokeball_catch_calculation(void)
if (odds > 254) // mon caught
{
- EmitBallThrow(0, BALL_3_SHAKES_SUCCESS);
+ EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS);
MarkBufferBankForExecution(gActiveBank);
gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
@@ -11120,7 +11120,7 @@ static void atkEF_pokeball_catch_calculation(void)
if (gLastUsedItem == ITEM_MASTER_BALL)
shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check?
- EmitBallThrow(0, shakes);
+ EmitBallThrowAnim(0, shakes);
MarkBufferBankForExecution(gActiveBank);
if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above
@@ -11238,7 +11238,7 @@ static void atkF2_display_dex_info(void)
}
}
-void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags)
+void HandleBattleWindow(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags)
{
s32 destY, destX;
u16 var = 0;
@@ -11275,10 +11275,10 @@ void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags)
var = 0x1026;
}
- if (flags & 1)
+ if (flags & WINDOW_CLEAR)
var = 0;
- if (flags & 0x80)
+ if (flags & WINDOW_x80)
CopyToBgTilemapBufferRect_ChangePalette(1, &var, destX, destY, 1, 1, 0x11);
else
CopyToBgTilemapBufferRect_ChangePalette(0, &var, destX, destY, 1, 1, 0x11);
@@ -11286,7 +11286,7 @@ void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags)
}
}
-void BattleCreateCursorAt(u8 cursorPosition)
+void BattleCreateYesNoCursorAt(u8 cursorPosition)
{
u16 src[2];
src[0] = 1;
@@ -11296,7 +11296,7 @@ void BattleCreateCursorAt(u8 cursorPosition)
CopyBgTilemapBufferToVram(0);
}
-void BattleDestroyCursorAt(u8 cursorPosition)
+void BattleDestroyYesNoCursorAt(u8 cursorPosition)
{
u16 src[2];
src[0] = 0x1016;
@@ -11311,26 +11311,26 @@ static void atkF3_nickname_caught_poke(void)
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
- sub_8056A3C(0x18, 8, 0x1D, 0xD, 0);
- sub_814F9EC(gText_BattleYesNoChoice, 0xC);
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
gBattleCommunication[MULTIUSE_STATE]++;
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
break;
case 1:
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 0;
- BattleCreateCursorAt(0);
+ BattleCreateYesNoCursorAt(0);
}
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
{
PlaySE(SE_SELECT);
- BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 1;
- BattleCreateCursorAt(1);
+ BattleCreateYesNoCursorAt(1);
}
if (gMain.newKeys & A_BUTTON)
{
diff --git a/src/pokemon_2.c b/src/pokemon_2.c
index 27441f952..78c205517 100644
--- a/src/pokemon_2.c
+++ b/src/pokemon_2.c
@@ -84,7 +84,7 @@ bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 bank)
return FALSE;
}
-u8 sub_8069F34(u8 bank)
+u8 GetDefaultMoveTarget(u8 bank)
{
u8 status = GetBankIdentity(bank) & 1;
@@ -194,6 +194,7 @@ void sub_806A1C0(u16 arg0, u8 bankIdentity)
gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity];
else
gUnknown_0202499C = gUnknown_08329D98[bankIdentity];
+
gUnknown_0202499C.paletteTag = arg0;
gUnknown_0202499C.anims = gUnknown_0830536C[arg0];
}
@@ -1304,7 +1305,7 @@ void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex)
}
void sub_803FA70(u8 bank);
-void sub_805EF84(u8 bank, bool8);
+void ClearTemporarySpeciesSpriteData(u8 bank, bool8);
extern struct BattlePokemon gBattleMons[4];
@@ -1360,5 +1361,5 @@ void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex)
gBattleMons[bank].status2 = 0;
sub_803FA70(bank);
- sub_805EF84(bank, FALSE);
+ ClearTemporarySpeciesSpriteData(bank, FALSE);
}
diff --git a/src/pokemon_3.c b/src/pokemon_3.c
index 5ff99aee2..aa45c3d24 100644
--- a/src/pokemon_3.c
+++ b/src/pokemon_3.c
@@ -1659,7 +1659,7 @@ u16 sub_806EFF0(u16 arg0)
return gUnknown_0831F578[arg0];
}
-u16 sub_806F000(u8 playerGender)
+u16 PlayerGenderToFrontTrainerPicId(u8 playerGender)
{
if (playerGender)
return sub_806EFF0(0x3F);
diff --git a/src/reshow_battle_screen.c b/src/reshow_battle_screen.c
index 343ddb9c0..002f4f069 100644
--- a/src/reshow_battle_screen.c
+++ b/src/reshow_battle_screen.c
@@ -220,9 +220,9 @@ static bool8 LoadBankSpriteGfx(u8 bank)
BattleLoadSubstituteSpriteGfx(bank, FALSE);
}
else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && bank == 0)
- LoadBackTrainerBankSpriteGfx(gSaveBlock2Ptr->playerGender, bank);
+ DecompressTrainerBackPic(gSaveBlock2Ptr->playerGender, bank);
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL && bank == 0)
- LoadBackTrainerBankSpriteGfx(BACK_PIC_WALLY, bank);
+ DecompressTrainerBackPic(BACK_PIC_WALLY, bank);
else if (!gBattleSpritesDataPtr->bankData[bank].behindSubstitute)
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[bank]], bank);
else