summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bard_music.c65
-rw-r--r--src/battle_2.c43
-rw-r--r--src/battle_ai_switch_items.c20
-rw-r--r--src/battle_anim.c22
-rw-r--r--src/battle_controller_link_opponent.c1891
-rw-r--r--src/battle_controller_link_partner.c1719
-rw-r--r--src/battle_controller_opponent.c2033
-rw-r--r--src/battle_controller_player.c3150
-rw-r--r--src/battle_controller_player_partner.c1960
-rw-r--r--src/battle_controller_recorded_opponent.c1829
-rw-r--r--src/battle_controller_recorded_player.c1844
-rw-r--r--src/battle_controller_safari.c714
-rw-r--r--src/battle_controller_wally.c1597
-rw-r--r--src/battle_controllers.c296
-rw-r--r--src/battle_dome_cards.c2
-rw-r--r--src/battle_interface.c59
-rw-r--r--src/battle_message.c10
-rw-r--r--src/battle_script_commands.c112
-rw-r--r--src/battle_util.c4
-rw-r--r--src/evolution_graphics.c611
-rw-r--r--src/evolution_scene.c1506
-rwxr-xr-xsrc/field_map_obj.c9
-rw-r--r--src/math_util.c86
-rw-r--r--src/pokemon_2.c7
-rw-r--r--src/pokemon_3.c10
-rw-r--r--src/reshow_battle_screen.c4
-rw-r--r--src/secret_base.c2272
27 files changed, 21564 insertions, 311 deletions
diff --git a/src/bard_music.c b/src/bard_music.c
new file mode 100644
index 000000000..6fb1496e5
--- /dev/null
+++ b/src/bard_music.c
@@ -0,0 +1,65 @@
+
+// Includes
+#include "global.h"
+#include "bard_music.h"
+#include "easy_chat.h"
+
+#include "data/bard_music/bard_sounds.h"
+#include "data/bard_music/word_pitch.h"
+#include "data/bard_music/default_sound.h"
+#include "data/bard_music/length_table.h"
+
+s16 CalcWordPitch(int arg0, int songPos)
+{
+ return gBardSoundPitchTables[arg0][songPos];
+}
+
+const struct BardSound *GetWordSounds(u16 word)
+{
+ u32 category;
+ u32 subword;
+ const struct BardSound (*ptr)[6];
+
+ if (ECWord_CheckIfOutsideOfValidRange(word))
+ {
+ return gBardSound_InvalidWord;
+ }
+ category = word >> 9;
+ subword = word & 0x1ff;
+ switch (category)
+ {
+ case EC_GROUP_POKEMON:
+ case EC_GROUP_POKEMON_2:
+ ptr = gBardSounds_Pokemon;
+ break;
+ case EC_GROUP_MOVE_1:
+ case EC_GROUP_MOVE_2:
+ ptr = gBardSounds_Moves;
+ break;
+ default:
+ ptr = gBardSoundsTable[category];
+ break;
+ }
+ ptr += subword;
+ return *ptr;
+}
+
+void GetWordPhonemes(struct BardSong *song, u16 word)
+{
+ int i;
+ const struct BardSound *sound;
+
+ song->length = 0;
+ for (i = 0; i < 6; i ++)
+ {
+ sound = &song->sound[i];
+ if (sound->var00 != 0xFF)
+ {
+ song->phonemes[i].length = sound->var01 + gBardSoundLengthTable[sound->var00];
+ song->phonemes[i].pitch = CalcWordPitch(word + 30, i);
+ song->length += song->phonemes[i].length;
+ }
+ }
+ song->currPhoneme = 0;
+ song->voiceInflection = 0;
+}
diff --git a/src/battle_2.c b/src/battle_2.c
index bd2899aec..289425ee2 100644
--- a/src/battle_2.c
+++ b/src/battle_2.c
@@ -86,7 +86,7 @@ extern u16 gTrainerBattleOpponent_B;
extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT];
extern void (*gPreBattleCallback1)(void);
extern void (*gBattleMainFunc)(void);
-extern void (*gUnknown_030061E8)(void);
+extern void (*gCB2_AfterEvolution)(void);
extern struct UnknownPokemonStruct2 gUnknown_02022FF8[3]; // what is it used for?
extern struct UnknownPokemonStruct2* gUnknown_02023058; // what is it used for?
extern u8 gUnknown_02039B28[]; // possibly a struct?
@@ -239,7 +239,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);
@@ -2122,7 +2121,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;
@@ -2248,17 +2247,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;
@@ -2268,9 +2267,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)
@@ -2278,9 +2277,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)
@@ -2288,7 +2287,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;
}
@@ -2306,11 +2305,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]++;
}
@@ -2341,14 +2340,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]++;
}
@@ -2359,7 +2358,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]++;
}
@@ -3682,7 +3681,7 @@ static void TryDoEventsBeforeFirstTurn(void)
TurnValuesCleanUp(FALSE);
SpecialStatusesClear();
*(&gBattleStruct->field_91) = gAbsentBankFlags;
- sub_814F9EC(gText_EmptyString3, 0);
+ BattleHandleAddTextPrinter(gText_EmptyString3, 0);
gBattleMainFunc = HandleTurnActionSelectionState;
ResetSentPokesToOpponentValue();
@@ -3789,7 +3788,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();
@@ -4017,7 +4016,7 @@ static void HandleTurnActionSelectionState(void)
}
else
{
- EmitOpenBag(0, gBattleStruct->field_60[gActiveBank]);
+ EmitChooseItem(0, gBattleStruct->field_60[gActiveBank]);
MarkBufferBankForExecution(gActiveBank);
}
break;
@@ -4062,7 +4061,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:
@@ -4931,7 +4930,7 @@ static void HandleEndTurn_FinishBattle(void)
BeginFastPaletteFade(3);
FadeOutMapMusic(5);
gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions;
- gUnknown_030061E8 = BattleMainCB2;
+ gCB2_AfterEvolution = BattleMainCB2;
}
else
{
diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c
index d86be6fad..a57df85fb 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,8 +940,8 @@ static bool8 ShouldUseItem(void)
if (shouldUse)
{
- EmitCmd33(1, 1, 0);
- *(gBattleStruct->field_C0 + (gActiveBank / 2) * 2) = item;
+ EmitTwoReturnValues(1, ACTION_USE_ITEM, 0);
+ *(gBattleStruct->chosenItem + (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..fa3ac73be 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;
@@ -672,7 +660,7 @@ bool8 IsAnimBankSpriteVisible(u8 bank)
else
return FALSE;
}
- if (!AnimBankSpriteExists(bank))
+ if (!IsBankSpritePresent(bank))
return FALSE;
if (IsContest())
return TRUE; // this line wont ever be reached.
@@ -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_link_opponent.c b/src/battle_controller_link_opponent.c
new file mode 100644
index 000000000..968f6d49f
--- /dev/null
+++ b/src/battle_controller_link_opponent.c
@@ -0,0 +1,1891 @@
+#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 "battle_link_817C95C.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"
+#include "data2.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 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 MusicPlayerInfo gMPlay_BGM;
+extern struct UnusedControllerStruct gUnknown_02022D0C;
+extern u16 gTrainerBattleOpponent_A;
+extern u16 gTrainerBattleOpponent_B;
+
+extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
+extern const struct BattleMove gBattleMoves[];
+extern const u8 gUnknown_0831F578[];
+
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+extern void sub_81851A8(u8 *);
+extern u16 sub_8068B48(void);
+
+// this file's functions
+static void LinkOpponentHandleGetMonData(void);
+static void LinkOpponentHandleGetRawMonData(void);
+static void LinkOpponentHandleSetMonData(void);
+static void LinkOpponentHandleSetRawMonData(void);
+static void LinkOpponentHandleLoadMonSprite(void);
+static void LinkOpponentHandleSwitchInAnim(void);
+static void LinkOpponentHandleReturnMonToBall(void);
+static void LinkOpponentHandleDrawTrainerPic(void);
+static void LinkOpponentHandleTrainerSlide(void);
+static void LinkOpponentHandleTrainerSlideBack(void);
+static void LinkOpponentHandleFaintAnimation(void);
+static void LinkOpponentHandlePaletteFade(void);
+static void LinkOpponentHandleSuccessBallThrowAnim(void);
+static void LinkOpponentHandleBallThrowAnim(void);
+static void LinkOpponentHandlePause(void);
+static void LinkOpponentHandleMoveAnimation(void);
+static void LinkOpponentHandlePrintString(void);
+static void LinkOpponentHandlePrintStringPlayerOnly(void);
+static void LinkOpponentHandleChooseAction(void);
+static void LinkOpponentHandleUnknownYesNoBox(void);
+static void LinkOpponentHandleChooseMove(void);
+static void LinkOpponentHandleChooseItem(void);
+static void LinkOpponentHandleChoosePokemon(void);
+static void LinkOpponentHandleCmd23(void);
+static void LinkOpponentHandleHealthBarUpdate(void);
+static void LinkOpponentHandleExpUpdate(void);
+static void LinkOpponentHandleStatusIconUpdate(void);
+static void LinkOpponentHandleStatusAnimation(void);
+static void LinkOpponentHandleStatusXor(void);
+static void LinkOpponentHandleDataTransfer(void);
+static void LinkOpponentHandleDMA3Transfer(void);
+static void LinkOpponentHandlePlayBGM(void);
+static void LinkOpponentHandleCmd32(void);
+static void LinkOpponentHandleTwoReturnValues(void);
+static void LinkOpponentHandleChosenMonReturnValue(void);
+static void LinkOpponentHandleOneReturnValue(void);
+static void LinkOpponentHandleOneReturnValue_Duplicate(void);
+static void LinkOpponentHandleCmd37(void);
+static void LinkOpponentHandleCmd38(void);
+static void LinkOpponentHandleCmd39(void);
+static void LinkOpponentHandleCmd40(void);
+static void LinkOpponentHandleHitAnimation(void);
+static void LinkOpponentHandleCmd42(void);
+static void LinkOpponentHandleEffectivenessSound(void);
+static void LinkOpponentHandlePlayFanfareOrBGM(void);
+static void LinkOpponentHandleFaintingCry(void);
+static void LinkOpponentHandleIntroSlide(void);
+static void LinkOpponentHandleIntroTrainerBallThrow(void);
+static void LinkOpponentHandleDrawPartyStatusSummary(void);
+static void LinkOpponentHandleCmd49(void);
+static void LinkOpponentHandleCmd50(void);
+static void LinkOpponentHandleSpriteInvisibility(void);
+static void LinkOpponentHandleBattleAnimation(void);
+static void LinkOpponentHandleLinkStandbyMsg(void);
+static void LinkOpponentHandleResetActionMoveSelection(void);
+static void LinkOpponentHandleCmd55(void);
+static void nullsub_92(void);
+
+static void LinkOpponentBufferRunCommand(void);
+static void LinkOpponentBufferExecCompleted(void);
+static void sub_8064DD0(void);
+static u32 CopyLinkOpponentMonData(u8 monId, u8 *dst);
+static void SetLinkOpponentMonData(u8 monId);
+static void sub_8066494(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void LinkOpponentDoMoveAnimation(void);
+static void sub_8067618(u8 taskId);
+static void sub_80676FC(struct Sprite *sprite);
+static void sub_806782C(void);
+
+static void (*const sLinkOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(void) =
+{
+ LinkOpponentHandleGetMonData,
+ LinkOpponentHandleGetRawMonData,
+ LinkOpponentHandleSetMonData,
+ LinkOpponentHandleSetRawMonData,
+ LinkOpponentHandleLoadMonSprite,
+ LinkOpponentHandleSwitchInAnim,
+ LinkOpponentHandleReturnMonToBall,
+ LinkOpponentHandleDrawTrainerPic,
+ LinkOpponentHandleTrainerSlide,
+ LinkOpponentHandleTrainerSlideBack,
+ LinkOpponentHandleFaintAnimation,
+ LinkOpponentHandlePaletteFade,
+ LinkOpponentHandleSuccessBallThrowAnim,
+ LinkOpponentHandleBallThrowAnim,
+ LinkOpponentHandlePause,
+ LinkOpponentHandleMoveAnimation,
+ LinkOpponentHandlePrintString,
+ LinkOpponentHandlePrintStringPlayerOnly,
+ LinkOpponentHandleChooseAction,
+ LinkOpponentHandleUnknownYesNoBox,
+ LinkOpponentHandleChooseMove,
+ LinkOpponentHandleChooseItem,
+ LinkOpponentHandleChoosePokemon,
+ LinkOpponentHandleCmd23,
+ LinkOpponentHandleHealthBarUpdate,
+ LinkOpponentHandleExpUpdate,
+ LinkOpponentHandleStatusIconUpdate,
+ LinkOpponentHandleStatusAnimation,
+ LinkOpponentHandleStatusXor,
+ LinkOpponentHandleDataTransfer,
+ LinkOpponentHandleDMA3Transfer,
+ LinkOpponentHandlePlayBGM,
+ LinkOpponentHandleCmd32,
+ LinkOpponentHandleTwoReturnValues,
+ LinkOpponentHandleChosenMonReturnValue,
+ LinkOpponentHandleOneReturnValue,
+ LinkOpponentHandleOneReturnValue_Duplicate,
+ LinkOpponentHandleCmd37,
+ LinkOpponentHandleCmd38,
+ LinkOpponentHandleCmd39,
+ LinkOpponentHandleCmd40,
+ LinkOpponentHandleHitAnimation,
+ LinkOpponentHandleCmd42,
+ LinkOpponentHandleEffectivenessSound,
+ LinkOpponentHandlePlayFanfareOrBGM,
+ LinkOpponentHandleFaintingCry,
+ LinkOpponentHandleIntroSlide,
+ LinkOpponentHandleIntroTrainerBallThrow,
+ LinkOpponentHandleDrawPartyStatusSummary,
+ LinkOpponentHandleCmd49,
+ LinkOpponentHandleCmd50,
+ LinkOpponentHandleSpriteInvisibility,
+ LinkOpponentHandleBattleAnimation,
+ LinkOpponentHandleLinkStandbyMsg,
+ LinkOpponentHandleResetActionMoveSelection,
+ LinkOpponentHandleCmd55,
+ nullsub_92
+};
+
+static void nullsub_28(void)
+{
+}
+
+void SetControllerToLinkOpponent(void)
+{
+ gBattleBankFunc[gActiveBank] = LinkOpponentBufferRunCommand;
+}
+
+static void LinkOpponentBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sLinkOpponentBufferCommands))
+ sLinkOpponentBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ LinkOpponentBufferExecCompleted();
+}
+
+static void CompleteOnBankSpriteCallbackDummy2(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ LinkOpponentBufferExecCompleted();
+}
+
+static void sub_8064470(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ FreeTrainerFrontPicPalette(gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_80644D8(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8064520(void)
+{
+ bool32 r8 = FALSE;
+ bool32 r4 = FALSE;
+
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ r8 = TRUE;
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ {
+ r8 = TRUE;
+ }
+ r4 = TRUE;
+ }
+
+ if (r8)
+ {
+ if (r4 || !IsAnimBankSpriteVisible(gActiveBank ^ BIT_MON))
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ return;
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1)
+ return;
+
+ 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);
+ }
+ else
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ return;
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+
+ if (GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON2)
+ {
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+ }
+ }
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_80644D8;
+ }
+}
+
+static void sub_8064734(void)
+{
+ bool32 r10 = FALSE;
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ }
+ if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1)
+ {
+ sub_8172EF0(gActiveBank ^ BIT_MON, &gEnemyParty[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], &gEnemyParty[gBattlePartyID[gActiveBank ^ BIT_MON]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank ^ BIT_MON);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank ^ BIT_MON]);
+ }
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[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)
+ {
+ if (GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON1)
+ m4aMPlayContinue(&gMPlay_BGM);
+ }
+ else
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ }
+ }
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 1;
+ r10 = TRUE;
+ }
+
+ if (r10)
+ {
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON2)
+ {
+ if (++gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 1)
+ return;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ }
+
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank ^ BIT_MON]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank ^ BIT_MON, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank ^ BIT_MON]], MON_DATA_SPECIES));
+ }
+
+
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 0;
+
+ gBattleBankFunc[gActiveBank] = sub_8064520;
+ }
+ }
+}
+
+static void sub_8064B04(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0)
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80)
+ {
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ }
+ else
+ {
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+ LinkOpponentBufferExecCompleted();
+ }
+ }
+ }
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], HEALTH_BAR, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8064C14(void)
+{
+ if (!gSprites[gBankSpriteIds[gActiveBank]].inUse)
+ {
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8064C58(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ sub_805EEE0(gActiveBank);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ LinkOpponentBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ LinkOpponentBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_8064D60(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+
+ gBattleBankFunc[gActiveBank] = sub_8064DD0;
+ }
+}
+
+static void sub_8064DD0(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive && !IsCryPlayingOrClearCrySongs())
+ {
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy
+ || gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy_2)
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ LinkOpponentBufferExecCompleted();
+ }
+ }
+}
+
+static void sub_8064E50(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 0);
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ CopyBattleSpriteInvisibility(gActiveBank);
+ gBattleBankFunc[gActiveBank] = sub_8064D60;
+ }
+}
+
+static void sub_8064F40(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80)
+ {
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ }
+
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+ gBattleBankFunc[gActiveBank] = sub_8064E50;
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ LinkOpponentBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = LinkOpponentBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTROLLER_TERMINATOR_NOP;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void LinkOpponentHandleGetMonData(void)
+{
+ u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two pokemon, trying to get more will result in overwriting data
+ u32 size = 0;
+ u8 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyLinkOpponentMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyLinkOpponentMonData(i, monData + size);
+ monToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ LinkOpponentBufferExecCompleted();
+}
+
+static u32 CopyLinkOpponentMonData(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(&gEnemyParty[monId], MON_DATA_SPECIES);
+ battleMon.item = GetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM);
+ for (size = 0; size < 4; size++)
+ {
+ battleMon.moves[size] = GetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + size);
+ battleMon.pp[size] = GetMonData(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ }
+ battleMon.ppBonuses = GetMonData(&gEnemyParty[monId], MON_DATA_PP_BONUSES);
+ battleMon.friendship = GetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP);
+ battleMon.experience = GetMonData(&gEnemyParty[monId], MON_DATA_EXP);
+ battleMon.hpIV = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ battleMon.attackIV = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ battleMon.defenseIV = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ battleMon.speedIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gEnemyParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gEnemyParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gEnemyParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gEnemyParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gEnemyParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gEnemyParty[monId], MON_DATA_IS_EGG);
+ battleMon.altAbility = GetMonData(&gEnemyParty[monId], MON_DATA_ALT_ABILITY);
+ battleMon.otId = GetMonData(&gEnemyParty[monId], MON_DATA_OT_ID);
+ GetMonData(&gEnemyParty[monId], MON_DATA_NICKNAME, nickname);
+ StringCopy10(battleMon.nickname, nickname);
+ GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_SPECIES);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ data16 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_MOVE1 + size);
+ moveData.pp[size] = GetMonData(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ }
+ moveData.ppBonuses = GetMonData(&gEnemyParty[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(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ dst[size] = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE);
+ size = 1;
+ break;
+ case REQUEST_OTID_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_HP_EV);
+ size = 1;
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_EV);
+ size = 1;
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_EV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void LinkOpponentHandleGetRawMonData(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetLinkOpponentMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetLinkOpponentMonData(i);
+ monToCheck >>= 1;
+ }
+ }
+ LinkOpponentBufferExecCompleted();
+}
+
+static void SetLinkOpponentMonData(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(&gEnemyParty[monId], MON_DATA_SPECIES, &battlePokemon->species);
+ SetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM, &battlePokemon->item);
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + i, &battlePokemon->moves[i]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1 + i, &battlePokemon->pp[i]);
+ }
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP_BONUSES, &battlePokemon->ppBonuses);
+ SetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP, &battlePokemon->friendship);
+ SetMonData(&gEnemyParty[monId], MON_DATA_EXP, &battlePokemon->experience);
+ iv = battlePokemon->hpIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &iv);
+ iv = battlePokemon->attackIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &iv);
+ iv = battlePokemon->defenseIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &iv);
+ iv = battlePokemon->speedIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gEnemyParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gEnemyParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MOVES_PP_BATTLE:
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + i, &moveData->moves[i]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1 + i, &moveData->pp[i]);
+ }
+ SetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBank][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_OTID_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_EXP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][7]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][8]);
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_STATUS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ }
+}
+
+static void LinkOpponentHandleSetRawMonData(void)
+{
+ u8 *dst = (u8 *)&gEnemyParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = gBattleBufferA[gActiveBank][3 + i];
+
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleLoadMonSprite(void)
+{
+ u16 species = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ 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]);
+
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+
+ gBattleBankFunc[gActiveBank] = sub_8064B04;
+}
+
+static void LinkOpponentHandleSwitchInAnim(void)
+{
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ sub_8066494(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_8064F40;
+}
+
+static void sub_8066494(u8 bank, bool8 dontClearSubstituteBit)
+{
+ u16 species;
+
+ ClearTemporarySpeciesSpriteData(bank, dontClearSubstituteBit);
+ gBattlePartyID[bank] = gBattleBufferA[bank][1];
+ species = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_SPECIES);
+ gUnknown_03005D7C[bank] = CreateInvisibleSpriteWithCallback(sub_805D714);
+ BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[bank]], bank);
+ 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, 0xFE);
+}
+
+static void LinkOpponentHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = DoSwitchOutAnimation;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ sub_805EEE0(gActiveBank);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+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_OPPONENT_MON);
+ gBattleBankFunc[gActiveBank] = sub_8064C58;
+ }
+ break;
+ }
+}
+
+static void LinkOpponentHandleDrawTrainerPic(void)
+{
+ s16 xPos;
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ if ((GetBankIdentity(gActiveBank) & BIT_MON) != 0) // second mon
+ xPos = 152;
+ else // first mon
+ xPos = 200;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
+ {
+ if (gActiveBank == 1)
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_B);
+ }
+ else
+ {
+ if ((gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_FIRE_RED
+ || (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_LEAF_GREEN)
+ {
+ if (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender != 0)
+ trainerPicId = gUnknown_0831F578[0x4F];
+ else
+ trainerPicId = gUnknown_0831F578[0x4E];
+ }
+ else if ((gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_RUBY
+ || (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_SAPPHIRE)
+ {
+ if (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender != 0)
+ trainerPicId = gUnknown_0831F578[0x51];
+ else
+ trainerPicId = gUnknown_0831F578[0x50];
+ }
+ else
+ {
+ trainerPicId = PlayerGenderToFrontTrainerPicId(gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender);
+ }
+ }
+ }
+ else
+ {
+ xPos = 176;
+ if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00)
+ {
+ trainerPicId = sub_8068B48();
+ }
+ else if ((gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].version & 0xFF) == VERSION_FIRE_RED
+ || (gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].version & 0xFF) == VERSION_LEAF_GREEN)
+ {
+ if (gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].gender != 0)
+ trainerPicId = gUnknown_0831F578[0x4F];
+ else
+ trainerPicId = gUnknown_0831F578[0x4E];
+ }
+ else if ((gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].version & 0xFF) == VERSION_RUBY
+ || (gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].version & 0xFF) == VERSION_SAPPHIRE)
+ {
+ if (gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].gender != 0)
+ trainerPicId = gUnknown_0831F578[0x51];
+ else
+ trainerPicId = gUnknown_0831F578[0x50];
+ }
+ else
+ {
+ trainerPicId = PlayerGenderToFrontTrainerPicId(gLinkPlayers[GetMultiplayerId() ^ BIT_SIDE].gender);
+ }
+ }
+
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ xPos,
+ (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 40,
+ sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = -240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 2;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam = trainerPicId;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void LinkOpponentHandleTrainerSlide(void)
+{
+ u32 trainerPicId;
+
+ if (gActiveBank == 1)
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_B);
+
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, 176, (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 40, 0x1E);
+
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 96;
+ gSprites[gBankSpriteIds[gActiveBank]].pos1.x += 32;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam = trainerPicId;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy2; // this line is redundant, because LinkOpponentBufferExecCompleted changes the battle bank function
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleTrainerSlideBack(void)
+{
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 280;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], SpriteCallbackDummy);
+ gBattleBankFunc[gActiveBank] = sub_8064470;
+}
+
+static void LinkOpponentHandleFaintAnimation(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;
+ PlaySE12WithPanning(SE_POKE_DEAD, PAN_SIDE_OPPONENT);
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039934;
+ gBattleBankFunc[gActiveBank] = sub_8064C14;
+ }
+ }
+}
+
+static void LinkOpponentHandlePaletteFade(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleSuccessBallThrowAnim(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleBallThrowAnim(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandlePause(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleMoveAnimation(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
+ {
+ LinkOpponentBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = LinkOpponentDoMoveAnimation;
+ sub_817E0FC(move, gWeatherMoveAnim, gAnimDisableStructPtr);
+ }
+ }
+}
+
+static void LinkOpponentDoMoveAnimation(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;
+ LinkOpponentBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void LinkOpponentHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter;
+ sub_817C95C(*stringId);
+}
+
+static void LinkOpponentHandlePrintStringPlayerOnly(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleChooseAction(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleUnknownYesNoBox(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleChooseMove(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleChooseItem(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleChoosePokemon(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd23(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleHealthBarUpdate(void)
+{
+ s16 hpVal;
+
+ LoadBattleBarGfx(0);
+ hpVal = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (hpVal != INSTANT_HP_BAR_DROP)
+ {
+ u32 maxHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+ u32 curHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, curHP, hpVal);
+ }
+ else
+ {
+ u32 maxHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, 0, hpVal);
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthbarDone;
+}
+
+static void LinkOpponentHandleExpUpdate(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleStatusIconUpdate(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 bank;
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[gBattlePartyID[gActiveBank]], HEALTHBOX_STATUS_ICON);
+ bank = gActiveBank;
+ gBattleSpritesDataPtr->healthBoxesData[bank].statusAnimActive = 0;
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void LinkOpponentHandleStatusAnimation(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 LinkOpponentHandleStatusXor(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleDataTransfer(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleDMA3Transfer(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandlePlayBGM(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd32(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleTwoReturnValues(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleChosenMonReturnValue(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleOneReturnValue(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleOneReturnValue_Duplicate(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ LinkOpponentBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void LinkOpponentHandleCmd42(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleEffectivenessSound(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);
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, 25, 5);
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleIntroTrainerBallThrow(void)
+{
+ u8 paletteNum;
+ u8 taskId;
+
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 280;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], sub_80676FC);
+
+ taskId = CreateTask(sub_8067618, 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_28;
+}
+
+static void sub_8067618(u8 taskId)
+{
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_8066494(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_8066494(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_8066494(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_8064734;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+}
+
+static void sub_80676FC(struct Sprite *sprite)
+{
+ FreeTrainerFrontPicPalette(sprite->oam.affineParam);
+ FreeSpriteOamMatrix(sprite);
+ DestroySprite(sprite);
+}
+
+static void LinkOpponentHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ LinkOpponentBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+
+ if (gBattleBufferA[gActiveBank][2] != 0)
+ {
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E < 2)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E++;
+ return;
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E = 0;
+ }
+ }
+
+ 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_806782C;
+ }
+}
+
+static void sub_806782C(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ LinkOpponentBufferExecCompleted();
+ }
+}
+
+static void LinkOpponentHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd50(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleSpriteInvisibility(void)
+{
+ if (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(gActiveBank);
+ }
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleBattleAnimation(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))
+ LinkOpponentBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+
+ sub_817E32C(animationId);
+ }
+}
+
+static void LinkOpponentHandleLinkStandbyMsg(void)
+{
+ sub_81851A8(&gBattleBufferA[gActiveBank][2]);
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleResetActionMoveSelection(void)
+{
+ LinkOpponentBufferExecCompleted();
+}
+
+static void LinkOpponentHandleCmd55(void)
+{
+ sub_81851A8(&gBattleBufferA[gActiveBank][4]);
+
+ if (gBattleBufferA[gActiveBank][1] == BATTLE_DREW)
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ else
+ gBattleOutcome = gBattleBufferA[gActiveBank][1] ^ BATTLE_DREW;
+
+ gSaveBlock2Ptr->field_CA9_b = gBattleBufferA[gActiveBank][2];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ LinkOpponentBufferExecCompleted();
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_92(void)
+{
+}
diff --git a/src/battle_controller_link_partner.c b/src/battle_controller_link_partner.c
new file mode 100644
index 000000000..4a70a4dc1
--- /dev/null
+++ b/src/battle_controller_link_partner.c
@@ -0,0 +1,1719 @@
+#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 "battle_link_817C95C.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"
+#include "data2.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 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_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+extern void sub_81851A8(u8 *);
+
+// this file's functions
+static void LinkPartnerHandleGetMonData(void);
+static void LinkPartnerHandleGetRawMonData(void);
+static void LinkPartnerHandleSetMonData(void);
+static void LinkPartnerHandleSetRawMonData(void);
+static void LinkPartnerHandleLoadMonSprite(void);
+static void LinkPartnerHandleSwitchInAnim(void);
+static void LinkPartnerHandleReturnMonToBall(void);
+static void LinkPartnerHandleDrawTrainerPic(void);
+static void LinkPartnerHandleTrainerSlide(void);
+static void LinkPartnerHandleTrainerSlideBack(void);
+static void LinkPartnerHandleFaintAnimation(void);
+static void LinkPartnerHandlePaletteFade(void);
+static void LinkPartnerHandleSuccessBallThrowAnim(void);
+static void LinkPartnerHandleBallThrowAnim(void);
+static void LinkPartnerHandlePause(void);
+static void LinkPartnerHandleMoveAnimation(void);
+static void LinkPartnerHandlePrintString(void);
+static void LinkPartnerHandlePrintStringPlayerOnly(void);
+static void LinkPartnerHandleChooseAction(void);
+static void LinkPartnerHandleUnknownYesNoBox(void);
+static void LinkPartnerHandleChooseMove(void);
+static void LinkPartnerHandleChooseItem(void);
+static void LinkPartnerHandleChoosePokemon(void);
+static void LinkPartnerHandleCmd23(void);
+static void LinkPartnerHandleHealthBarUpdate(void);
+static void LinkPartnerHandleExpUpdate(void);
+static void LinkPartnerHandleStatusIconUpdate(void);
+static void LinkPartnerHandleStatusAnimation(void);
+static void LinkPartnerHandleStatusXor(void);
+static void LinkPartnerHandleDataTransfer(void);
+static void LinkPartnerHandleDMA3Transfer(void);
+static void LinkPartnerHandlePlayBGM(void);
+static void LinkPartnerHandleCmd32(void);
+static void LinkPartnerHandleTwoReturnValues(void);
+static void LinkPartnerHandleChosenMonReturnValue(void);
+static void LinkPartnerHandleOneReturnValue(void);
+static void LinkPartnerHandleOneReturnValue_Duplicate(void);
+static void LinkPartnerHandleCmd37(void);
+static void LinkPartnerHandleCmd38(void);
+static void LinkPartnerHandleCmd39(void);
+static void LinkPartnerHandleCmd40(void);
+static void LinkPartnerHandleHitAnimation(void);
+static void LinkPartnerHandleCmd42(void);
+static void LinkPartnerHandleEffectivenessSound(void);
+static void LinkPartnerHandlePlayFanfareOrBGM(void);
+static void LinkPartnerHandleFaintingCry(void);
+static void LinkPartnerHandleIntroSlide(void);
+static void LinkPartnerHandleIntroTrainerBallThrow(void);
+static void LinkPartnerHandleDrawPartyStatusSummary(void);
+static void LinkPartnerHandleCmd49(void);
+static void LinkPartnerHandleCmd50(void);
+static void LinkPartnerHandleSpriteInvisibility(void);
+static void LinkPartnerHandleBattleAnimation(void);
+static void LinkPartnerHandleLinkStandbyMsg(void);
+static void LinkPartnerHandleResetActionMoveSelection(void);
+static void LinkPartnerHandleCmd55(void);
+static void nullsub_113(void);
+
+static void LinkPartnerBufferRunCommand(void);
+static void LinkPartnerBufferExecCompleted(void);
+static void sub_814B554(void);
+static u32 CopyLinkPartnerMonData(u8 monId, u8 *dst);
+static void SetLinkPartnerMonData(u8 monId);
+static void sub_814CC98(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void LinkPartnerDoMoveAnimation(void);
+static void sub_814DCCC(u8 taskId);
+static void sub_814DE9C(void);
+
+static void (*const sLinkPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(void) =
+{
+ LinkPartnerHandleGetMonData,
+ LinkPartnerHandleGetRawMonData,
+ LinkPartnerHandleSetMonData,
+ LinkPartnerHandleSetRawMonData,
+ LinkPartnerHandleLoadMonSprite,
+ LinkPartnerHandleSwitchInAnim,
+ LinkPartnerHandleReturnMonToBall,
+ LinkPartnerHandleDrawTrainerPic,
+ LinkPartnerHandleTrainerSlide,
+ LinkPartnerHandleTrainerSlideBack,
+ LinkPartnerHandleFaintAnimation,
+ LinkPartnerHandlePaletteFade,
+ LinkPartnerHandleSuccessBallThrowAnim,
+ LinkPartnerHandleBallThrowAnim,
+ LinkPartnerHandlePause,
+ LinkPartnerHandleMoveAnimation,
+ LinkPartnerHandlePrintString,
+ LinkPartnerHandlePrintStringPlayerOnly,
+ LinkPartnerHandleChooseAction,
+ LinkPartnerHandleUnknownYesNoBox,
+ LinkPartnerHandleChooseMove,
+ LinkPartnerHandleChooseItem,
+ LinkPartnerHandleChoosePokemon,
+ LinkPartnerHandleCmd23,
+ LinkPartnerHandleHealthBarUpdate,
+ LinkPartnerHandleExpUpdate,
+ LinkPartnerHandleStatusIconUpdate,
+ LinkPartnerHandleStatusAnimation,
+ LinkPartnerHandleStatusXor,
+ LinkPartnerHandleDataTransfer,
+ LinkPartnerHandleDMA3Transfer,
+ LinkPartnerHandlePlayBGM,
+ LinkPartnerHandleCmd32,
+ LinkPartnerHandleTwoReturnValues,
+ LinkPartnerHandleChosenMonReturnValue,
+ LinkPartnerHandleOneReturnValue,
+ LinkPartnerHandleOneReturnValue_Duplicate,
+ LinkPartnerHandleCmd37,
+ LinkPartnerHandleCmd38,
+ LinkPartnerHandleCmd39,
+ LinkPartnerHandleCmd40,
+ LinkPartnerHandleHitAnimation,
+ LinkPartnerHandleCmd42,
+ LinkPartnerHandleEffectivenessSound,
+ LinkPartnerHandlePlayFanfareOrBGM,
+ LinkPartnerHandleFaintingCry,
+ LinkPartnerHandleIntroSlide,
+ LinkPartnerHandleIntroTrainerBallThrow,
+ LinkPartnerHandleDrawPartyStatusSummary,
+ LinkPartnerHandleCmd49,
+ LinkPartnerHandleCmd50,
+ LinkPartnerHandleSpriteInvisibility,
+ LinkPartnerHandleBattleAnimation,
+ LinkPartnerHandleLinkStandbyMsg,
+ LinkPartnerHandleResetActionMoveSelection,
+ LinkPartnerHandleCmd55,
+ nullsub_113
+};
+
+static void nullsub_112(void)
+{
+}
+
+void SetControllerToLinkPartner(void)
+{
+ gBattleBankFunc[gActiveBank] = LinkPartnerBufferRunCommand;
+}
+
+static void LinkPartnerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sLinkPartnerBufferCommands))
+ sLinkPartnerBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ LinkPartnerBufferExecCompleted();
+}
+
+static void sub_814AF54(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ nullsub_25(0);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_814AFBC(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_814B004(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_814AFBC;
+ }
+}
+
+static void sub_814B0E8(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_814B004;
+ }
+}
+
+static void sub_814B290(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].animEnded && gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0)
+ LinkPartnerBufferExecCompleted();
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], HEALTH_BAR, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_814B340(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]);
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_814B3DC(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ LinkPartnerBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ LinkPartnerBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_814B4E0(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ CopyBattleSpriteInvisibility(gActiveBank);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+
+ gBattleBankFunc[gActiveBank] = sub_814B554;
+ }
+}
+
+static void sub_814B554(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void sub_814B5A8(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_814B4E0;
+ }
+}
+
+static void sub_814B69C(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_814B5A8;
+ }
+}
+
+static void LinkPartnerBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = LinkPartnerBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTROLLER_TERMINATOR_NOP;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ LinkPartnerBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleGetMonData(void)
+{
+ u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two pokemon, trying to get more will result in overwriting data
+ u32 size = 0;
+ u8 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyLinkPartnerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyLinkPartnerMonData(i, monData + size);
+ monToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ LinkPartnerBufferExecCompleted();
+}
+
+static u32 CopyLinkPartnerMonData(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_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG);
+ battleMon.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_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void LinkPartnerHandleGetRawMonData(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetLinkPartnerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetLinkPartnerMonData(i);
+ monToCheck >>= 1;
+ }
+ }
+ LinkPartnerBufferExecCompleted();
+}
+
+static void SetLinkPartnerMonData(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_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[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_SPEED_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_SPEED_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_SPEED_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_SPEED, &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 LinkPartnerHandleSetRawMonData(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];
+
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleLoadMonSprite(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_814B290;
+}
+
+static void LinkPartnerHandleSwitchInAnim(void)
+{
+ ClearTemporarySpeciesSpriteData(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_814CC98(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_814B69C;
+}
+
+static void sub_814CC98(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 LinkPartnerHandleReturnMonToBall(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]);
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+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_PLAYER_MON);
+ gBattleBankFunc[gActiveBank] = sub_814B3DC;
+ }
+ break;
+ }
+}
+
+static void LinkPartnerHandleDrawTrainerPic(void)
+{
+ s16 xPos;
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ if ((GetBankIdentity(gActiveBank) & BIT_MON) != 0) // second mon
+ xPos = 90;
+ else // first mon
+ xPos = 32;
+ }
+ else
+ {
+ xPos = 80;
+ }
+
+ if ((gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_FIRE_RED
+ || (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_LEAF_GREEN)
+ {
+ trainerPicId = gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender + BACK_PIC_RED;
+ }
+ else if ((gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_RUBY
+ || (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_SAPPHIRE)
+ {
+ trainerPicId = gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender + BACK_PIC_RS_BRENDAN;
+ }
+ else
+ {
+ trainerPicId = gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender;
+ }
+
+ DecompressTrainerBackPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, xPos, (8 - gTrainerBackPicCoords[trainerPicId].coords) * 4 + 80, 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 LinkPartnerHandleTrainerSlide(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleTrainerSlideBack(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_814AF54;
+}
+
+static void LinkPartnerHandleFaintAnimation(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, PAN_SIDE_PLAYER);
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 5;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039C00;
+ gBattleBankFunc[gActiveBank] = sub_814B340;
+ }
+ }
+}
+
+static void LinkPartnerHandlePaletteFade(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleSuccessBallThrowAnim(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleBallThrowAnim(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandlePause(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleMoveAnimation(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
+ {
+ LinkPartnerBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = LinkPartnerDoMoveAnimation;
+ sub_817E0FC(move, gWeatherMoveAnim, gAnimDisableStructPtr);
+ }
+ }
+}
+
+static void LinkPartnerDoMoveAnimation(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;
+ LinkPartnerBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void LinkPartnerHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter;
+ sub_817C95C(*stringId);
+}
+
+static void LinkPartnerHandlePrintStringPlayerOnly(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleChooseAction(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleUnknownYesNoBox(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleChooseMove(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleChooseItem(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleChoosePokemon(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd23(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleHealthBarUpdate(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 LinkPartnerHandleExpUpdate(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleStatusIconUpdate(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 LinkPartnerHandleStatusAnimation(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 LinkPartnerHandleStatusXor(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleDataTransfer(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleDMA3Transfer(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandlePlayBGM(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd32(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleTwoReturnValues(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleChosenMonReturnValue(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleOneReturnValue(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleOneReturnValue_Duplicate(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ LinkPartnerBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void LinkPartnerHandleCmd42(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleEffectivenessSound(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);
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, -25, 5);
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleIntroTrainerBallThrow(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 ((gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_FIRE_RED
+ || (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_LEAF_GREEN)
+ {
+ trainerPicId = gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender + BACK_PIC_RED;
+ }
+ else if ((gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_RUBY
+ || (gLinkPlayers[GetBankMultiplayerId(gActiveBank)].version & 0xFF) == VERSION_SAPPHIRE)
+ {
+ trainerPicId = gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender + BACK_PIC_RS_BRENDAN;
+ }
+ else
+ {
+ trainerPicId = gLinkPlayers[GetBankMultiplayerId(gActiveBank)].gender;
+ }
+
+ LoadCompressedPalette(gTrainerBackPicPaletteTable[trainerPicId].data, 0x100 + paletteNum * 16, 32);
+
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = paletteNum;
+
+ taskId = CreateTask(sub_814DCCC, 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_112;
+}
+
+static void sub_814DCCC(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_814CC98(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_814CC98(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ sub_814CC98(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_814B0E8;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+ }
+}
+
+static void LinkPartnerHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ LinkPartnerBufferExecCompleted();
+ }
+ 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_814DE9C;
+ }
+}
+
+static void sub_814DE9C(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ LinkPartnerBufferExecCompleted();
+ }
+}
+
+static void LinkPartnerHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd50(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleSpriteInvisibility(void)
+{
+ if (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(gActiveBank);
+ }
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleBattleAnimation(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))
+ LinkPartnerBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+
+ sub_817E32C(animationId);
+ }
+}
+
+static void LinkPartnerHandleLinkStandbyMsg(void)
+{
+ sub_81851A8(&gBattleBufferA[gActiveBank][2]);
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleResetActionMoveSelection(void)
+{
+ LinkPartnerBufferExecCompleted();
+}
+
+static void LinkPartnerHandleCmd55(void)
+{
+ sub_81851A8(&gBattleBufferA[gActiveBank][4]);
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ gSaveBlock2Ptr->field_CA9_b = gBattleBufferA[gActiveBank][2];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ LinkPartnerBufferExecCompleted();
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_113(void)
+{
+}
diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c
new file mode 100644
index 000000000..7ffd9d64b
--- /dev/null
+++ b/src/battle_controller_opponent.c
@@ -0,0 +1,2033 @@
+#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 "battle_ai_script_commands.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"
+#include "data2.h"
+
+extern u32 gBattleExecBuffer;
+extern u8 gActiveBank;
+extern u8 gBankTarget;
+extern u8 gAbsentBankFlags;
+extern bool8 gDoingBattleAnim;
+extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
+extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
+extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
+extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
+extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
+extern struct MusicPlayerInfo gMPlay_BGM;
+extern u8 gUnknown_03005D7C[BATTLE_BANKS_COUNT];
+extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
+extern void *gUnknown_020244D8;
+extern void *gUnknown_020244DC;
+extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
+extern struct SpriteTemplate gUnknown_0202499C;
+extern struct UnusedControllerStruct gUnknown_02022D0C;
+extern u16 gTrainerBattleOpponent_A;
+extern u16 gTrainerBattleOpponent_B;
+extern u32 gTransformedPersonalities[BATTLE_BANKS_COUNT];
+extern u16 gBattle_BG0_X;
+extern u16 gBattle_BG0_Y;
+extern u16 gUnknown_020243FC;
+extern u8 gUnknown_020244B4[];
+extern void (*gPreBattleCallback1)(void);
+
+extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
+extern const struct BattleMove gBattleMoves[];
+
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+extern void sub_81A57E4(u8 bank, u16 stringId);
+extern u8 sub_81A4CB0(void);
+extern u8 sub_81D5588(u16 trainerId);
+extern u8 GetFrontierTrainerFrontSpriteId(u16 trainerId);
+extern u8 GetEreaderTrainerFrontSpriteId(void);
+
+// this file's functions
+static void OpponentHandleGetMonData(void);
+static void OpponentHandleGetRawMonData(void);
+static void OpponentHandleSetMonData(void);
+static void OpponentHandleSetRawMonData(void);
+static void OpponentHandleLoadMonSprite(void);
+static void OpponentHandleSwitchInAnim(void);
+static void OpponentHandleReturnMonToBall(void);
+static void OpponentHandleDrawTrainerPic(void);
+static void OpponentHandleTrainerSlide(void);
+static void OpponentHandleTrainerSlideBack(void);
+static void OpponentHandleFaintAnimation(void);
+static void OpponentHandlePaletteFade(void);
+static void OpponentHandleSuccessBallThrowAnim(void);
+static void OpponentHandleBallThrow(void);
+static void OpponentHandlePause(void);
+static void OpponentHandleMoveAnimation(void);
+static void OpponentHandlePrintString(void);
+static void OpponentHandlePrintStringPlayerOnly(void);
+static void OpponentHandleChooseAction(void);
+static void OpponentHandleUnknownYesNoBox(void);
+static void OpponentHandleChooseMove(void);
+static void OpponentHandleChooseItem(void);
+static void OpponentHandleChoosePokemon(void);
+static void OpponentHandleCmd23(void);
+static void OpponentHandleHealthBarUpdate(void);
+static void OpponentHandleExpUpdate(void);
+static void OpponentHandleStatusIconUpdate(void);
+static void OpponentHandleStatusAnimation(void);
+static void OpponentHandleStatusXor(void);
+static void OpponentHandleDataTransfer(void);
+static void OpponentHandleDMA3Transfer(void);
+static void OpponentHandlePlayBGM(void);
+static void OpponentHandleCmd32(void);
+static void OpponentHandleTwoReturnValues(void);
+static void OpponentHandleChosenMonReturnValue(void);
+static void OpponentHandleOneReturnValue(void);
+static void OpponentHandleOneReturnValue_Duplicate(void);
+static void OpponentHandleCmd37(void);
+static void OpponentHandleCmd38(void);
+static void OpponentHandleCmd39(void);
+static void OpponentHandleCmd40(void);
+static void OpponentHandleHitAnimation(void);
+static void OpponentHandleCmd42(void);
+static void OpponentHandleEffectivenessSound(void);
+static void OpponentHandlePlayFanfareOrBGM(void);
+static void OpponentHandleFaintingCry(void);
+static void OpponentHandleIntroSlide(void);
+static void OpponentHandleIntroTrainerBallThrow(void);
+static void OpponentHandleDrawPartyStatusSummary(void);
+static void OpponentHandleCmd49(void);
+static void OpponentHandleCmd50(void);
+static void OpponentHandleSpriteInvisibility(void);
+static void OpponentHandleBattleAnimation(void);
+static void OpponentHandleLinkStandbyMsg(void);
+static void OpponentHandleResetActionMoveSelection(void);
+static void OpponentHandleCmd55(void);
+static void nullsub_91(void);
+
+static void OpponentBufferRunCommand(void);
+static void OpponentBufferExecCompleted(void);
+static void sub_805FC80(void);
+static u32 GetOpponentMonData(u8 monId, u8 *dst);
+static void SetOpponentMonData(u8 monId);
+static void sub_80613DC(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void OpponentDoMoveAnimation(void);
+static void sub_806280C(struct Sprite *sprite);
+static void sub_8062828(u8 taskId);
+static void sub_8062A2C(void);
+
+static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(void) =
+{
+ OpponentHandleGetMonData,
+ OpponentHandleGetRawMonData,
+ OpponentHandleSetMonData,
+ OpponentHandleSetRawMonData,
+ OpponentHandleLoadMonSprite,
+ OpponentHandleSwitchInAnim,
+ OpponentHandleReturnMonToBall,
+ OpponentHandleDrawTrainerPic,
+ OpponentHandleTrainerSlide,
+ OpponentHandleTrainerSlideBack,
+ OpponentHandleFaintAnimation,
+ OpponentHandlePaletteFade,
+ OpponentHandleSuccessBallThrowAnim,
+ OpponentHandleBallThrow,
+ OpponentHandlePause,
+ OpponentHandleMoveAnimation,
+ OpponentHandlePrintString,
+ OpponentHandlePrintStringPlayerOnly,
+ OpponentHandleChooseAction,
+ OpponentHandleUnknownYesNoBox,
+ OpponentHandleChooseMove,
+ OpponentHandleChooseItem,
+ OpponentHandleChoosePokemon,
+ OpponentHandleCmd23,
+ OpponentHandleHealthBarUpdate,
+ OpponentHandleExpUpdate,
+ OpponentHandleStatusIconUpdate,
+ OpponentHandleStatusAnimation,
+ OpponentHandleStatusXor,
+ OpponentHandleDataTransfer,
+ OpponentHandleDMA3Transfer,
+ OpponentHandlePlayBGM,
+ OpponentHandleCmd32,
+ OpponentHandleTwoReturnValues,
+ OpponentHandleChosenMonReturnValue,
+ OpponentHandleOneReturnValue,
+ OpponentHandleOneReturnValue_Duplicate,
+ 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 sUnknown_0831C7AC[] = {0xB0, 0xB0, 0xC8, 0x98, 0x28, 0x28, 0x28, 0x20};
+
+static void nullsub_26(void)
+{
+}
+
+void SetControllerToOpponent(void)
+{
+ gBattleBankFunc[gActiveBank] = OpponentBufferRunCommand;
+}
+
+static void OpponentBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sOpponentBufferCommands))
+ sOpponentBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ OpponentBufferExecCompleted();
+}
+
+static void CompleteOnBankSpriteCallbackDummy2(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ OpponentBufferExecCompleted();
+}
+
+static void sub_805F240(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ FreeTrainerFrontPicPalette(gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void sub_805F2A8(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void sub_805F2F0(void)
+{
+ bool8 var = FALSE;
+ bool8 var2;
+
+ if (!IsDoubleBattle() || ((IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)) || (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ var = TRUE;
+ var2 = FALSE;
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy)
+ var = TRUE;
+ var2 = TRUE;
+ }
+
+ gUnknown_020244D8 = &gBattleSpritesDataPtr->healthBoxesData[gActiveBank];
+ gUnknown_020244DC = &gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON];
+
+ if (var)
+ {
+ if (var2 == TRUE)
+ {
+ if (var2 && 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);
+ }
+ else
+ return;
+ }
+ else if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ if (GetBankIdentity(gActiveBank) == 3)
+ {
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80 == 0 && gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1 == 0)
+ {
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+ }
+ else
+ return;
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ }
+ else
+ return;
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_805F2A8;
+ }
+}
+
+static void sub_805F560(void)
+{
+ bool32 sp = FALSE;
+ bool32 r10 = FALSE;
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI) && IsDoubleBattle() && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1)
+ sub_8172EF0(gActiveBank ^ BIT_MON, &gEnemyParty[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], &gEnemyParty[gBattlePartyID[gActiveBank ^ BIT_MON]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank ^ BIT_MON);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank ^ BIT_MON]);
+ }
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[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)
+ {
+ if (GetBankIdentity(gActiveBank) == 1)
+ m4aMPlayContinue(&gMPlay_BGM);
+ }
+ else
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 1;
+ sp = TRUE;
+ }
+
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ r10 = 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)
+ {
+ r10 = TRUE;
+ }
+ }
+
+ if (sp && r10)
+ {
+ if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank ^ BIT_MON]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank ^ BIT_MON, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank ^ BIT_MON]], MON_DATA_SPECIES));
+ }
+
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 0;
+
+ gBattleBankFunc[gActiveBank] = sub_805F2F0;
+ }
+}
+
+static void sub_805F994(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy && gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], HEALTH_BAR, 0);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ OpponentBufferExecCompleted();
+}
+
+static void sub_805FAC4(void)
+{
+ if (!gSprites[gBankSpriteIds[gActiveBank]].inUse)
+ {
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void sub_805FB08(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ sub_805EEE0(gActiveBank);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ OpponentBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ OpponentBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_805FC10(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+ gBattleBankFunc[gActiveBank] = sub_805FC80;
+ }
+}
+
+static void sub_805FC80(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive && !IsCryPlayingOrClearCrySongs())
+ {
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy || gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy_2)
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ OpponentBufferExecCompleted();
+ }
+ }
+}
+
+static void sub_805FD00(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 0);
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ CopyBattleSpriteInvisibility(gActiveBank);
+ gBattleBankFunc[gActiveBank] = sub_805FC10;
+ }
+}
+
+static void sub_805FDF0(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+ gBattleBankFunc[gActiveBank] = sub_805FD00;
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ OpponentBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = OpponentBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTROLLER_TERMINATOR_NOP;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void OpponentHandleGetMonData(void)
+{
+ u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two pokemon, trying to get more will result in overwriting data
+ u32 size = 0;
+ u8 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += GetOpponentMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += GetOpponentMonData(i, monData + size);
+ monToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ OpponentBufferExecCompleted();
+}
+
+static u32 GetOpponentMonData(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(&gEnemyParty[monId], MON_DATA_SPECIES);
+ battleMon.item = GetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM);
+ for (size = 0; size < 4; size++)
+ {
+ battleMon.moves[size] = GetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + size);
+ battleMon.pp[size] = GetMonData(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ }
+ battleMon.ppBonuses = GetMonData(&gEnemyParty[monId], MON_DATA_PP_BONUSES);
+ battleMon.friendship = GetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP);
+ battleMon.experience = GetMonData(&gEnemyParty[monId], MON_DATA_EXP);
+ battleMon.hpIV = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ battleMon.attackIV = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ battleMon.defenseIV = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ battleMon.speedIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gEnemyParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gEnemyParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gEnemyParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gEnemyParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gEnemyParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gEnemyParty[monId], MON_DATA_IS_EGG);
+ battleMon.altAbility = GetMonData(&gEnemyParty[monId], MON_DATA_ALT_ABILITY);
+ battleMon.otId = GetMonData(&gEnemyParty[monId], MON_DATA_OT_ID);
+ GetMonData(&gEnemyParty[monId], MON_DATA_NICKNAME, nickname);
+ StringCopy10(battleMon.nickname, nickname);
+ GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_SPECIES);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ data16 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_MOVE1 + size);
+ moveData.pp[size] = GetMonData(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ }
+ moveData.ppBonuses = GetMonData(&gEnemyParty[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(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ dst[size] = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE);
+ size = 1;
+ break;
+ case REQUEST_OTID_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_HP_EV);
+ size = 1;
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_EV);
+ size = 1;
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_EV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void OpponentHandleGetRawMonData(void)
+{
+ struct BattlePokemon battleMon;
+ u8 *src = (u8 *)&gEnemyParty[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);
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetOpponentMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetOpponentMonData(i);
+ monToCheck >>= 1;
+ }
+ }
+ OpponentBufferExecCompleted();
+}
+
+static void SetOpponentMonData(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(&gEnemyParty[monId], MON_DATA_SPECIES, &battlePokemon->species);
+ SetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM, &battlePokemon->item);
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + i, &battlePokemon->moves[i]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1 + i, &battlePokemon->pp[i]);
+ }
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP_BONUSES, &battlePokemon->ppBonuses);
+ SetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP, &battlePokemon->friendship);
+ SetMonData(&gEnemyParty[monId], MON_DATA_EXP, &battlePokemon->experience);
+ iv = battlePokemon->hpIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &iv);
+ iv = battlePokemon->attackIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &iv);
+ iv = battlePokemon->defenseIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &iv);
+ iv = battlePokemon->speedIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gEnemyParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gEnemyParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MOVES_PP_BATTLE:
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + i, &moveData->moves[i]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1 + i, &moveData->pp[i]);
+ }
+ SetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBank][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_OTID_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_EXP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][7]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][8]);
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_STATUS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ }
+}
+
+static void OpponentHandleSetRawMonData(void)
+{
+ u8 *dst = (u8 *)&gEnemyParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = gBattleBufferA[gActiveBank][3 + i];
+
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleLoadMonSprite(void)
+{
+ u16 species = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ 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]].data2 = species;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = gActiveBank;
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], gBattleMonForms[gActiveBank]);
+
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+
+ gBattleBankFunc[gActiveBank] = sub_805F994;
+}
+
+static void OpponentHandleSwitchInAnim(void)
+{
+ *(gBattleStruct->field_5C + gActiveBank) = 6;
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ sub_80613DC(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_805FDF0;
+}
+
+static void sub_80613DC(u8 bank, bool8 dontClearSubstituteBit)
+{
+ u16 species;
+
+ ClearTemporarySpeciesSpriteData(bank, dontClearSubstituteBit);
+ gBattlePartyID[bank] = gBattleBufferA[bank][1];
+ species = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_SPECIES);
+ gUnknown_03005D7C[bank] = CreateInvisibleSpriteWithCallback(sub_805D714);
+ BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[bank]], bank);
+ sub_806A068(species, GetBankIdentity(bank));
+
+ gBankSpriteIds[bank] = CreateSprite(&gUnknown_0202499C,
+ sub_80A5C6C(bank, 2),
+ sub_80A6138(bank),
+ sub_80A82E4(bank));
+
+ gSprites[gBankSpriteIds[bank]].data0 = bank;
+ gSprites[gBankSpriteIds[bank]].data2 = species;
+
+ gSprites[gUnknown_03005D7C[bank]].data1 = gBankSpriteIds[bank];
+ gSprites[gUnknown_03005D7C[bank]].data2 = bank;
+
+ 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, 0xFE);
+}
+
+static void OpponentHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = DoSwitchOutAnimation;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ sub_805EEE0(gActiveBank);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ OpponentBufferExecCompleted();
+ }
+}
+
+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_OPPONENT_MON);
+ gBattleBankFunc[gActiveBank] = sub_805FB08;
+ }
+ break;
+ }
+}
+
+static void OpponentHandleDrawTrainerPic(void)
+{
+ u32 trainerPicId;
+ s16 xPos;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_SECRET_BASE)
+ {
+ trainerPicId = GetSecretBaseTrainerPicIndex();
+ }
+ else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_3FE)
+ {
+ trainerPicId = sub_81A4CB0();
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_x4000000)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ {
+ if (gActiveBank == 1)
+ trainerPicId = sub_81D5588(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = sub_81D5588(gTrainerBattleOpponent_B);
+ }
+ else
+ {
+ trainerPicId = sub_81D5588(gTrainerBattleOpponent_A);
+ }
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
+ {
+ if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000))
+ {
+ if (gActiveBank == 1)
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_B);
+ }
+ else
+ {
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ }
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER)
+ {
+ trainerPicId = GetEreaderTrainerFrontSpriteId();
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ {
+ if (gActiveBank != 1)
+ trainerPicId = gTrainers[gTrainerBattleOpponent_B].trainerPic;
+ else
+ trainerPicId = gTrainers[gTrainerBattleOpponent_A].trainerPic;
+ }
+ else
+ {
+ trainerPicId = gTrainers[gTrainerBattleOpponent_A].trainerPic;
+ }
+
+ if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS))
+ {
+ if ((GetBankIdentity(gActiveBank) & BIT_MON) != 0) // second mon
+ xPos = 152;
+ else // first mon
+ xPos = 200;
+ }
+ else
+ {
+ xPos = 176;
+ }
+
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ xPos,
+ (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 40,
+ sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = -240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 2;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam = trainerPicId;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void OpponentHandleTrainerSlide(void)
+{
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_SECRET_BASE)
+ {
+ trainerPicId = GetSecretBaseTrainerPicIndex();
+ }
+ else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_3FE)
+ {
+ trainerPicId = sub_81A4CB0();
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_x4000000)
+ {
+ if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ {
+ if (gActiveBank == 1)
+ trainerPicId = sub_81D5588(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = sub_81D5588(gTrainerBattleOpponent_B);
+ }
+ else
+ {
+ trainerPicId = sub_81D5588(gTrainerBattleOpponent_A);
+ }
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
+ {
+ if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000))
+ {
+ if (gActiveBank == 1)
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_B);
+ }
+ else
+ {
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ }
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER)
+ {
+ trainerPicId = GetEreaderTrainerFrontSpriteId();
+ }
+ else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ {
+ if (gActiveBank != 1)
+ trainerPicId = gTrainers[gTrainerBattleOpponent_B].trainerPic;
+ else
+ trainerPicId = gTrainers[gTrainerBattleOpponent_A].trainerPic;
+ }
+ else
+ {
+ trainerPicId = gTrainers[gTrainerBattleOpponent_A].trainerPic;
+ }
+
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C, 176, (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 40, 0x1E);
+
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = 96;
+ gSprites[gBankSpriteIds[gActiveBank]].pos1.x += 32;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = -2;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam = trainerPicId;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy2;
+}
+
+static void OpponentHandleTrainerSlideBack(void)
+{
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 280;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], SpriteCallbackDummy);
+ gBattleBankFunc[gActiveBank] = sub_805F240;
+}
+
+static void OpponentHandleFaintAnimation(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;
+ PlaySE12WithPanning(SE_POKE_DEAD, PAN_SIDE_OPPONENT);
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039934;
+ gBattleBankFunc[gActiveBank] = sub_805FAC4;
+ }
+ }
+}
+
+static void OpponentHandlePaletteFade(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleSuccessBallThrowAnim(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleBallThrow(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandlePause(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleMoveAnimation(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
+ {
+ OpponentBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = OpponentDoMoveAnimation;
+ }
+ }
+}
+
+static void OpponentDoMoveAnimation(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;
+ OpponentBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void OpponentHandlePrintString(void)
+{
+ u16 *stringId;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ stringId = (u16*)(&gBattleBufferA[gActiveBank][2]);
+ BufferStringBattle(*stringId);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gBattleBankFunc[gActiveBank] = CompleteOnInactiveTextPrinter;
+ sub_81A57E4(gActiveBank, *stringId);
+}
+
+static void OpponentHandlePrintStringPlayerOnly(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleChooseAction(void)
+{
+ AI_TrySwitchOrUseItem();
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleUnknownYesNoBox(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleChooseMove(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
+ {
+ EmitTwoReturnValues(1, 10, ChooseMoveAndTargetInBattlePalace());
+ OpponentBufferExecCompleted();
+ }
+ else
+ {
+ u8 chosenMoveId;
+ struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]);
+
+ if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER))
+ {
+
+ BattleAI_SetupAIData(0xF);
+ chosenMoveId = BattleAI_ChooseMoveOrAction();
+
+ switch (chosenMoveId)
+ {
+ case 5:
+ EmitTwoReturnValues(1, ACTION_WATCHES_CAREFULLY, 0);
+ break;
+ case 4:
+ EmitTwoReturnValues(1, ACTION_RUN, 0);
+ break;
+ case 6:
+ EmitTwoReturnValues(1, 15, gBankTarget);
+ break;
+ default:
+ if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_x10))
+ gBankTarget = gActiveBank;
+ if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH)
+ {
+ gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1);
+ if (gAbsentBankFlags & gBitTable[gBankTarget])
+ gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2);
+ }
+ EmitTwoReturnValues(1, 10, (chosenMoveId) | (gBankTarget << 8));
+ break;
+ }
+ OpponentBufferExecCompleted();
+ }
+ else
+ {
+ u16 move;
+ do
+ {
+ chosenMoveId = Random() & 3;
+ move = moveInfo->moves[chosenMoveId];
+ } while (move == MOVE_NONE);
+
+ if (gBattleMoves[move].target & (MOVE_TARGET_USER | MOVE_TARGET_x10))
+ EmitTwoReturnValues(1, 10, (chosenMoveId) | (gActiveBank << 8));
+ else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
+ EmitTwoReturnValues(1, 10, (chosenMoveId) | (GetBankByIdentity(Random() & 2) << 8));
+ else
+ EmitTwoReturnValues(1, 10, (chosenMoveId) | (GetBankByIdentity(IDENTITY_PLAYER_MON1) << 8));
+
+ OpponentBufferExecCompleted();
+ }
+ }
+}
+
+static void OpponentHandleChooseItem(void)
+{
+ EmitOneReturnValue(1, *(gBattleStruct->chosenItem + (gActiveBank / 2) * 2));
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleChoosePokemon(void)
+{
+ s32 chosenMonId;
+
+ if (*(gBattleStruct->field_294 + gActiveBank) == 6)
+ {
+ chosenMonId = GetMostSuitableMonToSwitchInto();
+
+ if (chosenMonId == 6)
+ {
+ s32 bank1, bank2, firstId, lastId;
+
+ if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
+ {
+ bank2 = bank1 = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
+ }
+ else
+ {
+ bank1 = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
+ bank2 = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
+ }
+
+ if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000))
+ {
+ if (gActiveBank == 1)
+ firstId = 0, lastId = 3;
+ else
+ firstId = 3, lastId = 6;
+ }
+ else
+ {
+ firstId = 0, lastId = 6;
+ }
+
+ for (chosenMonId = firstId; chosenMonId < lastId; chosenMonId++)
+ {
+ if (GetMonData(&gEnemyParty[chosenMonId], MON_DATA_HP) != 0
+ && chosenMonId != gBattlePartyID[bank1]
+ && chosenMonId != gBattlePartyID[bank2])
+ {
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ chosenMonId = *(gBattleStruct->field_294 + gActiveBank);
+ *(gBattleStruct->field_294 + gActiveBank) = 6;
+ }
+
+
+ *(gBattleStruct->field_5C + gActiveBank) = chosenMonId;
+ EmitChosenMonReturnValue(1, chosenMonId, NULL);
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd23(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleHealthBarUpdate(void)
+{
+ s16 hpVal;
+
+ LoadBattleBarGfx(0);
+ hpVal = (gBattleBufferA[gActiveBank][3] << 8) | gBattleBufferA[gActiveBank][2];
+
+ if (hpVal != INSTANT_HP_BAR_DROP)
+ {
+ u32 maxHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+ u32 curHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, curHP, hpVal);
+ }
+ else
+ {
+ u32 maxHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, 0, hpVal);
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthbarDone;
+}
+
+static void OpponentHandleExpUpdate(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleStatusIconUpdate(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 bank;
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[gBattlePartyID[gActiveBank]], HEALTHBOX_STATUS_ICON);
+ bank = gActiveBank;
+ gBattleSpritesDataPtr->healthBoxesData[bank].statusAnimActive = 0;
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void OpponentHandleStatusAnimation(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 OpponentHandleStatusXor(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleDataTransfer(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleDMA3Transfer(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandlePlayBGM(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd32(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleTwoReturnValues(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleChosenMonReturnValue(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleOneReturnValue(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleOneReturnValue_Duplicate(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ OpponentBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void OpponentHandleCmd42(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleEffectivenessSound(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);
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, 25, 5);
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleIntroTrainerBallThrow(void)
+{
+ u8 paletteNum;
+ u8 taskId;
+
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 280;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], sub_806280C);
+
+ taskId = CreateTask(sub_8062828, 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_26;
+}
+
+static void sub_806280C(struct Sprite *sprite)
+{
+ FreeTrainerFrontPicPalette(sprite->oam.affineParam);
+ FreeSpriteOamMatrix(sprite);
+ DestroySprite(sprite);
+}
+
+static void sub_8062828(u8 taskId)
+{
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_80613DC(gActiveBank, FALSE);
+ }
+ else if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_80613DC(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_80613DC(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_80613DC(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_805F560;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+}
+
+static void OpponentHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ OpponentBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+
+ if (gBattleBufferA[gActiveBank][2] != 0)
+ {
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E < 2)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E++;
+ return;
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E = 0;
+ }
+ }
+
+ 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_8062A2C;
+ }
+}
+
+static void sub_8062A2C(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ OpponentBufferExecCompleted();
+ }
+}
+
+static void OpponentHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd50(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleSpriteInvisibility(void)
+{
+ if (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(gActiveBank);
+ }
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleBattleAnimation(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))
+ OpponentBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+ }
+}
+
+static void OpponentHandleLinkStandbyMsg(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleResetActionMoveSelection(void)
+{
+ OpponentBufferExecCompleted();
+}
+
+static void OpponentHandleCmd55(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK && !(gBattleTypeFlags & BATTLE_TYPE_WILD))
+ {
+ gMain.inBattle = 0;
+ gMain.callback1 = gPreBattleCallback1;
+ SetMainCallback2(gMain.savedCallback);
+ }
+ OpponentBufferExecCompleted();
+}
+
+static void nullsub_91(void)
+{
+}
diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c
new file mode 100644
index 000000000..10d361cb9
--- /dev/null
+++ b/src/battle_controller_player.c
@@ -0,0 +1,3150 @@
+#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"
+#include "data2.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 gPlayerDpadHoldFrames;
+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 sPlayerBufferCommands[CONTROLLER_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 SetControllerToPlayer(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerBufferRunCommand;
+ gDoingBattleAnim = FALSE;
+ gPlayerDpadHoldFrames = 0;
+}
+
+static void PlayerBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTROLLER_TERMINATOR_NOP;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void PlayerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sPlayerBufferCommands))
+ sPlayerBufferCommands[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)
+ gPlayerDpadHoldFrames++;
+ else
+ gPlayerDpadHoldFrames = 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 || gPlayerDpadHoldFrames > 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)
+ gPlayerDpadHoldFrames++;
+ else
+ gPlayerDpadHoldFrames = 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 || gPlayerDpadHoldFrames > 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)
+ gPlayerDpadHoldFrames++;
+ else
+ gPlayerDpadHoldFrames = 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 || gPlayerDpadHoldFrames > 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)
+ {
+ CopyBattleSpriteInvisibility(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], HEALTH_BAR, 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 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyPlayerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyPlayerMonData(i, monData + size);
+ monToCheck >>= 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_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG);
+ battleMon.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_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+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 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetPlayerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetPlayerMonData(i);
+ monToCheck >>= 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_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[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_SPEED_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_SPEED_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_SPEED_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_SPEED, &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_PLAYER_MON);
+ gBattleBankFunc[gActiveBank] = sub_8059744;
+ }
+ break;
+ }
+}
+
+// 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, PAN_SIDE_PLAYER);
+ 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 = TRUE;
+ 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 (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(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..34fd8a3eb
--- /dev/null
+++ b/src/battle_controller_player_partner.c
@@ -0,0 +1,1960 @@
+#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"
+#include "data2.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 sPlayerPartnerBufferCommands[CONTROLLER_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 SetControllerToPlayerPartner(void)
+{
+ gBattleBankFunc[gActiveBank] = PlayerPartnerBufferRunCommand;
+}
+
+static void PlayerPartnerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sPlayerPartnerBufferCommands))
+ sPlayerPartnerBufferCommands[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], HEALTH_BAR, 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)
+ {
+ CopyBattleSpriteInvisibility(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] = CONTROLLER_TERMINATOR_NOP;
+ }
+ 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 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyPlayerPartnerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyPlayerPartnerMonData(i, monData + size);
+ monToCheck >>= 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_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG);
+ battleMon.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_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void PlayerPartnerHandleGetRawMonData(void)
+{
+ PlayerPartnerBufferExecCompleted();
+}
+
+static void PlayerPartnerHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetPlayerPartnerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetPlayerPartnerMonData(i);
+ monToCheck >>= 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_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[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_SPEED_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_SPEED_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_SPEED_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_SPEED, &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_PLAYER_MON);
+ gBattleBankFunc[gActiveBank] = sub_81BB828;
+ }
+ break;
+ }
+}
+
+// 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, PAN_SIDE_PLAYER);
+ 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 (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(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_opponent.c b/src/battle_controller_recorded_opponent.c
new file mode 100644
index 000000000..0dc7631ce
--- /dev/null
+++ b/src/battle_controller_recorded_opponent.c
@@ -0,0 +1,1829 @@
+#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 "battle_link_817C95C.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"
+#include "data2.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 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 MusicPlayerInfo gMPlay_BGM;
+extern struct UnusedControllerStruct gUnknown_02022D0C;
+extern u16 gTrainerBattleOpponent_A;
+extern u16 gTrainerBattleOpponent_B;
+extern u8 gUnknown_0203C7B4;
+
+extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[];
+
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+extern u16 sub_8068B48(void);
+
+// this file's functions
+static void RecordedOpponentHandleGetMonData(void);
+static void RecordedOpponentHandleGetRawMonData(void);
+static void RecordedOpponentHandleSetMonData(void);
+static void RecordedOpponentHandleSetRawMonData(void);
+static void RecordedOpponentHandleLoadMonSprite(void);
+static void RecordedOpponentHandleSwitchInAnim(void);
+static void RecordedOpponentHandleReturnMonToBall(void);
+static void RecordedOpponentHandleDrawTrainerPic(void);
+static void RecordedOpponentHandleTrainerSlide(void);
+static void RecordedOpponentHandleTrainerSlideBack(void);
+static void RecordedOpponentHandleFaintAnimation(void);
+static void RecordedOpponentHandlePaletteFade(void);
+static void RecordedOpponentHandleSuccessBallThrowAnim(void);
+static void RecordedOpponentHandleBallThrowAnim(void);
+static void RecordedOpponentHandlePause(void);
+static void RecordedOpponentHandleMoveAnimation(void);
+static void RecordedOpponentHandlePrintString(void);
+static void RecordedOpponentHandlePrintStringPlayerOnly(void);
+static void RecordedOpponentHandleChooseAction(void);
+static void RecordedOpponentHandleUnknownYesNoBox(void);
+static void RecordedOpponentHandleChooseMove(void);
+static void RecordedOpponentHandleChooseItem(void);
+static void RecordedOpponentHandleChoosePokemon(void);
+static void RecordedOpponentHandleCmd23(void);
+static void RecordedOpponentHandleHealthBarUpdate(void);
+static void RecordedOpponentHandleExpUpdate(void);
+static void RecordedOpponentHandleStatusIconUpdate(void);
+static void RecordedOpponentHandleStatusAnimation(void);
+static void RecordedOpponentHandleStatusXor(void);
+static void RecordedOpponentHandleDataTransfer(void);
+static void RecordedOpponentHandleDMA3Transfer(void);
+static void RecordedOpponentHandlePlayBGM(void);
+static void RecordedOpponentHandleCmd32(void);
+static void RecordedOpponentHandleTwoReturnValues(void);
+static void RecordedOpponentHandleChosenMonReturnValue(void);
+static void RecordedOpponentHandleOneReturnValue(void);
+static void RecordedOpponentHandleOneReturnValue_Duplicate(void);
+static void RecordedOpponentHandleCmd37(void);
+static void RecordedOpponentHandleCmd38(void);
+static void RecordedOpponentHandleCmd39(void);
+static void RecordedOpponentHandleCmd40(void);
+static void RecordedOpponentHandleHitAnimation(void);
+static void RecordedOpponentHandleCmd42(void);
+static void RecordedOpponentHandleEffectivenessSound(void);
+static void RecordedOpponentHandlePlayFanfareOrBGM(void);
+static void RecordedOpponentHandleFaintingCry(void);
+static void RecordedOpponentHandleIntroSlide(void);
+static void RecordedOpponentHandleIntroTrainerBallThrow(void);
+static void RecordedOpponentHandleDrawPartyStatusSummary(void);
+static void RecordedOpponentHandleCmd49(void);
+static void RecordedOpponentHandleCmd50(void);
+static void RecordedOpponentHandleSpriteInvisibility(void);
+static void RecordedOpponentHandleBattleAnimation(void);
+static void RecordedOpponentHandleLinkStandbyMsg(void);
+static void RecordedOpponentHandleResetActionMoveSelection(void);
+static void RecordedOpponentHandleCmd55(void);
+static void nullsub_119(void);
+
+static void RecordedOpponentBufferRunCommand(void);
+static void RecordedOpponentBufferExecCompleted(void);
+static void sub_8186F14(void);
+static u32 CopyRecordedOpponentMonData(u8 monId, u8 *dst);
+static void SetRecordedOpponentMonData(u8 monId);
+static void sub_81885D8(u8 bank, bool8 dontClearSubstituteBit);
+static void DoSwitchOutAnimation(void);
+static void RecordedOpponentDoMoveAnimation(void);
+static void sub_8189548(u8 taskId);
+static void sub_818962C(struct Sprite *sprite);
+static void sub_818975C(void);
+
+static void (*const sRecordedOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(void) =
+{
+ RecordedOpponentHandleGetMonData,
+ RecordedOpponentHandleGetRawMonData,
+ RecordedOpponentHandleSetMonData,
+ RecordedOpponentHandleSetRawMonData,
+ RecordedOpponentHandleLoadMonSprite,
+ RecordedOpponentHandleSwitchInAnim,
+ RecordedOpponentHandleReturnMonToBall,
+ RecordedOpponentHandleDrawTrainerPic,
+ RecordedOpponentHandleTrainerSlide,
+ RecordedOpponentHandleTrainerSlideBack,
+ RecordedOpponentHandleFaintAnimation,
+ RecordedOpponentHandlePaletteFade,
+ RecordedOpponentHandleSuccessBallThrowAnim,
+ RecordedOpponentHandleBallThrowAnim,
+ RecordedOpponentHandlePause,
+ RecordedOpponentHandleMoveAnimation,
+ RecordedOpponentHandlePrintString,
+ RecordedOpponentHandlePrintStringPlayerOnly,
+ RecordedOpponentHandleChooseAction,
+ RecordedOpponentHandleUnknownYesNoBox,
+ RecordedOpponentHandleChooseMove,
+ RecordedOpponentHandleChooseItem,
+ RecordedOpponentHandleChoosePokemon,
+ RecordedOpponentHandleCmd23,
+ RecordedOpponentHandleHealthBarUpdate,
+ RecordedOpponentHandleExpUpdate,
+ RecordedOpponentHandleStatusIconUpdate,
+ RecordedOpponentHandleStatusAnimation,
+ RecordedOpponentHandleStatusXor,
+ RecordedOpponentHandleDataTransfer,
+ RecordedOpponentHandleDMA3Transfer,
+ RecordedOpponentHandlePlayBGM,
+ RecordedOpponentHandleCmd32,
+ RecordedOpponentHandleTwoReturnValues,
+ RecordedOpponentHandleChosenMonReturnValue,
+ RecordedOpponentHandleOneReturnValue,
+ RecordedOpponentHandleOneReturnValue_Duplicate,
+ RecordedOpponentHandleCmd37,
+ RecordedOpponentHandleCmd38,
+ RecordedOpponentHandleCmd39,
+ RecordedOpponentHandleCmd40,
+ RecordedOpponentHandleHitAnimation,
+ RecordedOpponentHandleCmd42,
+ RecordedOpponentHandleEffectivenessSound,
+ RecordedOpponentHandlePlayFanfareOrBGM,
+ RecordedOpponentHandleFaintingCry,
+ RecordedOpponentHandleIntroSlide,
+ RecordedOpponentHandleIntroTrainerBallThrow,
+ RecordedOpponentHandleDrawPartyStatusSummary,
+ RecordedOpponentHandleCmd49,
+ RecordedOpponentHandleCmd50,
+ RecordedOpponentHandleSpriteInvisibility,
+ RecordedOpponentHandleBattleAnimation,
+ RecordedOpponentHandleLinkStandbyMsg,
+ RecordedOpponentHandleResetActionMoveSelection,
+ RecordedOpponentHandleCmd55,
+ nullsub_119
+};
+
+static void nullsub_70(void)
+{
+}
+
+void SetControllerToRecordedOpponent(void)
+{
+ gBattleBankFunc[gActiveBank] = RecordedOpponentBufferRunCommand;
+}
+
+static void RecordedOpponentBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sRecordedOpponentBufferCommands))
+ sRecordedOpponentBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void CompleteOnBankSpriteCallbackDummy2(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void sub_81865C8(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ FreeTrainerFrontPicPalette(gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam);
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8186630(void)
+{
+ if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 == 0xFF)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 0;
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8186678(void)
+{
+ bool8 var = FALSE;
+
+ if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].animEnded)
+ {
+ var = TRUE;
+ }
+
+ }
+ else
+ {
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gHealthBoxesIds[gActiveBank ^ BIT_MON]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].animEnded
+ && gSprites[gBankSpriteIds[gActiveBank ^ BIT_MON]].animEnded)
+ {
+ var = TRUE;
+ }
+ }
+
+ if (var)
+ {
+ if (GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON1)
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ return;
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].field_1_x1)
+ return;
+
+ 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);
+ }
+
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_9 = 3;
+ gBattleBankFunc[gActiveBank] = sub_8186630;
+ }
+}
+
+static void sub_818686C(void)
+{
+ bool32 r9 = FALSE;
+ bool32 r8 = FALSE;
+
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank ^ BIT_MON].flag_x8)
+ sub_8172EF0(gActiveBank ^ BIT_MON, &gEnemyParty[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], &gEnemyParty[gBattlePartyID[gActiveBank ^ BIT_MON]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank ^ BIT_MON);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank ^ BIT_MON]);
+ }
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[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)
+ {
+ if (GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON1)
+ m4aMPlayContinue(&gMPlay_BGM);
+ }
+ else
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ }
+ }
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 1;
+ r9 = TRUE;
+ }
+
+ if (!IsDoubleBattle())
+ {
+ 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]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank ^ BIT_MON, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank ^ BIT_MON]], MON_DATA_SPECIES));
+ }
+
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+
+ gBattleSpritesDataPtr->animationData->field_9_x1 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x20 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x80 = 0;
+
+ gBattleBankFunc[gActiveBank] = sub_8186678;
+ }
+}
+
+static void sub_8186C48(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].pos2.x == 0)
+ {
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80)
+ {
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ }
+ else
+ {
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+ RecordedOpponentBufferExecCompleted();
+ }
+ }
+ }
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], HEALTH_BAR, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8186D58(void)
+{
+ if (!gSprites[gBankSpriteIds[gActiveBank]].inUse)
+ {
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void sub_8186D9C(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ sub_805EEE0(gActiveBank);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ RecordedOpponentBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_8186EA4(void)
+{
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+
+ gBattleBankFunc[gActiveBank] = sub_8186F14;
+ }
+}
+
+static void sub_8186F14(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive
+ && !IsCryPlayingOrClearCrySongs())
+ {
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy
+ || gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy_2)
+ {
+ m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100);
+ RecordedOpponentBufferExecCompleted();
+ }
+ }
+}
+
+static void sub_8186F94(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80 = 0;
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1 = 0;
+
+ FreeSpriteTilesByTag(0x27F9);
+ FreeSpritePaletteByTag(0x27F9);
+
+ StartSpriteAnim(&gSprites[gBankSpriteIds[gActiveBank]], 0);
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[gBattlePartyID[gActiveBank]], HEALTHBOX_ALL);
+ sub_8076918(gActiveBank);
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+ CopyBattleSpriteInvisibility(gActiveBank);
+ gBattleBankFunc[gActiveBank] = sub_8186EA4;
+ }
+}
+
+static void sub_8187084(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x80)
+ {
+ sub_8172EF0(gActiveBank, &gEnemyParty[gBattlePartyID[gActiveBank]]);
+ }
+
+ if (gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && !gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x8)
+ {
+ DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBank]]);
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+ gBattleBankFunc[gActiveBank] = sub_8186F94;
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = RecordedOpponentBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTROLLER_TERMINATOR_NOP;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void RecordedOpponentHandleGetMonData(void)
+{
+ u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two pokemon, trying to get more will result in overwriting data
+ u32 size = 0;
+ u8 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyRecordedOpponentMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyRecordedOpponentMonData(i, monData + size);
+ monToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ RecordedOpponentBufferExecCompleted();
+}
+
+static u32 CopyRecordedOpponentMonData(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(&gEnemyParty[monId], MON_DATA_SPECIES);
+ battleMon.item = GetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM);
+ for (size = 0; size < 4; size++)
+ {
+ battleMon.moves[size] = GetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + size);
+ battleMon.pp[size] = GetMonData(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ }
+ battleMon.ppBonuses = GetMonData(&gEnemyParty[monId], MON_DATA_PP_BONUSES);
+ battleMon.friendship = GetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP);
+ battleMon.experience = GetMonData(&gEnemyParty[monId], MON_DATA_EXP);
+ battleMon.hpIV = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ battleMon.attackIV = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ battleMon.defenseIV = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ battleMon.speedIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gEnemyParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gEnemyParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gEnemyParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gEnemyParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gEnemyParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gEnemyParty[monId], MON_DATA_IS_EGG);
+ battleMon.altAbility = GetMonData(&gEnemyParty[monId], MON_DATA_ALT_ABILITY);
+ battleMon.otId = GetMonData(&gEnemyParty[monId], MON_DATA_OT_ID);
+ GetMonData(&gEnemyParty[monId], MON_DATA_NICKNAME, nickname);
+ StringCopy10(battleMon.nickname, nickname);
+ GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_SPECIES);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ data16 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_MOVE1 + size);
+ moveData.pp[size] = GetMonData(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ }
+ moveData.ppBonuses = GetMonData(&gEnemyParty[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(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + size);
+ dst[size] = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE);
+ size = 1;
+ break;
+ case REQUEST_OTID_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_HP_EV);
+ size = 1;
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_EV);
+ size = 1;
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_EV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gEnemyParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gEnemyParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void RecordedOpponentHandleGetRawMonData(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetRecordedOpponentMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetRecordedOpponentMonData(i);
+ monToCheck >>= 1;
+ }
+ }
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void SetRecordedOpponentMonData(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(&gEnemyParty[monId], MON_DATA_SPECIES, &battlePokemon->species);
+ SetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM, &battlePokemon->item);
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + i, &battlePokemon->moves[i]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1 + i, &battlePokemon->pp[i]);
+ }
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP_BONUSES, &battlePokemon->ppBonuses);
+ SetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP, &battlePokemon->friendship);
+ SetMonData(&gEnemyParty[monId], MON_DATA_EXP, &battlePokemon->experience);
+ iv = battlePokemon->hpIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &iv);
+ iv = battlePokemon->attackIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &iv);
+ iv = battlePokemon->defenseIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &iv);
+ iv = battlePokemon->speedIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gEnemyParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gEnemyParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HELDITEM_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MOVES_PP_BATTLE:
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(&gEnemyParty[monId], MON_DATA_MOVE1 + i, &moveData->moves[i]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1 + i, &moveData->pp[i]);
+ }
+ SetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBank][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PP_DATA_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gEnemyParty[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(&gEnemyParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBank][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_OTID_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_EXP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][4]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][5]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBank][6]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][7]);
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][8]);
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_STATUS_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_HP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_ATK_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_DEF_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPEED_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPEED, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPATK_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ SetMonData(&gEnemyParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBank][3]);
+ break;
+ }
+}
+
+static void RecordedOpponentHandleSetRawMonData(void)
+{
+ u8 *dst = (u8 *)&gEnemyParty[gBattlePartyID[gActiveBank]] + gBattleBufferA[gActiveBank][1];
+ u8 i;
+
+ for (i = 0; i < gBattleBufferA[gActiveBank][2]; i++)
+ dst[i] = gBattleBufferA[gActiveBank][3 + i];
+
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleLoadMonSprite(void)
+{
+ u16 species = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ 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]);
+
+ SetBankEnemyShadowSpriteCallback(gActiveBank, GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES));
+
+ gBattleBankFunc[gActiveBank] = sub_8186C48;
+}
+
+static void RecordedOpponentHandleSwitchInAnim(void)
+{
+ gBattlePartyID[gActiveBank] = gBattleBufferA[gActiveBank][1];
+ sub_81885D8(gActiveBank, gBattleBufferA[gActiveBank][2]);
+ gBattleBankFunc[gActiveBank] = sub_8187084;
+}
+
+static void sub_81885D8(u8 bank, bool8 dontClearSubstituteBit)
+{
+ u16 species;
+
+ ClearTemporarySpeciesSpriteData(bank, dontClearSubstituteBit);
+ gBattlePartyID[bank] = gBattleBufferA[bank][1];
+ species = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_SPECIES);
+ gUnknown_03005D7C[bank] = CreateInvisibleSpriteWithCallback(sub_805D714);
+ BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[bank]], bank);
+ 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, 0xFE);
+}
+
+static void RecordedOpponentHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = DoSwitchOutAnimation;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ sub_805EEE0(gActiveBank);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+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_OPPONENT_MON);
+ gBattleBankFunc[gActiveBank] = sub_8186D9C;
+ }
+ break;
+ }
+}
+
+static void RecordedOpponentHandleDrawTrainerPic(void)
+{
+ s16 xPos;
+ u32 trainerPicId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
+ {
+ if ((GetBankIdentity(gActiveBank) & BIT_MON) != 0) // second mon
+ xPos = 152;
+ else // first mon
+ xPos = 200;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
+ {
+ if (gActiveBank == 1)
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_A);
+ else
+ trainerPicId = GetFrontierTrainerFrontSpriteId(gTrainerBattleOpponent_B);
+ }
+ else
+ {
+ trainerPicId = PlayerGenderToFrontTrainerPicId(sub_8185F40());
+ }
+ }
+ else
+ {
+ xPos = 176;
+ if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00)
+ {
+ trainerPicId = sub_8068B48();
+ }
+ else
+ {
+ trainerPicId = PlayerGenderToFrontTrainerPicId(gLinkPlayers[gUnknown_0203C7B4 ^ BIT_SIDE].gender);
+ }
+ }
+
+ DecompressTrainerFrontPic(trainerPicId, gActiveBank);
+ sub_806A12C(trainerPicId, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ xPos,
+ (8 - gTrainerFrontPicCoords[trainerPicId].coords) * 4 + 40,
+ sub_80A82E4(gActiveBank));
+
+ gSprites[gBankSpriteIds[gActiveBank]].pos2.x = -240;
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 2;
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.affineParam = trainerPicId;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_805D7AC;
+
+ gBattleBankFunc[gActiveBank] = CompleteOnBankSpriteCallbackDummy;
+}
+
+static void RecordedOpponentHandleTrainerSlide(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleTrainerSlideBack(void)
+{
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 280;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], SpriteCallbackDummy);
+ gBattleBankFunc[gActiveBank] = sub_81865C8;
+}
+
+static void RecordedOpponentHandleFaintAnimation(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;
+ PlaySE12WithPanning(SE_POKE_DEAD, PAN_SIDE_OPPONENT);
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_8039934;
+ gBattleBankFunc[gActiveBank] = sub_8186D58;
+ }
+ }
+}
+
+static void RecordedOpponentHandlePaletteFade(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleSuccessBallThrowAnim(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleBallThrowAnim(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandlePause(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleMoveAnimation(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
+ {
+ RecordedOpponentBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = RecordedOpponentDoMoveAnimation;
+ }
+ }
+}
+
+static void RecordedOpponentDoMoveAnimation(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;
+ RecordedOpponentBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void RecordedOpponentHandlePrintString(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 RecordedOpponentHandlePrintStringPlayerOnly(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleChooseAction(void)
+{
+ EmitTwoReturnValues(1, RecordedBattle_ReadBankAction(gActiveBank), 0);
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleUnknownYesNoBox(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleChooseMove(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));
+ }
+
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleChooseItem(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleChoosePokemon(void)
+{
+ *(gBattleStruct->field_5C + gActiveBank) = RecordedBattle_ReadBankAction(gActiveBank);
+ EmitChosenMonReturnValue(1, *(gBattleStruct->field_5C + gActiveBank), NULL);
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd23(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleHealthBarUpdate(void)
+{
+ s16 hpVal;
+
+ LoadBattleBarGfx(0);
+ hpVal = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (hpVal != INSTANT_HP_BAR_DROP)
+ {
+ u32 maxHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+ u32 curHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, curHP, hpVal);
+ }
+ else
+ {
+ u32 maxHP = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_MAX_HP);
+
+ SetBattleBarStruct(gActiveBank, gHealthBoxesIds[gActiveBank], maxHP, 0, hpVal);
+ }
+
+ gBattleBankFunc[gActiveBank] = CompleteOnHealthbarDone;
+}
+
+static void RecordedOpponentHandleExpUpdate(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleStatusIconUpdate(void)
+{
+ if (!mplay_80342A4(gActiveBank))
+ {
+ u8 bank;
+
+ UpdateHealthboxAttribute(gHealthBoxesIds[gActiveBank], &gEnemyParty[gBattlePartyID[gActiveBank]], HEALTHBOX_STATUS_ICON);
+ bank = gActiveBank;
+ gBattleSpritesDataPtr->healthBoxesData[bank].statusAnimActive = 0;
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedStatusAnimation;
+ }
+}
+
+static void RecordedOpponentHandleStatusAnimation(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 RecordedOpponentHandleStatusXor(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleDataTransfer(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleDMA3Transfer(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandlePlayBGM(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd32(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleTwoReturnValues(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleChosenMonReturnValue(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleOneReturnValue(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleOneReturnValue_Duplicate(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd37(void)
+{
+ gUnknown_02022D0C.field_0 = 0;
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd38(void)
+{
+ gUnknown_02022D0C.field_0 = gBattleBufferA[gActiveBank][1];
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd39(void)
+{
+ gUnknown_02022D0C.flag_x80 = 0;
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd40(void)
+{
+ gUnknown_02022D0C.flag_x80 ^= 1;
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ RecordedOpponentBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void RecordedOpponentHandleCmd42(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleEffectivenessSound(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);
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry3(species, 25, 5);
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleIntroTrainerBallThrow(void)
+{
+ u8 paletteNum;
+ u8 taskId;
+
+ oamt_add_pos2_onto_pos1(&gSprites[gBankSpriteIds[gActiveBank]]);
+
+ gSprites[gBankSpriteIds[gActiveBank]].data0 = 35;
+ gSprites[gBankSpriteIds[gActiveBank]].data2 = 280;
+ gSprites[gBankSpriteIds[gActiveBank]].data4 = gSprites[gBankSpriteIds[gActiveBank]].pos1.y;
+ gSprites[gBankSpriteIds[gActiveBank]].callback = sub_80A6EEC;
+
+ StoreSpriteCallbackInData6(&gSprites[gBankSpriteIds[gActiveBank]], sub_818962C);
+
+ taskId = CreateTask(sub_8189548, 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_70;
+}
+
+static void sub_8189548(u8 taskId)
+{
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_81885D8(gActiveBank, FALSE);
+ }
+ else
+ {
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_81885D8(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_81885D8(gActiveBank, FALSE);
+ gActiveBank ^= BIT_MON;
+ }
+ gBattleBankFunc[gActiveBank] = sub_818686C;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+}
+
+static void sub_818962C(struct Sprite *sprite)
+{
+ FreeTrainerFrontPicPalette(sprite->oam.affineParam);
+ FreeSpriteOamMatrix(sprite);
+ DestroySprite(sprite);
+}
+
+static void RecordedOpponentHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ RecordedOpponentBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+
+ if (gBattleBufferA[gActiveBank][2] != 0)
+ {
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E < 2)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E++;
+ return;
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_1_x1E = 0;
+ }
+ }
+
+ 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_818975C;
+ }
+}
+
+static void sub_818975C(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5++ > 0x5C)
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].field_5 = 0;
+ RecordedOpponentBufferExecCompleted();
+ }
+}
+
+static void RecordedOpponentHandleCmd49(void)
+{
+ if (gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1)
+ gTasks[gUnknown_020244B4[gActiveBank]].func = sub_8073C30;
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd50(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleSpriteInvisibility(void)
+{
+ if (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(gActiveBank);
+ }
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleBattleAnimation(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))
+ RecordedOpponentBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+ }
+}
+
+static void RecordedOpponentHandleLinkStandbyMsg(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleResetActionMoveSelection(void)
+{
+ RecordedOpponentBufferExecCompleted();
+}
+
+static void RecordedOpponentHandleCmd55(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == BATTLE_DREW)
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ else
+ gBattleOutcome = gBattleBufferA[gActiveBank][1] ^ BATTLE_DREW;
+
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ RecordedOpponentBufferExecCompleted();
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_119(void)
+{
+}
diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c
new file mode 100644
index 000000000..a3343a391
--- /dev/null
+++ b/src/battle_controller_recorded_player.c
@@ -0,0 +1,1844 @@
+#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"
+#include "data2.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 sRecordedPlayerBufferCommands[CONTROLLER_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 SetControllerToRecordedPlayer(void)
+{
+ gBattleBankFunc[gActiveBank] = RecordedPlayerBufferRunCommand;
+}
+
+static void RecordedPlayerBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sRecordedPlayerBufferCommands))
+ sRecordedPlayerBufferCommands[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], HEALTH_BAR, 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)
+ {
+ CopyBattleSpriteInvisibility(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] = CONTROLLER_TERMINATOR_NOP;
+ }
+ 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 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyRecordedPlayerMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyRecordedPlayerMonData(i, monData + size);
+ monToCheck >>= 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_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG);
+ battleMon.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_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void RecordedPlayerHandleGetRawMonData(void)
+{
+ RecordedPlayerBufferExecCompleted();
+}
+
+static void RecordedPlayerHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetRecordedPlayerMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetRecordedPlayerMonData(i);
+ monToCheck >>= 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_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[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_SPEED_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_SPEED_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_SPEED_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_SPEED, &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_PLAYER_MON);
+ gBattleBankFunc[gActiveBank] = sub_818A1B0;
+ }
+ break;
+ }
+}
+
+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[GetBankMultiplayerId(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 (IsBankSpritePresent(gActiveBank))
+ {
+ gSprites[gBankSpriteIds[gActiveBank]].invisible = gBattleBufferA[gActiveBank][1];
+ CopyBattleSpriteInvisibility(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..0c5b698cf
--- /dev/null
+++ b/src/battle_controller_safari.c
@@ -0,0 +1,714 @@
+#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"
+#include "data2.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 sSafariBufferCommands[CONTROLLER_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 SetControllerToSafari(void)
+{
+ gBattleBankFunc[gActiveBank] = SafariBufferRunCommand;
+}
+
+static void SafariBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sSafariBufferCommands))
+ sSafariBufferCommands[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] = CONTROLLER_TERMINATOR_NOP;
+ }
+ 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();
+}
+
+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..c2addd30c
--- /dev/null
+++ b/src/battle_controller_wally.c
@@ -0,0 +1,1597 @@
+#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"
+#include "data2.h"
+#include "party_menu.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 void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(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_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 gTrainerBackPicPaletteTable[];
+
+extern const u8 gText_WhatWillWallyDo[];
+extern const u8 gText_BattleMenu[];
+
+extern void sub_8172EF0(u8 bank, struct Pokemon *mon);
+extern void sub_806A068(u16, u8);
+
+// this file's functions
+static void WallyHandleGetMonData(void);
+static void WallyHandleGetRawMonData(void);
+static void WallyHandleSetMonData(void);
+static void WallyHandleSetRawMonData(void);
+static void WallyHandleLoadMonSprite(void);
+static void WallyHandleSwitchInAnim(void);
+static void WallyHandleReturnMonToBall(void);
+static void WallyHandleDrawTrainerPic(void);
+static void WallyHandleTrainerSlide(void);
+static void WallyHandleTrainerSlideBack(void);
+static void WallyHandleFaintAnimation(void);
+static void WallyHandlePaletteFade(void);
+static void WallyHandleSuccessBallThrowAnim(void);
+static void WallyHandleBallThrowAnim(void);
+static void WallyHandlePause(void);
+static void WallyHandleMoveAnimation(void);
+static void WallyHandlePrintString(void);
+static void WallyHandlePrintStringPlayerOnly(void);
+static void WallyHandleChooseAction(void);
+static void WallyHandleUnknownYesNoBox(void);
+static void WallyHandleChooseMove(void);
+static void WallyHandleChooseItem(void);
+static void WallyHandleChoosePokemon(void);
+static void WallyHandleCmd23(void);
+static void WallyHandleHealthBarUpdate(void);
+static void WallyHandleExpUpdate(void);
+static void WallyHandleStatusIconUpdate(void);
+static void WallyHandleStatusAnimation(void);
+static void WallyHandleStatusXor(void);
+static void WallyHandleDataTransfer(void);
+static void WallyHandleDMA3Transfer(void);
+static void WallyHandlePlayBGM(void);
+static void WallyHandleCmd32(void);
+static void WallyHandleTwoReturnValues(void);
+static void WallyHandleChosenMonReturnValue(void);
+static void WallyHandleOneReturnValue(void);
+static void WallyHandleOneReturnValue_Duplicate(void);
+static void WallyHandleCmd37(void);
+static void WallyHandleCmd38(void);
+static void WallyHandleCmd39(void);
+static void WallyHandleCmd40(void);
+static void WallyHandleHitAnimation(void);
+static void WallyHandleCmd42(void);
+static void WallyHandleEffectivenessSound(void);
+static void WallyHandlePlayFanfareOrBGM(void);
+static void WallyHandleFaintingCry(void);
+static void WallyHandleIntroSlide(void);
+static void WallyHandleIntroTrainerBallThrow(void);
+static void WallyHandleDrawPartyStatusSummary(void);
+static void WallyHandleCmd49(void);
+static void WallyHandleCmd50(void);
+static void WallyHandleSpriteInvisibility(void);
+static void WallyHandleBattleAnimation(void);
+static void WallyHandleLinkStandbyMsg(void);
+static void WallyHandleResetActionMoveSelection(void);
+static void WallyHandleCmd55(void);
+static void nullsub_118(void);
+
+static void WallyBufferRunCommand(void);
+static void WallyBufferExecCompleted(void);
+static void CompleteOnChosenItem(void);
+static void sub_8168818(void);
+static u32 CopyWallyMonData(u8 monId, u8 *dst);
+static void SetWallyMonData(u8 monId);
+static void WallyDoMoveAnimation(void);
+static void sub_816AC04(u8 taskId);
+
+static void (*const sWallyBufferCommands[CONTROLLER_CMDS_COUNT])(void) =
+{
+ WallyHandleGetMonData,
+ WallyHandleGetRawMonData,
+ WallyHandleSetMonData,
+ WallyHandleSetRawMonData,
+ WallyHandleLoadMonSprite,
+ WallyHandleSwitchInAnim,
+ WallyHandleReturnMonToBall,
+ WallyHandleDrawTrainerPic,
+ WallyHandleTrainerSlide,
+ WallyHandleTrainerSlideBack,
+ WallyHandleFaintAnimation,
+ WallyHandlePaletteFade,
+ WallyHandleSuccessBallThrowAnim,
+ WallyHandleBallThrowAnim,
+ WallyHandlePause,
+ WallyHandleMoveAnimation,
+ WallyHandlePrintString,
+ WallyHandlePrintStringPlayerOnly,
+ WallyHandleChooseAction,
+ WallyHandleUnknownYesNoBox,
+ WallyHandleChooseMove,
+ WallyHandleChooseItem,
+ WallyHandleChoosePokemon,
+ WallyHandleCmd23,
+ WallyHandleHealthBarUpdate,
+ WallyHandleExpUpdate,
+ WallyHandleStatusIconUpdate,
+ WallyHandleStatusAnimation,
+ WallyHandleStatusXor,
+ WallyHandleDataTransfer,
+ WallyHandleDMA3Transfer,
+ WallyHandlePlayBGM,
+ WallyHandleCmd32,
+ WallyHandleTwoReturnValues,
+ WallyHandleChosenMonReturnValue,
+ WallyHandleOneReturnValue,
+ WallyHandleOneReturnValue_Duplicate,
+ WallyHandleCmd37,
+ WallyHandleCmd38,
+ WallyHandleCmd39,
+ WallyHandleCmd40,
+ WallyHandleHitAnimation,
+ WallyHandleCmd42,
+ WallyHandleEffectivenessSound,
+ WallyHandlePlayFanfareOrBGM,
+ WallyHandleFaintingCry,
+ WallyHandleIntroSlide,
+ WallyHandleIntroTrainerBallThrow,
+ WallyHandleDrawPartyStatusSummary,
+ WallyHandleCmd49,
+ WallyHandleCmd50,
+ WallyHandleSpriteInvisibility,
+ WallyHandleBattleAnimation,
+ WallyHandleLinkStandbyMsg,
+ WallyHandleResetActionMoveSelection,
+ WallyHandleCmd55,
+ nullsub_118
+};
+
+static void nullsub_117(void)
+{
+}
+
+void SetControllerToWally(void)
+{
+ gBattleBankFunc[gActiveBank] = WallyBufferRunCommand;
+ gBattleStruct->wallyBattleState = 0;
+ gBattleStruct->wallyMovesState = 0;
+ gBattleStruct->wallyWaitFrames = 0;
+ gBattleStruct->wallyMoveFrames = 0;
+}
+
+static void WallyBufferRunCommand(void)
+{
+ if (gBattleExecBuffer & gBitTable[gActiveBank])
+ {
+ if (gBattleBufferA[gActiveBank][0] < ARRAY_COUNT(sWallyBufferCommands))
+ sWallyBufferCommands[gBattleBufferA[gActiveBank][0]]();
+ else
+ WallyBufferExecCompleted();
+ }
+}
+
+static void WallyHandleActions(void)
+{
+ switch (gBattleStruct->wallyBattleState)
+ {
+ case 0:
+ gBattleStruct->wallyWaitFrames = 64;
+ gBattleStruct->wallyBattleState++;
+ case 1:
+ if (--gBattleStruct->wallyWaitFrames == 0)
+ {
+ PlaySE(SE_SELECT);
+ EmitTwoReturnValues(1, ACTION_USE_MOVE, 0);
+ WallyBufferExecCompleted();
+ gBattleStruct->wallyBattleState++;
+ gBattleStruct->wallyMovesState = 0;
+ gBattleStruct->wallyWaitFrames = 64;
+ }
+ break;
+ case 2:
+ if (--gBattleStruct->wallyWaitFrames == 0)
+ {
+ PlaySE(SE_SELECT);
+ EmitTwoReturnValues(1, ACTION_USE_MOVE, 0);
+ WallyBufferExecCompleted();
+ gBattleStruct->wallyBattleState++;
+ gBattleStruct->wallyMovesState = 0;
+ gBattleStruct->wallyWaitFrames = 64;
+ }
+ break;
+ case 3:
+ if (--gBattleStruct->wallyWaitFrames == 0)
+ {
+ EmitTwoReturnValues(1, 9, 0);
+ WallyBufferExecCompleted();
+ gBattleStruct->wallyBattleState++;
+ gBattleStruct->wallyMovesState = 0;
+ gBattleStruct->wallyWaitFrames = 64;
+ }
+ break;
+ case 4:
+ if (--gBattleStruct->wallyWaitFrames == 0)
+ {
+ PlaySE(SE_SELECT);
+ ActionSelectionDestroyCursorAt(0);
+ ActionSelectionCreateCursorAt(1, 0);
+ gBattleStruct->wallyWaitFrames = 64;
+ gBattleStruct->wallyBattleState++;
+ }
+ break;
+ case 5:
+ if (--gBattleStruct->wallyWaitFrames == 0)
+ {
+ PlaySE(SE_SELECT);
+ EmitTwoReturnValues(1, ACTION_USE_ITEM, 0);
+ WallyBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ WallyBufferExecCompleted();
+}
+
+static void CompleteOnInactiveTextPrinter(void)
+{
+ if (!IsTextPrinterActive(0))
+ WallyBufferExecCompleted();
+}
+
+static void CompleteOnFinishedAnimation(void)
+{
+ if (!gDoingBattleAnim)
+ WallyBufferExecCompleted();
+}
+
+static void OpenBagAfterPaletteFade(void)
+{
+ if (!gPaletteFade.active)
+ {
+ gBattleBankFunc[gActiveBank] = CompleteOnChosenItem;
+ nullsub_35();
+ FreeAllWindowBuffers();
+ DoWallyTutorialBagMenu();
+ }
+}
+
+static void CompleteOnChosenItem(void)
+{
+ if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
+ {
+ EmitOneReturnValue(1, gScriptItemId);
+ WallyBufferExecCompleted();
+ }
+}
+
+static void sub_816864C(void)
+{
+ 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
+ && gSprites[gUnknown_03005D7C[gActiveBank]].callback == SpriteCallbackDummy
+ && gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ {
+ 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_8168818;
+ }
+
+}
+
+static void sub_8168818(void)
+{
+ bool32 r4 = FALSE;
+
+ if (gSprites[gHealthBoxesIds[gActiveBank]].callback == SpriteCallbackDummy)
+ r4 = TRUE;
+
+ if (r4 && 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);
+
+ CreateTask(c3_0802FDF4, 10);
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+
+ WallyBufferExecCompleted();
+ }
+}
+
+static void CompleteOnHealthbarDone(void)
+{
+ s16 hpValue = sub_8074AA0(gActiveBank, gHealthBoxesIds[gActiveBank], HEALTH_BAR, 0);
+
+ SetHealthboxSpriteVisible(gHealthBoxesIds[gActiveBank]);
+
+ if (hpValue != -1)
+ {
+ UpdateHpTextInHealthbox(gHealthBoxesIds[gActiveBank], hpValue, HP_CURRENT);
+ }
+ else
+ {
+ sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank);
+ WallyBufferExecCompleted();
+ }
+}
+
+static void DoHitAnimBlinkSpriteEffect(void)
+{
+ u8 spriteId = gBankSpriteIds[gActiveBank];
+
+ if (gSprites[spriteId].data1 == 32)
+ {
+ gSprites[spriteId].data1 = 0;
+ gSprites[spriteId].invisible = 0;
+ gDoingBattleAnim = FALSE;
+ WallyBufferExecCompleted();
+ }
+ else
+ {
+ if ((gSprites[spriteId].data1 % 4) == 0)
+ gSprites[spriteId].invisible ^= 1;
+ gSprites[spriteId].data1++;
+ }
+}
+
+static void sub_8168A20(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].specialAnimActive)
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ WallyBufferExecCompleted();
+ }
+}
+
+static void CompleteOnBankSpriteCallbackDummy2(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].callback == SpriteCallbackDummy)
+ WallyBufferExecCompleted();
+}
+
+static void CompleteOnFinishedBattleAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animFromTableActive)
+ WallyBufferExecCompleted();
+}
+
+static void WallyBufferExecCompleted(void)
+{
+ gBattleBankFunc[gActiveBank] = WallyBufferRunCommand;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ u8 playerId = GetMultiplayerId();
+
+ PrepareBufferDataTransferLink(2, 4, &playerId);
+ gBattleBufferA[gActiveBank][0] = CONTROLLER_TERMINATOR_NOP;
+ }
+ else
+ {
+ gBattleExecBuffer &= ~gBitTable[gActiveBank];
+ }
+}
+
+static void CompleteOnFinishedStatusAnimation(void)
+{
+ if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBank].statusAnimActive)
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleGetMonData(void)
+{
+ u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two pokemon, trying to get more will result in overwriting data
+ u32 size = 0;
+ u8 monToCheck;
+ s32 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ size += CopyWallyMonData(gBattlePartyID[gActiveBank], monData);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ size += CopyWallyMonData(i, monData + size);
+ monToCheck >>= 1;
+ }
+ }
+ EmitDataTransfer(1, size, monData);
+ WallyBufferExecCompleted();
+}
+
+static u32 CopyWallyMonData(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_SPEED_IV);
+ battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG);
+ battleMon.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_SPEED_EV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_EV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV);
+ size = 1;
+ break;
+ case REQUEST_FRIENDSHIP_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
+ size = 1;
+ break;
+ case REQUEST_POKERUS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS);
+ size = 1;
+ break;
+ case REQUEST_MET_LOCATION_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION);
+ size = 1;
+ break;
+ case REQUEST_MET_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_MET_GAME_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME);
+ size = 1;
+ break;
+ case REQUEST_POKEBALL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL);
+ size = 1;
+ break;
+ case REQUEST_ALL_IVS_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 6;
+ break;
+ case REQUEST_HP_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
+ size = 1;
+ break;
+ case REQUEST_ATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
+ size = 1;
+ break;
+ case REQUEST_DEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
+ size = 1;
+ break;
+ case REQUEST_SPEED_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
+ size = 1;
+ break;
+ case REQUEST_SPATK_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
+ size = 1;
+ break;
+ case REQUEST_SPDEF_IV_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
+ size = 1;
+ break;
+ case REQUEST_PERSONALITY_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_CHECKSUM_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_STATUS_BATTLE:
+ data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
+ dst[0] = (data32 & 0x000000FF);
+ dst[1] = (data32 & 0x0000FF00) >> 8;
+ dst[2] = (data32 & 0x00FF0000) >> 16;
+ dst[3] = (data32 & 0xFF000000) >> 24;
+ size = 4;
+ break;
+ case REQUEST_LEVEL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
+ size = 1;
+ break;
+ case REQUEST_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_MAX_HP_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_ATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_DEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPEED_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPATK_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_SPDEF_BATTLE:
+ data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
+ dst[0] = data16;
+ dst[1] = data16 >> 8;
+ size = 2;
+ break;
+ case REQUEST_COOL_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY);
+ size = 1;
+ break;
+ case REQUEST_CUTE_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE);
+ size = 1;
+ break;
+ case REQUEST_SMART_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH);
+ size = 1;
+ break;
+ case REQUEST_SHEEN_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN);
+ size = 1;
+ break;
+ case REQUEST_COOL_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_BEAUTY_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_CUTE_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_SMART_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON);
+ size = 1;
+ break;
+ case REQUEST_TOUGH_RIBBON_BATTLE:
+ dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON);
+ size = 1;
+ break;
+ }
+
+ return size;
+}
+
+static void WallyHandleGetRawMonData(void)
+{
+ PlayerHandleGetRawMonData();
+}
+
+static void WallyHandleSetMonData(void)
+{
+ u8 monToCheck;
+ u8 i;
+
+ if (gBattleBufferA[gActiveBank][2] == 0)
+ {
+ SetWallyMonData(gBattlePartyID[gActiveBank]);
+ }
+ else
+ {
+ monToCheck = gBattleBufferA[gActiveBank][2];
+ for (i = 0; i < 6; i++)
+ {
+ if (monToCheck & 1)
+ SetWallyMonData(i);
+ monToCheck >>= 1;
+ }
+ }
+ WallyBufferExecCompleted();
+}
+
+static void SetWallyMonData(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_SPEED_IV, &iv);
+ iv = battlePokemon->spAttackIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv);
+ iv = battlePokemon->spDefenseIV;
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv);
+ SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
+ SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
+ SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
+ SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp);
+ SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
+ SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
+ }
+ break;
+ case REQUEST_SPECIES_BATTLE:
+ SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[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_SPEED_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_SPEED_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_SPEED_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_SPEED, &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 WallyHandleSetRawMonData(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleLoadMonSprite(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleSwitchInAnim(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleReturnMonToBall(void)
+{
+ if (gBattleBufferA[gActiveBank][1] == 0)
+ {
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_SWITCH_OUT_PLAYER_MON);
+ gBattleBankFunc[gActiveBank] = sub_8168A20;
+ }
+ else
+ {
+ FreeSpriteOamMatrix(&gSprites[gBankSpriteIds[gActiveBank]]);
+ DestroySprite(&gSprites[gBankSpriteIds[gActiveBank]]);
+ SetHealthboxSpriteInvisible(gHealthBoxesIds[gActiveBank]);
+ WallyBufferExecCompleted();
+ }
+}
+
+static void WallyHandleDrawTrainerPic(void)
+{
+ DecompressTrainerBackPic(BACK_PIC_WALLY, gActiveBank);
+ sub_806A12C(BACK_PIC_WALLY, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ 80,
+ 80 + 4 * (8 - gTrainerBackPicCoords[BACK_PIC_WALLY].coords),
+ 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 WallyHandleTrainerSlide(void)
+{
+ DecompressTrainerBackPic(BACK_PIC_WALLY, gActiveBank);
+ sub_806A12C(BACK_PIC_WALLY, GetBankIdentity(gActiveBank));
+ gBankSpriteIds[gActiveBank] = CreateSprite(&gUnknown_0202499C,
+ 80,
+ 80 + 4 * (8 - gTrainerBackPicCoords[BACK_PIC_WALLY].coords),
+ 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 WallyHandleTrainerSlideBack(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleFaintAnimation(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandlePaletteFade(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleSuccessBallThrowAnim(void)
+{
+ gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
+ gDoingBattleAnim = TRUE;
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, GetBankByIdentity(IDENTITY_OPPONENT_MON1), B_ANIM_SAFARI_BALL_THROW);
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedAnimation;
+}
+
+static void WallyHandleBallThrowAnim(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] = CompleteOnFinishedAnimation;
+}
+
+static void WallyHandlePause(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleMoveAnimation(void)
+{
+ 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
+ {
+ WallyBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 0;
+ gBattleBankFunc[gActiveBank] = WallyDoMoveAnimation;
+ }
+
+}
+
+static void WallyDoMoveAnimation(void)
+{
+ u16 move = gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8);
+
+ 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)
+ {
+ sub_805EB9C(0);
+ DoMoveAnim(move);
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].animationState = 2;
+ }
+ break;
+ case 2:
+ gAnimScriptCallback();
+ if (!gAnimScriptActive)
+ {
+ sub_805EB9C(1);
+ if (gBattleSpritesDataPtr->bankData[gActiveBank].behindSubstitute)
+ {
+ DoSpecialBattleAnimation(gActiveBank, gActiveBank, gActiveBank, B_ANIM_MON_TO_SUBSTITUTE);
+ }
+ 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;
+ WallyBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void WallyHandlePrintString(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 WallyHandlePrintStringPlayerOnly(void)
+{
+ if (GetBankSide(gActiveBank) == SIDE_PLAYER)
+ WallyHandlePrintString();
+ else
+ WallyBufferExecCompleted();
+}
+
+static void HandleChooseActionAfterDma3(void)
+{
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 160;
+ gBattleBankFunc[gActiveBank] = WallyHandleActions;
+ }
+}
+
+static void WallyHandleChooseAction(void)
+{
+ s32 i;
+
+ gBattleBankFunc[gActiveBank] = HandleChooseActionAfterDma3;
+ BattleHandleAddTextPrinter(gText_BattleMenu, 2);
+
+ for (i = 0; i < 4; i++)
+ ActionSelectionDestroyCursorAt(i);
+
+ ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBank], 0);
+ BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillWallyDo);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 1);
+}
+
+static void WallyHandleUnknownYesNoBox(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleChooseMove(void)
+{
+ switch (gBattleStruct->wallyMovesState)
+ {
+ case 0:
+ InitMoveSelectionsVarsAndStrings();
+ gBattleStruct->wallyMovesState++;
+ gBattleStruct->wallyMoveFrames = 80;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0x140;
+ gBattleStruct->wallyMovesState++;
+ }
+ break;
+ case 2:
+ if (--gBattleStruct->wallyMoveFrames == 0)
+ {
+ PlaySE(SE_SELECT);
+ EmitTwoReturnValues(1, 10, 0x100);
+ WallyBufferExecCompleted();
+ }
+ break;
+ }
+}
+
+static void WallyHandleChooseItem(void)
+{
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gBattleBankFunc[gActiveBank] = OpenBagAfterPaletteFade;
+ gBankInMenu = gActiveBank;
+}
+
+static void WallyHandleChoosePokemon(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd23(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleHealthBarUpdate(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 WallyHandleExpUpdate(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleStatusIconUpdate(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleStatusAnimation(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleStatusXor(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleDataTransfer(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleDMA3Transfer(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandlePlayBGM(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd32(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleTwoReturnValues(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleChosenMonReturnValue(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleOneReturnValue(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleOneReturnValue_Duplicate(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd37(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd38(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd39(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd40(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleHitAnimation(void)
+{
+ if (gSprites[gBankSpriteIds[gActiveBank]].invisible == TRUE)
+ {
+ WallyBufferExecCompleted();
+ }
+ else
+ {
+ gDoingBattleAnim = TRUE;
+ gSprites[gBankSpriteIds[gActiveBank]].data1 = 0;
+ DoHitAnimHealthboxEffect(gActiveBank);
+ gBattleBankFunc[gActiveBank] = DoHitAnimBlinkSpriteEffect;
+ }
+}
+
+static void WallyHandleCmd42(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleEffectivenessSound(void)
+{
+ PlaySE(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandlePlayFanfareOrBGM(void)
+{
+ if (gBattleBufferA[gActiveBank][3])
+ {
+ BattleMusicStop();
+ PlayBGM(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+ else
+ {
+ PlayFanfare(gBattleBufferA[gActiveBank][1] | (gBattleBufferA[gActiveBank][2] << 8));
+ }
+
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleFaintingCry(void)
+{
+ u16 species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES);
+
+ PlayCry1(species, 25);
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleIntroSlide(void)
+{
+ HandleIntroSlide(gBattleBufferA[gActiveBank][1]);
+ gUnknown_020243FC |= 1;
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleIntroTrainerBallThrow(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[BACK_PIC_WALLY].data, 0x100 + paletteNum * 16, 32);
+ gSprites[gBankSpriteIds[gActiveBank]].oam.paletteNum = paletteNum;
+
+ taskId = CreateTask(sub_816AC04, 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;
+}
+
+static void sub_816AA80(u8 bank)
+{
+ u16 species;
+
+ gBattleSpritesDataPtr->bankData[bank].transformSpecies = 0;
+ 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 sub_816AC04(u8 taskId)
+{
+ if (gTasks[taskId].data[1] < 31)
+ {
+ gTasks[taskId].data[1]++;
+ }
+ else
+ {
+ u8 savedActiveBank = gActiveBank;
+
+ gActiveBank = gTasks[taskId].data[0];
+ gBattleBufferA[gActiveBank][1] = gBattlePartyID[gActiveBank];
+ sub_816AA80(gActiveBank);
+ gBattleBankFunc[gActiveBank] = sub_816864C;
+ gActiveBank = savedActiveBank;
+ DestroyTask(taskId);
+ }
+}
+
+static void WallyHandleDrawPartyStatusSummary(void)
+{
+ if (gBattleBufferA[gActiveBank][1] != 0 && GetBankSide(gActiveBank) == SIDE_PLAYER)
+ {
+ WallyBufferExecCompleted();
+ }
+ else
+ {
+ gBattleSpritesDataPtr->healthBoxesData[gActiveBank].flag_x1 = 1;
+ gUnknown_020244B4[gActiveBank] = CreatePartyStatusSummarySprites(gActiveBank, (struct HpAndStatus *)&gBattleBufferA[gActiveBank][4], gBattleBufferA[gActiveBank][1], gBattleBufferA[gActiveBank][2]);
+ WallyBufferExecCompleted();
+ }
+}
+
+static void WallyHandleCmd49(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd50(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleSpriteInvisibility(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleBattleAnimation(void)
+{
+ u8 animationId = gBattleBufferA[gActiveBank][1];
+ u16 argument = gBattleBufferA[gActiveBank][2] | (gBattleBufferA[gActiveBank][3] << 8);
+
+ if (DoBattleAnimationFromTable(gActiveBank, gActiveBank, gActiveBank, animationId, argument))
+ WallyBufferExecCompleted();
+ else
+ gBattleBankFunc[gActiveBank] = CompleteOnFinishedBattleAnimation;
+}
+
+static void WallyHandleLinkStandbyMsg(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleResetActionMoveSelection(void)
+{
+ WallyBufferExecCompleted();
+}
+
+static void WallyHandleCmd55(void)
+{
+ gBattleOutcome = gBattleBufferA[gActiveBank][1];
+ FadeOutMapMusic(5);
+ BeginFastPaletteFade(3);
+ WallyBufferExecCompleted();
+
+ if (!(gBattleTypeFlags & BATTLE_TYPE_WILD) && gBattleTypeFlags & BATTLE_TYPE_LINK)
+ gBattleBankFunc[gActiveBank] = sub_80587B0;
+}
+
+static void nullsub_118(void)
+{
+}
diff --git a/src/battle_controllers.c b/src/battle_controllers.c
index 9ac18c72f..5c874438e 100644
--- a/src/battle_controllers.c
+++ b/src/battle_controllers.c
@@ -145,30 +145,30 @@ static void SetControllersVariables(void)
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
{
- gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToPlayerPartnerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToPlayerPartner;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
}
else
{
- gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToPlayerPartnerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToPlayerPartner;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
}
@@ -189,15 +189,15 @@ static void SetControllersVariables(void)
gBattleMainFunc = BeginBattleIntro;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
- gBattleBankFunc[0] = SetBankFuncToSafariBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToSafari;
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
- gBattleBankFunc[0] = SetBankFuncToWallyBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToWally;
else
- gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
gNoOfAllBanks = 2;
@@ -210,20 +210,20 @@ static void SetControllersVariables(void)
{
gBattleMainFunc = BeginBattleIntro;
- gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToRecordedOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
gNoOfAllBanks = 2;
}
else // see how the banks are switched
{
- gBattleBankFunc[1] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToRecordedPlayer;
gBanksByIdentity[1] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[0] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedOpponent;
gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1;
gNoOfAllBanks = 2;
@@ -231,10 +231,10 @@ static void SetControllersVariables(void)
}
else
{
- gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
}
}
@@ -243,16 +243,16 @@ static void SetControllersVariables(void)
{
gBattleMainFunc = BeginBattleIntro;
- gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToPlayer;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
gNoOfAllBanks = 4;
@@ -263,16 +263,16 @@ static void SetControllersVariables(void)
{
gBattleMainFunc = BeginBattleIntro;
- gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedPlayer;
gBanksByIdentity[0] = 0;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = 1;
- gBattleBankFunc[2] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToRecordedPlayer;
gBanksByIdentity[2] = 2;
- gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToOpponent;
gBanksByIdentity[3] = 3;
gNoOfAllBanks = 4;
@@ -307,7 +307,7 @@ static void SetControllersVariables(void)
if (i == var)
{
- gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetControllerToRecordedPlayer;
switch (gLinkPlayers[i].lp_field_18)
{
case 0:
@@ -325,7 +325,7 @@ static void SetControllersVariables(void)
else if ((!(gLinkPlayers[i].lp_field_18 & 1) && !(gLinkPlayers[var].lp_field_18 & 1))
|| ((gLinkPlayers[i].lp_field_18 & 1) && (gLinkPlayers[var].lp_field_18 & 1)))
{
- gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetControllerToRecordedPlayer;
switch (gLinkPlayers[i].lp_field_18)
{
case 0:
@@ -342,7 +342,7 @@ static void SetControllersVariables(void)
}
else
{
- gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetControllerToRecordedOpponent;
switch (gLinkPlayers[i].lp_field_18)
{
case 0:
@@ -361,51 +361,51 @@ static void SetControllersVariables(void)
}
else if (gBattleTypeFlags & BATTLE_TYPE_WILD)
{
- gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[2] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToRecordedPlayer;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
- gBattleBankFunc[1] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToRecordedOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[3] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToRecordedOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
}
else
{
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
}
}
else
{
- gBattleBankFunc[1] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToRecordedPlayer;
gBanksByIdentity[1] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[3] = SetBankFuncToRecordedPlayerBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToRecordedPlayer;
gBanksByIdentity[3] = IDENTITY_PLAYER_MON2;
if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
- gBattleBankFunc[0] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToRecordedOpponent;
gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToRecordedOpponentBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToRecordedOpponent;
gBanksByIdentity[2] = IDENTITY_OPPONENT_MON2;
}
else
{
- gBattleBankFunc[0] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToOpponent;
gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToOpponent;
gBanksByIdentity[2] = IDENTITY_OPPONENT_MON2;
}
}
@@ -424,20 +424,20 @@ static void SetControllersVariablesInLinkBattle(void)
{
gBattleMainFunc = BeginBattleIntro;
- gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToLinkOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
gNoOfAllBanks = 2;
}
else
{
- gBattleBankFunc[1] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToPlayer;
gBanksByIdentity[1] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[0] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToLinkOpponent;
gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1;
gNoOfAllBanks = 2;
@@ -449,32 +449,32 @@ static void SetControllersVariablesInLinkBattle(void)
{
gBattleMainFunc = BeginBattleIntro;
- gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToLinkOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToPlayer;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[3] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToLinkOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
gNoOfAllBanks = 4;
}
else
{
- gBattleBankFunc[1] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToPlayer;
gBanksByIdentity[1] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[0] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToLinkOpponent;
gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[3] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToPlayer;
gBanksByIdentity[3] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[2] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToLinkOpponent;
gBanksByIdentity[2] = IDENTITY_OPPONENT_MON2;
gNoOfAllBanks = 4;
@@ -486,32 +486,32 @@ static void SetControllersVariablesInLinkBattle(void)
{
gBattleMainFunc = BeginBattleIntro;
- gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToPlayer;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToLinkPartnerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToLinkPartner;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
gNoOfAllBanks = 4;
}
else
{
- gBattleBankFunc[0] = SetBankFuncToLinkPartnerBufferRunCommand;
+ gBattleBankFunc[0] = SetControllerToLinkPartner;
gBanksByIdentity[0] = IDENTITY_PLAYER_MON1;
- gBattleBankFunc[1] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[1] = SetControllerToLinkOpponent;
gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1;
- gBattleBankFunc[2] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[2] = SetControllerToPlayer;
gBanksByIdentity[2] = IDENTITY_PLAYER_MON2;
- gBattleBankFunc[3] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[3] = SetControllerToLinkOpponent;
gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2;
gNoOfAllBanks = 4;
@@ -549,7 +549,7 @@ static void SetControllersVariablesInLinkBattle(void)
if (i == multiplayerId)
{
- gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToPlayerBufferRunCommand;
+ gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetControllerToPlayer;
switch (gLinkPlayers[i].lp_field_18)
{
case 0:
@@ -569,7 +569,7 @@ static void SetControllersVariablesInLinkBattle(void)
if ((!(gLinkPlayers[i].lp_field_18 & 1) && !(gLinkPlayers[multiplayerId].lp_field_18 & 1))
|| ((gLinkPlayers[i].lp_field_18 & 1) && (gLinkPlayers[multiplayerId].lp_field_18 & 1)))
{
- gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToLinkPartnerBufferRunCommand;
+ gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetControllerToLinkPartner;
switch (gLinkPlayers[i].lp_field_18)
{
case 0:
@@ -586,7 +586,7 @@ static void SetControllersVariablesInLinkBattle(void)
}
else
{
- gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToLinkOpponentBufferRunCommand;
+ gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetControllerToLinkOpponent;
switch (gLinkPlayers[i].lp_field_18)
{
case 0:
@@ -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 monToCheck)
{
gBattleBuffersTransferData[0] = CONTROLLER_GETMONDATA;
- gBattleBuffersTransferData[1] = arg1;
- gBattleBuffersTransferData[2] = arg2;
+ gBattleBuffersTransferData[1] = requestId;
+ gBattleBuffersTransferData[2] = monToCheck;
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 monToCheck, u8 bytes, void *data)
{
s32 i;
gBattleBuffersTransferData[0] = CONTROLLER_SETMONDATA;
- gBattleBuffersTransferData[1] = request;
- gBattleBuffersTransferData[2] = c;
+ gBattleBuffersTransferData[1] = requestId;
+ gBattleBuffersTransferData[2] = monToCheck;
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,60 +1009,60 @@ 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);
}
void EmitFaintAnimation(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_FAINTANIMATION;
- gBattleBuffersTransferData[1] = 10;
- gBattleBuffersTransferData[2] = 10;
- gBattleBuffersTransferData[3] = 10;
+ gBattleBuffersTransferData[1] = CONTROLLER_FAINTANIMATION;
+ gBattleBuffersTransferData[2] = CONTROLLER_FAINTANIMATION;
+ gBattleBuffersTransferData[3] = CONTROLLER_FAINTANIMATION;
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);
}
@@ -1146,7 +1146,7 @@ void EmitPrintStringPlayerOnly(u8 bufferId, u16 stringID)
struct StringInfoBattle* stringInfo;
gBattleBuffersTransferData[0] = CONTROLLER_PRINTSTRINGPLAYERONLY;
- gBattleBuffersTransferData[1] = 17;
+ gBattleBuffersTransferData[1] = CONTROLLER_PRINTSTRINGPLAYERONLY;
gBattleBuffersTransferData[2] = stringID;
gBattleBuffersTransferData[3] = (stringID & 0xFF00) >> 8;
@@ -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;
@@ -1226,9 +1226,9 @@ void EmitChoosePokemon(u8 bufferId, u8 caseId, u8 arg2, u8 abilityId, u8* arg4)
void EmitCmd23(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_23;
- gBattleBuffersTransferData[1] = 23;
- gBattleBuffersTransferData[2] = 23;
- gBattleBuffersTransferData[3] = 23;
+ gBattleBuffersTransferData[1] = CONTROLLER_23;
+ gBattleBuffersTransferData[2] = CONTROLLER_23;
+ gBattleBuffersTransferData[3] = CONTROLLER_23;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1289,7 +1289,7 @@ void EmitDataTransfer(u8 bufferId, u16 size, void *data)
s32 i;
gBattleBuffersTransferData[0] = CONTROLLER_DATATRANSFER;
- gBattleBuffersTransferData[1] = 29;
+ gBattleBuffersTransferData[1] = CONTROLLER_DATATRANSFER;
gBattleBuffersTransferData[2] = size;
gBattleBuffersTransferData[3] = (size & 0xFF00) >> 8;
for (i = 0; i < size; 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,36 +1394,36 @@ 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);
}
void EmitCmd42(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_42;
- gBattleBuffersTransferData[1] = 42;
- gBattleBuffersTransferData[2] = 42;
- gBattleBuffersTransferData[3] = 42;
+ gBattleBuffersTransferData[1] = CONTROLLER_42;
+ gBattleBuffersTransferData[2] = CONTROLLER_42;
+ gBattleBuffersTransferData[3] = CONTROLLER_42;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1448,9 +1448,9 @@ void EmitPlayFanfareOrBGM(u8 bufferId, u16 songId, bool8 playBGM)
void EmitFaintingCry(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_FAINTINGCRY;
- gBattleBuffersTransferData[1] = 45;
- gBattleBuffersTransferData[2] = 45;
- gBattleBuffersTransferData[3] = 45;
+ gBattleBuffersTransferData[1] = CONTROLLER_FAINTINGCRY;
+ gBattleBuffersTransferData[2] = CONTROLLER_FAINTINGCRY;
+ gBattleBuffersTransferData[3] = CONTROLLER_FAINTINGCRY;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1464,9 +1464,9 @@ void EmitIntroSlide(u8 bufferId, u8 terrainId)
void EmitIntroTrainerBallThrow(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_INTROTRAINERBALLTHROW;
- gBattleBuffersTransferData[1] = 47;
- gBattleBuffersTransferData[2] = 47;
- gBattleBuffersTransferData[3] = 47;
+ gBattleBuffersTransferData[1] = CONTROLLER_INTROTRAINERBALLTHROW;
+ gBattleBuffersTransferData[2] = CONTROLLER_INTROTRAINERBALLTHROW;
+ gBattleBuffersTransferData[3] = CONTROLLER_INTROTRAINERBALLTHROW;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1477,7 +1477,7 @@ void EmitDrawPartyStatusSummary(u8 bufferId, struct HpAndStatus* hpAndStatus, u8
gBattleBuffersTransferData[0] = CONTROLLER_DRAWPARTYSTATUSSUMMARY;
gBattleBuffersTransferData[1] = arg2 & 0x7F;
gBattleBuffersTransferData[2] = (arg2 & 0x80) >> 7;
- gBattleBuffersTransferData[3] = 48;
+ gBattleBuffersTransferData[3] = CONTROLLER_DRAWPARTYSTATUSSUMMARY;
for (i = 0; i < (s32)(sizeof(struct HpAndStatus) * 6); i++)
gBattleBuffersTransferData[4 + i] = *(i + (u8*)(hpAndStatus));
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, sizeof(struct HpAndStatus) * 6 + 4);
@@ -1486,18 +1486,18 @@ void EmitDrawPartyStatusSummary(u8 bufferId, struct HpAndStatus* hpAndStatus, u8
void EmitCmd49(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_49;
- gBattleBuffersTransferData[1] = 49;
- gBattleBuffersTransferData[2] = 49;
- gBattleBuffersTransferData[3] = 49;
+ gBattleBuffersTransferData[1] = CONTROLLER_49;
+ gBattleBuffersTransferData[2] = CONTROLLER_49;
+ gBattleBuffersTransferData[3] = CONTROLLER_49;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
void EmitCmd50(u8 bufferId)
{
gBattleBuffersTransferData[0] = CONTROLLER_50;
- gBattleBuffersTransferData[1] = 50;
- gBattleBuffersTransferData[2] = 50;
- gBattleBuffersTransferData[3] = 50;
+ gBattleBuffersTransferData[1] = CONTROLLER_50;
+ gBattleBuffersTransferData[2] = CONTROLLER_50;
+ gBattleBuffersTransferData[3] = CONTROLLER_50;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
@@ -1505,8 +1505,8 @@ void EmitSpriteInvisibility(u8 bufferId, bool8 isInvisible)
{
gBattleBuffersTransferData[0] = CONTROLLER_SPRITEINVISIBILITY;
gBattleBuffersTransferData[1] = isInvisible;
- gBattleBuffersTransferData[2] = 51;
- gBattleBuffersTransferData[3] = 51;
+ gBattleBuffersTransferData[2] = CONTROLLER_SPRITEINVISIBILITY;
+ gBattleBuffersTransferData[3] = CONTROLLER_SPRITEINVISIBILITY;
PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4);
}
diff --git a/src/battle_dome_cards.c b/src/battle_dome_cards.c
index 5251ee06a..e6c67b20e 100644
--- a/src/battle_dome_cards.c
+++ b/src/battle_dome_cards.c
@@ -124,7 +124,7 @@ static void sub_818D0C4(u16 species, u32 otId, u32 personality, u8 paletteSlot,
else
{
gUnknown_0203CCEC.paletteTag = paletteTag;
- LoadCompressedObjectPalette(sub_806E7CC(species, otId, personality));
+ LoadCompressedObjectPalette(GetMonSpritePalStructFromOtIdPersonality(species, otId, personality));
}
}
else
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 5797650bc..4bd6ca5b7 100644
--- a/src/battle_message.c
+++ b/src/battle_message.c
@@ -1858,16 +1858,16 @@ u32 BattleStringExpandPlaceholders(const u8* src, u8* dst)
toCpy = gLinkPlayers[multiplayerID].name;
break;
case B_TXT_1F: // link partner name?
- toCpy = gLinkPlayers[sub_806D864(2 ^ gLinkPlayers[multiplayerID].lp_field_18)].name;
+ toCpy = gLinkPlayers[GetBankMultiplayerId(2 ^ gLinkPlayers[multiplayerID].lp_field_18)].name;
break;
case B_TXT_20: // link opponent 1 name?
- toCpy = gLinkPlayers[sub_806D864(1 ^ gLinkPlayers[multiplayerID].lp_field_18)].name;
+ toCpy = gLinkPlayers[GetBankMultiplayerId(1 ^ gLinkPlayers[multiplayerID].lp_field_18)].name;
break;
case B_TXT_21: // link opponent 2 name?
- toCpy = gLinkPlayers[sub_806D864(3 ^ gLinkPlayers[multiplayerID].lp_field_18)].name;
+ toCpy = gLinkPlayers[GetBankMultiplayerId(3 ^ gLinkPlayers[multiplayerID].lp_field_18)].name;
break;
case B_TXT_22: // link scripting active name
- toCpy = gLinkPlayers[sub_806D864(gBattleScripting.bank)].name;
+ toCpy = gLinkPlayers[GetBankMultiplayerId(gBattleScripting.bank)].name;
break;
case B_TXT_PLAYER_NAME: // player name
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
@@ -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 784c2e80d..f846059c2 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);
@@ -5463,7 +5463,7 @@ static void atk4F_jump_if_cannot_switch(void)
party = gPlayerParty;
val = 0;
- if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE)
+ if (sub_806D82C(GetBankMultiplayerId(gActiveBank)) == TRUE)
val = 3;
}
else
@@ -5485,7 +5485,7 @@ static void atk4F_jump_if_cannot_switch(void)
val = 0;
- if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE)
+ if (sub_806D82C(GetBankMultiplayerId(gActiveBank)) == TRUE)
val = 3;
}
@@ -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++;
@@ -7933,7 +7933,7 @@ static void atk8F_forcerandomswitch(void)
else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
|| (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000))
{
- if (sub_806D82C(sub_806D864(gBankTarget)) == 1)
+ if (sub_806D82C(GetBankMultiplayerId(gBankTarget)) == 1)
{
firstMonId = 3;
lastMonId = 6;
@@ -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/battle_util.c b/src/battle_util.c
index 537bb2793..15c11dbb2 100644
--- a/src/battle_util.c
+++ b/src/battle_util.c
@@ -1729,7 +1729,7 @@ bool8 sub_80423F4(u8 bank, u8 r1, u8 r2)
if (GetBankSide(bank) == SIDE_PLAYER)
{
party = gPlayerParty;
- r7 = sub_806D864(bank);
+ r7 = GetBankMultiplayerId(bank);
r6 = sub_806D82C(r7);
}
else
@@ -1748,7 +1748,7 @@ bool8 sub_80423F4(u8 bank, u8 r1, u8 r2)
}
else
{
- r7 = sub_806D864(bank);
+ r7 = GetBankMultiplayerId(bank);
if (GetBankSide(bank) == SIDE_PLAYER)
party = gPlayerParty;
else
diff --git a/src/evolution_graphics.c b/src/evolution_graphics.c
new file mode 100644
index 000000000..eca5d4bdc
--- /dev/null
+++ b/src/evolution_graphics.c
@@ -0,0 +1,611 @@
+#include "global.h"
+#include "evolution_graphics.h"
+#include "sprite.h"
+#include "trig.h"
+#include "rng.h"
+#include "decompress.h"
+#include "task.h"
+#include "sound.h"
+#include "songs.h"
+#include "palette.h"
+
+// this file's functions
+static void EvoSparkle_DummySpriteCb(struct Sprite* sprite);
+static void EvoTask_BeginPreSet1_FadeAndPlaySE(u8 taskID);
+static void EvoTask_CreatePreEvoSparkleSet1(u8 taskID);
+static void EvoTask_WaitForPre1SparklesToGoUp(u8 taskID);
+static void EvoTask_BeginPreSparklesSet2(u8 taskID);
+static void EvoTask_CreatePreEvoSparklesSet2(u8 taskID);
+static void EvoTask_DestroyPreSet2Task(u8 taskID);
+static void EvoTask_BeginPostSparklesSet1(u8 taskID);
+static void EvoTask_CreatePostEvoSparklesSet1(u8 taskID);
+static void EvoTask_DestroyPostSet1Task(u8 taskID);
+static void EvoTask_BeginPostSparklesSet2_AndFlash(u8 taskID);
+static void EvoTask_CreatePostEvoSparklesSet2_AndFlash(u8 taskID);
+static void EvoTask_BeginPostSparklesSet2_AndFlash_Trade(u8 taskID);
+static void EvoTask_CreatePostEvoSparklesSet2_AndFlash_Trade(u8 taskID);
+static void EvoTask_DestroyPostSet2AndFlashTask(u8 taskID);
+static void sub_817C4EC(u8 taskID);
+static void sub_817C510(u8 taskID);
+static void PreEvoVisible_PostEvoInvisible_KillTask(u8 taskID);
+static void PreEvoInvisible_PostEvoVisible_KillTask(u8 taskID);
+static void sub_817C560(u8 taskID);
+
+static const u16 sEvoSparklePalette[] = INCBIN_U16("graphics/misc/evo_sparkle.gbapal");
+static const u8 sEvoSparkleTiles[] = INCBIN_U8("graphics/misc/evo_sparkle.4bpp.lz");
+
+static const struct CompressedSpriteSheet sEvoSparkleSpriteSheets[] =
+{
+ {sEvoSparkleTiles, 0x20, 1001},
+ {NULL, 0, 0}
+};
+
+static const struct SpritePalette sEvoSparkleSpritePals[] =
+{
+ {sEvoSparklePalette, 1001},
+ {NULL, 0}
+};
+
+static const struct OamData sOamData_EvoSparkle =
+{
+ .y = 160,
+ .affineMode = 0,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = 0,
+ .shape = 0,
+ .x = 0,
+ .matrixNum = 0,
+ .size = 0,
+ .tileNum = 0,
+ .priority = 1,
+ .paletteNum = 0,
+ .affineParam = 0,
+};
+
+static const union AnimCmd sSpriteAnim_EvoSparkle[] =
+{
+ ANIMCMD_FRAME(0, 8),
+ ANIMCMD_END
+};
+
+static const union AnimCmd *const sSpriteAnimTable_EvoSparkle[] =
+{
+ sSpriteAnim_EvoSparkle,
+};
+
+static const struct SpriteTemplate sEvoSparkleSpriteTemplate =
+{
+ .tileTag = 1001,
+ .paletteTag = 1001,
+ .oam = &sOamData_EvoSparkle,
+ .anims = sSpriteAnimTable_EvoSparkle,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = EvoSparkle_DummySpriteCb
+};
+
+static const s16 sEvoSparkleMatrices[] =
+{
+ 0x3C0, 0x380, 0x340, 0x300, 0x2C0, 0x280, 0x240, 0x200, 0x1C0,
+ 0x180, 0x140, 0x100, -4, 0x10, -3, 0x30, -2, 0x50,
+ -1, 0x70, 0x1, 0x70, 0x2, 0x50, 0x3, 0x30, 0x4, 0x10
+};
+
+static void EvoSparkle_DummySpriteCb(struct Sprite *sprite)
+{
+
+}
+
+static void SetEvoSparklesMatrices(void)
+{
+ u16 i;
+ for (i = 0; i < 12; i++)
+ {
+ SetOamMatrix(20 + i, sEvoSparkleMatrices[i], 0, 0, sEvoSparkleMatrices[i]);
+ }
+}
+
+static void SpriteCB_PreEvoSparkleSet1(struct Sprite* sprite)
+{
+ if (sprite->pos1.y > 8)
+ {
+ u8 matrixNum;
+
+ sprite->pos1.y = 88 - (sprite->data7 * sprite->data7) / 80;
+ sprite->pos2.y = Sin((u8)(sprite->data6), sprite->data5) / 4;
+ sprite->pos2.x = Cos((u8)(sprite->data6), sprite->data5);
+ sprite->data6 += 4;
+ if (sprite->data7 & 1)
+ sprite->data5--;
+ sprite->data7++;
+ if (sprite->pos2.y > 0)
+ sprite->subpriority = 1;
+ else
+ sprite->subpriority = 20;
+ matrixNum = sprite->data5 / 4 + 20;
+ if (matrixNum > 31)
+ matrixNum = 31;
+ sprite->oam.matrixNum = matrixNum;
+ }
+ else
+ DestroySprite(sprite);
+}
+
+static void CreatePreEvoSparkleSet1(u8 arg0)
+{
+ u8 spriteID = CreateSprite(&sEvoSparkleSpriteTemplate, 120, 88, 0);
+ if (spriteID != MAX_SPRITES)
+ {
+ gSprites[spriteID].data5 = 48;
+ gSprites[spriteID].data6 = arg0;
+ gSprites[spriteID].data7 = 0;
+ gSprites[spriteID].oam.affineMode = 1;
+ gSprites[spriteID].oam.matrixNum = 31;
+ gSprites[spriteID].callback = SpriteCB_PreEvoSparkleSet1;
+ }
+}
+
+static void SpriteCB_PreEvoSparkleSet2(struct Sprite* sprite)
+{
+ if (sprite->pos1.y < 88)
+ {
+ sprite->pos1.y = 8 + (sprite->data7 * sprite->data7) / 5;
+ sprite->pos2.y = Sin((u8)(sprite->data6), sprite->data5) / 4;
+ sprite->pos2.x = Cos((u8)(sprite->data6), sprite->data5);
+ sprite->data5 = 8 + Sin((u8)(sprite->data7 * 4), 40);
+ sprite->data7++;
+ }
+ else
+ DestroySprite(sprite);
+}
+
+static void CreatePreEvoSparkleSet2(u8 arg0)
+{
+ u8 spriteID = CreateSprite(&sEvoSparkleSpriteTemplate, 120, 8, 0);
+ if (spriteID != MAX_SPRITES)
+ {
+ gSprites[spriteID].data5 = 8;
+ gSprites[spriteID].data6 = arg0;
+ gSprites[spriteID].data7 = 0;
+ gSprites[spriteID].oam.affineMode = 1;
+ gSprites[spriteID].oam.matrixNum = 25;
+ gSprites[spriteID].subpriority = 1;
+ gSprites[spriteID].callback = SpriteCB_PreEvoSparkleSet2;
+ }
+}
+
+static void SpriteCB_PostEvoSparkleSet1(struct Sprite* sprite)
+{
+ if (sprite->data5 > 8)
+ {
+ sprite->pos2.y = Sin((u8)(sprite->data6), sprite->data5);
+ sprite->pos2.x = Cos((u8)(sprite->data6), sprite->data5);
+ sprite->data5 -= sprite->data3;
+ sprite->data6 += 4;
+ }
+ else
+ DestroySprite(sprite);
+}
+
+static void CreatePostEvoSparkleSet1(u8 arg0, u8 arg1)
+{
+ u8 spriteID = CreateSprite(&sEvoSparkleSpriteTemplate, 120, 56, 0);
+ if (spriteID != MAX_SPRITES)
+ {
+ gSprites[spriteID].data3 = arg1;
+ gSprites[spriteID].data5 = 120;
+ gSprites[spriteID].data6 = arg0;
+ gSprites[spriteID].data7 = 0;
+ gSprites[spriteID].oam.affineMode = 1;
+ gSprites[spriteID].oam.matrixNum = 31;
+ gSprites[spriteID].subpriority = 1;
+ gSprites[spriteID].callback = SpriteCB_PostEvoSparkleSet1;
+ }
+}
+
+static void SpriteCB_PostEvoSparkleSet2(struct Sprite* sprite)
+{
+ if (!(sprite->data7 & 3))
+ sprite->pos1.y++;
+ if (sprite->data6 < 128)
+ {
+ u8 matrixNum;
+
+ sprite->pos2.y = -Sin((u8)(sprite->data6), sprite->data5);
+ sprite->pos1.x = 120 + (sprite->data3 * sprite->data7) / 3;
+ sprite->data6++;
+ matrixNum = 31 - (sprite->data6 * 12 / 128);
+ if (sprite->data6 > 64)
+ sprite->subpriority = 1;
+ else
+ {
+ sprite->invisible = 0;
+ sprite->subpriority = 20;
+ if (sprite->data6 > 112 && sprite->data6 & 1)
+ sprite->invisible = 1;
+ }
+ if (matrixNum < 20)
+ matrixNum = 20;
+ sprite->oam.matrixNum = matrixNum;
+ sprite->data7++;
+ }
+ else
+ DestroySprite(sprite);
+}
+
+static void CreatePostEvoSparkleSet2(u8 arg0)
+{
+ u8 spriteID = CreateSprite(&sEvoSparkleSpriteTemplate, 120, 56, 0);
+ if (spriteID != MAX_SPRITES)
+ {
+ gSprites[spriteID].data3 = 3 - (Random() % 7);
+ gSprites[spriteID].data5 = 48 + (Random() & 0x3F);
+ gSprites[spriteID].data7 = 0;
+ gSprites[spriteID].oam.affineMode = 1;
+ gSprites[spriteID].oam.matrixNum = 31;
+ gSprites[spriteID].subpriority = 20;
+ gSprites[spriteID].callback = SpriteCB_PostEvoSparkleSet2;
+ }
+}
+
+void LoadEvoSparkleSpriteAndPal(void)
+{
+ LoadCompressedObjectPicUsingHeap(&sEvoSparkleSpriteSheets[0]);
+ LoadSpritePalettes(sEvoSparkleSpritePals);
+}
+
+#define tFrameCounter data[15]
+
+u8 LaunchTask_PreEvoSparklesSet1(u16 arg0)
+{
+ u8 taskID = CreateTask(EvoTask_BeginPreSet1_FadeAndPlaySE, 0);
+ gTasks[taskID].data[1] = arg0;
+ return taskID;
+}
+
+static void EvoTask_BeginPreSet1_FadeAndPlaySE(u8 taskID)
+{
+ SetEvoSparklesMatrices();
+ gTasks[taskID].tFrameCounter = 0;
+ BeginNormalPaletteFade(3 << gTasks[taskID].data[1], 0xA, 0, 0x10, 0x7FFF);
+ gTasks[taskID].func = EvoTask_CreatePreEvoSparkleSet1;
+ PlaySE(SE_W025);
+}
+
+static void EvoTask_CreatePreEvoSparkleSet1(u8 taskID)
+{
+ if (gTasks[taskID].tFrameCounter < 64)
+ {
+ if (!(gTasks[taskID].tFrameCounter & 7))
+ {
+ u8 i;
+ for (i = 0; i < 4; i++)
+ CreatePreEvoSparkleSet1((0x78 & gTasks[taskID].tFrameCounter) * 2 + i * 64);
+ }
+ gTasks[taskID].tFrameCounter++;
+ }
+ else
+ {
+ gTasks[taskID].tFrameCounter = 96;
+ gTasks[taskID].func = EvoTask_WaitForPre1SparklesToGoUp;
+ }
+}
+
+static void EvoTask_WaitForPre1SparklesToGoUp(u8 taskID)
+{
+ if (gTasks[taskID].tFrameCounter != 0)
+ gTasks[taskID].tFrameCounter--;
+ else
+ DestroyTask(taskID);
+}
+
+u8 LaunchTask_PreEvoSparklesSet2(void)
+{
+ return CreateTask(EvoTask_BeginPreSparklesSet2, 0);
+}
+
+static void EvoTask_BeginPreSparklesSet2(u8 taskID)
+{
+ SetEvoSparklesMatrices();
+ gTasks[taskID].tFrameCounter = 0;
+ gTasks[taskID].func = EvoTask_CreatePreEvoSparklesSet2;
+ PlaySE(SE_W062B);
+}
+
+static void EvoTask_CreatePreEvoSparklesSet2(u8 taskID)
+{
+ if (gTasks[taskID].tFrameCounter < 96)
+ {
+ if (gTasks[taskID].tFrameCounter < 6)
+ {
+ u8 i;
+ for (i = 0; i < 9; i++)
+ CreatePreEvoSparkleSet2(i * 16);
+ }
+ gTasks[taskID].tFrameCounter++;
+ }
+ else
+ gTasks[taskID].func = EvoTask_DestroyPreSet2Task;
+}
+
+static void EvoTask_DestroyPreSet2Task(u8 taskID)
+{
+ DestroyTask(taskID);
+}
+
+u8 LaunchTask_PostEvoSparklesSet1(void)
+{
+ return CreateTask(EvoTask_BeginPostSparklesSet1, 0);
+}
+
+static void EvoTask_BeginPostSparklesSet1(u8 taskID)
+{
+ SetEvoSparklesMatrices();
+ gTasks[taskID].tFrameCounter = 0;
+ gTasks[taskID].func = EvoTask_CreatePostEvoSparklesSet1;
+ PlaySE(SE_REAPOKE);
+}
+
+static void EvoTask_CreatePostEvoSparklesSet1(u8 taskID)
+{
+ if (gTasks[taskID].tFrameCounter < 48)
+ {
+ if (gTasks[taskID].tFrameCounter == 0)
+ {
+ u8 i;
+ for (i = 0; i < 16; i++)
+ CreatePostEvoSparkleSet1(i * 16, 4);
+ }
+ if (gTasks[taskID].tFrameCounter == 32)
+ {
+ u8 i;
+ for (i = 0; i < 16; i++)
+ CreatePostEvoSparkleSet1(i * 16, 8);
+ }
+ gTasks[taskID].tFrameCounter++;
+ }
+ else
+ gTasks[taskID].func = EvoTask_DestroyPostSet1Task;
+}
+
+static void EvoTask_DestroyPostSet1Task(u8 taskID)
+{
+ DestroyTask(taskID);
+}
+
+u8 LaunchTask_PostEvoSparklesSet2AndFlash(u16 species)
+{
+ u8 taskID = CreateTask(EvoTask_BeginPostSparklesSet2_AndFlash, 0);
+ gTasks[taskID].data[2] = species;
+ return taskID;
+}
+
+static void EvoTask_BeginPostSparklesSet2_AndFlash(u8 taskID)
+{
+ SetEvoSparklesMatrices();
+ gTasks[taskID].tFrameCounter = 0;
+ CpuSet(&gPlttBufferFaded[0x20], &gPlttBufferUnfaded[0x20], 0x30);
+ BeginNormalPaletteFade(0xFFF9041C, 0, 0, 0x10, 0x7FFF); // was 0xFFF9001C in R/S
+ gTasks[taskID].func = EvoTask_CreatePostEvoSparklesSet2_AndFlash;
+ PlaySE(SE_W080);
+}
+
+static void EvoTask_CreatePostEvoSparklesSet2_AndFlash(u8 taskID)
+{
+ if (gTasks[taskID].tFrameCounter < 128)
+ {
+ u8 i;
+ switch (gTasks[taskID].tFrameCounter)
+ {
+ default:
+ if (gTasks[taskID].tFrameCounter < 50)
+ CreatePostEvoSparkleSet2(Random() & 7);
+ break;
+ case 0:
+ for (i = 0; i < 8; i++)
+ CreatePostEvoSparkleSet2(i);
+ break;
+ case 32:
+ BeginNormalPaletteFade(0xFFFF041C, 0x10, 0x10, 0, 0x7FFF); // was 0xFFF9001C in R/S
+ break;
+ }
+ gTasks[taskID].tFrameCounter++;
+ }
+ else
+ gTasks[taskID].func = EvoTask_DestroyPostSet2AndFlashTask;
+}
+
+static void EvoTask_DestroyPostSet2AndFlashTask(u8 taskID)
+{
+ if (!gPaletteFade.active)
+ DestroyTask(taskID);
+}
+
+u8 LaunchTask_PostEvoSparklesSet2AndFlash_Trade(u16 species)
+{
+ u8 taskID = CreateTask(EvoTask_BeginPostSparklesSet2_AndFlash_Trade, 0);
+ gTasks[taskID].data[2] = species;
+ return taskID;
+}
+
+static void EvoTask_BeginPostSparklesSet2_AndFlash_Trade(u8 taskID)
+{
+ SetEvoSparklesMatrices();
+ gTasks[taskID].tFrameCounter = 0;
+ CpuSet(&gPlttBufferFaded[0x20], &gPlttBufferUnfaded[0x20], 0x30);
+ BeginNormalPaletteFade(0xFFF90400, 0, 0, 0x10, 0x7FFF); // was 0xFFFF0001 in R/S
+ gTasks[taskID].func = EvoTask_CreatePostEvoSparklesSet2_AndFlash_Trade;
+ PlaySE(SE_W080);
+}
+
+static void EvoTask_CreatePostEvoSparklesSet2_AndFlash_Trade(u8 taskID)
+{
+ if (gTasks[taskID].tFrameCounter < 128)
+ {
+ u8 i;
+ switch (gTasks[taskID].tFrameCounter)
+ {
+ default:
+ if (gTasks[taskID].tFrameCounter < 50)
+ CreatePostEvoSparkleSet2(Random() & 7);
+ break;
+ case 0:
+ for (i = 0; i < 8; i++)
+ CreatePostEvoSparkleSet2(i);
+ break;
+ case 32:
+ BeginNormalPaletteFade(0xFFFF0400, 0x10, 0x10, 0, 0x7FFF); // was 0xFFFF0001 in R/S
+ break;
+ }
+ gTasks[taskID].tFrameCounter++;
+ }
+ else
+ gTasks[taskID].func = EvoTask_DestroyPostSet2AndFlashTask;
+}
+
+#undef tFrameCounter
+
+static void PokeEvoSprite_DummySpriteCB(struct Sprite* sprite)
+{
+
+}
+
+#define tPreEvoSpriteID data[1]
+#define tPostEvoSpriteID data[2]
+#define tEvoStopped data[8]
+
+u8 sub_817C3A0(u8 preEvoSpriteID, u8 postEvoSpriteID)
+{
+ u16 i;
+ u16 stack[16];
+ u8 taskID;
+ s32 toDiv;
+
+ for (i = 0; i < 16; i++)
+ stack[i] = 0x7FFF;
+
+ taskID = CreateTask(sub_817C4EC, 0);
+ gTasks[taskID].tPreEvoSpriteID = preEvoSpriteID;
+ gTasks[taskID].tPostEvoSpriteID = postEvoSpriteID;
+ gTasks[taskID].data[3] = 256;
+ gTasks[taskID].data[4] = 16;
+
+ toDiv = 65536;
+ SetOamMatrix(30, 256, 0, 0, 256);
+ SetOamMatrix(31, toDiv / gTasks[taskID].data[4], 0, 0, toDiv / gTasks[taskID].data[4]);
+
+ gSprites[preEvoSpriteID].callback = PokeEvoSprite_DummySpriteCB;
+ gSprites[preEvoSpriteID].oam.affineMode = 1;
+ gSprites[preEvoSpriteID].oam.matrixNum = 30;
+ gSprites[preEvoSpriteID].invisible = 0;
+ CpuSet(stack, &gPlttBufferFaded[0x100 + (gSprites[preEvoSpriteID].oam.paletteNum * 16)], 16);
+
+ gSprites[postEvoSpriteID].callback = PokeEvoSprite_DummySpriteCB;
+ gSprites[postEvoSpriteID].oam.affineMode = 1;
+ gSprites[postEvoSpriteID].oam.matrixNum = 31;
+ gSprites[postEvoSpriteID].invisible = 0;
+ CpuSet(stack, &gPlttBufferFaded[0x100 + (gSprites[postEvoSpriteID].oam.paletteNum * 16)], 16);
+
+ gTasks[taskID].tEvoStopped = FALSE;
+ return taskID;
+}
+
+static void sub_817C4EC(u8 taskID)
+{
+ gTasks[taskID].data[5] = 0;
+ gTasks[taskID].data[6] = 8;
+ gTasks[taskID].func = sub_817C510;
+}
+
+static void sub_817C510(u8 taskID)
+{
+ if (gTasks[taskID].tEvoStopped)
+ PreEvoVisible_PostEvoInvisible_KillTask(taskID);
+ else if (gTasks[taskID].data[6] == 128)
+ PreEvoInvisible_PostEvoVisible_KillTask(taskID);
+ else
+ {
+ gTasks[taskID].data[6] += 2;
+ gTasks[taskID].data[5] ^= 1;
+ gTasks[taskID].func = sub_817C560;
+ }
+}
+
+static void sub_817C560(u8 taskID)
+{
+ if (gTasks[taskID].tEvoStopped)
+ gTasks[taskID].func = PreEvoVisible_PostEvoInvisible_KillTask;
+ else
+ {
+ u16 oamMatrixArg;
+ u8 r6 = 0;
+ if (gTasks[taskID].data[5] == 0)
+ {
+ if (gTasks[taskID].data[3] < 256 - gTasks[taskID].data[6])
+ gTasks[taskID].data[3] += gTasks[taskID].data[6];
+ else
+ {
+ gTasks[taskID].data[3] = 256;
+ r6++;
+ }
+ if (gTasks[taskID].data[4] > 16 + gTasks[taskID].data[6])
+ gTasks[taskID].data[4] -= gTasks[taskID].data[6];
+ else
+ {
+ gTasks[taskID].data[4] = 16;
+ r6++;
+ }
+ }
+ else
+ {
+ if (gTasks[taskID].data[4] < 256 - gTasks[taskID].data[6])
+ gTasks[taskID].data[4] += gTasks[taskID].data[6];
+ else
+ {
+ gTasks[taskID].data[4] = 256;
+ r6++;
+ }
+ if (gTasks[taskID].data[3] > 16 + gTasks[taskID].data[6])
+ gTasks[taskID].data[3] -= gTasks[taskID].data[6];
+ else
+ {
+ gTasks[taskID].data[3] = 16;
+ r6++;
+ }
+ }
+ oamMatrixArg = 65536 / gTasks[taskID].data[3];
+ SetOamMatrix(30, oamMatrixArg, 0, 0, oamMatrixArg);
+
+ oamMatrixArg = 65536 / gTasks[taskID].data[4];
+ SetOamMatrix(31, oamMatrixArg, 0, 0, oamMatrixArg);
+ if (r6 == 2)
+ gTasks[taskID].func = sub_817C510;
+ }
+}
+
+static void PreEvoInvisible_PostEvoVisible_KillTask(u8 taskID)
+{
+ gSprites[gTasks[taskID].tPreEvoSpriteID].oam.affineMode = 0;
+ gSprites[gTasks[taskID].tPreEvoSpriteID].oam.matrixNum = 0;
+ gSprites[gTasks[taskID].tPreEvoSpriteID].invisible = 1;
+
+ gSprites[gTasks[taskID].tPostEvoSpriteID].oam.affineMode = 0;
+ gSprites[gTasks[taskID].tPostEvoSpriteID].oam.matrixNum = 0;
+ gSprites[gTasks[taskID].tPostEvoSpriteID].invisible = 0;
+
+ DestroyTask(taskID);
+}
+
+static void PreEvoVisible_PostEvoInvisible_KillTask(u8 taskID)
+{
+ gSprites[gTasks[taskID].tPreEvoSpriteID].oam.affineMode = 0;
+ gSprites[gTasks[taskID].tPreEvoSpriteID].oam.matrixNum = 0;
+ gSprites[gTasks[taskID].tPreEvoSpriteID].invisible = 0;
+
+ gSprites[gTasks[taskID].tPostEvoSpriteID].oam.affineMode = 0;
+ gSprites[gTasks[taskID].tPostEvoSpriteID].oam.matrixNum = 0;
+ gSprites[gTasks[taskID].tPostEvoSpriteID].invisible = 1;
+
+ DestroyTask(taskID);
+}
diff --git a/src/evolution_scene.c b/src/evolution_scene.c
new file mode 100644
index 000000000..68731a14a
--- /dev/null
+++ b/src/evolution_scene.c
@@ -0,0 +1,1506 @@
+#include "global.h"
+#include "evolution_scene.h"
+#include "evolution_graphics.h"
+#include "sprite.h"
+#include "malloc.h"
+#include "task.h"
+#include "palette.h"
+#include "main.h"
+#include "text.h"
+#include "text_window.h"
+#include "pokemon.h"
+#include "string_util.h"
+#include "battle.h"
+#include "unknown_task.h"
+#include "decompress.h"
+#include "m4a.h"
+#include "menu.h"
+#include "pokedex.h"
+#include "species.h"
+#include "sound.h"
+#include "songs.h"
+#include "overworld.h"
+#include "battle_message.h"
+#include "gpu_regs.h"
+#include "bg.h"
+#include "link.h"
+#include "blend_palette.h"
+#include "trig.h"
+
+struct EvoInfo
+{
+ u8 preEvoSpriteID;
+ u8 postEvoSpriteID;
+ u8 evoTaskID;
+ u8 field_3;
+ u16 savedPalette[48];
+};
+
+static EWRAM_DATA struct EvoInfo *sEvoStructPtr = NULL;
+static EWRAM_DATA u16 *sEvoMovingBgPtr = NULL;
+
+extern u16 gBattle_BG0_X;
+extern u16 gBattle_BG0_Y;
+extern u16 gBattle_BG1_X;
+extern u16 gBattle_BG1_Y;
+extern u16 gBattle_BG2_X;
+extern u16 gBattle_BG2_Y;
+extern u16 gBattle_BG3_X;
+extern u16 gBattle_BG3_Y;
+extern u8 gBattleTerrain;
+extern struct SpriteTemplate gUnknown_0202499C;
+extern bool8 gAffineAnimsDisabled;
+extern u16 gMoveToLearn;
+
+extern u8 gBattleCommunication[];
+#define sEvoCursorPos gBattleCommunication[1] // when learning a new move
+#define sEvoGraphicsTaskID gBattleCommunication[2]
+
+extern const struct WindowTemplate gUnknown_0833900C;
+extern const struct CompressedSpriteSheet gMonFrontPicTable[];
+extern const u8 gUnknown_085B58C9[][4];
+extern const u16 gUnknown_085B5884[];
+extern const u8 gUnknown_085B58D9[];
+extern const u16 gUnknown_085B51E4[];
+extern const u32 gUnknown_085B4134[];
+extern const u32 gUnknown_085B482C[];
+extern const u32 gUnknown_085B4D10[];
+
+// strings
+extern const u8 gText_ShedinjaJapaneseName2[];
+extern const u8 gText_PkmnIsEvolving[];
+extern const u8 gText_CongratsPkmnEvolved[];
+extern const u8 gText_BattleYesNoChoice[];
+extern const u8 gText_PkmnStoppedEvolving[];
+extern const u8 gText_EllipsisQuestionMark[];
+extern const u8 gText_CommunicationStandby5[];
+
+extern void copy_decompressed_tile_data_to_vram_autofree(u8 arg0, const void *arg1, bool32 arg2, u16 arg3, u8 arg4);
+extern u32 sub_80391E0(u8, u8);
+extern void SpriteCallbackDummy_2(struct Sprite *sprite);
+extern void sub_80356D0(void);
+extern void sub_807B154(void);
+extern void sub_806A068(u16, u8);
+extern void sub_807F19C(void);
+extern void sub_807B140(void);
+extern void EvolutionRenameMon(struct Pokemon *mon, u16 oldSpecies, u16 newSpecies);
+extern void sub_8085784(void);
+extern void sub_81BFA38(struct Pokemon *party, u8 monId, u8 partyCount, void *CB2_ptr, u16 move);
+extern u8 sub_81C1B94(void);
+extern void sub_807F1A8(u8 arg0, const u8 *arg1, u8 arg2);
+extern void sub_800E084(void);
+
+// this file's functions
+static void Task_EvolutionScene(u8 taskID);
+static void Task_TradeEvolutionScene(u8 taskID);
+static void CB2_EvolutionSceneUpdate(void);
+static void CB2_TradeEvolutionSceneUpdate(void);
+static void EvoDummyFunc(void);
+static void VBlankCB_EvolutionScene(void);
+static void VBlankCB_TradeEvolutionScene(void);
+static void sub_81150D8(void);
+static void sub_8140134(void);
+static void EvoScene_DoMonAnimation(u8 monSpriteId, u16 speciesId);
+static bool32 EvoScene_IsMonAnimFinished(u8 monSpriteId);
+static void InitMovingBackgroundTask(bool8 isLink);
+static void sub_813FEE8(u8 taskId);
+static void sub_8140174(void);
+
+static void CB2_BeginEvolutionScene(void)
+{
+ UpdatePaletteFade();
+ RunTasks();
+}
+
+#define tState data[0]
+#define tPreEvoSpecies data[1]
+#define tPostEvoSpecies data[2]
+#define tCanStop data[3]
+#define tBits data[3]
+#define tLearnsFirstMove data[4]
+#define tLearnMoveState data[6]
+#define tData7 data[7]
+#define tData8 data[8]
+#define tEvoWasStopped data[9]
+#define tPartyID data[10]
+
+#define TASK_BIT_CAN_STOP 0x1
+#define TASK_BIT_LEARN_MOVE 0x80
+
+static void Task_BeginEvolutionScene(u8 taskID)
+{
+ struct Pokemon* mon = NULL;
+ switch (gTasks[taskID].tState)
+ {
+ case 0:
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gTasks[taskID].tState++;
+ break;
+ case 1:
+ if (!gPaletteFade.active)
+ {
+ u16 speciesToEvolve;
+ bool8 canStopEvo;
+ u8 partyID;
+
+ mon = &gPlayerParty[gTasks[taskID].tPartyID];
+ speciesToEvolve = gTasks[taskID].tPostEvoSpecies;
+ canStopEvo = gTasks[taskID].tCanStop;
+ partyID = gTasks[taskID].tPartyID;
+
+ DestroyTask(taskID);
+ EvolutionScene(mon, speciesToEvolve, canStopEvo, partyID);
+ }
+ break;
+ }
+}
+
+void BeginEvolutionScene(struct Pokemon* mon, u16 speciesToEvolve, bool8 canStopEvo, u8 partyID)
+{
+ u8 taskID = CreateTask(Task_BeginEvolutionScene, 0);
+ gTasks[taskID].tState = 0;
+ gTasks[taskID].tPostEvoSpecies = speciesToEvolve;
+ gTasks[taskID].tCanStop = canStopEvo;
+ gTasks[taskID].tPartyID = partyID;
+ SetMainCallback2(CB2_BeginEvolutionScene);
+}
+
+void EvolutionScene(struct Pokemon* mon, u16 speciesToEvolve, bool8 canStopEvo, u8 partyID)
+{
+ u8 name[20];
+ u16 currSpecies;
+ u32 trainerId, personality;
+ const struct CompressedSpritePalette* pokePal;
+ u8 ID;
+
+ SetHBlankCallback(NULL);
+ SetVBlankCallback(NULL);
+ CpuFill32(0, (void*)(VRAM), VRAM_SIZE);
+
+ SetGpuReg(REG_OFFSET_MOSAIC, 0);
+ SetGpuReg(REG_OFFSET_WIN0H, 0);
+ SetGpuReg(REG_OFFSET_WIN0V, 0);
+ SetGpuReg(REG_OFFSET_WIN1H, 0);
+ SetGpuReg(REG_OFFSET_WIN1V, 0);
+ SetGpuReg(REG_OFFSET_WININ, 0);
+ SetGpuReg(REG_OFFSET_WINOUT, 0);
+
+ ResetPaletteFade();
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gBattle_BG2_X = 0;
+ gBattle_BG2_Y = 0;
+ gBattle_BG3_X = 256;
+ gBattle_BG3_Y = 0;
+
+ gBattleTerrain = BATTLE_TERRAIN_PLAIN;
+
+ sub_80356D0();
+ LoadBattleTextboxAndBackground();
+ ResetSpriteData();
+ remove_some_task();
+ ResetTasks();
+ FreeAllSpritePalettes();
+
+ gReservedSpritePaletteCount = 4;
+
+ sEvoStructPtr = AllocZeroed(sizeof(struct EvoInfo));
+ AllocateMonSpritesGfx();
+
+ GetMonData(mon, MON_DATA_NICKNAME, name);
+ StringCopy10(gStringVar1, name);
+ StringCopy(gStringVar2, gSpeciesNames[speciesToEvolve]);
+
+ // preEvo sprite
+ currSpecies = GetMonData(mon, MON_DATA_SPECIES);
+ trainerId = GetMonData(mon, MON_DATA_OT_ID);
+ personality = GetMonData(mon, MON_DATA_PERSONALITY);
+ DecompressPicFromTable_2(&gMonFrontPicTable[currSpecies],
+ gMonSpritesGfxPtr->sprites[1],
+ currSpecies);
+ pokePal = GetMonSpritePalStructFromOtIdPersonality(currSpecies, trainerId, personality);
+ LoadCompressedPalette(pokePal->data, 0x110, 0x20);
+
+ sub_806A068(currSpecies, 1);
+ gUnknown_0202499C.affineAnims = gDummySpriteAffineAnimTable;
+ sEvoStructPtr->preEvoSpriteID = ID = CreateSprite(&gUnknown_0202499C, 120, 64, 30);
+
+ gSprites[ID].callback = SpriteCallbackDummy_2;
+ gSprites[ID].oam.paletteNum = 1;
+ gSprites[ID].invisible = 1;
+
+ // postEvo sprite
+ DecompressPicFromTable_2(&gMonFrontPicTable[speciesToEvolve],
+ gMonSpritesGfxPtr->sprites[3],
+ speciesToEvolve);
+ pokePal = GetMonSpritePalStructFromOtIdPersonality(speciesToEvolve, trainerId, personality);
+ LoadCompressedPalette(pokePal->data, 0x120, 0x20);
+
+ sub_806A068(speciesToEvolve, 3);
+ gUnknown_0202499C.affineAnims = gDummySpriteAffineAnimTable;
+ sEvoStructPtr->postEvoSpriteID = ID = CreateSprite(&gUnknown_0202499C, 120, 64, 30);
+ gSprites[ID].callback = SpriteCallbackDummy_2;
+ gSprites[ID].oam.paletteNum = 2;
+ gSprites[ID].invisible = 1;
+
+ LoadEvoSparkleSpriteAndPal();
+
+ sEvoStructPtr->evoTaskID = ID = CreateTask(Task_EvolutionScene, 0);
+ gTasks[ID].tState = 0;
+ gTasks[ID].tPreEvoSpecies = currSpecies;
+ gTasks[ID].tPostEvoSpecies = speciesToEvolve;
+ gTasks[ID].tCanStop = canStopEvo;
+ gTasks[ID].tLearnsFirstMove = TRUE;
+ gTasks[ID].tEvoWasStopped = FALSE;
+ gTasks[ID].tPartyID = partyID;
+
+ memcpy(&sEvoStructPtr->savedPalette, &gPlttBufferUnfaded[0x20], 0x60);
+
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG_ALL_ON | DISPCNT_OBJ_1D_MAP);
+
+ SetHBlankCallback(EvoDummyFunc);
+ SetVBlankCallback(VBlankCB_EvolutionScene);
+ m4aMPlayAllStop();
+ SetMainCallback2(CB2_EvolutionSceneUpdate);
+}
+
+static void CB2_EvolutionSceneLoadGraphics(void)
+{
+ u8 ID;
+ const struct CompressedSpritePalette* pokePal;
+ u16 postEvoSpecies;
+ u32 trainerId, personality;
+ struct Pokemon* Mon = &gPlayerParty[gTasks[sEvoStructPtr->evoTaskID].tPartyID];
+
+ postEvoSpecies = gTasks[sEvoStructPtr->evoTaskID].tPostEvoSpecies;
+ trainerId = GetMonData(Mon, MON_DATA_OT_ID);
+ personality = GetMonData(Mon, MON_DATA_PERSONALITY);
+
+ SetHBlankCallback(NULL);
+ SetVBlankCallback(NULL);
+ CpuFill32(0, (void*)(VRAM), VRAM_SIZE);
+
+ SetGpuReg(REG_OFFSET_MOSAIC, 0);
+ SetGpuReg(REG_OFFSET_WIN0H, 0);
+ SetGpuReg(REG_OFFSET_WIN0V, 0);
+ SetGpuReg(REG_OFFSET_WIN1H, 0);
+ SetGpuReg(REG_OFFSET_WIN1V, 0);
+ SetGpuReg(REG_OFFSET_WININ, 0);
+ SetGpuReg(REG_OFFSET_WINOUT, 0);
+
+ ResetPaletteFade();
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gBattle_BG2_X = 0;
+ gBattle_BG2_Y = 0;
+ gBattle_BG3_X = 256;
+ gBattle_BG3_Y = 0;
+
+ gBattleTerrain = BATTLE_TERRAIN_PLAIN;
+
+ sub_80356D0();
+ LoadBattleTextboxAndBackground();
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ gReservedSpritePaletteCount = 4;
+
+ DecompressPicFromTable_2(&gMonFrontPicTable[postEvoSpecies],
+ gMonSpritesGfxPtr->sprites[3],
+ postEvoSpecies);
+ pokePal = GetMonSpritePalStructFromOtIdPersonality(postEvoSpecies, trainerId, personality);
+
+ LoadCompressedPalette(pokePal->data, 0x120, 0x20);
+
+ sub_806A068(postEvoSpecies, 3);
+ gUnknown_0202499C.affineAnims = gDummySpriteAffineAnimTable;
+ sEvoStructPtr->postEvoSpriteID = ID = CreateSprite(&gUnknown_0202499C, 120, 64, 30);
+
+ gSprites[ID].callback = SpriteCallbackDummy_2;
+ gSprites[ID].oam.paletteNum = 2;
+
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG_ALL_ON | DISPCNT_OBJ_1D_MAP);
+
+ SetHBlankCallback(EvoDummyFunc);
+ SetVBlankCallback(VBlankCB_EvolutionScene);
+ SetMainCallback2(CB2_EvolutionSceneUpdate);
+
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
+
+ ShowBg(0);
+ ShowBg(1);
+ ShowBg(2);
+ ShowBg(3);
+}
+
+static void CB2_TradeEvolutionSceneLoadGraphics(void)
+{
+ struct Pokemon* Mon = &gPlayerParty[gTasks[sEvoStructPtr->evoTaskID].tPartyID];
+ u16 postEvoSpecies = gTasks[sEvoStructPtr->evoTaskID].tPostEvoSpecies;
+
+ switch (gMain.state)
+ {
+ case 0:
+ SetGpuReg(REG_OFFSET_DISPCNT, 0);
+ SetHBlankCallback(NULL);
+ SetVBlankCallback(NULL);
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ gReservedSpritePaletteCount = 4;
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gBattle_BG2_X = 0;
+ gBattle_BG2_Y = 0;
+ gBattle_BG3_X = 256;
+ gBattle_BG3_Y = 0;
+ gMain.state++;
+ break;
+ case 1:
+ ResetPaletteFade();
+ SetHBlankCallback(EvoDummyFunc);
+ SetVBlankCallback(VBlankCB_TradeEvolutionScene);
+ gMain.state++;
+ break;
+ case 2:
+ sub_807F19C();
+ gMain.state++;
+ break;
+ case 3:
+ FillBgTilemapBufferRect(1, 0, 0, 0, 0x20, 0x20, 0x11);
+ CopyBgTilemapBufferToVram(1);
+ gMain.state++;
+ break;
+ case 4:
+ {
+ const struct CompressedSpritePalette* pokePal;
+ u32 trainerId = GetMonData(Mon, MON_DATA_OT_ID);
+ u32 personality = GetMonData(Mon, MON_DATA_PERSONALITY);
+ DecompressPicFromTable_2(&gMonFrontPicTable[postEvoSpecies],
+ gMonSpritesGfxPtr->sprites[3],
+ postEvoSpecies);
+ pokePal = GetMonSpritePalStructFromOtIdPersonality(postEvoSpecies, trainerId, personality);
+ LoadCompressedPalette(pokePal->data, 0x120, 0x20);
+ gMain.state++;
+ }
+ break;
+ case 5:
+ {
+ u8 ID;
+
+ sub_806A068(postEvoSpecies, 1);
+ gUnknown_0202499C.affineAnims = gDummySpriteAffineAnimTable;
+ sEvoStructPtr->postEvoSpriteID = ID = CreateSprite(&gUnknown_0202499C, 120, 64, 30);
+
+ gSprites[ID].callback = SpriteCallbackDummy_2;
+ gSprites[ID].oam.paletteNum = 2;
+ gMain.state++;
+ sub_807B154();
+ }
+ break;
+ case 6:
+ if (gLinkVSyncDisabled)
+ {
+ sub_800E0E8();
+ sub_800DFB4(0, 0);
+ }
+ BlendPalettes(-1,0x10, 0);
+ gMain.state++;
+ break;
+ case 7:
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
+ sub_807B140();
+ ShowBg(0);
+ ShowBg(1);
+ SetMainCallback2(CB2_TradeEvolutionSceneUpdate);
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG0_ON | DISPCNT_BG1_ON | DISPCNT_OBJ_1D_MAP);
+ break;
+ }
+}
+
+void TradeEvolutionScene(struct Pokemon* mon, u16 speciesToEvolve, u8 preEvoSpriteID, u8 partyID)
+{
+ u8 name[20];
+ u16 currSpecies;
+ u32 trainerId, personality;
+ const struct CompressedSpritePalette* pokePal;
+ u8 ID;
+
+ GetMonData(mon, MON_DATA_NICKNAME, name);
+ StringCopy10(gStringVar1, name);
+ StringCopy(gStringVar2, gSpeciesNames[speciesToEvolve]);
+
+ gAffineAnimsDisabled = TRUE;
+
+ // preEvo sprite
+ currSpecies = GetMonData(mon, MON_DATA_SPECIES);
+ personality = GetMonData(mon, MON_DATA_PERSONALITY);
+ trainerId = GetMonData(mon, MON_DATA_OT_ID);
+
+ sEvoStructPtr = AllocZeroed(sizeof(struct EvoInfo));
+ sEvoStructPtr->preEvoSpriteID = preEvoSpriteID;
+
+ DecompressPicFromTable_2(&gMonFrontPicTable[speciesToEvolve],
+ gMonSpritesGfxPtr->sprites[1],
+ speciesToEvolve);
+
+ pokePal = GetMonSpritePalStructFromOtIdPersonality(speciesToEvolve, trainerId, personality);
+ LoadCompressedPalette(pokePal->data, 0x120, 0x20);
+
+ sub_806A068(speciesToEvolve, 1);
+ gUnknown_0202499C.affineAnims = gDummySpriteAffineAnimTable;
+ sEvoStructPtr->postEvoSpriteID = ID = CreateSprite(&gUnknown_0202499C, 120, 64, 30);
+
+ gSprites[ID].callback = SpriteCallbackDummy_2;
+ gSprites[ID].oam.paletteNum = 2;
+ gSprites[ID].invisible = 1;
+
+ LoadEvoSparkleSpriteAndPal();
+
+ sEvoStructPtr->evoTaskID = ID = CreateTask(Task_TradeEvolutionScene, 0);
+ gTasks[ID].tState = 0;
+ gTasks[ID].tPreEvoSpecies = currSpecies;
+ gTasks[ID].tPostEvoSpecies = speciesToEvolve;
+ gTasks[ID].tLearnsFirstMove = TRUE;
+ gTasks[ID].tEvoWasStopped = FALSE;
+ gTasks[ID].tPartyID = partyID;
+
+ gBattle_BG0_X = 0;
+ gBattle_BG0_Y = 0;
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gBattle_BG2_X = 0;
+ gBattle_BG2_Y = 0;
+ gBattle_BG3_X = 256;
+ gBattle_BG3_Y = 0;
+
+ gTextFlags.flag_1 = 1;
+
+ SetVBlankCallback(VBlankCB_TradeEvolutionScene);
+ SetMainCallback2(CB2_TradeEvolutionSceneUpdate);
+}
+
+static void CB2_EvolutionSceneUpdate(void)
+{
+ AnimateSprites();
+ BuildOamBuffer();
+ RunTextPrinters();
+ UpdatePaletteFade();
+ RunTasks();
+}
+
+static void CB2_TradeEvolutionSceneUpdate(void)
+{
+ AnimateSprites();
+ BuildOamBuffer();
+ RunTextPrinters();
+ UpdatePaletteFade();
+ RunTasks();
+}
+
+static void CreateShedinja(u16 preEvoSpecies, struct Pokemon* mon)
+{
+ u32 data = 0;
+ if (gEvolutionTable[preEvoSpecies].evolutions[0].method == EVO_LEVEL_NINJASK && gPlayerPartyCount < 6)
+ {
+ s32 i;
+ struct Pokemon* Shedinja = &gPlayerParty[gPlayerPartyCount];
+ const struct EvolutionData* evoTable;
+ const struct EvolutionData* evos;
+
+ CopyMon(&gPlayerParty[gPlayerPartyCount], mon, sizeof(struct Pokemon));
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_SPECIES, (&gEvolutionTable[preEvoSpecies].evolutions[1].targetSpecies));
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_NICKNAME, (gSpeciesNames[gEvolutionTable[preEvoSpecies].evolutions[1].targetSpecies]));
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_HELD_ITEM, (&data));
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_MARKINGS, (&data));
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_10, (&data));
+
+ for (i = MON_DATA_COOL_RIBBON; i < MON_DATA_COOL_RIBBON + 5; i++)
+ SetMonData(&gPlayerParty[gPlayerPartyCount], i, (&data));
+ for (i = MON_DATA_CHAMPION_RIBBON; i <= MON_DATA_FATEFUL_ENCOUNTER; i++)
+ SetMonData(&gPlayerParty[gPlayerPartyCount], i, (&data));
+
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_STATUS, (&data));
+ data = 0xFF;
+ SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_MAIL, (&data));
+
+ CalculateMonStats(&gPlayerParty[gPlayerPartyCount]);
+ CalculatePlayerPartyCount();
+
+ // can't match it otherwise, ehh
+ evoTable = gEvolutionTable;
+ evos = evoTable + preEvoSpecies;
+ GetSetPokedexFlag(SpeciesToNationalPokedexNum(evos->evolutions[1].targetSpecies), FLAG_SET_SEEN);
+ GetSetPokedexFlag(SpeciesToNationalPokedexNum(evos->evolutions[1].targetSpecies), FLAG_SET_CAUGHT);
+
+ if (GetMonData(Shedinja, MON_DATA_SPECIES) == SPECIES_SHEDINJA
+ && GetMonData(Shedinja, MON_DATA_LANGUAGE) == LANGUAGE_JAPANESE
+ && GetMonData(mon, MON_DATA_SPECIES) == SPECIES_NINJASK)
+ SetMonData(Shedinja, MON_DATA_NICKNAME, gText_ShedinjaJapaneseName2);
+ }
+}
+
+static void Task_EvolutionScene(u8 taskID)
+{
+ u32 var;
+ struct Pokemon* mon = &gPlayerParty[gTasks[taskID].tPartyID];
+
+ // check if B Button was held, so the evolution gets stopped
+ if (gMain.heldKeys == B_BUTTON
+ && gTasks[taskID].tState == 8
+ && gTasks[sEvoGraphicsTaskID].isActive
+ && gTasks[taskID].tBits & TASK_BIT_CAN_STOP)
+ {
+ gTasks[taskID].tState = 17;
+ gTasks[sEvoGraphicsTaskID].EvoGraphicsTaskEvoStop = TRUE;
+ sub_8140134();
+ return;
+ }
+
+ switch (gTasks[taskID].tState)
+ {
+ case 0:
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
+ gSprites[sEvoStructPtr->preEvoSpriteID].invisible = 0;
+ gTasks[taskID].tState++;
+ ShowBg(0);
+ ShowBg(1);
+ ShowBg(2);
+ ShowBg(3);
+ break;
+ case 1: // print 'whoa, poke is evolving!!!' msg
+ if (!gPaletteFade.active)
+ {
+ StringExpandPlaceholders(gStringVar4, gText_PkmnIsEvolving);
+ BattleHandleAddTextPrinter(gStringVar4, 0);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 2: // wait for string, animate mon(and play its cry)
+ if (!IsTextPrinterActive(0))
+ {
+ EvoScene_DoMonAnimation(sEvoStructPtr->preEvoSpriteID, gTasks[taskID].tPreEvoSpecies);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 3:
+ if (EvoScene_IsMonAnimFinished(sEvoStructPtr->preEvoSpriteID)) // wait for animation, play tu du SE
+ {
+ PlaySE(BGM_ME_SHINKA);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 4: // play evolution music and fade screen black
+ if (!IsSEPlaying())
+ {
+ PlayNewMapMusic(BGM_SHINKA);
+ gTasks[taskID].tState++;
+ BeginNormalPaletteFade(0x1C, 4, 0, 0x10, 0);
+ }
+ break;
+ case 5: // launch moving bg task, preapre evo sparkles
+ if (!gPaletteFade.active)
+ {
+ InitMovingBackgroundTask(FALSE);
+ sEvoGraphicsTaskID = LaunchTask_PreEvoSparklesSet1(17);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 6: // another set of evo sparkles
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ gTasks[taskID].tState++;
+ sEvoStructPtr->field_3 = 1;
+ sEvoGraphicsTaskID = LaunchTask_PreEvoSparklesSet2();
+ }
+ break;
+ case 7: // launch task that flashes pre evo with post evo sprites
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ sEvoGraphicsTaskID = sub_817C3A0(sEvoStructPtr->preEvoSpriteID, sEvoStructPtr->postEvoSpriteID);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 8: // wait for the above task to finish
+ if (--sEvoStructPtr->field_3 == 0)
+ {
+ sEvoStructPtr->field_3 = 3;
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 9: // post evo sparkles
+ sEvoGraphicsTaskID = LaunchTask_PostEvoSparklesSet1();
+ gTasks[taskID].tState++;
+ break;
+ case 10:
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ sEvoGraphicsTaskID = LaunchTask_PostEvoSparklesSet2AndFlash(gTasks[taskID].tPostEvoSpecies);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 11: // play tu du sound after evolution
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ PlaySE(SE_EXP);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 12: // stop music, return screen to pre-fade state
+ if (IsSEPlaying())
+ {
+ m4aMPlayAllStop();
+ memcpy(&gPlttBufferUnfaded[0x20], sEvoStructPtr->savedPalette, 0x60);
+ sub_8140174();
+ BeginNormalPaletteFade(0x1C, 0, 0x10, 0, 0);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 13: // animate mon
+ if (!gPaletteFade.active)
+ {
+ EvoScene_DoMonAnimation(sEvoStructPtr->postEvoSpriteID, gTasks[taskID].tPostEvoSpecies);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 14: // congratulations string and rename prompt
+ if (IsCryFinished())
+ {
+ StringExpandPlaceholders(gStringVar4, gText_CongratsPkmnEvolved);
+ BattleHandleAddTextPrinter(gStringVar4, 0);
+ PlayBGM(BGM_FANFA5);
+ gTasks[taskID].tState++;
+ SetMonData(mon, MON_DATA_SPECIES, (void*)(&gTasks[taskID].tPostEvoSpecies));
+ CalculateMonStats(mon);
+ EvolutionRenameMon(mon, gTasks[taskID].tPreEvoSpecies, gTasks[taskID].tPostEvoSpecies);
+ GetSetPokedexFlag(SpeciesToNationalPokedexNum(gTasks[taskID].tPostEvoSpecies), FLAG_SET_SEEN);
+ GetSetPokedexFlag(SpeciesToNationalPokedexNum(gTasks[taskID].tPostEvoSpecies), FLAG_SET_CAUGHT);
+ IncrementGameStat(GAME_STAT_EVOLVED_POKEMON);
+ }
+ break;
+ case 15: // check if it wants to learn a new move
+ if (!IsTextPrinterActive(0))
+ {
+ var = MonTryLearningNewMove(mon, gTasks[taskID].tLearnsFirstMove);
+ if (var != 0 && !gTasks[taskID].tEvoWasStopped)
+ {
+ u8 text[20];
+
+ if (!(gTasks[taskID].tBits & TASK_BIT_LEARN_MOVE))
+ {
+ StopMapMusic();
+ sub_8085784();
+ }
+
+ gTasks[taskID].tBits |= TASK_BIT_LEARN_MOVE;
+ gTasks[taskID].tLearnsFirstMove = FALSE;
+ gTasks[taskID].tLearnMoveState = 0;
+ GetMonData(mon, MON_DATA_NICKNAME, text);
+ StringCopy10(gBattleTextBuff1, text);
+
+ if (var == 0xFFFF) // no place to learn it
+ gTasks[taskID].tState = 22;
+ else if (var == 0xFFFE) // it already knows that move
+ break;
+ else
+ gTasks[taskID].tState = 20; // has less than 4 moves, so it's been learned
+ }
+ else // no move to learn
+ {
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gTasks[taskID].tState++;
+ }
+ }
+ break;
+ case 16: // task has finished, return
+ if (!gPaletteFade.active)
+ {
+ if (!(gTasks[taskID].tBits & TASK_BIT_LEARN_MOVE))
+ {
+ StopMapMusic();
+ sub_8085784();
+ }
+ if (!gTasks[taskID].tEvoWasStopped)
+ CreateShedinja(gTasks[taskID].tPreEvoSpecies, mon);
+
+ DestroyTask(taskID);
+ FreeMonSpritesGfx();
+ Free(sEvoStructPtr);
+ sEvoStructPtr = NULL;
+ FreeAllWindowBuffers();
+ SetMainCallback2(gCB2_AfterEvolution);
+ }
+ break;
+ case 17: // evolution has been canceled, stop music and re-fade palette
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ m4aMPlayAllStop();
+ BeginNormalPaletteFade(0x6001C, 0, 0x10, 0, 0x7FFF);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 18: // animate pokemon trying to evolve again, evolution has been stopped
+ if (!gPaletteFade.active)
+ {
+ EvoScene_DoMonAnimation(sEvoStructPtr->preEvoSpriteID, gTasks[taskID].tPreEvoSpecies);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 19: // after the animation, print the string 'WHOA IT DID NOT EVOLVE!!!'
+ if (EvoScene_IsMonAnimFinished(sEvoStructPtr->preEvoSpriteID))
+ {
+ if (gTasks[taskID].tEvoWasStopped)
+ StringExpandPlaceholders(gStringVar4, gText_EllipsisQuestionMark);
+ else // Fire Red leftover probably
+ StringExpandPlaceholders(gStringVar4, gText_PkmnStoppedEvolving);
+
+ BattleHandleAddTextPrinter(gStringVar4, 0);
+ gTasks[taskID].tEvoWasStopped = TRUE;
+ gTasks[taskID].tState = 15;
+ }
+ break;
+ case 20: // pokemon learned a new move, print string and play a fanfare
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BufferMoveToLearnIntoBattleTextBuff2();
+ PlayFanfare(BGM_FANFA1);
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[3]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tLearnsFirstMove = 0x40; // re-used as a counter
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 21: // wait a bit and check if can learn another move
+ if (!IsTextPrinterActive(0) && !IsSEPlaying() && --gTasks[taskID].tLearnsFirstMove == 0)
+ gTasks[taskID].tState = 15;
+ break;
+ case 22: // try to learn a new move
+ switch (gTasks[taskID].tLearnMoveState)
+ {
+ case 0:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BufferMoveToLearnIntoBattleTextBuff2();
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[4]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 1:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[5]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 2:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[6]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tData7 = 5;
+ gTasks[taskID].tData8 = 10;
+ gTasks[taskID].tLearnMoveState++;
+ }
+ case 3:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
+ BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
+ gTasks[taskID].tLearnMoveState++;
+ sEvoCursorPos = 0;
+ BattleCreateYesNoCursorAt(0);
+ }
+ break;
+ case 4:
+ if (gMain.newKeys & DPAD_UP && sEvoCursorPos != 0)
+ {
+ PlaySE(SE_SELECT);
+ BattleDestroyYesNoCursorAt(sEvoCursorPos);
+ sEvoCursorPos = 0;
+ BattleCreateYesNoCursorAt(0);
+ }
+ if (gMain.newKeys & DPAD_DOWN && sEvoCursorPos == 0)
+ {
+ PlaySE(SE_SELECT);
+ BattleDestroyYesNoCursorAt(sEvoCursorPos);
+ sEvoCursorPos = 1;
+ BattleCreateYesNoCursorAt(1);
+ }
+ if (gMain.newKeys & A_BUTTON)
+ {
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
+ PlaySE(SE_SELECT);
+
+ if (sEvoCursorPos != 0)
+ {
+ gTasks[taskID].tLearnMoveState = gTasks[taskID].tData8;
+ }
+ else
+ {
+ gTasks[taskID].tLearnMoveState = gTasks[taskID].tData7;
+ if (gTasks[taskID].tLearnMoveState == 5)
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ }
+ }
+ if (gMain.newKeys & B_BUTTON)
+ {
+ HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
+ PlaySE(SE_SELECT);
+ gTasks[taskID].tLearnMoveState = gTasks[taskID].tData8;
+ }
+ break;
+ case 5:
+ if (!gPaletteFade.active)
+ {
+ FreeAllWindowBuffers();
+ sub_81BFA38(gPlayerParty, gTasks[taskID].tPartyID,
+ gPlayerPartyCount - 1, CB2_EvolutionSceneLoadGraphics,
+ gMoveToLearn);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 6:
+ if (!gPaletteFade.active && gMain.callback2 == CB2_EvolutionSceneUpdate)
+ {
+ var = sub_81C1B94(); // moveID
+ if (var == 4)
+ {
+ gTasks[taskID].tLearnMoveState = 10;
+ }
+ else
+ {
+ u16 move = GetMonData(mon, var + MON_DATA_MOVE1);
+ if (IsHMMove2(move))
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[307]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tLearnMoveState = 12;
+ }
+ else
+ {
+ PREPARE_MOVE_BUFFER(gBattleTextBuff2, move)
+
+ RemoveMonPPBonus(mon, var);
+ SetMonMoveSlot(mon, gMoveToLearn, var);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ }
+ }
+ break;
+ case 7:
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[207]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tLearnMoveState++;
+ break;
+ case 8:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[7]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 9:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[208]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tState = 20;
+ }
+ break;
+ case 10:
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[8]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tData7 = 11;
+ gTasks[taskID].tData8 = 0;
+ gTasks[taskID].tLearnMoveState = 3;
+ break;
+ case 11:
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[9]);
+ BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
+ gTasks[taskID].tState = 15;
+ break;
+ case 12:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ gTasks[taskID].tLearnMoveState = 5;
+ break;
+ }
+ break;
+ }
+}
+
+static void Task_TradeEvolutionScene(u8 taskID)
+{
+ u32 var = 0;
+ struct Pokemon* mon = &gPlayerParty[gTasks[taskID].tPartyID];
+
+ switch (gTasks[taskID].tState)
+ {
+ case 0:
+ StringExpandPlaceholders(gStringVar4, gText_PkmnIsEvolving);
+ sub_807F1A8(0, gStringVar4, 1);
+ gTasks[taskID].tState++;
+ break;
+ case 1:
+ if (!IsTextPrinterActive(0))
+ {
+ PlayCry1(gTasks[taskID].tPreEvoSpecies, 0);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 2:
+ if (IsCryFinished())
+ {
+ m4aSongNumStop(BGM_SHINKA);
+ PlaySE(BGM_ME_SHINKA);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 3:
+ if (!IsSEPlaying())
+ {
+ PlayBGM(BGM_SHINKA);
+ gTasks[taskID].tState++;
+ BeginNormalPaletteFade(0x1C, 4, 0, 0x10, 0);
+ }
+ break;
+ case 4:
+ if (!gPaletteFade.active)
+ {
+ InitMovingBackgroundTask(TRUE);
+ var = gSprites[sEvoStructPtr->preEvoSpriteID].oam.paletteNum + 16;
+ sEvoGraphicsTaskID = LaunchTask_PreEvoSparklesSet1(var);
+ gTasks[taskID].tState++;
+ SetGpuReg(REG_OFFSET_BG3CNT, 0x603);
+ }
+ break;
+ case 5:
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ gTasks[taskID].tState++;
+ sEvoStructPtr->field_3 = 1;
+ sEvoGraphicsTaskID = LaunchTask_PreEvoSparklesSet2();
+ }
+ break;
+ case 6:
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ sEvoGraphicsTaskID = sub_817C3A0(sEvoStructPtr->preEvoSpriteID, sEvoStructPtr->postEvoSpriteID);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 7:
+ if (--sEvoStructPtr->field_3 == 0)
+ {
+ sEvoStructPtr->field_3 = 3;
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 8:
+ sEvoGraphicsTaskID = LaunchTask_PostEvoSparklesSet1();
+ gTasks[taskID].tState++;
+ break;
+ case 9:
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ sEvoGraphicsTaskID = LaunchTask_PostEvoSparklesSet2AndFlash_Trade(gTasks[taskID].tPostEvoSpecies);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 10:
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ PlaySE(SE_EXP);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 11:
+ if (IsSEPlaying())
+ {
+ Free(sEvoMovingBgPtr);
+ EvoScene_DoMonAnimation(sEvoStructPtr->postEvoSpriteID, gTasks[taskID].tPostEvoSpecies);
+ memcpy(&gPlttBufferUnfaded[0x20], sEvoStructPtr->savedPalette, 0x60);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 12:
+ if (IsCryFinished())
+ {
+ StringExpandPlaceholders(gStringVar4, gText_CongratsPkmnEvolved);
+ sub_807F1A8(0, gStringVar4, 1);
+ PlayFanfare(BGM_FANFA5);
+ gTasks[taskID].tState++;
+ SetMonData(mon, MON_DATA_SPECIES, (&gTasks[taskID].tPostEvoSpecies));
+ CalculateMonStats(mon);
+ EvolutionRenameMon(mon, gTasks[taskID].tPreEvoSpecies, gTasks[taskID].tPostEvoSpecies);
+ GetSetPokedexFlag(SpeciesToNationalPokedexNum(gTasks[taskID].tPostEvoSpecies), FLAG_SET_SEEN);
+ GetSetPokedexFlag(SpeciesToNationalPokedexNum(gTasks[taskID].tPostEvoSpecies), FLAG_SET_CAUGHT);
+ IncrementGameStat(GAME_STAT_EVOLVED_POKEMON);
+ }
+ break;
+ case 13:
+ if (!IsTextPrinterActive(0) && IsFanfareTaskInactive() == TRUE)
+ {
+ var = MonTryLearningNewMove(mon, gTasks[taskID].tLearnsFirstMove);
+ if (var != 0 && !gTasks[taskID].tEvoWasStopped)
+ {
+ u8 text[20];
+
+ gTasks[taskID].tBits |= TASK_BIT_LEARN_MOVE;
+ gTasks[taskID].tLearnsFirstMove = FALSE;
+ gTasks[taskID].tLearnMoveState = 0;
+ GetMonData(mon, MON_DATA_NICKNAME, text);
+ StringCopy10(gBattleTextBuff1, text);
+
+ if (var == 0xFFFF)
+ gTasks[taskID].tState = 20;
+ else if (var == 0xFFFE)
+ break;
+ else
+ gTasks[taskID].tState = 18;
+ }
+ else
+ {
+ PlayBGM(BGM_SHINKA);
+ sub_807F1A8(0, gText_CommunicationStandby5, 1);
+ gTasks[taskID].tState++;
+ }
+ }
+ break;
+ case 14:
+ if (!IsTextPrinterActive(0))
+ {
+ DestroyTask(taskID);
+ Free(sEvoStructPtr);
+ sEvoStructPtr = NULL;
+ gTextFlags.flag_1 = 0;
+ SetMainCallback2(gCB2_AfterEvolution);
+ }
+ break;
+ case 15:
+ if (!gTasks[sEvoGraphicsTaskID].isActive)
+ {
+ m4aMPlayAllStop();
+ BeginNormalPaletteFade((1 << (gSprites[sEvoStructPtr->preEvoSpriteID].oam.paletteNum + 16)) | (0x4001C), 0, 0x10, 0, 0x7FFF);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 16:
+ if (!gPaletteFade.active)
+ {
+ EvoScene_DoMonAnimation(sEvoStructPtr->preEvoSpriteID, gTasks[taskID].tPreEvoSpecies);
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 17:
+ if (EvoScene_IsMonAnimFinished(sEvoStructPtr->preEvoSpriteID))
+ {
+ StringExpandPlaceholders(gStringVar4, gText_EllipsisQuestionMark);
+ sub_807F1A8(0, gStringVar4, 1);
+ gTasks[taskID].tEvoWasStopped = 1;
+ gTasks[taskID].tState = 13;
+ }
+ break;
+ case 18:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BufferMoveToLearnIntoBattleTextBuff2();
+ PlayFanfare(BGM_FANFA1);
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[3]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnsFirstMove = 0x40; // re-used as a counter
+ gTasks[taskID].tState++;
+ }
+ break;
+ case 19:
+ if (!IsTextPrinterActive(0) && IsFanfareTaskInactive() == TRUE && --gTasks[taskID].tLearnsFirstMove == 0)
+ gTasks[taskID].tState = 13;
+ break;
+ case 20:
+ switch (gTasks[taskID].tLearnMoveState)
+ {
+ case 0:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BufferMoveToLearnIntoBattleTextBuff2();
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[4]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 1:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[5]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 2:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[6]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tData7 = 5;
+ gTasks[taskID].tData8 = 9;
+ gTasks[taskID].tLearnMoveState++;
+ }
+ case 3:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ sub_809882C(0, 0xA8, 0xE0);
+ CreateYesNoMenu(&gUnknown_0833900C, 0xA8, 0xE, 0);
+ sEvoCursorPos = 0;
+ gTasks[taskID].tLearnMoveState++;
+ sEvoCursorPos = 0;
+ }
+ break;
+ case 4:
+ switch (sub_8198C58())
+ {
+ case 0:
+ sEvoCursorPos = 0;
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[292]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState = gTasks[taskID].tData7;
+ if (gTasks[taskID].tLearnMoveState == 5)
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ break;
+ case 1:
+ case -1:
+ sEvoCursorPos = 1;
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[292]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState = gTasks[taskID].tData8;
+ break;
+ }
+ break;
+ case 5:
+ if (!gPaletteFade.active)
+ {
+ if (gLinkVSyncDisabled)
+ sub_800E084();
+
+ Free(GetBgTilemapBuffer(3));
+ Free(GetBgTilemapBuffer(1));
+ Free(GetBgTilemapBuffer(0));
+ FreeAllWindowBuffers();
+
+ sub_81BFA38(gPlayerParty, gTasks[taskID].tPartyID,
+ gPlayerPartyCount - 1, CB2_TradeEvolutionSceneLoadGraphics,
+ gMoveToLearn);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 6:
+ if (!gPaletteFade.active && gMain.callback2 == CB2_TradeEvolutionSceneUpdate)
+ {
+ var = sub_81C1B94(); // moveID
+ if (var == 4)
+ {
+ gTasks[taskID].tLearnMoveState = 9;
+ }
+ else
+ {
+ u16 move = GetMonData(mon, var + MON_DATA_MOVE1);
+ if (IsHMMove2(move))
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[307]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState = 11;
+ }
+ else
+ {
+ PREPARE_MOVE_BUFFER(gBattleTextBuff2, move)
+
+ RemoveMonPPBonus(mon, var);
+ SetMonMoveSlot(mon, gMoveToLearn, var);
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[207]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ }
+ }
+ break;
+ case 7:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[7]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tLearnMoveState++;
+ }
+ break;
+ case 8:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[208]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tState = 18;
+ }
+ break;
+ case 9:
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[8]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tData7 = 10;
+ gTasks[taskID].tData8 = 0;
+ gTasks[taskID].tLearnMoveState = 3;
+ break;
+ case 10:
+ BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[9]);
+ sub_807F1A8(0, gDisplayedStringBattle, 1);
+ gTasks[taskID].tState = 13;
+ break;
+ case 11:
+ if (!IsTextPrinterActive(0) && !IsSEPlaying())
+ gTasks[taskID].tLearnMoveState = 5;
+ break;
+ }
+ break;
+ }
+}
+
+#undef tState
+#undef tPreEvoSpecies
+#undef tPostEvoSpecies
+#undef tCanStop
+#undef tBits
+#undef tLearnsFirstMove
+#undef tLearnMoveState
+#undef tData7
+#undef tData8
+#undef tEvoWasStopped
+#undef tPartyID
+
+static void EvoDummyFunc(void)
+{
+}
+
+static void VBlankCB_EvolutionScene(void)
+{
+ SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X);
+ SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y);
+ SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X);
+ SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y);
+ SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X);
+ SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y);
+ SetGpuReg(REG_OFFSET_BG3HOFS, gBattle_BG3_X);
+ SetGpuReg(REG_OFFSET_BG3VOFS, gBattle_BG3_Y);
+
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ TransferPlttBuffer();
+ sub_80BA0A8();
+}
+
+static void VBlankCB_TradeEvolutionScene(void)
+{
+ SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X);
+ SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y);
+ SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X);
+ SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y);
+ SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X);
+ SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y);
+ SetGpuReg(REG_OFFSET_BG3HOFS, gBattle_BG3_X);
+ SetGpuReg(REG_OFFSET_BG3VOFS, gBattle_BG3_Y);
+
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ TransferPlttBuffer();
+ sub_80BA0A8();
+}
+
+static void sub_813FDEC(u8 taskId)
+{
+ s16 *data = gTasks[taskId].data;
+
+ if (data[6] != 0)
+ return;
+ if (data[5]++ < 20)
+ return;
+
+ if (data[0]++ > gUnknown_085B58C9[data[2]][3])
+ {
+ if (gUnknown_085B58C9[data[2]][1] == data[1])
+ {
+ data[3]++;
+ if (data[3] == gUnknown_085B58C9[data[2]][2])
+ {
+ data[3] = 0;
+ data[2]++;
+ }
+ data[1] = gUnknown_085B58C9[data[2]][0];
+ }
+ else
+ {
+ LoadPalette(&sEvoMovingBgPtr[data[1] * 16], 0xA0, 0x20);
+ data[0] = 0;
+ data[1]++;
+ }
+ }
+
+ if (data[2] == 4)
+ DestroyTask(taskId);
+}
+
+static void sub_813FEA4(bool8 isLink)
+{
+ u8 taskId = CreateTask(sub_813FEE8, 7);
+
+ if (!isLink)
+ gTasks[taskId].data[2] = 0;
+ else
+ gTasks[taskId].data[2] = 1;
+}
+
+static void sub_813FEE8(u8 taskId)
+{
+ u16 *outer_X, *outer_Y;
+
+ u16 *inner_X = &gBattle_BG1_X;
+ u16 *inner_Y = &gBattle_BG1_Y;
+
+ if (!gTasks[taskId].data[2])
+ {
+ outer_X = &gBattle_BG2_X;
+ outer_Y = &gBattle_BG2_Y;
+ }
+ else
+ {
+ outer_X = &gBattle_BG3_X;
+ outer_Y = &gBattle_BG3_Y;
+ }
+
+ gTasks[taskId].data[0] = (gTasks[taskId].data[0] + 5) & 0xFF;
+ gTasks[taskId].data[1] = (gTasks[taskId].data[0] + 0x80) & 0xFF;
+
+ *inner_X = Cos(gTasks[taskId].data[0], 4) + 8;
+ *inner_Y = Sin(gTasks[taskId].data[0], 4) + 16;
+
+ *outer_X = Cos(gTasks[taskId].data[1], 4) + 8;
+ *outer_Y = Sin(gTasks[taskId].data[1], 4) + 16;
+
+ if (!FuncIsActiveTask(sub_813FDEC))
+ {
+ DestroyTask(taskId);
+
+ *inner_X = 0;
+ *inner_Y = 0;
+
+ *outer_X = 256;
+ *outer_Y = 0;
+ }
+}
+
+static void InitMovingBgValues(u16 *movingBgs)
+{
+ s32 i, j;
+
+ for (i = 0; i < 50; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ movingBgs[i * 16 + j] = gUnknown_085B5884[gUnknown_085B58D9[i * 16 + j]];
+ }
+ }
+}
+
+static void InitMovingBackgroundTask(bool8 isLink)
+{
+ u8 innerBgId, outerBgId;
+
+ sEvoMovingBgPtr = AllocZeroed(0x640);
+ InitMovingBgValues(sEvoMovingBgPtr);
+
+ if (!isLink)
+ innerBgId = 1, outerBgId = 2;
+ else
+ innerBgId = 1, outerBgId = 3;
+
+ LoadPalette(gUnknown_085B51E4, 0xA0, 0x20);
+
+ copy_decompressed_tile_data_to_vram_autofree(1, gUnknown_085B4134, FALSE, 0, 0);
+ CopyToBgTilemapBuffer(1, gUnknown_085B482C, 0, 0);
+ CopyToBgTilemapBuffer(outerBgId, gUnknown_085B4D10, 0, 0);
+ CopyBgTilemapBufferToVram(1);
+ CopyBgTilemapBufferToVram(outerBgId);
+
+ if (!isLink)
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, 0x442);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0x808);
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG2_ON | DISPCNT_BG1_ON | DISPCNT_BG0_ON | DISPCNT_OBJ_1D_MAP);
+
+ SetBgAttribute(innerBgId, BG_CTRL_ATTR_MOSAIC, 2);
+ SetBgAttribute(outerBgId, BG_CTRL_ATTR_MOSAIC, 2);
+
+ ShowBg(1);
+ ShowBg(2);
+ }
+ else
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, 0x842);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0x808);
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG3_ON | DISPCNT_BG1_ON | DISPCNT_BG0_ON | DISPCNT_OBJ_1D_MAP);
+ }
+
+ CreateTask(sub_813FDEC, 5);
+ sub_813FEA4(isLink);
+}
+
+static void sub_8140100(void) // unused
+{
+ u8 taskId = FindTaskIdByFunc(sub_813FDEC);
+
+ if (taskId != 0xFF)
+ gTasks[taskId].data[6] = 1;
+
+ FillPalette(0, 0xA0, 0x20);
+}
+
+static void sub_8140134(void)
+{
+ u8 taskId;
+
+ if ((taskId = FindTaskIdByFunc(sub_813FDEC)) != 0xFF)
+ DestroyTask(taskId);
+ if ((taskId = FindTaskIdByFunc(sub_813FEE8)) != 0xFF)
+ DestroyTask(taskId);
+
+ FillPalette(0, 0xA0, 0x20);
+ sub_8140174();
+}
+
+static void sub_8140174(void)
+{
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gBattle_BG2_X = 0;
+ SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, sub_80391E0(1, 5));
+ SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, sub_80391E0(2, 5));
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG3_ON | DISPCNT_BG0_ON | DISPCNT_OBJ_1D_MAP);
+ Free(sEvoMovingBgPtr);
+}
+
+static void EvoScene_DoMonAnimation(u8 monSpriteId, u16 speciesId)
+{
+ DoMonFrontSpriteAnimation(&gSprites[monSpriteId], speciesId, FALSE, 0);
+}
+
+static bool32 EvoScene_IsMonAnimFinished(u8 monSpriteId)
+{
+ if (gSprites[monSpriteId].callback == SpriteCallbackDummy)
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/src/field_map_obj.c b/src/field_map_obj.c
index e822fc1ca..9932563f2 100755
--- a/src/field_map_obj.c
+++ b/src/field_map_obj.c
@@ -21,6 +21,7 @@
#include "field_effect_helpers.h"
#include "field_camera.h"
#include "trainer_see.h"
+#include "decoration.h"
#include "field_map_obj.h"
#define NUM_FIELD_MAP_OBJECT_TEMPLATES 0x51
@@ -1755,18 +1756,18 @@ void sub_808F254(u8 localId, u8 mapNum, u8 mapGroup)
}
}
-void sub_808F28C(u8 localId, u8 mapNum, u8 mapGroup, u8 action)
+void sub_808F28C(u8 localId, u8 mapNum, u8 mapGroup, u8 decorCat)
{
u8 mapObjectId;
if (!TryGetFieldObjectIdByLocalIdAndMap(localId, mapNum, mapGroup, &mapObjectId))
{
- switch (action)
+ switch (decorCat)
{
- case 6:
+ case DECORCAT_DOLL:
sub_808F228(&gMapObjects[mapObjectId], gUnknown_082766A2);
break;
- case 7:
+ case DECORCAT_CUSHION:
sub_808F228(&gMapObjects[mapObjectId], gUnknown_082766A6);
break;
}
diff --git a/src/math_util.c b/src/math_util.c
new file mode 100644
index 000000000..83935454a
--- /dev/null
+++ b/src/math_util.c
@@ -0,0 +1,86 @@
+#include "global.h"
+
+s16 sub_8151534(s16 x, s16 y)
+{
+ s32 result;
+
+ result = x;
+ result *= y;
+ result /= 256;
+ return result;
+}
+
+s16 sub_8151550(u8 s, s16 x, s16 y)
+{
+ s32 result;
+
+ result = x;
+ result *= y;
+ result /= (1 << s);
+ return result;
+}
+
+s32 sub_8151574(s32 x, s32 y)
+{
+ s64 result;
+
+ result = x;
+ result *= y;
+ result /= 256;
+ return result;
+}
+
+s16 sub_81515B0(s16 x, s16 y)
+{
+ if (y == 0)
+ {
+ return 0;
+ }
+ return (x << 8) / y;
+}
+
+s16 sub_81515D4(u8 s, s16 x, s16 y)
+{
+ if (y == 0)
+ {
+ return 0;
+ }
+ return (x << s) / y;
+}
+
+s32 sub_81515FC(s32 x, s32 y)
+{
+ s64 _x;
+
+ if (y == 0)
+ {
+ return 0;
+ }
+ _x = x;
+ _x *= 256;
+ return _x / y;
+}
+
+s16 sub_8151624(s16 y)
+{
+ s32 x;
+
+ x = 0x10000;
+ return x / y;
+}
+
+s16 sub_815163C(u8 s, s16 y)
+{
+ s32 x;
+
+ x = 0x100 << s;
+ return x / y;
+}
+
+s32 sub_815165C(s32 y)
+{
+ s64 x;
+
+ x = 0x10000;
+ return x / y;
+}
diff --git a/src/pokemon_2.c b/src/pokemon_2.c
index 3802cc5eb..7014be492 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..27da8b18e 100644
--- a/src/pokemon_3.c
+++ b/src/pokemon_3.c
@@ -618,7 +618,7 @@ bool16 sub_806D82C(u8 id)
return retVal;
}
-s32 sub_806D864(u16 a1)
+s32 GetBankMultiplayerId(u16 a1)
{
s32 id;
for (id = 0; id < MAX_LINK_PLAYERS; id++)
@@ -1267,10 +1267,10 @@ const struct CompressedSpritePalette *sub_806E794(struct Pokemon *mon)
u16 species = GetMonData(mon, MON_DATA_SPECIES2, 0);
u32 otId = GetMonData(mon, MON_DATA_OT_ID, 0);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0);
- return sub_806E7CC(species, otId, personality);
+ return GetMonSpritePalStructFromOtIdPersonality(species, otId, personality);
}
-const struct CompressedSpritePalette *sub_806E7CC(u16 species, u32 otId , u32 personality)
+const struct CompressedSpritePalette *GetMonSpritePalStructFromOtIdPersonality(u16 species, u32 otId , u32 personality)
{
u32 shinyValue;
@@ -1477,7 +1477,7 @@ const u8* GetTrainerPartnerName(void)
else
{
u8 id = GetMultiplayerId();
- return gLinkPlayers[sub_806D864(gLinkPlayers[id].lp_field_18 ^ 2)].name;
+ return gLinkPlayers[GetBankMultiplayerId(gLinkPlayers[id].lp_field_18 ^ 2)].name;
}
}
@@ -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
diff --git a/src/secret_base.c b/src/secret_base.c
new file mode 100644
index 000000000..7a1a53828
--- /dev/null
+++ b/src/secret_base.c
@@ -0,0 +1,2272 @@
+
+// Includes
+#include "global.h"
+#include "malloc.h"
+#include "task.h"
+#include "palette.h"
+#include "list_menu.h"
+#include "window.h"
+#include "menu.h"
+#include "menu_helpers.h"
+#include "new_menu_helpers.h"
+#include "menu_indicators.h"
+#include "map_constants.h"
+#include "songs.h"
+#include "sound.h"
+#include "overworld.h"
+#include "fieldmap.h"
+#include "field_camera.h"
+#include "field_player_avatar.h"
+#include "field_screen.h"
+#include "field_weather.h"
+#include "field_map_obj.h"
+#include "field_effect.h"
+#include "fldeff_80F9BCC.h"
+#include "metatile_behavior.h"
+#include "map_name_popup.h"
+#include "string_util.h"
+#include "script.h"
+#include "event_scripts.h"
+#include "strings.h"
+#include "international_string_util.h"
+#include "event_data.h"
+#include "battle.h"
+#include "rom6.h"
+#include "decoration.h"
+#include "link.h"
+#include "tv.h"
+#include "secret_base.h"
+
+// Static type declarations
+
+struct SecretBaseListMenuBuffer {
+ struct ListMenuItem items[11];
+ u8 names[11][32];
+};
+
+struct SecretBaseRecordMixer {
+ struct SecretBaseRecord *records;
+ u32 version;
+ u32 language;
+};
+
+// Static RAM declarations
+EWRAM_DATA u8 sCurSecretBaseId = 0;
+EWRAM_DATA u8 gUnknown_0203A01D = 0;
+EWRAM_DATA struct SecretBaseListMenuBuffer *gUnknown_0203A020 = NULL;
+
+// Static ROM declarations
+
+void sub_80E9C9C(u8 taskId);
+void game_continue(u8 taskId);
+void sub_80E9DEC(u32 a0, bool8 flag, struct ListMenu *menu);
+void sub_80E9E00(u8 taskId);
+void sub_80E9E44(u8 taskId);
+void sub_80E9E90(u8 taskId);
+void sub_80E9F20(u8 taskId);
+void sub_80E9FB0(u8 taskId);
+void sub_80E9FFC(u8 taskId);
+void sub_80EA06C(u8 taskId);
+void sub_80EA120(u8 taskId);
+void sub_80EA13C(u8 taskId);
+void sub_80EA18C(u8 taskId);
+void task_pc_turn_off(u8 taskId);
+u8 sub_80EA20C(u8 secretBaseRecordId);
+
+// .rodata
+
+const struct {
+ u16 tile1;
+ u16 tile2;
+} gUnknown_0858CFCC[] = {
+ {0x0026, 0x0036},
+ {0x0027, 0x0037},
+ {0x01a0, 0x01a1},
+ {0x01a8, 0x01a9},
+ {0x01b0, 0x01b1},
+ {0x0208, 0x0210},
+ {0x0271, 0x0278}
+};
+
+const u8 gUnknown_0858CFE8[] = {
+ MAP_ID_SECRET_BASE_RED_CAVE1, 0x00, 0x01, 0x03,
+ MAP_ID_SECRET_BASE_RED_CAVE2, 0x00, 0x05, 0x09,
+ MAP_ID_SECRET_BASE_RED_CAVE3, 0x00, 0x01, 0x03,
+ MAP_ID_SECRET_BASE_RED_CAVE4, 0x00, 0x07, 0x0d,
+ MAP_ID_SECRET_BASE_BROWN_CAVE1, 0x00, 0x02, 0x03,
+ MAP_ID_SECRET_BASE_BROWN_CAVE2, 0x00, 0x09, 0x02,
+ MAP_ID_SECRET_BASE_BROWN_CAVE3, 0x00, 0x0d, 0x04,
+ MAP_ID_SECRET_BASE_BROWN_CAVE4, 0x00, 0x01, 0x02,
+ MAP_ID_SECRET_BASE_BLUE_CAVE1, 0x00, 0x01, 0x03,
+ MAP_ID_SECRET_BASE_BLUE_CAVE2, 0x00, 0x01, 0x02,
+ MAP_ID_SECRET_BASE_BLUE_CAVE3, 0x00, 0x03, 0x0f,
+ MAP_ID_SECRET_BASE_BLUE_CAVE4, 0x00, 0x03, 0x0e,
+ MAP_ID_SECRET_BASE_YELLOW_CAVE1, 0x00, 0x09, 0x03,
+ MAP_ID_SECRET_BASE_YELLOW_CAVE2, 0x00, 0x08, 0x07,
+ MAP_ID_SECRET_BASE_YELLOW_CAVE3, 0x00, 0x03, 0x06,
+ MAP_ID_SECRET_BASE_YELLOW_CAVE4, 0x00, 0x05, 0x09,
+ MAP_ID_SECRET_BASE_TREE1, 0x00, 0x02, 0x03,
+ MAP_ID_SECRET_BASE_TREE2, 0x00, 0x05, 0x06,
+ MAP_ID_SECRET_BASE_TREE3, 0x00, 0x0f, 0x03,
+ MAP_ID_SECRET_BASE_TREE4, 0x00, 0x04, 0x0a,
+ MAP_ID_SECRET_BASE_SHRUB1, 0x00, 0x03, 0x03,
+ MAP_ID_SECRET_BASE_SHRUB2, 0x00, 0x01, 0x02,
+ MAP_ID_SECRET_BASE_SHRUB3, 0x00, 0x07, 0x08,
+ MAP_ID_SECRET_BASE_SHRUB4, 0x00, 0x09, 0x06
+};
+
+const struct MenuAction gUnknown_0858D048[] = {
+ {gUnknown_085EA79D, {.void_u8 = sub_80E9FFC}},
+ {gText_Cancel, {.void_u8 = sub_80EA18C}}
+};
+
+const struct YesNoFuncTable gUnknown_0858D058 = {
+ sub_80EA120, sub_80EA13C
+};
+
+const u8 gUnknown_0858D060[10] = {
+ 0x23, 0x24, 0x0f, 0x1f, 0x21,
+ 0x2f, 0x0e, 0x14, 0x20, 0x22
+};
+
+const struct WindowTemplate gUnknown_0858D06C[] = {
+ { 0, 18, 1, 11, 18, 15, 0x01 },
+ { 0, 2, 1, 28, 4, 15, 0xc7 }
+};
+
+const struct ListMenuTemplate gUnknown_0858D07C = {
+ NULL,
+ sub_80E9DEC,
+ NULL,
+ 0, 0,
+ 0, 0, 8, 0,
+ 9, 2, 1, 3, FALSE, 0, FALSE, 1
+};
+
+// .text
+
+void ClearSecretBase(struct SecretBaseRecord *sbr)
+{
+ u16 i;
+
+ CpuFastFill16(0, sbr, sizeof(struct SecretBaseRecord));
+ for (i = 0; i < 7; i ++)
+ {
+ sbr->trainerName[i] = EOS;
+ }
+}
+
+void ResetSecretBases(void)
+{
+ u16 i;
+
+ for (i = 0; i < 20; i ++)
+ {
+ ClearSecretBase(&gSaveBlock1Ptr->secretBases[i]);
+ }
+}
+
+void sub_80E8B58(void)
+{
+ sCurSecretBaseId = gSpecialVar_0x8004;
+}
+
+void sub_80E8B6C(void)
+{
+ u16 i;
+
+ gSpecialVar_ScriptResult = FALSE;
+ for (i = 0; i < 20; i ++)
+ {
+ if (sCurSecretBaseId != gSaveBlock1Ptr->secretBases[i].secretBaseId)
+ {
+ continue;
+ }
+ gSpecialVar_ScriptResult = TRUE;
+ VarSet(VAR_0x4054, i);
+ break;
+ }
+}
+
+void sub_80E8BC8(void)
+{
+ if (gSaveBlock1Ptr->secretBases[0].secretBaseId != 0)
+ {
+ gSpecialVar_ScriptResult = TRUE;
+ }
+ else
+ {
+ gSpecialVar_ScriptResult = FALSE;
+ }
+}
+
+u8 sub_80E8BF8(void)
+{
+ s16 x;
+ s16 y;
+ s16 behavior;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ behavior = MapGridGetMetatileBehaviorAt(x, y) & 0xFFF;
+ if (behavior == 0x90 || behavior == 0x91)
+ {
+ return 1;
+ }
+ if (behavior == 0x92 || behavior == 0x93)
+ {
+ return 2;
+ }
+ if (behavior == 0x9a || behavior == 0x9b)
+ {
+ return 3;
+ }
+ if (behavior == 0x94 || behavior == 0x95)
+ {
+ return 4;
+ }
+ if (behavior == 0x96 || behavior == 0x97 || behavior == 0x9c || behavior == 0x9d)
+ {
+ return 5;
+ }
+ if (behavior == 0x98 || behavior == 0x99)
+ {
+ return 6;
+ }
+ return 0;
+}
+
+void sub_80E8C98(void)
+{
+ gSpecialVar_0x8007 = sub_80E8BF8();
+}
+
+void sub_80E8CB0(s16 *xPtr, s16 *yPtr, u16 tile)
+{
+ struct MapData *mapData;
+ s16 x;
+ s16 y;
+
+ mapData = gMapHeader.mapData;
+ for (y = 0; y < mapData->height; y ++)
+ {
+ for (x = 0; x < mapData->width; x ++)
+ {
+ if ((mapData->map[y * mapData->width + x] & 0x3ff) == tile)
+ {
+ *xPtr = x;
+ *yPtr = y;
+ return;
+ }
+ }
+ }
+}
+
+void sub_80E8D4C(void)
+{
+ s16 x;
+ s16 y;
+ s16 tile;
+ u16 i;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ tile = MapGridGetMetatileIdAt(x, y);
+ for (i = 0; i < 7; i ++)
+ {
+ if (gUnknown_0858CFCC[i].tile1 == tile)
+ {
+ MapGridSetMetatileIdAt(x, y, gUnknown_0858CFCC[i].tile2 | 0xC00);
+ CurrentMapDrawMetatileAt(x, y);
+ return;
+ }
+ }
+ for (i = 0; i < 7; i ++)
+ {
+ if (gUnknown_0858CFCC[i].tile2 == tile)
+ {
+ MapGridSetMetatileIdAt(x, y, gUnknown_0858CFCC[i].tile1 | 0xC00);
+ CurrentMapDrawMetatileAt(x, y);
+ return;
+ }
+ }
+}
+
+u8 sub_80E8DF4(const u8 *src)
+{
+ u8 i;
+
+ for (i = 0; i < 7; i ++)
+ {
+ if (src[i] == EOS)
+ {
+ return i;
+ }
+ }
+ return 7;
+}
+
+void sub_80E8E18(void)
+{
+ u16 i;
+
+ gSaveBlock1Ptr->secretBases[0].secretBaseId = sCurSecretBaseId;
+ for (i = 0; i < 4; i ++)
+ {
+ gSaveBlock1Ptr->secretBases[0].trainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
+ }
+ VarSet(VAR_0x4054, 0);
+ StringCopyN(gSaveBlock1Ptr->secretBases[0].trainerName, gSaveBlock2Ptr->playerName, sub_80E8DF4(gSaveBlock2Ptr->playerName));
+ gSaveBlock1Ptr->secretBases[0].gender = gSaveBlock2Ptr->playerGender;
+ gSaveBlock1Ptr->secretBases[0].language = GAME_LANGUAGE;
+ VarSet(VAR_SECRET_BASE_MAP, gMapHeader.regionMapSectionId);
+}
+
+void sub_80E8EE0(struct MapEvents *events)
+{
+ u16 bgEventIndex;
+ u16 i;
+ u16 j;
+ s16 tile_id;
+ s16 x;
+ s16 y;
+
+ for (bgEventIndex = 0; bgEventIndex < events->bgEventCount; bgEventIndex ++)
+ {
+ if (events->bgEvents[bgEventIndex].kind == 8)
+ {
+ for (j = 0; j < 20; j ++)
+ {
+ if (gSaveBlock1Ptr->secretBases[j].secretBaseId == events->bgEvents[bgEventIndex].bgUnion.secretBaseId)
+ {
+ x = events->bgEvents[bgEventIndex].x + 7;
+ y = events->bgEvents[bgEventIndex].y + 7;
+ tile_id = MapGridGetMetatileIdAt(x, y);
+ for (i = 0; i < 7; i ++)
+ {
+ if (gUnknown_0858CFCC[i].tile1 == tile_id)
+ {
+ MapGridSetMetatileIdAt(x, y, gUnknown_0858CFCC[i].tile2 | 0xc00);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+void sub_80E8F9C(void)
+{
+ s8 idx;
+
+ idx = sCurSecretBaseId / 10 * 4;
+ warp1_set_2(MAP_GROUP_SECRET_BASE_RED_CAVE1, gUnknown_0858CFE8[idx], gUnknown_0858CFE8[idx + 1]);
+}
+
+void sub_80E8FD0(u8 taskId)
+{
+ u16 secretBaseRecordId;
+
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ if (!gPaletteFade.active)
+ {
+ gTasks[taskId].data[0] = 1;
+ }
+ break;
+ case 1:
+ secretBaseRecordId = VarGet(VAR_0x4054);
+ if (gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_10 < 255)
+ {
+ gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_10 ++;
+ }
+ sub_80E8F9C();
+ warp_in();
+ gFieldCallback = sub_80AF168;
+ SetMainCallback2(c2_load_new_map);
+ DestroyTask(taskId);
+ break;
+ }
+}
+
+void sub_80E9068(void)
+{
+ CreateTask(sub_80E8FD0, 0);
+ fade_screen(1, 0);
+ saved_warp2_set(0, gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, -1);
+}
+
+bool8 sub_80E909C(void)
+{
+ if (gMapHeader.mapType == MAP_TYPE_SECRET_BASE && VarGet(VAR_0x4097) == 0)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void sub_80E90C8(u8 taskId)
+{
+ FieldObjectTurn(&gMapObjects[gPlayerAvatar.mapObjectId], DIR_NORTH);
+ if (sub_80ABDFC() == TRUE)
+ {
+ EnableBothScriptContexts();
+ DestroyTask(taskId);
+ }
+}
+
+void sub_80E9108(void)
+{
+ s16 x;
+ s16 y;
+
+ ScriptContext2_Enable();
+ HideMapNamePopUpWindow();
+ sub_80E8CB0(&x, &y, 0x220);
+ x += 7;
+ y += 7;
+ MapGridSetMetatileIdAt(x, y, 0x220 | 0xC00);
+ CurrentMapDrawMetatileAt(x, y);
+ pal_fill_black();
+ CreateTask(sub_80E90C8, 0);
+}
+
+void sub_80E916C(u8 taskId)
+{
+ s8 idx;
+
+ if (!gPaletteFade.active)
+ {
+ idx = sCurSecretBaseId / 10 * 4;
+ Overworld_SetWarpDestination(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, -1, gUnknown_0858CFE8[idx + 2], gUnknown_0858CFE8[idx + 3]);
+ warp_in();
+ gFieldCallback = sub_80E9108;
+ SetMainCallback2(c2_load_new_map);
+ DestroyTask(taskId);
+ }
+}
+
+void sub_80E91F8(void)
+{
+ CreateTask(sub_80E916C, 0);
+ fade_screen(1, 0);
+}
+
+bool8 CurrentMapIsSecretBase(void)
+{
+ if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_SECRET_BASE_RED_CAVE1 && (u8)gSaveBlock1Ptr->location.mapNum <= MAP_ID_SECRET_BASE_SHRUB4)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void sub_80E9238(u8 flagIn)
+{
+ u16 curBaseId;
+ u16 x;
+ u16 y;
+ u8 *decorations;
+ u8 *decorPos;
+
+ if (CurrentMapIsSecretBase())
+ {
+ curBaseId = VarGet(VAR_0x4054);
+ decorations = gSaveBlock1Ptr->secretBases[curBaseId].decorations;
+ decorPos = gSaveBlock1Ptr->secretBases[curBaseId].decorationPos;
+ for (x = 0; x < 16; x ++)
+ {
+ if (decorations[x] > 0 && decorations[x] <= 0x78 && gDecorations[decorations[x]].permission != DECORPERM_SOLID_MAT) {
+ sub_8127D38((decorPos[x] >> 4) + 7, (decorPos[x] & 0xF) + 7, decorations[x]);
+ }
+ }
+ if (curBaseId != 0)
+ {
+ sub_80E8CB0(&x, &y, 0x220);
+ MapGridSetMetatileIdAt(x + 7, y + 7, 0x221 | 0xc00);
+ }
+ else if (flagIn == 1 && VarGet(VAR_0x4089) == 1)
+ {
+ sub_80E8CB0(&x, &y, 0x220);
+ MapGridSetMetatileIdAt(x + 7, y + 7, 0x20a | 0xc00);
+ }
+ }
+}
+
+void sub_80E933C(void)
+{
+ u8 *roomDecor;
+ u8 *roomDecorPos;
+ u8 decorIdx;
+ u8 objIdx;
+ u8 metatile;
+ u8 category;
+ u8 permission;
+ u8 nDecor;
+ u16 curBase;
+
+ objIdx = 0;
+ if (!CurrentMapIsSecretBase())
+ {
+ roomDecor = gSaveBlock1Ptr->playerRoomDecor;
+ roomDecorPos = gSaveBlock1Ptr->playerRoomDecorPos;
+ nDecor = 12;
+ }
+ else
+ {
+ curBase = VarGet(VAR_0x4054);
+ roomDecor = gSaveBlock1Ptr->secretBases[curBase].decorations;
+ roomDecorPos = gSaveBlock1Ptr->secretBases[curBase].decorationPos;
+ nDecor = 16;
+ }
+ for (decorIdx = 0; decorIdx < nDecor; decorIdx ++)
+ {
+ if (roomDecor[decorIdx] != DECOR_NONE)
+ {
+ permission = gDecorations[roomDecor[decorIdx]].permission;
+ category = gDecorations[roomDecor[decorIdx]].category;
+ if (permission == DECORPERM_SOLID_MAT)
+ {
+ for (objIdx = 0; objIdx < gMapHeader.events->mapObjectCount; objIdx ++)
+ {
+ if (gMapHeader.events->mapObjects[objIdx].flagId == gSpecialVar_0x8004 + 0xAE)
+ {
+ break;
+ }
+ }
+ if (objIdx == gMapHeader.events->mapObjectCount)
+ {
+ continue;
+ }
+ gSpecialVar_0x8006 = roomDecorPos[decorIdx] >> 4;
+ gSpecialVar_0x8007 = roomDecorPos[decorIdx] & 0xF;
+ metatile = MapGridGetMetatileBehaviorAt(gSpecialVar_0x8006 + 7, gSpecialVar_0x8007 + 7);
+ if (MetatileBehavior_IsMB_B5(metatile) == TRUE || MetatileBehavior_IsMB_C3(metatile) == TRUE)
+ {
+ gSpecialVar_ScriptResult = gMapHeader.events->mapObjects[objIdx].graphicsId + VAR_0x3F20;
+ VarSet(gSpecialVar_ScriptResult, gDecorations[roomDecor[decorIdx]].tiles[0]);
+ gSpecialVar_ScriptResult = gMapHeader.events->mapObjects[objIdx].localId;
+ FlagClear(gSpecialVar_0x8004 + 0xAE);
+ show_sprite(gSpecialVar_ScriptResult, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
+ sub_808EBA8(gSpecialVar_ScriptResult, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, gSpecialVar_0x8006, gSpecialVar_0x8007);
+ sub_808F254(gSpecialVar_ScriptResult, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
+ if (CurrentMapIsSecretBase() == TRUE && VarGet(VAR_0x4054) != 0)
+ {
+ if (category == DECORCAT_DOLL)
+ {
+ sub_808F28C(gSpecialVar_ScriptResult, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, DECORCAT_DOLL);
+ }
+ else if (category == DECORCAT_CUSHION)
+ {
+ sub_808F28C(gSpecialVar_ScriptResult, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, DECORCAT_CUSHION);
+ }
+ }
+ gSpecialVar_0x8004 ++;
+ }
+ }
+ }
+ }
+}
+
+void sub_80E9578(void)
+{
+ u8 objectEventIdx;
+ u16 flagId;
+
+ for (objectEventIdx = 0; objectEventIdx < gMapHeader.events->mapObjectCount; objectEventIdx ++)
+ {
+ flagId = gMapHeader.events->mapObjects[objectEventIdx].flagId;
+ if (flagId >= 0xAE && flagId <= 0xBB)
+ {
+ RemoveFieldObjectByLocalIdAndMap(gMapHeader.events->mapObjects[objectEventIdx].localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
+ FlagSet(flagId);
+ }
+ }
+}
+
+void sub_80E95D4(void)
+{
+ VarSet(VAR_0x401F, gUnknown_0858D060[sub_80EA20C(VarGet(VAR_0x4054))]);
+}
+
+void sub_80E9608(struct Coords16 *coords, struct MapEvents *events)
+{
+ s16 bgEventIdx;
+
+ for (bgEventIdx = 0; bgEventIdx < events->bgEventCount; bgEventIdx ++)
+ {
+ if (events->bgEvents[bgEventIdx].kind == 8 && coords->x == events->bgEvents[bgEventIdx].x + 7 && coords->y == events->bgEvents[bgEventIdx].y + 7)
+ {
+ sCurSecretBaseId = events->bgEvents[bgEventIdx].bgUnion.secretBaseId;
+ break;
+ }
+ }
+}
+
+void sub_80E9668(struct Coords16 *coords, struct MapEvents *events)
+{
+ sub_80E9608(coords, events);
+ sub_80E8B6C();
+ ScriptContext1_SetupScript(gUnknown_08275BB7);
+}
+
+bool8 sub_80E9680(void)
+{
+ sub_80E8B58();
+ sub_80E8B6C();
+ if (gSpecialVar_ScriptResult == TRUE)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void sub_80E96A4(u8 taskId)
+{
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ ScriptContext2_Enable();
+ gTasks[taskId].data[0] = 1;
+ break;
+ case 1:
+ if (!gPaletteFade.active)
+ {
+ gTasks[taskId].data[0] = 2;
+ }
+ break;
+ case 2:
+ copy_saved_warp2_bank_and_enter_x_to_warp1(0x7e);
+ warp_in();
+ gFieldCallback = mapldr_default;
+ SetMainCallback2(c2_load_new_map);
+ ScriptContext2_Disable();
+ DestroyTask(taskId);
+ break;
+ }
+}
+
+void sub_80E9728(void)
+{
+ CreateTask(sub_80E96A4, 0);
+ fade_screen(1, 0);
+}
+
+void sub_80E9744(void)
+{
+ if (gSaveBlock1Ptr->secretBases[0].secretBaseId != sCurSecretBaseId)
+ {
+ gSpecialVar_ScriptResult = TRUE;
+ }
+ else
+ {
+ gSpecialVar_ScriptResult = FALSE;
+ }
+}
+
+u8 *sub_80E9780(u8 *dest, u8 secretBaseRecordId)
+{
+ *StringCopyN(dest, gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerName, sub_80E8DF4(gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerName)) = EOS;
+ ConvertInternationalString(dest, gSaveBlock1Ptr->secretBases[secretBaseRecordId].language);
+ return StringAppend(dest, gText_ApostropheSBase);
+}
+
+u8 *GetSecretBaseMapName(u8 *dest)
+{
+ return sub_80E9780(dest, VarGet(VAR_0x4054));
+}
+
+void sub_80E980C(void)
+{
+ u8 secretBaseRecordId;
+ const u8 *src;
+
+ secretBaseRecordId = VarGet(VAR_0x4054);
+ src = gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerName;
+ *StringCopyN(gStringVar1, src, sub_80E8DF4(src)) = EOS;
+ ConvertInternationalString(gStringVar1, gSaveBlock1Ptr->secretBases[secretBaseRecordId].language);
+}
+
+bool8 sub_80E9878(u8 secretBaseRecordId)
+{
+ if (gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_1_6 != 0)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+u8 sub_80E98AC(struct Pokemon *pokemon)
+{
+ u16 evTotal;
+
+ evTotal = GetMonData(pokemon, MON_DATA_HP_EV);
+ evTotal += GetMonData(pokemon, MON_DATA_ATK_EV);
+ evTotal += GetMonData(pokemon, MON_DATA_DEF_EV);
+ evTotal += GetMonData(pokemon, MON_DATA_SPEED_EV);
+ evTotal += GetMonData(pokemon, MON_DATA_SPATK_EV);
+ evTotal += GetMonData(pokemon, MON_DATA_SPDEF_EV);
+ return evTotal / 6;
+}
+
+#ifdef NONMATCHING
+// This function is a meme
+void sub_80E9914(void)
+{
+ u32 zero;
+ u32 *personality;
+ u16 partyIdx;
+ u16 moveIdx;
+ u16 sbPartyIdx;
+ u16 *species;
+ u16 *items;
+ u16 *moves;
+ u8 *levels;
+ u8 *evs;
+
+ sbPartyIdx = 0;
+ personality = gSaveBlock1Ptr->secretBases[0].partyPersonality;
+ if (gSaveBlock1Ptr->secretBases[0].secretBaseId != 0)
+ {
+ partyIdx = 0;
+ moves = gSaveBlock1Ptr->secretBases[0].partyMoves;
+ species = gSaveBlock1Ptr->secretBases[0].partySpecies;
+ items = gSaveBlock1Ptr->secretBases[0].partyHeldItems;
+ levels = gSaveBlock1Ptr->secretBases[0].partyLevels;
+ evs = gSaveBlock1Ptr->secretBases[0].partyEVs;
+ zero = 0;
+ for (partyIdx = 0; partyIdx < PARTY_SIZE; partyIdx ++)
+ {
+ for (moveIdx = 0; moveIdx < 4; moveIdx ++)
+ {
+ moves[partyIdx * 4 + moveIdx] = zero;
+ }
+ species[partyIdx] = zero;
+ items[partyIdx] = zero;
+ levels[partyIdx] = zero;
+ personality[partyIdx] = zero;
+ evs[partyIdx] = zero;
+ if (GetMonData(&gPlayerParty[partyIdx], MON_DATA_SPECIES) != SPECIES_NONE && !GetMonData(&gPlayerParty[partyIdx], MON_DATA_IS_EGG))
+ {
+ for (moveIdx = 0; moveIdx < 4; moveIdx ++)
+ {
+ moves[sbPartyIdx * 4 + moveIdx] = GetMonData(&gPlayerParty[partyIdx], MON_DATA_MOVE1 + moveIdx);
+ }
+ species[sbPartyIdx] = GetMonData(&gPlayerParty[partyIdx], MON_DATA_SPECIES);
+ items[sbPartyIdx] = GetMonData(&gPlayerParty[partyIdx], MON_DATA_HELD_ITEM);
+ levels[sbPartyIdx] = GetMonData(&gPlayerParty[partyIdx], MON_DATA_LEVEL);
+ personality[sbPartyIdx] = GetMonData(&gPlayerParty[partyIdx], MON_DATA_PERSONALITY);
+ evs[sbPartyIdx] = sub_80E98AC(&gPlayerParty[partyIdx]);
+ sbPartyIdx ++;
+ }
+ }
+ }
+}
+#else
+__attribute__((naked)) void sub_80E9914(void)
+{
+ asm_unified("\tpush {r4-r7,lr}\n"
+ "\tmov r7, r10\n"
+ "\tmov r6, r9\n"
+ "\tmov r5, r8\n"
+ "\tpush {r5-r7}\n"
+ "\tsub sp, 0x24\n"
+ "\tmovs r0, 0\n"
+ "\tmov r10, r0\n"
+ "\tldr r0, =gSaveBlock1Ptr\n"
+ "\tldr r1, [r0]\n"
+ "\tldr r2, =0x00001ad0\n"
+ "\tadds r2, r1, r2\n"
+ "\tstr r2, [sp]\n"
+ "\tldr r3, =0x00001a9c\n"
+ "\tadds r0, r1, r3\n"
+ "\tldrb r0, [r0]\n"
+ "\tcmp r0, 0\n"
+ "\tbne _080E993A\n"
+ "\tb _080E9A60\n"
+ "_080E993A:\n"
+ "\tmovs r6, 0\n"
+ "\tldr r7, =0x00001ae8\n"
+ "\tadds r7, r1, r7\n"
+ "\tstr r7, [sp, 0x14]\n"
+ "\tldr r0, =0x00001b18\n"
+ "\tadds r0, r1, r0\n"
+ "\tstr r0, [sp, 0xC]\n"
+ "\tldr r2, =0x00001b24\n"
+ "\tadds r2, r1, r2\n"
+ "\tstr r2, [sp, 0x10]\n"
+ "\tadds r3, 0x94\n"
+ "\tadds r3, r1, r3\n"
+ "\tstr r3, [sp, 0x18]\n"
+ "\tldr r7, =0x00001b36\n"
+ "\tadds r7, r1, r7\n"
+ "\tstr r7, [sp, 0x1C]\n"
+ "\tmov r9, r6\n"
+ "_080E995C:\n"
+ "\tmovs r4, 0\n"
+ "\tlsls r5, r6, 2\n"
+ "\tlsls r3, r6, 1\n"
+ "\tldr r0, =gPlayerParty\n"
+ "\tmov r8, r0\n"
+ "\tadds r1, r6, 0x1\n"
+ "\tstr r1, [sp, 0x4]\n"
+ "\tadds r2, r5, 0\n"
+ "\tldr r1, [sp, 0x14]\n"
+ "_080E996E:\n"
+ "\tadds r0, r2, r4\n"
+ "\tlsls r0, 1\n"
+ "\tadds r0, r1, r0\n"
+ "\tmov r7, r9\n"
+ "\tstrh r7, [r0]\n"
+ "\tadds r0, r4, 0x1\n"
+ "\tlsls r0, 16\n"
+ "\tlsrs r4, r0, 16\n"
+ "\tcmp r4, 0x3\n"
+ "\tbls _080E996E\n"
+ "\tldr r1, [sp, 0xC]\n"
+ "\tadds r0, r1, r3\n"
+ "\tmov r2, r9\n"
+ "\tstrh r2, [r0]\n"
+ "\tldr r7, [sp, 0x10]\n"
+ "\tadds r0, r7, r3\n"
+ "\tstrh r2, [r0]\n"
+ "\tldr r1, [sp, 0x18]\n"
+ "\tadds r0, r1, r6\n"
+ "\tmov r2, r9\n"
+ "\tstrb r2, [r0]\n"
+ "\tldr r3, [sp]\n"
+ "\tadds r0, r3, r5\n"
+ "\tmov r7, r9\n"
+ "\tstr r7, [r0]\n"
+ "\tldr r1, [sp, 0x1C]\n"
+ "\tadds r0, r1, r6\n"
+ "\tstrb r7, [r0]\n"
+ "\tmovs r2, 0x64\n"
+ "\tadds r5, r6, 0\n"
+ "\tmuls r5, r2\n"
+ "\tmov r3, r8\n"
+ "\tadds r4, r5, r3\n"
+ "\tadds r0, r4, 0\n"
+ "\tmovs r1, 0xB\n"
+ "\tbl GetMonData\n"
+ "\tcmp r0, 0\n"
+ "\tbeq _080E9A54\n"
+ "\tadds r0, r4, 0\n"
+ "\tmovs r1, 0x2D\n"
+ "\tbl GetMonData\n"
+ "\tcmp r0, 0\n"
+ "\tbne _080E9A54\n"
+ "\tmovs r4, 0\n"
+ "\tmov r7, r10\n"
+ "\tlsls r7, 2\n"
+ "\tmov r8, r7\n"
+ "\tmov r0, r10\n"
+ "\tlsls r7, r0, 1\n"
+ "\tadds r0, 0x1\n"
+ "\tstr r0, [sp, 0x8]\n"
+ "\tldr r2, =gPlayerParty\n"
+ "_080E99DA:\n"
+ "\tadds r1, r4, 0\n"
+ "\tadds r1, 0xD\n"
+ "\tadds r0, r5, r2\n"
+ "\tstr r2, [sp, 0x20]\n"
+ "\tbl GetMonData\n"
+ "\tmov r3, r8\n"
+ "\tadds r1, r3, r4\n"
+ "\tlsls r1, 1\n"
+ "\tldr r3, [sp, 0x14]\n"
+ "\tadds r1, r3, r1\n"
+ "\tstrh r0, [r1]\n"
+ "\tadds r0, r4, 0x1\n"
+ "\tlsls r0, 16\n"
+ "\tlsrs r4, r0, 16\n"
+ "\tldr r2, [sp, 0x20]\n"
+ "\tcmp r4, 0x3\n"
+ "\tbls _080E99DA\n"
+ "\tmovs r0, 0x64\n"
+ "\tadds r4, r6, 0\n"
+ "\tmuls r4, r0\n"
+ "\tldr r0, =gPlayerParty\n"
+ "\tadds r4, r0\n"
+ "\tadds r0, r4, 0\n"
+ "\tmovs r1, 0xB\n"
+ "\tbl GetMonData\n"
+ "\tldr r2, [sp, 0xC]\n"
+ "\tadds r1, r2, r7\n"
+ "\tstrh r0, [r1]\n"
+ "\tadds r0, r4, 0\n"
+ "\tmovs r1, 0xC\n"
+ "\tbl GetMonData\n"
+ "\tldr r3, [sp, 0x10]\n"
+ "\tadds r1, r3, r7\n"
+ "\tstrh r0, [r1]\n"
+ "\tadds r0, r4, 0\n"
+ "\tmovs r1, 0x38\n"
+ "\tbl GetMonData\n"
+ "\tldr r1, [sp, 0x18]\n"
+ "\tadd r1, r10\n"
+ "\tstrb r0, [r1]\n"
+ "\tadds r0, r4, 0\n"
+ "\tmovs r1, 0\n"
+ "\tbl GetMonData\n"
+ "\tldr r1, [sp]\n"
+ "\tadd r1, r8\n"
+ "\tstr r0, [r1]\n"
+ "\tadds r0, r4, 0\n"
+ "\tbl sub_80E98AC\n"
+ "\tldr r1, [sp, 0x1C]\n"
+ "\tadd r1, r10\n"
+ "\tstrb r0, [r1]\n"
+ "\tldr r7, [sp, 0x8]\n"
+ "\tlsls r0, r7, 16\n"
+ "\tlsrs r0, 16\n"
+ "\tmov r10, r0\n"
+ "_080E9A54:\n"
+ "\tldr r1, [sp, 0x4]\n"
+ "\tlsls r0, r1, 16\n"
+ "\tlsrs r6, r0, 16\n"
+ "\tcmp r6, 0x5\n"
+ "\tbhi _080E9A60\n"
+ "\tb _080E995C\n"
+ "_080E9A60:\n"
+ "\tadd sp, 0x24\n"
+ "\tpop {r3-r5}\n"
+ "\tmov r8, r3\n"
+ "\tmov r9, r4\n"
+ "\tmov r10, r5\n"
+ "\tpop {r4-r7}\n"
+ "\tpop {r0}\n"
+ "\tbx r0\n"
+ "\t.pool");
+}
+#endif
+
+void sub_80E9A90(void)
+{
+ u16 sbr_e;
+
+ sbr_e = gSaveBlock1Ptr->secretBases[0].sbr_field_e;
+ ClearSecretBase(&gSaveBlock1Ptr->secretBases[0]);
+ gSaveBlock1Ptr->secretBases[0].sbr_field_e = sbr_e;
+ sub_80E9728();
+}
+
+void sub_80E9AC0(void)
+{
+ IncrementGameStat(GAME_STAT_MOVED_SECRET_BASE);
+ sub_80E9A90();
+}
+
+void sub_80E9AD0(void)
+{
+ u16 i;
+ u16 j;
+ s16 tile;
+ struct MapEvents *events;
+
+ events = gMapHeader.events;
+ for (i = 0; i < events->bgEventCount; i ++)
+ {
+ if (events->bgEvents[i].kind == 8 && gSaveBlock1Ptr->secretBases[0].secretBaseId == events->bgEvents[i].bgUnion.secretBaseId)
+ {
+ tile = MapGridGetMetatileIdAt(events->bgEvents[i].x + 7, events->bgEvents[i].y + 7);
+ for (j = 0; j < 7; j ++)
+ {
+ if (gUnknown_0858CFCC[j].tile2 == tile)
+ {
+ MapGridSetMetatileIdAt(events->bgEvents[i].x + 7, events->bgEvents[i].y + 7, gUnknown_0858CFCC[j].tile1 | 0xc00);
+ break;
+ }
+ }
+ DrawWholeMapView();
+ break;
+ }
+ }
+}
+
+void sub_80E9B70(void)
+{
+ u16 sbr_e;
+
+ sub_80E9AD0();
+ IncrementGameStat(GAME_STAT_MOVED_SECRET_BASE);
+ sbr_e = gSaveBlock1Ptr->secretBases[0].sbr_field_e;
+ ClearSecretBase(&gSaveBlock1Ptr->secretBases[0]);
+ gSaveBlock1Ptr->secretBases[0].sbr_field_e = sbr_e;
+}
+
+u8 sub_80E9BA8(void)
+{
+ u8 sum;
+ s16 i;
+
+ sum = 0;
+ for (i = 1; i < 20; i ++)
+ {
+ if (sub_80E9878(i) == TRUE)
+ {
+ sum ++;
+ }
+ }
+ return sum;
+}
+
+void sub_80E9BDC(void)
+{
+ if (sub_80E9878(VarGet(VAR_0x4054)) == TRUE)
+ {
+ gSpecialVar_ScriptResult = 1;
+ }
+ else if (sub_80E9BA8() > 9)
+ {
+ gSpecialVar_ScriptResult = 2;
+ }
+ else
+ {
+ gSpecialVar_ScriptResult = 0;
+ }
+}
+
+void sub_80E9C2C(void)
+{
+ gSaveBlock1Ptr->secretBases[VarGet(VAR_0x4054)].sbr_field_1_6 ^= 1;
+ FlagSet(0x10C);
+}
+
+void sub_80E9C74(void)
+{
+ CreateTask(sub_8126AD8, 0);
+}
+
+void sub_80E9C88(void)
+{
+ CreateTask(sub_80E9C9C, 0);
+}
+
+void sub_80E9C9C(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ ScriptContext2_Enable();
+ data[0] = sub_80E9BA8();
+ if (data[0] != 0)
+ {
+ data[1] = 0;
+ data[2] = 0;
+ sub_8197434(0, 0);
+ gUnknown_0203A020 = calloc(1, sizeof(struct SecretBaseListMenuBuffer));
+ data[6] = AddWindow(&gUnknown_0858D06C[0]);
+ game_continue(taskId);
+ sub_80E9E00(taskId);
+ gTasks[taskId].func = sub_80E9E90;
+ }
+ else
+ {
+ DisplayItemMessageOnField(taskId, gText_NoRegistry, task_pc_turn_off);
+ }
+}
+
+void game_continue(u8 taskId)
+{
+ s16 *data;
+ u8 i;
+ u8 count;
+
+ data = gTasks[taskId].data;
+ count = 0;
+ for (i = 1; i < 20; i ++)
+ {
+ if (sub_80E9878(i))
+ {
+ sub_80E9780(gUnknown_0203A020->names[count], i);
+ gUnknown_0203A020->items[count].unk_00 = gUnknown_0203A020->names[count];
+ gUnknown_0203A020->items[count].unk_04 = i;
+ count ++;
+ }
+ }
+ gUnknown_0203A020->items[count].unk_00 = gText_Cancel;
+ gUnknown_0203A020->items[count].unk_04 = -2;
+ data[0] = count + 1;
+ if (data[0] < 8)
+ {
+ data[3] = data[0];
+ }
+ else
+ {
+ data[3] = 8;
+ }
+ gUnknown_03006310 = gUnknown_0858D07C;
+ gUnknown_03006310.unk_10 = data[6];
+ gUnknown_03006310.unk_0c = data[0];
+ gUnknown_03006310.unk_00 = gUnknown_0203A020->items;
+ gUnknown_03006310.unk_0e = data[3];
+}
+
+void sub_80E9DEC(u32 a0, bool8 flag, struct ListMenu *menu)
+{
+ if (flag != TRUE)
+ {
+ PlaySE(SE_SELECT);
+ }
+}
+
+void sub_80E9E00(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ SetStandardWindowBorderStyle(data[6], 0);
+ data[5] = ListMenuInit(&gUnknown_03006310, data[2], data[1]);
+ sub_80E9E44(taskId);
+ schedule_bg_copy_tilemap_to_vram(0);
+}
+
+void sub_80E9E44(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ data[8] = AddScrollIndicatorArrowPairParametrized(0x02, 0xbc, 0x0c, 0x94, data[0] - data[3], 0x13f8, 0x13f8, &data[2]);
+}
+
+void sub_80E9E90(u8 taskId)
+{
+ s16 *data;
+ s32 input;
+
+ data = gTasks[taskId].data;
+ input = ListMenuHandleInput(data[5]);
+ get_coro_args_x18_x1A(data[5], &data[2], &data[1]);
+ switch (input)
+ {
+ case -1:
+ break;
+ case -2:
+ PlaySE(SE_SELECT);
+ sub_81AE6C8(data[5], NULL, NULL);
+ RemoveScrollIndicatorArrowPair(data[8]);
+ sub_819746C(data[6], 0);
+ ClearWindowTilemap(data[6]);
+ RemoveWindow(data[6]);
+ schedule_bg_copy_tilemap_to_vram(0);
+ free(gUnknown_0203A020);
+ task_pc_turn_off(taskId);
+ break;
+ default:
+ PlaySE(SE_SELECT);
+ data[4] = input;
+ sub_80E9F20(taskId);
+ break;
+ }
+}
+
+void sub_80E9F20(u8 taskId)
+{
+ struct WindowTemplate template;
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ RemoveScrollIndicatorArrowPair(data[8]);
+ template = gUnknown_0858D06C[1];
+ template.width = GetMaxWidthInMenuTable(gUnknown_0858D048, 2);
+ data[7] = AddWindow(&template);
+ SetStandardWindowBorderStyle(data[7], 0);
+ PrintMenuTable(data[7], 2, gUnknown_0858D048);
+ InitMenuInUpperLeftCornerPlaySoundWhenAPressed(data[7], 2, 0);
+ schedule_bg_copy_tilemap_to_vram(0);
+ gTasks[taskId].func = sub_80E9FB0;
+}
+
+void sub_80E9FB0(u8 taskId)
+{
+ s8 input;
+
+ input = ProcessMenuInputNoWrapAround();
+ switch (input)
+ {
+ case -1:
+ PlaySE(SE_SELECT);
+ sub_80EA18C(taskId);
+ break;
+ case -2:
+ break;
+ default:
+ PlaySE(SE_SELECT);
+ gUnknown_0858D048[input].func.void_u8(taskId);
+ break;
+ }
+}
+
+void sub_80E9FFC(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ sub_819746C(data[6], FALSE);
+ sub_819746C(data[7], FALSE);
+ ClearWindowTilemap(data[6]);
+ ClearWindowTilemap(data[7]);
+ RemoveWindow(data[7]);
+ schedule_bg_copy_tilemap_to_vram(0);
+ sub_80E9780(gStringVar1, data[4]);
+ StringExpandPlaceholders(gStringVar4, gText_OkayToDeleteFromRegistry);
+ DisplayItemMessageOnField(taskId, gStringVar4, sub_80EA06C);
+}
+
+void sub_80EA06C(u8 taskId)
+{
+ sub_8197930();
+ sub_8121F68(taskId, &gUnknown_0858D058);
+}
+
+void sub_80EA08C(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ sub_8197434(0, 0);
+ sub_81AE6C8(data[5], &data[2], &data[1]);
+ gSaveBlock1Ptr->secretBases[data[4]].sbr_field_1_6 = 0;
+ game_continue(taskId);
+ sub_812225C(&data[2], &data[1], data[3], data[0]);
+ sub_80E9E00(taskId);
+ gTasks[taskId].func = sub_80E9E90;
+}
+
+void sub_80EA120(u8 taskId)
+{
+ DisplayItemMessageOnField(taskId, gText_RegisteredDataDeleted, sub_80EA08C);
+}
+
+void sub_80EA13C(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ sub_8197434(0, 0);
+ sub_81AE6C8(data[5], &data[2], &data[1]);
+ sub_80E9E00(taskId);
+ gTasks[taskId].func = sub_80E9E90;
+}
+
+void sub_80EA18C(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ sub_80E9E44(taskId);
+ sub_819746C(data[7], 0);
+ ClearWindowTilemap(data[7]);
+ RemoveWindow(data[7]);
+ schedule_bg_copy_tilemap_to_vram(0);
+ gTasks[taskId].func = sub_80E9E90;
+}
+
+void task_pc_turn_off(u8 taskId)
+{
+ if (VarGet(VAR_0x4054) == 0)
+ {
+ ScriptContext1_SetupScript(gUnknown_0823B4E8);
+ }
+ else
+ {
+ ScriptContext1_SetupScript(gUnknown_0823B5E9);
+ }
+ DestroyTask(taskId);
+}
+
+u8 sub_80EA20C(u8 secretBaseRecordId)
+{
+ return (gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerId[0] % 5) + (gSaveBlock1Ptr->secretBases[secretBaseRecordId].gender * 5);
+}
+
+const u8 *sub_80EA250(void)
+{
+ u8 param;
+
+ param = sub_80EA20C(VarGet(VAR_0x4054));
+ if (param == 0)
+ {
+ return gUnknown_08274966;
+ }
+ if (param == 1)
+ {
+ return gUnknown_08274D13;
+ }
+ if (param == 2)
+ {
+ return gUnknown_08274FFE;
+ }
+ if (param == 3)
+ {
+ return gUnknown_08275367;
+ }
+ if (param == 4)
+ {
+ return gUnknown_082756C7;
+ }
+ if (param == 5)
+ {
+ return gUnknown_08274B24;
+ }
+ if (param == 6)
+ {
+ return gUnknown_08274E75;
+ }
+ if (param == 7)
+ {
+ return gUnknown_082751E1;
+ }
+ if (param == 8)
+ {
+ return gUnknown_082754F6;
+ }
+ return gUnknown_082758CC;
+}
+
+void sub_80EA2E4(void)
+{
+ sub_813BADC(TRUE);
+ gTrainerBattleOpponent_A = 0x400;
+ gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_SECRET_BASE;
+}
+
+void sub_80EA30C(void)
+{
+ gSaveBlock1Ptr->secretBases[VarGet(VAR_0x4054)].sbr_field_1_5 = gSpecialVar_ScriptResult;
+}
+
+void sub_80EA354(void)
+{
+ u16 secretBaseRecordId;
+ u8 i;
+
+ secretBaseRecordId = VarGet(VAR_0x4054);
+ if (!FlagGet(0x922))
+ {
+ for (i = 0; i < 20; i ++)
+ {
+ gSaveBlock1Ptr->secretBases[i].sbr_field_1_5 = FALSE;
+ }
+ FlagSet(0x922);
+ }
+ gSpecialVar_0x8004 = sub_80EA20C(secretBaseRecordId);
+ gSpecialVar_ScriptResult = gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_1_5;
+}
+
+
+void sub_80EA3E4(u8 taskId)
+{
+ s16 x;
+ s16 y;
+ u8 behavior;
+ u16 tileId;
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ switch (data[1])
+ {
+ case 0:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ gUnknown_0203A01D = TRUE;
+ }
+ else
+ {
+ gUnknown_0203A01D = FALSE;
+ }
+ PlayerGetDestCoords(&data[2], &data[3]);
+ data[1] = 1;
+ break;
+ case 1:
+ PlayerGetDestCoords(&x, &y);
+ if (x != data[2] || y != data[3])
+ {
+ data[2] = x;
+ data[3] = y;
+ VarSet(VAR_0x40EC, VarGet(VAR_0x40EC) + 1);
+ behavior = MapGridGetMetatileBehaviorAt(x, y);
+ tileId = MapGridGetMetatileIdAt(x, y);
+ if (tileId == 0x234 || tileId == 0x23C)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x20);
+ }
+ }
+ else if (tileId == 0x2b8 || tileId == 0x2b9 || tileId == 0x2ba || tileId == 0x2c0 || tileId == 0x2c1 || tileId == 0x2c2 || tileId == 0x2c8 || tileId == 0x2c9 || tileId == 0x2ca)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x01);
+ }
+ }
+ else if (tileId == 0x239 || tileId == 0x241 || tileId == 0x251 || tileId == 0x259)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x04);
+ }
+ }
+ else if ((behavior == 0x34 && tileId == 0x26d) || (behavior == 0x35 && MapGridGetMetatileIdAt(x, y) == 0x26a))
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x200);
+ }
+ }
+ else if (behavior == 0xc1 && tileId == 0x23d)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) ^ 0x1000);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x2000);
+ }
+ }
+ else if (behavior == 0x47 && tileId == 0x23e)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x1000);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) ^ 0x2000);
+ }
+ }
+ else if (MetatileBehavior_IsSecretBaseGlitterMat(behavior) == TRUE)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x80);
+ }
+ }
+ else if (MetatileBehavior_IsSecretBaseBalloon(behavior) == TRUE)
+ {
+ sub_80FA5E4(MapGridGetMetatileIdAt(x, y), x, y);
+ if (gUnknown_0203A01D == TRUE)
+ {
+ switch ((int)MapGridGetMetatileIdAt(x, y))
+ {
+ case 0x338:
+ case 0x33c:
+ case 0x340:
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x02);
+ break;
+ case 0x228:
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x100);
+ break;
+ }
+ }
+ }
+ else if (MetatileBehavior_IsMB_BE(behavior) == TRUE)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x400);
+ }
+ sub_80FA794(x, y);
+ }
+ else if (MetatileBehavior_IsSecretBaseSoundMat(behavior) == TRUE){
+ if (gUnknown_0203A01D == TRUE) {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x8000);
+ }
+ }
+ else if (MetatileBehavior_IsSecretBaseJumpMat(behavior) == TRUE)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x4000);
+ }
+ }
+ else if (MetatileBehavior_IsSecretBaseSpinMat(behavior) == TRUE)
+ {
+ if (gUnknown_0203A01D == TRUE)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x02);
+ }
+ }
+ }
+ break;
+ case 2:
+ if (!FieldEffectActiveListContains(data[4]))
+ {
+ data[1] = 1;
+ }
+ break;
+ }
+}
+
+void sub_80EA828(u8 secretBaseRecordId, struct SecretBaseRecord *base, u32 version, u32 language)
+{
+ int stringLength;
+ u8 *name;
+
+ gSaveBlock1Ptr->secretBases[secretBaseRecordId] = *base;
+ gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_1_6 = 2;
+ if (version == VERSION_SAPPHIRE || version == VERSION_RUBY)
+ {
+ gSaveBlock1Ptr->secretBases[secretBaseRecordId].language = LANGUAGE_ENGLISH;
+ }
+ if (version == VERSION_EMERALD && language == LANGUAGE_JAPANESE)
+ {
+ name = gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerName;
+ for (stringLength = 0; stringLength < 7; stringLength ++)
+ {
+ if (name[stringLength] == EOS)
+ {
+ break;
+ }
+ }
+ if (stringLength > 5)
+ {
+ gSaveBlock1Ptr->secretBases[secretBaseRecordId].language = LANGUAGE_ENGLISH;
+ }
+ }
+}
+
+bool8 sub_80EA8D4(struct SecretBaseRecord *sbr1, struct SecretBaseRecord *sbr2)
+{
+ u8 i;
+ for (i = 0; i < 4; i ++)
+ {
+ if (sbr1->trainerId[i] != sbr2->trainerId[i])
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+bool8 sub_80EA904(struct SecretBaseRecord *sbr1, struct SecretBaseRecord *sbr2)
+{
+ u8 i;
+
+ for (i = 0; i < OT_NAME_LENGTH && (sbr1->trainerName[i] != EOS || sbr2->trainerName[i] != EOS); i++)
+ {
+ if (sbr1->trainerName[i] != sbr2->trainerName[i])
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+bool8 sub_80EA950(struct SecretBaseRecord *sbr1, struct SecretBaseRecord *sbr2)
+{
+ if (sbr1->gender == sbr2->gender && sub_80EA8D4(sbr1, sbr2) && sub_80EA904(sbr1, sbr2))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+s16 sub_80EA990(u8 secretBaseRecordId)
+{
+ s16 i;
+
+ for (i = 0; i < 20; i ++)
+ {
+ if (gSaveBlock1Ptr->secretBases[i].secretBaseId == secretBaseRecordId)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+u8 sub_80EA9D8(void)
+{
+ s16 i;
+
+ for (i = 1; i < 20; i ++)
+ {
+ if (gSaveBlock1Ptr->secretBases[i].secretBaseId == 0)
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+u8 sub_80EAA18(void)
+{
+ s16 i;
+
+ for (i = 1; i < 20; i ++)
+ {
+ if (gSaveBlock1Ptr->secretBases[i].sbr_field_1_6 == 0 && gSaveBlock1Ptr->secretBases[i].sbr_field_1_0 == 0)
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+u8 sub_80EAA64(struct SecretBaseRecord *base, u32 version, u32 language)
+{
+ s16 secretBaseRecordId;
+
+ if (base->secretBaseId == 0)
+ {
+ return 0;
+ }
+ secretBaseRecordId = sub_80EA990(base->secretBaseId);
+ if (secretBaseRecordId != 0)
+ {
+ if (secretBaseRecordId != -1)
+ {
+ if (gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_1_0 == 1)
+ {
+ return 0;
+ }
+ if (gSaveBlock1Ptr->secretBases[secretBaseRecordId].sbr_field_1_6 != 2 || base->sbr_field_1_0 == 1)
+ {
+ sub_80EA828(secretBaseRecordId, base, version, language);
+ return secretBaseRecordId;
+ }
+ }
+ else
+ {
+ secretBaseRecordId = sub_80EA9D8();
+ if (secretBaseRecordId != 0)
+ {
+ sub_80EA828(secretBaseRecordId, base, version, language);
+ return secretBaseRecordId;
+ }
+ secretBaseRecordId = sub_80EAA18();
+ if (secretBaseRecordId != 0)
+ {
+ sub_80EA828(secretBaseRecordId, base, version, language);
+ return secretBaseRecordId;
+ }
+ }
+ }
+ return 0;
+}
+
+void sub_80EAAF4(void)
+{
+ u8 i;
+ u8 j;
+ struct SecretBaseRecord base;
+ struct SecretBaseRecord *secretBases;
+
+ secretBases = gSaveBlock1Ptr->secretBases;
+ for (i = 1; i < 19; i ++)
+ {
+ for (j = i + 1; j < 20; j ++)
+ {
+ if ((secretBases[i].sbr_field_1_6 == 0 && secretBases[j].sbr_field_1_6 == 1) || (secretBases[i].sbr_field_1_6 == 2 && secretBases[j].sbr_field_1_6 != 2))
+ {
+ base = secretBases[i];
+ secretBases[i] = secretBases[j];
+ secretBases[j] = base;
+ }
+ }
+ }
+}
+
+void sub_80EABA4(struct SecretBaseRecordMixer *mixer, u8 b)
+{
+ u16 i;
+
+ for (i = 1; i < 20; i ++)
+ {
+ if (mixer->records[i].sbr_field_1_6 == b)
+ {
+ sub_80EAA64(&mixer->records[i], mixer->version, mixer->language);
+ }
+ }
+}
+
+bool8 DoesSecretBaseBelongToPlayer(struct SecretBaseRecord *secretBase)
+{
+ u8 i;
+
+ if (secretBase->secretBaseId == 0)
+ return FALSE;
+
+ if (secretBase->secretBaseId && secretBase->gender != gSaveBlock2Ptr->playerGender)
+ return FALSE;
+
+ // Check if the player's trainer Id matches the secret base's id.
+ for (i = 0; i < 4; i ++)
+ {
+ if (secretBase->trainerId[i] != gSaveBlock2Ptr->playerTrainerId[i])
+ return FALSE;
+ }
+
+ for (i = 0; i < OT_NAME_LENGTH && (secretBase->trainerName[i] != EOS || gSaveBlock2Ptr->playerName[i] != EOS); i ++)
+ {
+ if (secretBase->trainerName[i] != gSaveBlock2Ptr->playerName[i])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void DeleteFirstOldBaseFromPlayerInRecordMixingFriendsRecords(struct SecretBaseRecord *basesA, struct SecretBaseRecord *basesB, struct SecretBaseRecord *basesC)
+{
+ u8 i;
+ u8 sbFlags = 0x0;
+
+ for (i = 0; i < 20; i ++)
+ {
+ if (!(sbFlags & 0x1)) // 001
+ {
+ if (DoesSecretBaseBelongToPlayer(&basesA[i]) == TRUE)
+ {
+ ClearSecretBase(&basesA[i]);
+ sbFlags |= 1;
+ }
+ }
+
+ if (!(sbFlags & 0x2)) // 010
+ {
+ if (DoesSecretBaseBelongToPlayer(&basesB[i]) == TRUE)
+ {
+ ClearSecretBase(&basesB[i]);
+ sbFlags |= 2;
+ }
+ }
+
+ if (!(sbFlags & 0x4)) // 100
+ {
+ if (DoesSecretBaseBelongToPlayer(&basesC[i]) == TRUE)
+ {
+ ClearSecretBase(&basesC[i]);
+ sbFlags |= 4;
+ }
+ }
+
+ if (sbFlags == 0x7) // 111
+ {
+ break;
+ }
+ }
+}
+
+bool8 sub_80EAD14(struct SecretBaseRecord *base, struct SecretBaseRecord *secretBases, u8 c)
+{
+ u8 i;
+
+ for (i = 0; i < 20; i ++)
+ {
+ if (secretBases[i].secretBaseId != 0)
+ {
+ if (sub_80EA950(base, &secretBases[i]) == TRUE)
+ {
+ if (c == 0)
+ {
+ ClearSecretBase(&secretBases[i]);
+ return FALSE;
+ }
+
+ if (base->sbr_field_e > secretBases[i].sbr_field_e)
+ {
+ ClearSecretBase(&secretBases[i]);
+ return FALSE;
+ }
+
+ secretBases[i].sbr_field_1_0 = base->sbr_field_1_0;
+
+ ClearSecretBase(base);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void sub_80EAD94(struct SecretBaseRecord *basesA, struct SecretBaseRecord *basesB, struct SecretBaseRecord *basesC, struct SecretBaseRecord *basesD)
+{
+ u8 i;
+
+ for (i = 1; i < 20; i ++)
+ {
+ if (basesA[i].secretBaseId)
+ {
+ if (basesA[i].sbr_field_1_6 == 1)
+ {
+ basesA[i].sbr_field_1_0 = 1;
+ }
+ if (!sub_80EAD14(&basesA[i], basesB, i))
+ {
+ if (!sub_80EAD14(&basesA[i], basesC, i))
+ {
+ sub_80EAD14(&basesA[i], basesD, i);
+ }
+ }
+ }
+ }
+ for (i = 0; i < 20; i ++)
+ {
+ if (basesB[i].secretBaseId)
+ {
+ basesB[i].sbr_field_1_5 = 0;
+ if (!sub_80EAD14(&basesB[i], basesC, i))
+ {
+ sub_80EAD14(&basesB[i], basesD, i);
+ }
+ }
+ }
+ for (i = 0; i < 20; i ++)
+ {
+ if (basesC[i].secretBaseId)
+ {
+ basesC[i].sbr_field_1_5 = 0;
+ sub_80EAD14(&basesC[i], basesD, i);
+ }
+ if (basesD[i].secretBaseId)
+ {
+ basesD[i].sbr_field_1_5 = 0;
+ }
+ }
+}
+
+void sub_80EAE90(struct SecretBaseRecord *base, u32 version, u32 language)
+{
+ if (base->sbr_field_1_0 == 1)
+ {
+ sub_80EAA64(base, version, language);
+ ClearSecretBase(base);
+ }
+}
+
+void sub_80EAEB4(struct SecretBaseRecordMixer *mixers)
+{
+ u16 i;
+
+ for (i = 0; i < 20; i ++)
+ {
+ sub_80EAE90(&mixers[0].records[i], mixers[0].version, mixers[0].language);
+ sub_80EAE90(&mixers[1].records[i], mixers[1].version, mixers[1].language);
+ sub_80EAE90(&mixers[2].records[i], mixers[2].version, mixers[2].language);
+ }
+}
+
+void sub_80EAEF4(struct SecretBaseRecordMixer *mixers)
+{
+ DeleteFirstOldBaseFromPlayerInRecordMixingFriendsRecords(mixers[0].records, mixers[1].records, mixers[2].records);
+ sub_80EAD94(gSaveBlock1Ptr->secretBases, mixers[0].records, mixers[1].records, mixers[2].records);
+ sub_80EAEB4(mixers);
+ sub_80EAA64(mixers[0].records, mixers[0].version, mixers[0].language);
+ sub_80EAA64(mixers[1].records, mixers[1].version, mixers[1].language);
+ sub_80EAA64(mixers[2].records, mixers[2].version, mixers[2].language);
+ sub_80EABA4(&mixers[0], 1);
+ sub_80EABA4(&mixers[1], 1);
+ sub_80EABA4(&mixers[2], 1);
+ sub_80EABA4(&mixers[0], 0);
+ sub_80EABA4(&mixers[1], 0);
+ sub_80EABA4(&mixers[2], 0);
+}
+
+void sub_80EAF80(void *records, size_t recordSize, u8 linkIdx)
+{
+ struct SecretBaseRecordMixer mixers[3];
+ u16 i;
+
+ if (FlagGet(0x60))
+ {
+ switch (GetLinkPlayerCount())
+ {
+ case 2:
+ memset(records + 2 * recordSize, 0, recordSize);
+ memset(records + 3 * recordSize, 0, recordSize);
+ break;
+ case 3:
+ memset(records + 3 * recordSize, 0, recordSize);
+ break;
+ }
+ switch (linkIdx)
+ {
+ case 0:
+ mixers[0].records = records + 1 * recordSize;
+ mixers[0].version = gLinkPlayers[1].version & 0xFF;
+ mixers[0].language = gLinkPlayers[1].language;
+ mixers[1].records = records + 2 * recordSize;
+ mixers[1].version = gLinkPlayers[2].version & 0xFF;
+ mixers[1].language = gLinkPlayers[2].language;
+ mixers[2].records = records + 3 * recordSize;
+ mixers[2].version = gLinkPlayers[3].version & 0xFF;
+ mixers[2].language = gLinkPlayers[3].language;
+ break;
+ case 1:
+ mixers[0].records = records + 2 * recordSize;
+ mixers[0].version = gLinkPlayers[2].version & 0xFF;
+ mixers[0].language = gLinkPlayers[2].language;
+ mixers[1].records = records + 3 * recordSize;
+ mixers[1].version = gLinkPlayers[3].version & 0xFF;
+ mixers[1].language = gLinkPlayers[3].language;
+ mixers[2].records = records + 0 * recordSize;
+ mixers[2].version = gLinkPlayers[0].version & 0xFF;
+ mixers[2].language = gLinkPlayers[0].language;
+ break;
+ case 2:
+ mixers[0].records = records + 3 * recordSize;
+ mixers[0].version = gLinkPlayers[3].version & 0xFF;
+ mixers[0].language = gLinkPlayers[3].language;
+ mixers[1].records = records + 0 * recordSize;
+ mixers[1].version = gLinkPlayers[0].version & 0xFF;
+ mixers[1].language = gLinkPlayers[0].language;
+ mixers[2].records = records + 1 * recordSize;
+ mixers[2].version = gLinkPlayers[1].version & 0xFF;
+ mixers[2].language = gLinkPlayers[1].language;
+ break;
+ case 3:
+ mixers[0].records = records + 0 * recordSize;
+ mixers[0].version = gLinkPlayers[0].version & 0xFF;
+ mixers[0].language = gLinkPlayers[0].language;
+ mixers[1].records = records + 1 * recordSize;
+ mixers[1].version = gLinkPlayers[1].version & 0xFF;
+ mixers[1].language = gLinkPlayers[1].language;
+ mixers[2].records = records + 2 * recordSize;
+ mixers[2].version = gLinkPlayers[2].version & 0xFF;
+ mixers[2].language = gLinkPlayers[2].language;
+ break;
+ }
+ sub_80EAEF4(mixers);
+ for (i = 1; i < 20; i ++)
+ {
+ if (gSaveBlock1Ptr->secretBases[i].sbr_field_1_0 == 1)
+ {
+ gSaveBlock1Ptr->secretBases[i].sbr_field_1_6 = 1;
+ gSaveBlock1Ptr->secretBases[i].sbr_field_1_0 = 0;
+ }
+ }
+ sub_80EAAF4();
+ for (i = 1; i < 20; i ++)
+ {
+ if (gSaveBlock1Ptr->secretBases[i].sbr_field_1_6 == 2)
+ {
+ gSaveBlock1Ptr->secretBases[i].sbr_field_1_6 = 0;
+ }
+ }
+ if (gSaveBlock1Ptr->secretBases[0].secretBaseId != 0 && gSaveBlock1Ptr->secretBases[0].sbr_field_e != 0xFFFF)
+ {
+ gSaveBlock1Ptr->secretBases[0].sbr_field_e ++;
+ }
+ }
+}
+
+void sub_80EB18C(struct SecretBaseRecord *bases)
+{
+ u32 i;
+
+ for (i = 0; i < 20; i ++)
+ {
+ if (bases[i].language == LANGUAGE_JAPANESE)
+ {
+ ClearSecretBase(&bases[i]);
+ }
+ }
+}
+
+void sub_80EB1AC(void)
+{
+ VarSet(VAR_0x40EC, 0);
+ VarSet(VAR_0x40ED, 0);
+ VarSet(VAR_0x40EE, 0);
+ VarSet(VAR_0x40EF, 0);
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40F0, TRUE);
+ }
+ else
+ {
+ VarSet(VAR_0x40F0, FALSE);
+ }
+ gUnknown_0203A01D = FALSE;
+}
+
+void sub_80EB218(void)
+{
+ if (VarGet(VAR_0x40F0) && gUnknown_0203A01D == TRUE && !CurrentMapIsSecretBase())
+ {
+ VarSet(VAR_0x40F0, FALSE);
+ gUnknown_0203A01D = FALSE;
+ sub_80EEA70();
+ VarSet(VAR_0x40EC, 0);
+ VarSet(VAR_0x40ED, 0);
+ VarSet(VAR_0x40EE, 0);
+ VarSet(VAR_0x40EF, 0);
+ VarSet(VAR_0x40F0, FALSE);
+ }
+}
+
+void sub_80EB290(void)
+{
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x800);
+ }
+}
+
+void sub_80EB2C8(void)
+{
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x400);
+ }
+}
+
+void sub_80EB300(void)
+{
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) & ~0x3800);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) & ~0x001);
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x2000);
+ }
+}
+
+void sub_80EB368(void)
+{
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) & ~0x3800);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) & ~0x001);
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x800);
+ }
+}
+
+void sub_80EB3D0(void)
+{
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) & ~0x3800);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) & ~0x001);
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x1000);
+ }
+}
+
+void sub_80EB438(void)
+{
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) & ~0x3800);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) & ~0x001);
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x001);
+ }
+}
+
+void sub_80EB498(void)
+{
+ s16 x;
+ s16 y;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ switch (MapGridGetMetatileIdAt(x, y))
+ {
+ case 0x31C:
+ case 0x31D:
+ case 0x31E:
+ case 0x31F:
+ case 0x324:
+ case 0x325:
+ case 0x326:
+ case 0x327:
+ case 0x32C:
+ case 0x32D:
+ case 0x330:
+ case 0x331:
+ case 0x332:
+ case 0x333:
+ case 0x334:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x4000);
+ }
+ break;
+ }
+}
+
+void sub_80EB56C(void)
+{
+ s16 x;
+ s16 y;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ switch (MapGridGetMetatileIdAt(x, y))
+ {
+ case 0x28a:
+ case 0x28b:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x40);
+ }
+ break;
+ case 0x2d8:
+ case 0x2d9:
+ case 0x2da:
+ case 0x2db:
+ case 0x2dc:
+ case 0x2dd:
+ case 0x2e8:
+ case 0x2e9:
+ case 0x2ea:
+ case 0x2eb:
+ case 0x2ec:
+ case 0x2ed:
+ case 0x2ee:
+ case 0x2ef:
+ case 0x2f8:
+ case 0x2f9:
+ case 0x2fa:
+ case 0x2fb:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x8);
+ }
+ break;
+ case 0x22c:
+ case 0x233:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x40);
+ }
+ break;
+ case 0x288:
+ case 0x289:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x100);
+ }
+ break;
+ case 0x22d:
+ case 0x22e:
+ case 0x22f:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x10);
+ }
+ break;
+ case 0x287:
+ case 0x28f:
+ case 0x298:
+ case 0x299:
+ case 0x29a:
+ case 0x29b:
+ case 0x29c:
+ case 0x29d:
+ case 0x29e:
+ case 0x29f:
+ case 0x2ab:
+ case 0x2b0:
+ case 0x2b1:
+ case 0x2b2:
+ case 0x2b4:
+ case 0x2b5:
+ case 0x2b6:
+ case 0x2b7:
+ case 0x2cb:
+ case 0x2cc:
+ case 0x2cd:
+ case 0x2ce:
+ case 0x2cf:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x8);
+ }
+ break;
+ }
+}
+
+void sub_80EB9E0(void)
+{
+ s16 x;
+ s16 y;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ switch (MapGridGetMetatileIdAt(x, y))
+ {
+ case 0x291:
+ case 0x294:
+ case 0x297:
+ case 0x2a1:
+ case 0x2a5:
+ case 0x2a9:
+ case 0x2ad:
+ case 0x2bb:
+ case 0x2be:
+ case 0x2c3:
+ case 0x2c6:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x8);
+ }
+ break;
+ }
+}
+
+void sub_80EBB28(void)
+{
+ s16 x;
+ s16 y;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ switch (MapGridGetMetatileIdAt(x, y))
+ {
+ case 0x290:
+ case 0x292:
+ case 0x293:
+ case 0x295:
+ case 0x296:
+ case 0x2a0:
+ case 0x2a2:
+ case 0x2a3:
+ case 0x2a4:
+ case 0x2a6:
+ case 0x2a7:
+ case 0x2a8:
+ case 0x2aa:
+ case 0x2ac:
+ case 0x2ae:
+ case 0x2af:
+ case 0x2bc:
+ case 0x2bd:
+ case 0x2bf:
+ case 0x2c4:
+ case 0x2c5:
+ case 0x2c7:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x8);
+ }
+ break;
+ case 0x280:
+ case 0x281:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x100);
+ }
+ break;
+ case 0x225:
+ case 0x226:
+ case 0x227:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x10);
+ }
+ break;
+ }
+}
+
+void sub_80EBE7C(void)
+{
+ s16 x;
+ s16 y;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ switch ((int)MapGridGetMetatileIdAt(x, y))
+ {
+ case 0x28d:
+ case 0x28e:
+ if (VarGet(VAR_0x4054) != 0)
+ {
+ VarSet(VAR_0x40EF, VarGet(VAR_0x40EF) | 0x4);
+ }
+ break;
+ }
+}