diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_2.c | 7 | ||||
-rw-r--r-- | src/battle_ai_switch_items.c | 18 | ||||
-rw-r--r-- | src/battle_anim.c | 1850 | ||||
-rw-r--r-- | src/battle_controllers.c | 1551 | ||||
-rw-r--r-- | src/battle_interface.c | 2632 | ||||
-rw-r--r-- | src/battle_script_commands.c | 34 | ||||
-rwxr-xr-x | src/braille_puzzles.c | 8 | ||||
-rw-r--r-- | src/coins.c | 4 | ||||
-rw-r--r-- | src/decompress.c | 2 | ||||
-rw-r--r-- | src/egg_hatch.c | 2 | ||||
-rw-r--r-- | src/event_data.c | 52 | ||||
-rwxr-xr-x | src/field_map_obj.c | 28 | ||||
-rwxr-xr-x | src/field_special_scene.c | 18 | ||||
-rw-r--r-- | src/international_string_util.c | 57 | ||||
-rw-r--r-- | src/lilycove_lady.c | 2 | ||||
-rw-r--r-- | src/mail.c | 577 | ||||
-rw-r--r-- | src/money.c | 4 | ||||
-rw-r--r-- | src/new_game.c | 4 | ||||
-rw-r--r-- | src/palette.c | 6 | ||||
-rw-r--r-- | src/pokemon_2.c | 2 | ||||
-rw-r--r-- | src/reset_save_heap.c | 2 | ||||
-rw-r--r-- | src/reshow_battle_screen.c | 4 | ||||
-rw-r--r-- | src/safari_zone.c | 4 | ||||
-rw-r--r-- | src/scrcmd.c | 2451 | ||||
-rw-r--r-- | src/script.c | 4 | ||||
-rw-r--r-- | src/sprite.c | 2 | ||||
-rw-r--r-- | src/text.c | 2 | ||||
-rw-r--r-- | src/tv.c | 30 | ||||
-rw-r--r-- | src/walda_phrase.c | 257 |
29 files changed, 9486 insertions, 128 deletions
diff --git a/src/battle_2.c b/src/battle_2.c index aeba69213..16c07114a 100644 --- a/src/battle_2.c +++ b/src/battle_2.c @@ -204,9 +204,6 @@ extern const u8 BattleScript_ActionSwitch[]; extern const u8 BattleScript_PrintFailedToRunString[]; // functions -extern void HandleLinkBattleSetup(void); // rom_3 -extern void SetUpBattleVarsAndBirchZigzagoon(void); // rom_3 -extern void sub_8032768(void); // rom_3 extern void dp12_8087EA4(void); extern void sub_80356D0(void); extern void GetFrontierTrainerName(u8* dst, u16 trainerId); // battle tower @@ -4083,7 +4080,7 @@ static void HandleTurnActionSelectionState(void) if (gBattleMons[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].status2 & STATUS2_MULTIPLETURNS || gBattleMons[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].status2 & STATUS2_RECHARGE) { - Emit_x32(0); + EmitCmd50(0); MarkBufferBankForExecution(gActiveBank); return; } @@ -4111,7 +4108,7 @@ static void HandleTurnActionSelectionState(void) { RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 3); } - Emit_x32(0); + EmitCmd50(0); MarkBufferBankForExecution(gActiveBank); return; } diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 661759a98..d86be6fad 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; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 0); return TRUE; } @@ -121,7 +121,7 @@ static bool8 ShouldSwitchIfWonderGuard(void) { // we found a mon *(gBattleStruct->field_294 + gActiveBank) = i; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 0); return TRUE; } } @@ -221,7 +221,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void) { // we found a mon *(gBattleStruct->field_294 + gActiveBank) = i; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 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; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 0); return TRUE; } else if (gBattleMoves[gUnknown_02024250[gActiveBank]].power == 0 && Random() & 1) { *(gBattleStruct->field_294 + gActiveBank) = 6; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 0); return TRUE; } @@ -258,7 +258,7 @@ static bool8 ShouldSwitchIfNaturalCure(void) if (Random() & 1) { *(gBattleStruct->field_294 + gActiveBank) = 6; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 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; - EmitCmd_x21(1, 2, 0); + EmitCmd33(1, 2, 0); return TRUE; } } @@ -611,7 +611,7 @@ void AI_TrySwitchOrUseItem(void) } } - EmitCmd_x21(1, 0, (gActiveBank ^ BIT_SIDE) << 8); + EmitCmd33(1, 0, (gActiveBank ^ BIT_SIDE) << 8); } #define TYPE_FORESIGHT 0xFE @@ -940,7 +940,7 @@ static bool8 ShouldUseItem(void) if (shouldUse) { - EmitCmd_x21(1, 1, 0); + EmitCmd33(1, 1, 0); *(gBattleStruct->field_C0 + (gActiveBank / 2) * 2) = item; gBattleResources->battleHistory->trainerItems[i] = 0; return shouldUse; diff --git a/src/battle_anim.c b/src/battle_anim.c new file mode 100644 index 000000000..023272017 --- /dev/null +++ b/src/battle_anim.c @@ -0,0 +1,1850 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "sprite.h" +#include "contest.h" +#include "m4a.h" +#include "pokemon.h" +#include "battle_interface.h" +#include "task.h" +#include "decompress.h" +#include "sound.h" +#include "dma3.h" +#include "bg.h" +#include "gpu_regs.h" +#include "palette.h" +#include "main.h" + +// sprites start at 10000 and thus must be subtracted of 10000 to account for the true index. +#define GET_TRUE_SPRITE_INDEX(i) ((i - 10000)) + +#define SCRIPT_READ_16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) +#define SCRIPT_READ_32(ptr) (((ptr)[0]) + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) +#define SCRIPT_READ_PTR(ptr) ((const u8*)(SCRIPT_READ_32(ptr))) + +#define ANIM_SPRITE_INDEX_COUNT 8 + +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern u16 gBattle_WIN0H; +extern u16 gBattle_WIN0V; +extern u16 gBattle_WIN1H; +extern u16 gBattle_WIN1V; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT]; +extern struct MusicPlayerInfo gMPlay_BGM; +extern struct MusicPlayerInfo gMPlay_SE1; +extern struct MusicPlayerInfo gMPlay_SE2; +extern u8 gDecompressionBuffer[]; + +extern const u16 gUnknown_082C8D64[]; +extern const u8 * const gBattleAnims_Moves[]; +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); +static void ScriptCmd_createsprite(void); +static void ScriptCmd_createvisualtask(void); +static void ScriptCmd_delay(void); +static void ScriptCmd_waitforvisualfinish(void); +static void ScriptCmd_hang1(void); +static void ScriptCmd_hang2(void); +static void ScriptCmd_end(void); +static void ScriptCmd_playse(void); +static void ScriptCmd_monbg(void); +static void ScriptCmd_clearmonbg(void); +static void ScriptCmd_setalpha(void); +static void ScriptCmd_blendoff(void); +static void ScriptCmd_call(void); +static void ScriptCmd_return(void); +static void ScriptCmd_setarg(void); +static void ScriptCmd_choosetwoturnanim(void); +static void ScriptCmd_jumpifmoveturn(void); +static void ScriptCmd_jump(void); +static void ScriptCmd_fadetobg(void); +static void ScriptCmd_restorebg(void); +static void ScriptCmd_waitbgfadeout(void); +static void ScriptCmd_waitbgfadein(void); +static void ScriptCmd_changebg(void); +static void ScriptCmd_playsewithpan(void); +static void ScriptCmd_setpan(void); +static void ScriptCmd_panse_1B(void); +static void ScriptCmd_loopsewithpan(void); +static void ScriptCmd_waitplaysewithpan(void); +static void ScriptCmd_setbldcnt(void); +static void ScriptCmd_createsoundtask(void); +static void ScriptCmd_waitsound(void); +static void ScriptCmd_jumpargeq(void); +static void ScriptCmd_monbg_22(void); +static void ScriptCmd_clearmonbg_23(void); +static void ScriptCmd_jumpifcontest(void); +static void ScriptCmd_fadetobgfromset(void); +static void ScriptCmd_panse_26(void); +static void ScriptCmd_panse_27(void); +static void ScriptCmd_monbgprio_28(void); +static void ScriptCmd_monbgprio_29(void); +static void ScriptCmd_monbgprio_2A(void); +static void ScriptCmd_invisible(void); +static void ScriptCmd_visible(void); +static void ScriptCmd_doublebattle_2D(void); +static void ScriptCmd_doublebattle_2E(void); +static void ScriptCmd_stopsound(void); + +static void RunAnimScriptCommand(void); +static void task_pA_ma0A_obj_to_bg_pal(u8 taskId); +static void sub_80A46A0(void); +static void sub_80A4980(u8 taskId); +static void sub_80A4BB0(u8 taskId); +static void Task_FadeToBg(u8 taskId); +static void Task_PanFromInitialToTarget(u8 taskId); +static void Task_LoopAndPlaySE(u8 taskId); +static void Task_WaitAndPlaySE(u8 taskId); +static void LoadDefaultBg(void); +static void LoadMoveBg(u16 bgId); + +// ewram +EWRAM_DATA static const u8 *sBattleAnimScriptPtr = NULL; +EWRAM_DATA static const u8 *sBattleAnimScriptRetAddr = NULL; +EWRAM_DATA void (*gAnimScriptCallback)(void) = NULL; +EWRAM_DATA static s8 gAnimFramesToWait = 0; +EWRAM_DATA bool8 gAnimScriptActive = FALSE; +EWRAM_DATA u8 gAnimVisualTaskCount = 0; +EWRAM_DATA u8 gAnimSoundTaskCount = 0; +EWRAM_DATA struct DisableStruct *gAnimDisableStructPtr = NULL; +EWRAM_DATA u32 gAnimMoveDmg = 0; +EWRAM_DATA u16 gAnimMovePower = 0; +EWRAM_DATA static u16 sAnimSpriteIndexArray[ANIM_SPRITE_INDEX_COUNT] = {0}; +EWRAM_DATA u8 gAnimFriendship = 0; +EWRAM_DATA u16 gWeatherMoveAnim = 0; +EWRAM_DATA s16 gBattleAnimArgs[ANIM_ARGS_COUNT] = {0}; +EWRAM_DATA static u16 sSoundAnimFramesToWait = 0; +EWRAM_DATA static u8 sMonAnimTaskIdArray[2] = {0}; +EWRAM_DATA u8 gAnimMoveTurn = 0; +EWRAM_DATA static u8 sAnimBackgroundFadeState = 0; +EWRAM_DATA static u16 sAnimMoveIndex = 0; // set but unused. +EWRAM_DATA u8 gAnimBankAttacker = 0; +EWRAM_DATA u8 gAnimBankTarget = 0; +EWRAM_DATA u16 gAnimSpeciesByBanks[BATTLE_BANKS_COUNT] = {0}; +EWRAM_DATA u8 gUnknown_02038440 = 0; + +// const rom data +static void (* const sScriptCmdTable[])(void) = +{ + ScriptCmd_loadspritegfx, + ScriptCmd_unloadspritegfx, + ScriptCmd_createsprite, + ScriptCmd_createvisualtask, + ScriptCmd_delay, + ScriptCmd_waitforvisualfinish, + ScriptCmd_hang1, + ScriptCmd_hang2, + ScriptCmd_end, + ScriptCmd_playse, + ScriptCmd_monbg, + ScriptCmd_clearmonbg, + ScriptCmd_setalpha, + ScriptCmd_blendoff, + ScriptCmd_call, + ScriptCmd_return, + ScriptCmd_setarg, + ScriptCmd_choosetwoturnanim, + ScriptCmd_jumpifmoveturn, + ScriptCmd_jump, + ScriptCmd_fadetobg, + ScriptCmd_restorebg, + ScriptCmd_waitbgfadeout, + ScriptCmd_waitbgfadein, + ScriptCmd_changebg, + ScriptCmd_playsewithpan, + ScriptCmd_setpan, + ScriptCmd_panse_1B, + ScriptCmd_loopsewithpan, + ScriptCmd_waitplaysewithpan, + ScriptCmd_setbldcnt, + ScriptCmd_createsoundtask, + ScriptCmd_waitsound, + ScriptCmd_jumpargeq, + ScriptCmd_monbg_22, + ScriptCmd_clearmonbg_23, + ScriptCmd_jumpifcontest, + ScriptCmd_fadetobgfromset, + ScriptCmd_panse_26, + ScriptCmd_panse_27, + ScriptCmd_monbgprio_28, + ScriptCmd_monbgprio_29, + ScriptCmd_monbgprio_2A, + ScriptCmd_invisible, + ScriptCmd_visible, + ScriptCmd_doublebattle_2D, + ScriptCmd_doublebattle_2E, + ScriptCmd_stopsound +}; + +void ClearBattleAnimationVars(void) +{ + s32 i; + + gAnimFramesToWait = 0; + gAnimScriptActive = FALSE; + gAnimVisualTaskCount = 0; + gAnimSoundTaskCount = 0; + gAnimDisableStructPtr = NULL; + gAnimMoveDmg = 0; + gAnimMovePower = 0; + gAnimFriendship = 0; + + // clear index array. + for (i = 0; i < ANIM_SPRITE_INDEX_COUNT; i++) + sAnimSpriteIndexArray[i] |= 0xFFFF; + + // clear anim args. + for (i = 0; i < ANIM_ARGS_COUNT; i++) + gBattleAnimArgs[i] = 0; + + sMonAnimTaskIdArray[0] = 0xFF; + sMonAnimTaskIdArray[1] = 0xFF; + gAnimMoveTurn = 0; + sAnimBackgroundFadeState = 0; + sAnimMoveIndex = 0; + gAnimBankAttacker = 0; + gAnimBankTarget = 0; + gUnknown_02038440 = 0; +} + +void DoMoveAnim(u16 move) +{ + gAnimBankAttacker = gBankAttacker; + gAnimBankTarget = gBankTarget; + DoBattleAnim(gBattleAnims_Moves, move, TRUE); +} + +void DoBattleAnim(const u8 *const animsTable[], u16 tableId, bool8 isMoveAnim) +{ + s32 i; + + if (!IsContest()) + { + sub_80A8278(); + UpdateOamPriorityInAllHealthboxes(0); + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + if (GetBankSide(i) != 0) + gAnimSpeciesByBanks[i] = GetMonData(&gEnemyParty[gBattlePartyID[i]], MON_DATA_SPECIES); + else + gAnimSpeciesByBanks[i] = GetMonData(&gPlayerParty[gBattlePartyID[i]], MON_DATA_SPECIES); + } + } + else + { + for (i = 0; i < 4; i++) + gAnimSpeciesByBanks[i] = gContestResources->field_18->field_0; + } + + if (!isMoveAnim) + sAnimMoveIndex = 0; + else + sAnimMoveIndex = tableId; + + for (i = 0; i < ANIM_ARGS_COUNT; i++) + gBattleAnimArgs[i] = 0; + + sMonAnimTaskIdArray[0] = 0xFF; + sMonAnimTaskIdArray[1] = 0xFF; + sBattleAnimScriptPtr = animsTable[tableId]; + gAnimScriptActive = TRUE; + gAnimFramesToWait = 0; + gAnimScriptCallback = RunAnimScriptCommand; + + for (i = 0; i < ANIM_SPRITE_INDEX_COUNT; i++) + sAnimSpriteIndexArray[i] |= 0xFFFF; + + if (isMoveAnim) + { + for (i = 0; gUnknown_082C8D64[i] != 0xFFFF; i++) + { + if (tableId == gUnknown_082C8D64[i]) + { + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 128); + break; + } + } + } + + gBattle_WIN0H = 0; + gBattle_WIN0V = 0; + gBattle_WIN1H = 0; + gBattle_WIN1V = 0; +} + +void DestroyAnimSprite(struct Sprite *sprite) +{ + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); + gAnimVisualTaskCount--; +} + +void DestroyAnimVisualTask(u8 taskId) +{ + DestroyTask(taskId); + gAnimVisualTaskCount--; +} + +void DestroyAnimSoundTask(u8 taskId) +{ + DestroyTask(taskId); + gAnimSoundTaskCount--; +} + +static void AddSpriteIndex(u16 index) +{ + s32 i; + + for (i = 0; i < ANIM_SPRITE_INDEX_COUNT; i++) + { + if (sAnimSpriteIndexArray[i] == 0xFFFF) + { + sAnimSpriteIndexArray[i] = index; + return; + } + } +} + +static void ClearSpriteIndex(u16 index) +{ + s32 i; + + for (i = 0; i < ANIM_SPRITE_INDEX_COUNT; i++) + { + if (sAnimSpriteIndexArray[i] == index) + { + sAnimSpriteIndexArray[i] |= 0xFFFF; + return; + } + } +} + +static void WaitAnimFrameCount(void) +{ + if (gAnimFramesToWait <= 0) + { + gAnimScriptCallback = RunAnimScriptCommand; + gAnimFramesToWait = 0; + } + else + { + gAnimFramesToWait--; + } +} + +static void RunAnimScriptCommand(void) +{ + do + { + sScriptCmdTable[sBattleAnimScriptPtr[0]](); + } while (gAnimFramesToWait == 0 && gAnimScriptActive); +} + +static void ScriptCmd_loadspritegfx(void) +{ + u16 index; + + sBattleAnimScriptPtr++; + index = SCRIPT_READ_16(sBattleAnimScriptPtr); + LoadCompressedObjectPicUsingHeap(&gBattleAnimPicTable[GET_TRUE_SPRITE_INDEX(index)]); + LoadCompressedObjectPaletteUsingHeap(&gBattleAnimPaletteTable[GET_TRUE_SPRITE_INDEX(index)]); + sBattleAnimScriptPtr += 2; + AddSpriteIndex(GET_TRUE_SPRITE_INDEX(index)); + gAnimFramesToWait = 1; + gAnimScriptCallback = WaitAnimFrameCount; +} + +static void ScriptCmd_unloadspritegfx(void) +{ + u16 index; + + sBattleAnimScriptPtr++; + index = SCRIPT_READ_16(sBattleAnimScriptPtr); + FreeSpriteTilesByTag(gBattleAnimPicTable[GET_TRUE_SPRITE_INDEX(index)].tag); + FreeSpritePaletteByTag(gBattleAnimPicTable[GET_TRUE_SPRITE_INDEX(index)].tag); + sBattleAnimScriptPtr += 2; + ClearSpriteIndex(GET_TRUE_SPRITE_INDEX(index)); +} + +static void ScriptCmd_createsprite(void) +{ + s32 i; + const struct SpriteTemplate *template; + u8 argVar; + u8 argsCount; + s16 subpriority; + + sBattleAnimScriptPtr++; + template = (const struct SpriteTemplate *)(SCRIPT_READ_32(sBattleAnimScriptPtr)); + sBattleAnimScriptPtr += 4; + + argVar = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + + argsCount = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + for (i = 0; i < argsCount; i++) + { + gBattleAnimArgs[i] = SCRIPT_READ_16(sBattleAnimScriptPtr); + sBattleAnimScriptPtr += 2; + } + + if (argVar & 0x80) + { + argVar ^= 0x80; + if (argVar >= 0x40) + argVar -= 0x40; + else + argVar *= -1; + + subpriority = sub_80A82E4(gAnimBankTarget) + (s8)(argVar); + } + else + { + if (argVar >= 0x40) + argVar -= 0x40; + else + argVar *= -1; + + subpriority = sub_80A82E4(gAnimBankAttacker) + (s8)(argVar); + } + + if (subpriority < 3) + subpriority = 3; + + CreateSpriteAndAnimate(template, sub_80A5C6C(gAnimBankTarget, 2), sub_80A5C6C(gAnimBankTarget, 3), subpriority); + gAnimVisualTaskCount++; +} + +static void ScriptCmd_createvisualtask(void) +{ + TaskFunc taskFunc; + u8 taskPriority; + u8 taskId; + u8 numArgs; + s32 i; + + sBattleAnimScriptPtr++; + + taskFunc = (TaskFunc)SCRIPT_READ_32(sBattleAnimScriptPtr); + sBattleAnimScriptPtr += 4; + + taskPriority = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + + numArgs = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + + for (i = 0; i < numArgs; i++) + { + gBattleAnimArgs[i] = SCRIPT_READ_16(sBattleAnimScriptPtr); + sBattleAnimScriptPtr += 2; + } + + taskId = CreateTask(taskFunc, taskPriority); + taskFunc(taskId); + gAnimVisualTaskCount++; +} + +static void ScriptCmd_delay(void) +{ + sBattleAnimScriptPtr++; + gAnimFramesToWait = sBattleAnimScriptPtr[0]; + if (gAnimFramesToWait == 0) + gAnimFramesToWait = -1; + sBattleAnimScriptPtr++; + gAnimScriptCallback = WaitAnimFrameCount; +} + +// wait for visual tasks to finish. +static void ScriptCmd_waitforvisualfinish(void) +{ + if (gAnimVisualTaskCount == 0) + { + sBattleAnimScriptPtr++; + gAnimFramesToWait = 0; + } + else + { + gAnimFramesToWait = 1; + } +} + +static void ScriptCmd_hang1(void) +{ +} + +static void ScriptCmd_hang2(void) +{ +} + +static void ScriptCmd_end(void) +{ + s32 i; + bool32 continuousAnim = FALSE; + + // keep waiting as long as there is animations to be done. + if (gAnimVisualTaskCount != 0 || gAnimSoundTaskCount != 0 + || sMonAnimTaskIdArray[0] != 0xFF || sMonAnimTaskIdArray[1] != 0xFF) + { + sSoundAnimFramesToWait = 0; + gAnimFramesToWait = 1; + return; + } + + // finish the sound effects. + if (IsSEPlaying()) + { + if (++sSoundAnimFramesToWait <= 90) // wait 90 frames, then halt the sound effect. + { + gAnimFramesToWait = 1; + return; + } + else + { + m4aMPlayStop(&gMPlay_SE1); + m4aMPlayStop(&gMPlay_SE2); + } + } + + // the SE has halted, so set the SE Frame Counter to 0 and continue. + sSoundAnimFramesToWait = 0; + + for (i = 0; i < ANIM_SPRITE_INDEX_COUNT; i++) + { + if (sAnimSpriteIndexArray[i] != 0xFFFF) + { + FreeSpriteTilesByTag(gBattleAnimPicTable[sAnimSpriteIndexArray[i]].tag); + FreeSpritePaletteByTag(gBattleAnimPicTable[sAnimSpriteIndexArray[i]].tag); + sAnimSpriteIndexArray[i] |= 0xFFFF; // set terminator. + } + } + + if (!continuousAnim) // may have been used for debug? + { + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 256); + if (!IsContest()) + { + sub_80A8278(); + UpdateOamPriorityInAllHealthboxes(1); + } + gAnimScriptActive = FALSE; + } +} + +static void ScriptCmd_playse(void) +{ + sBattleAnimScriptPtr++; + PlaySE(SCRIPT_READ_16(sBattleAnimScriptPtr)); + sBattleAnimScriptPtr += 2; +} + +#define t1_MONBG_BANK 0 +#define t1_MON_IN_BG2 1 +#define t1_CREATE_ANOTHER_TASK 2 +#define t1_IS_SECONDMON_BG 3 + +#define t2_BANK_SPRITE_ID 0 +#define t2_MON_IN_BG2 5 +#define t2_MONBG_BANK 6 + +static void sub_80A40F4(u8 taskId) +{ + u8 newTaskId; + + s16 *selfData = gTasks[taskId].data; + u8 bankSpriteId = gBankSpriteIds[selfData[t1_MONBG_BANK]]; + gSprites[bankSpriteId].invisible = 1; + + if (!selfData[t1_CREATE_ANOTHER_TASK]) + { + DestroyAnimVisualTask(taskId); + return; + } + + newTaskId = CreateTask(task_pA_ma0A_obj_to_bg_pal, 10); + gTasks[newTaskId].data[t2_BANK_SPRITE_ID] = bankSpriteId; + gTasks[newTaskId].data[1] = gSprites[bankSpriteId].pos1.x + gSprites[bankSpriteId].pos2.x; + gTasks[newTaskId].data[2] = gSprites[bankSpriteId].pos1.y + gSprites[bankSpriteId].pos2.y; + + if (!selfData[t1_MON_IN_BG2]) + { + gTasks[newTaskId].data[3] = gBattle_BG1_X; + gTasks[newTaskId].data[4] = gBattle_BG1_Y; + } + else + { + gTasks[newTaskId].data[3] = gBattle_BG2_X; + gTasks[newTaskId].data[4] = gBattle_BG2_Y; + } + + gTasks[newTaskId].data[t2_MON_IN_BG2] = selfData[t1_MON_IN_BG2]; + gTasks[newTaskId].data[t2_MONBG_BANK] = selfData[t1_MONBG_BANK]; + sMonAnimTaskIdArray[selfData[t1_IS_SECONDMON_BG]] = newTaskId; + DestroyAnimVisualTask(taskId); +} + +static void ScriptCmd_monbg(void) +{ + bool8 toBG_2; + u8 taskId; + u8 bank; + u8 animBank; + + sBattleAnimScriptPtr++; + + animBank = sBattleAnimScriptPtr[0]; + if (animBank & ANIM_BANK_TARGET) + bank = gAnimBankTarget; + else + bank = gAnimBankAttacker; + + if (IsAnimBankSpriteVisible(bank)) + { + u8 identity = GetBankIdentity(bank); + if (identity == IDENTITY_OPPONENT_MON1 || identity == IDENTITY_PLAYER_MON2 || IsContest()) + toBG_2 = FALSE; + else + toBG_2 = TRUE; + + sub_80A438C(bank, toBG_2, FALSE); + taskId = CreateTask(sub_80A40F4, 10); + gAnimVisualTaskCount++; + gTasks[taskId].data[t1_MONBG_BANK] = bank; + gTasks[taskId].data[t1_MON_IN_BG2] = toBG_2; + gTasks[taskId].data[t1_CREATE_ANOTHER_TASK] = TRUE; + gTasks[taskId].data[t1_IS_SECONDMON_BG] = 0; + + } + + bank ^= BIT_MON; + if (IsAnimBankSpriteVisible(bank)) + { + u8 identity = GetBankIdentity(bank); + if (identity == IDENTITY_OPPONENT_MON1 || identity == IDENTITY_PLAYER_MON2 || IsContest()) + toBG_2 = FALSE; + else + toBG_2 = TRUE; + + sub_80A438C(bank, toBG_2, FALSE); + taskId = CreateTask(sub_80A40F4, 10); + gAnimVisualTaskCount++; + gTasks[taskId].data[0] = bank; + gTasks[taskId].data[1] = toBG_2; + gTasks[taskId].data[t1_CREATE_ANOTHER_TASK] = TRUE; + gTasks[taskId].data[t1_IS_SECONDMON_BG] = 1; + } + + sBattleAnimScriptPtr++; + gAnimFramesToWait = 1; + gAnimScriptCallback = WaitAnimFrameCount; +} + +bool8 IsAnimBankSpriteVisible(u8 bank) +{ + if (IsContest()) + { + if (bank == gAnimBankAttacker) + return TRUE; + else + return FALSE; + } + if (!AnimBankSpriteExists(bank)) + return FALSE; + if (IsContest()) + return TRUE; // this line wont ever be reached. + if (!gBattleSpritesDataPtr->bankData[bank].invisible || !gSprites[gBankSpriteIds[bank]].invisible) + return TRUE; + + return FALSE; +} + +void sub_80A438C(u8 bank, bool8 toBG_2, bool8 setSpriteInvisible) +{ + struct UnknownAnimStruct2 unknownStruct; + u8 bankSpriteId; + + if (!toBG_2) + { + u8 bankIdentity; + + if (IsContest() == TRUE) + { + RequestDma3Fill(0, (void*)(VRAM + 0x8000), 0x2000, 1); + RequestDma3Fill(0xFF, (void*)(VRAM + 0xF000), 0x1000, 0); + } + else + { + RequestDma3Fill(0, (void*)(VRAM + 0x4000), 0x2000, 1); + RequestDma3Fill(0xFF, (void*)(VRAM + 0xe000), 0x1000, 0); + } + + sub_80A6B30(&unknownStruct); + CpuFill16(0, unknownStruct.unk0, 0x1000); + CpuFill16(0xFF, unknownStruct.unk4, 0x800); + + SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 2); + SetAnimBgAttribute(1, BG_ANIM_SCREEN_SIZE, 1); + SetAnimBgAttribute(1, BG_ANIM_AREA_OVERFLOW_MODE, 0); + + bankSpriteId = gBankSpriteIds[bank]; + + gBattle_BG1_X = -(gSprites[bankSpriteId].pos1.x + gSprites[bankSpriteId].pos2.x) + 0x20; + if (IsContest() && IsSpeciesNotUnown(gContestResources->field_18->field_0)) + gBattle_BG1_X--; + + gBattle_BG1_Y = -(gSprites[bankSpriteId].pos1.y + gSprites[bankSpriteId].pos2.y) + 0x20; + if (setSpriteInvisible) + gSprites[gBankSpriteIds[bank]].invisible = 1; + + SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X); + SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y); + + LoadPalette(&gPlttBufferUnfaded[0x100 + bank * 16], unknownStruct.unk8 * 16, 0x20); + CpuCopy32(&gPlttBufferUnfaded[0x100 + bank * 16], (void*)(BG_PLTT + unknownStruct.unk8 * 32), 0x20); + + if (IsContest()) + bankIdentity = 0; + else + bankIdentity = GetBankIdentity(bank); + + sub_8118FBC(1, 0, 0, bankIdentity, unknownStruct.unk8, unknownStruct.unk0, unknownStruct.unk4, unknownStruct.unkA); + + if (IsContest()) + sub_80A46A0(); + } + else + { + RequestDma3Fill(0, (void*)(VRAM + 0x6000), 0x2000, 1); + RequestDma3Fill(0, (void*)(VRAM + 0xF000), 0x1000, 1); + sub_80A6B90(&unknownStruct, 2); + CpuFill16(0, unknownStruct.unk0 + 0x1000, 0x1000); + CpuFill16(0, unknownStruct.unk4 + 0x400, 0x800); + SetAnimBgAttribute(2, BG_ANIM_PRIORITY, 2); + SetAnimBgAttribute(2, BG_ANIM_SCREEN_SIZE, 1); + SetAnimBgAttribute(2, BG_ANIM_AREA_OVERFLOW_MODE, 0); + + bankSpriteId = gBankSpriteIds[bank]; + + gBattle_BG2_X = -(gSprites[bankSpriteId].pos1.x + gSprites[bankSpriteId].pos2.x) + 0x20; + gBattle_BG2_Y = -(gSprites[bankSpriteId].pos1.y + gSprites[bankSpriteId].pos2.y) + 0x20; + + if (setSpriteInvisible) + gSprites[gBankSpriteIds[bank]].invisible = 1; + + SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X); + SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y); + + LoadPalette(&gPlttBufferUnfaded[0x100 + bank * 16], 0x90, 0x20); + CpuCopy32(&gPlttBufferUnfaded[0x100 + bank * 16], (void*)(BG_PLTT + 0x120), 0x20); + + sub_8118FBC(2, 0, 0, GetBankIdentity(bank), unknownStruct.unk8, unknownStruct.unk0 + 0x1000, unknownStruct.unk4 + 0x400, unknownStruct.unkA); + } +} + +static void sub_80A46A0(void) +{ + s32 i, j; + struct UnknownAnimStruct2 unknownStruct; + u16 *ptr; + + if (IsSpeciesNotUnown(gContestResources->field_18->field_0)) + { + sub_80A6B30(&unknownStruct); + ptr = unknownStruct.unk4; + for (i = 0; i < 8; i++) + { + for (j = 0; j < 4; j++) + { + u16 temp = ptr[j + i * 32]; + + ptr[j + i * 32] = ptr[7 - j + i * 32]; + ptr[7 - j + i * 32] = temp; + } + } + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + ptr[j + i * 32] ^= 0x400; + } + } +} + +void sub_80A4720(u16 a, u16 *b, u32 c, u8 d) +{ + s32 i, j; + s32 var; + + if (d == 0) + var = 32; + else + var = 64; + a <<= 12; + for (i = 0; i < var; i++) + { + for (j = 0; j < 32; j++) + b[j + i * 32] = ((b[j + i * 32] & 0xFFF) | a) + c; + } +} + +void sub_80A477C(bool8 to_BG2) +{ + struct UnknownAnimStruct2 unknownStruct; + sub_80A6B30(&unknownStruct); + + if (!to_BG2 || IsContest()) + { + sub_80A6C68(1); + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + } + else + { + sub_80A6C68(2); + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + } +} + +static void task_pA_ma0A_obj_to_bg_pal(u8 taskId) +{ + u8 spriteId, palIndex; + s16 x, y; + struct UnknownAnimStruct2 unknownStruct; + + spriteId = gTasks[taskId].data[0]; + palIndex = gTasks[taskId].data[6]; + sub_80A6B30(&unknownStruct); + x = gTasks[taskId].data[1] - (gSprites[spriteId].pos1.x + gSprites[spriteId].pos2.x); + y = gTasks[taskId].data[2] - (gSprites[spriteId].pos1.y + gSprites[spriteId].pos2.y); + + if (gTasks[taskId].data[5] == 0) + { + u16 *src; + u16 *dst; + + gBattle_BG1_X = x + gTasks[taskId].data[3]; + gBattle_BG1_Y = y + gTasks[taskId].data[4]; + src = gPlttBufferFaded + 0x100 + palIndex * 16; + dst = gPlttBufferFaded + 0x100 + unknownStruct.unk8 * 16 - 256; + CpuCopy32(src, dst, 0x20); + } + else + { + u16 *src; + u16 *dst; + + gBattle_BG2_X = x + gTasks[taskId].data[3]; + gBattle_BG2_Y = y + gTasks[taskId].data[4]; + src = gPlttBufferFaded + 0x100 + palIndex * 16; + dst = gPlttBufferFaded + 0x100 - 112; + CpuCopy32(src, dst, 0x20); + } +} + +static void ScriptCmd_clearmonbg(void) +{ + u8 animBankId; + u8 bank; + u8 taskId; + + sBattleAnimScriptPtr++; + animBankId = sBattleAnimScriptPtr[0]; + + if (animBankId == ANIM_BANK_ATTACKER) + animBankId = ANIM_BANK_ATK_PARTNER; + else if (animBankId == ANIM_BANK_TARGET) + animBankId = ANIM_BANK_DEF_PARTNER; + + if (animBankId == ANIM_BANK_ATTACKER || animBankId == ANIM_BANK_ATK_PARTNER) + bank = gAnimBankAttacker; + else + bank = gAnimBankTarget; + + if (sMonAnimTaskIdArray[0] != 0xFF) + gSprites[gBankSpriteIds[bank]].invisible = 0; + if (animBankId > 1 && sMonAnimTaskIdArray[1] != 0xFF) + gSprites[gBankSpriteIds[bank ^ BIT_MON]].invisible = 0; + else + animBankId = 0; + + taskId = CreateTask(sub_80A4980, 5); + gTasks[taskId].data[0] = animBankId; + gTasks[taskId].data[2] = bank; + + sBattleAnimScriptPtr++; +} + +static void sub_80A4980(u8 taskId) +{ + gTasks[taskId].data[1]++; + if (gTasks[taskId].data[1] != 1) + { + u8 to_BG2; + u8 identity = GetBankIdentity(gTasks[taskId].data[2]); + if (identity == IDENTITY_OPPONENT_MON1 || identity == IDENTITY_PLAYER_MON2 || IsContest()) + to_BG2 = FALSE; + else + to_BG2 = TRUE; + + if (sMonAnimTaskIdArray[0] != 0xFF) + { + sub_80A477C(to_BG2); + DestroyTask(sMonAnimTaskIdArray[0]); + sMonAnimTaskIdArray[0] = 0xFF; + } + if (gTasks[taskId].data[0] > 1) + { + sub_80A477C(to_BG2 ^ 1); + DestroyTask(sMonAnimTaskIdArray[1]); + sMonAnimTaskIdArray[1] = 0xFF; + } + DestroyTask(taskId); + } +} + +static void ScriptCmd_monbg_22(void) +{ + bool8 toBG_2; + u8 bank; + u8 animBankId; + + sBattleAnimScriptPtr++; + + animBankId = sBattleAnimScriptPtr[0]; + + if (animBankId == ANIM_BANK_ATTACKER) + animBankId = ANIM_BANK_ATK_PARTNER; + else if (animBankId == ANIM_BANK_TARGET) + animBankId = ANIM_BANK_DEF_PARTNER; + + if (animBankId == ANIM_BANK_ATTACKER || animBankId == ANIM_BANK_ATK_PARTNER) + bank = gAnimBankAttacker; + else + bank = gAnimBankTarget; + + if (IsAnimBankSpriteVisible(bank)) + { + u8 identity = GetBankIdentity(bank); + if (identity == IDENTITY_OPPONENT_MON1 || identity == IDENTITY_PLAYER_MON2 || IsContest()) + toBG_2 = FALSE; + else + toBG_2 = TRUE; + + sub_80A438C(bank, toBG_2, FALSE); + } + + bank ^= BIT_MON; + if (animBankId > 1 && IsAnimBankSpriteVisible(bank)) + { + u8 identity = GetBankIdentity(bank); + if (identity == IDENTITY_OPPONENT_MON1 || identity == IDENTITY_PLAYER_MON2 || IsContest()) + toBG_2 = FALSE; + else + toBG_2 = TRUE; + + sub_80A438C(bank, toBG_2, FALSE); + } + + sBattleAnimScriptPtr++; +} + +static void ScriptCmd_clearmonbg_23(void) +{ + u8 animBankId; + u8 bank; + u8 taskId; + + sBattleAnimScriptPtr++; + animBankId = sBattleAnimScriptPtr[0]; + + if (animBankId == ANIM_BANK_ATTACKER) + animBankId = ANIM_BANK_ATK_PARTNER; + else if (animBankId == ANIM_BANK_TARGET) + animBankId = ANIM_BANK_DEF_PARTNER; + + if (animBankId == ANIM_BANK_ATTACKER || animBankId == ANIM_BANK_ATK_PARTNER) + bank = gAnimBankAttacker; + else + bank = gAnimBankTarget; + + if (IsAnimBankSpriteVisible(bank)) + gSprites[gBankSpriteIds[bank]].invisible = 0; + if (animBankId > 1 && IsAnimBankSpriteVisible(bank ^ BIT_MON)) + gSprites[gBankSpriteIds[bank ^ BIT_MON]].invisible = 0; + else + animBankId = 0; + + taskId = CreateTask(sub_80A4BB0, 5); + gTasks[taskId].data[0] = animBankId; + gTasks[taskId].data[2] = bank; + + sBattleAnimScriptPtr++; +} + +static void sub_80A4BB0(u8 taskId) +{ + gTasks[taskId].data[1]++; + if (gTasks[taskId].data[1] != 1) + { + bool8 toBG_2; + u8 bank = gTasks[taskId].data[2]; + u8 identity = GetBankIdentity(bank); + if (identity == IDENTITY_OPPONENT_MON1 || identity == IDENTITY_PLAYER_MON2 || IsContest()) + toBG_2 = FALSE; + else + toBG_2 = TRUE; + + if (IsAnimBankSpriteVisible(bank)) + sub_80A477C(toBG_2); + if (gTasks[taskId].data[0] > 1 && IsAnimBankSpriteVisible(bank ^ BIT_MON)) + sub_80A477C(toBG_2 ^ 1); + + DestroyTask(taskId); + } +} + +#undef t1_MONBG_BANK +#undef t1_MON_IN_BG2 +#undef t1_CREATE_ANOTHER_TASK +#undef t1_IS_SECONDMON_BG + +#undef t2_BANK_SPRITE_ID +#undef t2_MON_IN_BG2 +#undef t2_MONBG_BANK + +static void ScriptCmd_setalpha(void) +{ + u16 half1, half2; + + sBattleAnimScriptPtr++; + half1 = *(sBattleAnimScriptPtr++); + half2 = *(sBattleAnimScriptPtr++) << 8; + SetGpuReg(REG_OFFSET_BLDCNT, 0x3F40); + SetGpuReg(REG_OFFSET_BLDALPHA, half1 | half2); +} + +static void ScriptCmd_setbldcnt(void) +{ + u16 half1, half2; + + sBattleAnimScriptPtr++; + half1 = *(sBattleAnimScriptPtr++); + half2 = *(sBattleAnimScriptPtr++) << 8; + SetGpuReg(REG_OFFSET_BLDCNT, half1 | half2); +} + +static void ScriptCmd_blendoff(void) +{ + sBattleAnimScriptPtr++; + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); +} + +static void ScriptCmd_call(void) +{ + sBattleAnimScriptPtr++; + sBattleAnimScriptRetAddr = sBattleAnimScriptPtr + 4; + sBattleAnimScriptPtr = SCRIPT_READ_PTR(sBattleAnimScriptPtr); +} + +static void ScriptCmd_return(void) +{ + sBattleAnimScriptPtr = sBattleAnimScriptRetAddr; +} + +static void ScriptCmd_setarg(void) +{ + const u8 *addr = sBattleAnimScriptPtr; + u16 value; + u8 argId; + + sBattleAnimScriptPtr++; + argId = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + value = SCRIPT_READ_16(sBattleAnimScriptPtr); + sBattleAnimScriptPtr = addr + 4; + gBattleAnimArgs[argId] = value; +} + +static void ScriptCmd_choosetwoturnanim(void) +{ + sBattleAnimScriptPtr++; + if (gAnimMoveTurn & 1) + sBattleAnimScriptPtr += 4; + sBattleAnimScriptPtr = SCRIPT_READ_PTR(sBattleAnimScriptPtr); +} + +static void ScriptCmd_jumpifmoveturn(void) +{ + u8 toCheck; + sBattleAnimScriptPtr++; + toCheck = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + + if (toCheck == gAnimMoveTurn) + sBattleAnimScriptPtr = SCRIPT_READ_PTR(sBattleAnimScriptPtr); + else + sBattleAnimScriptPtr += 4; +} + +static void ScriptCmd_jump(void) +{ + sBattleAnimScriptPtr++; + sBattleAnimScriptPtr = SCRIPT_READ_PTR(sBattleAnimScriptPtr); +} + +// Uses of this function that rely on a TRUE return are expecting inBattle to not be ticked as defined in contest behavior. As a result, if misused, this function cannot reliably discern between field and contest status and could result in undefined behavior. +bool8 IsContest(void) +{ + if (!gMain.inBattle) + return TRUE; + else + return FALSE; +} + +#define tBackgroundId data[0] +#define tState data[10] + +static void ScriptCmd_fadetobg(void) +{ + u8 backgroundId; + u8 taskId; + + sBattleAnimScriptPtr++; + backgroundId = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + taskId = CreateTask(Task_FadeToBg, 5); + gTasks[taskId].tBackgroundId = backgroundId; + sAnimBackgroundFadeState = 1; +} + +static void ScriptCmd_fadetobgfromset(void) +{ + u8 bg1, bg2, bg3; + u8 taskId; + + sBattleAnimScriptPtr++; + bg1 = sBattleAnimScriptPtr[0]; + bg2 = sBattleAnimScriptPtr[1]; + bg3 = sBattleAnimScriptPtr[2]; + sBattleAnimScriptPtr += 3; + taskId = CreateTask(Task_FadeToBg, 5); + + if (IsContest()) + gTasks[taskId].tBackgroundId = bg3; + else if (GetBankSide(gAnimBankTarget) == SIDE_PLAYER) + gTasks[taskId].tBackgroundId = bg2; + else + gTasks[taskId].tBackgroundId = bg1; + + sAnimBackgroundFadeState = 1; +} + +static void Task_FadeToBg(u8 taskId) +{ + if (gTasks[taskId].tState == 0) + { + BeginHardwarePaletteFade(0xE8, 0, 0, 16, 0); + gTasks[taskId].tState++; + return; + } + if (gPaletteFade.active) + return; + if (gTasks[taskId].tState == 1) + { + gTasks[taskId].tState++; + sAnimBackgroundFadeState = 2; + } + else if (gTasks[taskId].tState == 2) + { + s16 bgId = gTasks[taskId].tBackgroundId; + + if (bgId == -1) + LoadDefaultBg(); + else + LoadMoveBg(bgId); + + BeginHardwarePaletteFade(0xE8, 0, 16, 0, 1); + gTasks[taskId].tState++; + return; + } + if (gPaletteFade.active) + return; + if (gTasks[taskId].tState == 3) + { + DestroyTask(taskId); + sAnimBackgroundFadeState = 0; + } +} + +static void LoadMoveBg(u16 bgId) +{ + if (IsContest()) + { + const void *tilemap = gBattleAnimBackgroundTable[bgId].tilemap; + void *dmaSrc; + void *dmaDest; + + LZDecompressWram(tilemap, gDecompressionBuffer); + sub_80A4720(sub_80A6D94(), (void*)(gDecompressionBuffer), 0x100, 0); + dmaSrc = gDecompressionBuffer; + dmaDest = (void *)(VRAM + 0xD000); + DmaCopy32(3, dmaSrc, dmaDest, 0x800); + LZDecompressVram(gBattleAnimBackgroundTable[bgId].image, (void *)(VRAM + 0x2000)); + LoadCompressedPalette(gBattleAnimBackgroundTable[bgId].palette, sub_80A6D94() * 16, 32); + } + else + { + LZDecompressVram(gBattleAnimBackgroundTable[bgId].tilemap, (void *)(VRAM + 0xD000)); + LZDecompressVram(gBattleAnimBackgroundTable[bgId].image, (void *)(VRAM + 0x8000)); + LoadCompressedPalette(gBattleAnimBackgroundTable[bgId].palette, 32, 32); + } +} + +static void LoadDefaultBg(void) +{ + if (IsContest()) + LoadContestBgAfterMoveAnim(); + else + DrawMainBattleBackground(); +} + +static void ScriptCmd_restorebg(void) +{ + u8 taskId; + + sBattleAnimScriptPtr++; + taskId = CreateTask(Task_FadeToBg, 5); + gTasks[taskId].tBackgroundId = -1; + sAnimBackgroundFadeState = 1; +} + +#undef tBackgroundId +#undef tState + +static void ScriptCmd_waitbgfadeout(void) +{ + if (sAnimBackgroundFadeState == 2) + { + sBattleAnimScriptPtr++; + gAnimFramesToWait = 0; + } + else + { + gAnimFramesToWait = 1; + } +} + +static void ScriptCmd_waitbgfadein(void) +{ + if (sAnimBackgroundFadeState == 0) + { + sBattleAnimScriptPtr++; + gAnimFramesToWait = 0; + } + else + { + gAnimFramesToWait = 1; + } +} + +static void ScriptCmd_changebg(void) +{ + sBattleAnimScriptPtr++; + LoadMoveBg(sBattleAnimScriptPtr[0]); + sBattleAnimScriptPtr++; +} + +s8 BattleAnimAdjustPanning(s8 pan) +{ + if (!IsContest() && gBattleSpritesDataPtr->healthBoxesData[gAnimBankAttacker].flag_x10) + { + if (GetBankSide(gAnimBankAttacker) != SIDE_PLAYER) + pan = PAN_SIDE_OPPONENT; + else + pan = PAN_SIDE_PLAYER; + } + else if (IsContest()) + { + if (gAnimBankAttacker != gAnimBankTarget || gAnimBankAttacker != 2 || pan != PAN_SIDE_OPPONENT) + pan *= -1; + } + else if (GetBankSide(gAnimBankAttacker) == SIDE_PLAYER) + { + if (GetBankSide(gAnimBankTarget) == SIDE_PLAYER) + { + if (pan == PAN_SIDE_OPPONENT) + pan = PAN_SIDE_PLAYER; + else if (pan != PAN_SIDE_PLAYER) + pan *= -1; + } + } + else if (GetBankSide(gAnimBankTarget) == SIDE_OPPONENT) + { + if (pan == PAN_SIDE_PLAYER) + pan = PAN_SIDE_OPPONENT; + } + else + { + pan *= -1; + } + + if (pan > PAN_SIDE_OPPONENT) + pan = PAN_SIDE_OPPONENT; + else if (pan < PAN_SIDE_PLAYER) + pan = PAN_SIDE_PLAYER; + + return pan; +} + +s8 BattleAnimAdjustPanning2(s8 pan) +{ + if (!IsContest() && gBattleSpritesDataPtr->healthBoxesData[gAnimBankAttacker].flag_x10) + { + if (GetBankSide(gAnimBankAttacker) != SIDE_PLAYER) + pan = PAN_SIDE_OPPONENT; + else + pan = PAN_SIDE_PLAYER; + } + else + { + if (GetBankSide(gAnimBankAttacker) != SIDE_PLAYER || IsContest()) + pan = -pan; + } + return pan; +} + +s16 sub_80A52EC(s16 a) +{ + s16 var = a; + + if (var > 63) + var = 63; + else if (var < -64) + var = -64; + + return var; +} + +s16 CalculatePanIncrement(s16 sourcePan, s16 targetPan, s16 incrementPan) +{ + s16 ret; + + if (sourcePan < targetPan) + ret = ((incrementPan < 0) ? -incrementPan : incrementPan); + else if (sourcePan > targetPan) + ret = -((incrementPan < 0) ? -incrementPan : incrementPan); + else + ret = 0; + + return ret; +} + +static void ScriptCmd_playsewithpan(void) +{ + u16 songId; + s8 pan; + + sBattleAnimScriptPtr++; + songId = SCRIPT_READ_16(sBattleAnimScriptPtr); + pan = sBattleAnimScriptPtr[2]; + PlaySE12WithPanning(songId, BattleAnimAdjustPanning(pan)); + sBattleAnimScriptPtr += 3; +} + +static void ScriptCmd_setpan(void) +{ + s8 pan; + + sBattleAnimScriptPtr++; + pan = sBattleAnimScriptPtr[0]; + SE12PanpotControl(BattleAnimAdjustPanning(pan)); + sBattleAnimScriptPtr++; +} + +#define tInitialPan data[0] +#define tTargetPan data[1] +#define tIncrementPan data[2] +#define tFramesToWait data[3] +#define tCurrentPan data[4] +#define tFrameCounter data[8] + +static void ScriptCmd_panse_1B(void) +{ + u16 songNum; + s8 currentPanArg, incrementPan, incrementPanArg, currentPan, targetPan; + u8 framesToWait; + u8 taskId; + + sBattleAnimScriptPtr++; + songNum = SCRIPT_READ_16(sBattleAnimScriptPtr); + currentPanArg = sBattleAnimScriptPtr[2]; + incrementPan = sBattleAnimScriptPtr[3]; + incrementPanArg = sBattleAnimScriptPtr[4]; + framesToWait = sBattleAnimScriptPtr[5]; + + currentPan = BattleAnimAdjustPanning(currentPanArg); + targetPan = BattleAnimAdjustPanning(incrementPan); + incrementPan = CalculatePanIncrement(currentPan, targetPan, incrementPanArg); + taskId = CreateTask(Task_PanFromInitialToTarget, 1); + gTasks[taskId].tInitialPan = currentPan; + gTasks[taskId].tTargetPan = targetPan; + gTasks[taskId].tIncrementPan = incrementPan; + gTasks[taskId].tFramesToWait = framesToWait; + gTasks[taskId].tCurrentPan = currentPan; + + PlaySE12WithPanning(songNum, currentPan); + + gAnimSoundTaskCount++; + sBattleAnimScriptPtr += 6; +} + +void Task_PanFromInitialToTarget(u8 taskId) +{ + bool32 destroyTask = FALSE; + if (gTasks[taskId].tFrameCounter++ >= gTasks[taskId].tFramesToWait) + { + s16 pan; + s16 initialPanning, targetPanning, currentPan, incrementPan; + + gTasks[taskId].tFrameCounter = 0; + initialPanning = gTasks[taskId].tInitialPan; + targetPanning = gTasks[taskId].tTargetPan; + currentPan = gTasks[taskId].tCurrentPan; + incrementPan = gTasks[taskId].tIncrementPan; + pan = currentPan + incrementPan; + gTasks[taskId].tCurrentPan = pan; + + if (incrementPan == 0) // If we're not incrementing, just cancel the task immediately + { + destroyTask = TRUE; + } + else if (initialPanning < targetPanning) // Panning increasing + { + if (pan >= targetPanning) // Target reached + destroyTask = TRUE; + } + else // Panning decreasing + { + if (pan <= targetPanning) // Target reached + destroyTask = TRUE; + } + + if (destroyTask) + { + pan = targetPanning; + DestroyTask(taskId); + gAnimSoundTaskCount--; + } + + SE12PanpotControl(pan); + } +} + +static void ScriptCmd_panse_26(void) +{ + u16 songId; + s8 currentPan, targetPan, incrementPan; + u8 framesToWait; + u8 taskId; + + sBattleAnimScriptPtr++; + songId = SCRIPT_READ_16(sBattleAnimScriptPtr); + currentPan = sBattleAnimScriptPtr[2]; + targetPan = sBattleAnimScriptPtr[3]; + incrementPan = sBattleAnimScriptPtr[4]; + framesToWait = sBattleAnimScriptPtr[5]; + + taskId = CreateTask(Task_PanFromInitialToTarget, 1); + gTasks[taskId].tInitialPan = currentPan; + gTasks[taskId].tTargetPan = targetPan; + gTasks[taskId].tIncrementPan = incrementPan; + gTasks[taskId].tFramesToWait = framesToWait; + gTasks[taskId].tCurrentPan = currentPan; + + PlaySE12WithPanning(songId, currentPan); + + gAnimSoundTaskCount++; + sBattleAnimScriptPtr += 6; +} + +static void ScriptCmd_panse_27(void) +{ + u16 songId; + s8 targetPanArg, incrementPanArg, currentPanArg, currentPan, targetPan, incrementPan; + u8 framesToWait; + u8 taskId; + + sBattleAnimScriptPtr++; + songId = SCRIPT_READ_16(sBattleAnimScriptPtr); + currentPanArg = sBattleAnimScriptPtr[2]; + targetPanArg = sBattleAnimScriptPtr[3]; + incrementPanArg = sBattleAnimScriptPtr[4]; + framesToWait = sBattleAnimScriptPtr[5]; + + currentPan = BattleAnimAdjustPanning2(currentPanArg); + targetPan = BattleAnimAdjustPanning2(targetPanArg); + incrementPan = BattleAnimAdjustPanning2(incrementPanArg); + + taskId = CreateTask(Task_PanFromInitialToTarget, 1); + gTasks[taskId].tInitialPan = currentPan; + gTasks[taskId].tTargetPan = targetPan; + gTasks[taskId].tIncrementPan = incrementPan; + gTasks[taskId].tFramesToWait = framesToWait; + gTasks[taskId].tCurrentPan = currentPan; + + PlaySE12WithPanning(songId, currentPan); + + gAnimSoundTaskCount++; + sBattleAnimScriptPtr += 6; +} + +#undef tInitialPan +#undef tTargetPan +#undef tIncrementPan +#undef tFramesToWait +#undef tCurrentPan +#undef tFrameCounter + +#define tSongId data[0] +#define tPanning data[1] +#define tFramesToWait data[2] +#define tNumberOfPlays data[3] +#define tFrameCounter data[8] + +static void ScriptCmd_loopsewithpan(void) +{ + u16 songId; + s8 panningArg, panning; + u8 framesToWait, numberOfPlays; + u8 taskId; + + sBattleAnimScriptPtr++; + songId = SCRIPT_READ_16(sBattleAnimScriptPtr); + panningArg = sBattleAnimScriptPtr[2]; + framesToWait = sBattleAnimScriptPtr[3]; + numberOfPlays = sBattleAnimScriptPtr[4]; + panning = BattleAnimAdjustPanning(panningArg); + + taskId = CreateTask(Task_LoopAndPlaySE, 1); + gTasks[taskId].tSongId = songId; + gTasks[taskId].tPanning = panning; + gTasks[taskId].tFramesToWait = framesToWait; + gTasks[taskId].tNumberOfPlays = numberOfPlays; + gTasks[taskId].tFrameCounter = framesToWait; + gTasks[taskId].func(taskId); + + gAnimSoundTaskCount++; + sBattleAnimScriptPtr += 5; +} + +static void Task_LoopAndPlaySE(u8 taskId) +{ + if (gTasks[taskId].tFrameCounter++ >= gTasks[taskId].tFramesToWait) + { + u16 songId; + s8 panning; + u8 numberOfPlays; + + gTasks[taskId].tFrameCounter = 0; + songId = gTasks[taskId].tSongId; + panning = gTasks[taskId].tPanning; + numberOfPlays = --gTasks[taskId].tNumberOfPlays; + PlaySE12WithPanning(songId, panning); + if (numberOfPlays == 0) + { + DestroyTask(taskId); + gAnimSoundTaskCount--; + } + } +} + +#undef tSongId +#undef tPanning +#undef tFramesToWait +#undef tNumberOfPlays +#undef tFrameCounter + +#define tSongId data[0] +#define tPanning data[1] +#define tFramesToWait data[2] + +static void ScriptCmd_waitplaysewithpan(void) +{ + u16 songId; + s8 panningArg, panning; + u8 framesToWait; + u8 taskId; + + sBattleAnimScriptPtr++; + songId = SCRIPT_READ_16(sBattleAnimScriptPtr); + panningArg = sBattleAnimScriptPtr[2]; + framesToWait = sBattleAnimScriptPtr[3]; + panning = BattleAnimAdjustPanning(panningArg); + + taskId = CreateTask(Task_WaitAndPlaySE, 1); + gTasks[taskId].tSongId = songId; + gTasks[taskId].tPanning = panning; + gTasks[taskId].tFramesToWait = framesToWait; + + gAnimSoundTaskCount++; + sBattleAnimScriptPtr += 4; +} + +static void Task_WaitAndPlaySE(u8 taskId) +{ + if (gTasks[taskId].tFramesToWait-- <= 0) + { + PlaySE12WithPanning(gTasks[taskId].tSongId, gTasks[taskId].tPanning); + DestroyTask(taskId); + gAnimSoundTaskCount--; + } +} + +#undef tSongId +#undef tPanning +#undef tFramesToWait + +static void ScriptCmd_createsoundtask(void) +{ + TaskFunc func; + u8 numArgs, taskId; + s32 i; + + sBattleAnimScriptPtr++; + func = (TaskFunc)SCRIPT_READ_32(sBattleAnimScriptPtr); + sBattleAnimScriptPtr += 4; + numArgs = sBattleAnimScriptPtr[0]; + sBattleAnimScriptPtr++; + for (i = 0; i < numArgs; i++) + { + gBattleAnimArgs[i] = SCRIPT_READ_16(sBattleAnimScriptPtr); + sBattleAnimScriptPtr += 2; + } + taskId = CreateTask(func, 1); + func(taskId); + gAnimSoundTaskCount++; +} + +static void ScriptCmd_waitsound(void) +{ + if (gAnimSoundTaskCount != 0) + { + sSoundAnimFramesToWait = 0; + gAnimFramesToWait = 1; + } + else if (IsSEPlaying()) + { + if (++sSoundAnimFramesToWait > 90) + { + m4aMPlayStop(&gMPlay_SE1); + m4aMPlayStop(&gMPlay_SE2); + sSoundAnimFramesToWait = 0; + } + else + { + gAnimFramesToWait = 1; + } + } + else + { + sSoundAnimFramesToWait = 0; + sBattleAnimScriptPtr++; + gAnimFramesToWait = 0; + } +} + +static void ScriptCmd_jumpargeq(void) +{ + u8 argId; + s16 valueToCheck; + + sBattleAnimScriptPtr++; + argId = sBattleAnimScriptPtr[0]; + valueToCheck = SCRIPT_READ_16(sBattleAnimScriptPtr + 1); + + if (valueToCheck == gBattleAnimArgs[argId]) + sBattleAnimScriptPtr = SCRIPT_READ_PTR(sBattleAnimScriptPtr + 3); + else + sBattleAnimScriptPtr += 7; +} + +static void ScriptCmd_jumpifcontest(void) +{ + sBattleAnimScriptPtr++; + if (IsContest()) + sBattleAnimScriptPtr = SCRIPT_READ_PTR(sBattleAnimScriptPtr); + else + sBattleAnimScriptPtr += 4; +} + +static void ScriptCmd_monbgprio_28(void) +{ + u8 wantedBank; + u8 bank; + u8 bankIdentity; + + wantedBank = sBattleAnimScriptPtr[1]; + sBattleAnimScriptPtr += 2; + + if (wantedBank != ANIM_BANK_ATTACKER) + bank = gAnimBankTarget; + else + bank = gAnimBankAttacker; + + bankIdentity = GetBankIdentity(bank); + if (!IsContest() && (bankIdentity == IDENTITY_PLAYER_MON1 || bankIdentity == IDENTITY_OPPONENT_MON2)) + { + SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 1); + SetAnimBgAttribute(2, BG_ANIM_PRIORITY, 2); + } +} + +static void ScriptCmd_monbgprio_29(void) +{ + sBattleAnimScriptPtr++; + if (!IsContest()) + { + SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 1); + SetAnimBgAttribute(2, BG_ANIM_PRIORITY, 2); + } +} + +static void ScriptCmd_monbgprio_2A(void) +{ + u8 wantedBank; + u8 bankIdentity; + u8 bank; + + wantedBank = sBattleAnimScriptPtr[1]; + sBattleAnimScriptPtr += 2; + if (GetBankSide(gAnimBankAttacker) != GetBankSide(gAnimBankTarget)) + { + if (wantedBank != ANIM_BANK_ATTACKER) + bank = gAnimBankTarget; + else + bank = gAnimBankAttacker; + + bankIdentity = GetBankIdentity(bank); + if (!IsContest() && (bankIdentity == IDENTITY_PLAYER_MON1 || bankIdentity == IDENTITY_OPPONENT_MON2)) + { + SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 1); + SetAnimBgAttribute(2, BG_ANIM_PRIORITY, 2); + } + } +} + +static void ScriptCmd_invisible(void) +{ + u8 spriteId; + + spriteId = GetAnimBankSpriteId(sBattleAnimScriptPtr[1]); + if (spriteId != 0xFF) + gSprites[spriteId].invisible = 1; + + sBattleAnimScriptPtr += 2; +} + +static void ScriptCmd_visible(void) +{ + u8 spriteId; + + spriteId = GetAnimBankSpriteId(sBattleAnimScriptPtr[1]); + if (spriteId != 0xFF) + gSprites[spriteId].invisible = 0; + + sBattleAnimScriptPtr += 2; +} + +static void ScriptCmd_doublebattle_2D(void) +{ + u8 wantedBank; + u8 r4; + u8 spriteId; + + wantedBank = sBattleAnimScriptPtr[1]; + sBattleAnimScriptPtr += 2; + if (!IsContest() && IsDoubleBattle() + && GetBankSide(gAnimBankAttacker) == GetBankSide(gAnimBankTarget)) + { + if (wantedBank == ANIM_BANK_ATTACKER) + { + r4 = sub_80A8364(gAnimBankAttacker); + spriteId = GetAnimBankSpriteId(0); + } + else + { + r4 = sub_80A8364(gAnimBankTarget); + spriteId = GetAnimBankSpriteId(1); + } + if (spriteId != 0xFF) + { + gSprites[spriteId].invisible = FALSE; + if (r4 == 2) + gSprites[spriteId].oam.priority = 3; + + if (r4 == 1) + sub_80A477C(FALSE); + else + sub_80A477C(TRUE); + } + } +} + +static void ScriptCmd_doublebattle_2E(void) +{ + u8 wantedBank; + u8 r4; + u8 spriteId; + + wantedBank = sBattleAnimScriptPtr[1]; + sBattleAnimScriptPtr += 2; + if (!IsContest() && IsDoubleBattle() + && GetBankSide(gAnimBankAttacker) == GetBankSide(gAnimBankTarget)) + { + if (wantedBank == ANIM_BANK_ATTACKER) + { + r4 = sub_80A8364(gAnimBankAttacker); + spriteId = GetAnimBankSpriteId(0); + } + else + { + r4 = sub_80A8364(gAnimBankTarget); + spriteId = GetAnimBankSpriteId(1); + } + + if (spriteId != 0xFF && r4 == 2) + gSprites[spriteId].oam.priority = 2; + } +} + +static void ScriptCmd_stopsound(void) +{ + m4aMPlayStop(&gMPlay_SE1); + m4aMPlayStop(&gMPlay_SE2); + sBattleAnimScriptPtr++; +} diff --git a/src/battle_controllers.c b/src/battle_controllers.c new file mode 100644 index 000000000..9ac18c72f --- /dev/null +++ b/src/battle_controllers.c @@ -0,0 +1,1551 @@ +#include "global.h" +#include "battle.h" +#include "battle_controllers.h" +#include "link.h" +#include "task.h" +#include "battle_ai_script_commands.h" +#include "battle_anim.h" +#include "pokemon.h" +#include "species.h" +#include "recorded_battle.h" +#include "util.h" +#include "abilities.h" +#include "battle_message.h" + +extern u32 gBattleTypeFlags; +extern u32 gBattleExecBuffer; +extern void (*gBattleMainFunc)(void); +extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void); +extern u8 gBanksByIdentity[BATTLE_BANKS_COUNT]; +extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT]; +extern u8 gMoveSelectionCursor[BATTLE_BANKS_COUNT]; +extern u8 gNoOfAllBanks; +extern u8 gActiveBank; +extern u8 gUnknown_0202428C; +extern u32 gUnknown_02022FF4; +extern u8 gUnknown_0203C7B4; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200]; +extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; +extern u8 gBattleBuffersTransferData[0x100]; +extern u8 gUnknown_02022D08; +extern u8 gUnknown_02022D09; +extern u8 gUnknown_02022D0A; +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern u8 gAbsentBankFlags; +extern u8 gEffectBank; +extern u16 gBattleWeather; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; +extern u16 gCurrentMove; +extern u16 gLastUsedMove; +extern u16 gLastUsedItem; +extern u8 gBattleOutcome; +extern u8 gLastUsedAbility; +extern u8 gStringBank; + +extern const struct BattleMove gBattleMoves[]; + +extern void task00_08081A90(u8 taskId); // cable_club +extern void sub_81B8D64(u8 bank, u8 arg1); // party_menu + +// this file's funcionts +static void CreateTasksForSendRecvLinkBuffers(void); +static void SetControllersVariablesInLinkBattle(void); +static void SetControllersVariables(void); +static void SetBattlePartyIds(void); +static void Task_HandleSendLinkBuffersData(u8 taskId); +static void Task_HandleCopyReceivedLinkBuffersData(u8 taskId); + +void HandleLinkBattleSetup(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + if (gLinkVSyncDisabled) + sub_800B488(); + if (!gReceivedRemoteLinkPlayers) + sub_8009734(); + CreateTask(task00_08081A90, 0); + CreateTasksForSendRecvLinkBuffers(); + } +} + +void SetUpBattleVarsAndBirchZigzagoon(void) +{ + s32 i; + + gBattleMainFunc = nullsub_20; + + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + gBattleBankFunc[i] = nullsub_21; + gBanksByIdentity[i] = 0xFF; + gActionSelectionCursor[i] = 0; + gMoveSelectionCursor[i] = 0; + } + + HandleLinkBattleSetup(); + gBattleExecBuffer = 0; + ClearBattleAnimationVars(); + ClearBattleMonForms(); + BattleAI_HandleItemUseBeforeAISetup(0xF); + + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + ZeroEnemyPartyMons(); + CreateMon(&gEnemyParty[0], SPECIES_ZIGZAGOON, 2, 32, 0, 0, 0, 0); + i = 0; + SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &i); + } + + gUnknown_02022FF4 = 0; + gUnknown_0202428C = 0; +} + +void sub_8032768(void) +{ + s32 i; + u8 *data; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + sub_8184DA4(1); + else + sub_8184DA4(2); + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + sub_8185EB8(); + + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + SetControllersVariablesInLinkBattle(); + else + SetControllersVariables(); + + SetBattlePartyIds(); + + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + for (i = 0; i < gNoOfAllBanks; i++) + sub_81B8D64(i, 0); + } + + for (i = 0; i < sizeof(gBattleStruct->field_1A4); i++) + *(gBattleStruct->field_1A4 + i) = 0; + + for (i = 0; i < sizeof(gBattleStruct->field_204); i++) + *(gBattleStruct->field_204 + i) = 0; +} + +static void SetControllersVariables(void) +{ + s32 i; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + gBattleMainFunc = BeginBattleIntro; + + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + { + gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToPlayerPartnerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + } + else + { + gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToPlayerPartnerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + } + + gNoOfAllBanks = 4; + + sub_81B8D64(0, 0); + sub_81B8D64(1, 0); + sub_81B8D64(2, 1); + sub_81B8D64(3, 1); + + gBattlePartyID[0] = 0; + gBattlePartyID[1] = 0; + gBattlePartyID[2] = 3; + gBattlePartyID[3] = 3; + } + else if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gBattleMainFunc = BeginBattleIntro; + + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + gBattleBankFunc[0] = SetBankFuncToSafariBufferRunCommand; + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) + gBattleBankFunc[0] = SetBankFuncToWallyBufferRunCommand; + else + gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand; + + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gNoOfAllBanks = 2; + + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + { + if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + { + gBattleMainFunc = BeginBattleIntro; + + gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToRecordedOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gNoOfAllBanks = 2; + } + else // see how the banks are switched + { + gBattleBankFunc[1] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[0] = SetBankFuncToRecordedOpponentBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1; + + gNoOfAllBanks = 2; + } + } + else + { + gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + } + } + } + else + { + gBattleMainFunc = BeginBattleIntro; + + gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + + gNoOfAllBanks = 4; + + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + { + gBattleMainFunc = BeginBattleIntro; + + gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[0] = 0; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = 1; + + gBattleBankFunc[2] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[2] = 2; + + gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[3] = 3; + + gNoOfAllBanks = 4; + + sub_81B8D64(0, 0); + sub_81B8D64(1, 0); + sub_81B8D64(2, 1); + sub_81B8D64(3, 1); + + gBattlePartyID[0] = 0; + gBattlePartyID[1] = 0; + gBattlePartyID[2] = 3; + gBattlePartyID[3] = 3; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + u8 var; // multiplayer Id in a recorded battle? + + for (var = gUnknown_0203C7B4, i = 0; i < BATTLE_BANKS_COUNT; i++) + { + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + sub_81B8D64(gLinkPlayers[i].lp_field_18, 0); + break; + case 1: + case 2: + sub_81B8D64(gLinkPlayers[i].lp_field_18, 1); + break; + } + + if (i == var) + { + gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToRecordedPlayerBufferRunCommand; + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = IDENTITY_PLAYER_MON1; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 0; + break; + case 1: + case 2: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = IDENTITY_PLAYER_MON2; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 3; + break; + } + } + 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; + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = IDENTITY_PLAYER_MON1; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 0; + break; + case 1: + case 2: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = IDENTITY_PLAYER_MON2; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 3; + break; + } + } + else + { + gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToRecordedOpponentBufferRunCommand; + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = IDENTITY_OPPONENT_MON1; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 0; + break; + case 1: + case 2: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = IDENTITY_OPPONENT_MON2; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 3; + break; + } + } + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_WILD) + { + gBattleBankFunc[0] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[2] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + gBattleBankFunc[1] = SetBankFuncToRecordedOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[3] = SetBankFuncToRecordedOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + } + else + { + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + } + } + else + { + gBattleBankFunc[1] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[3] = SetBankFuncToRecordedPlayerBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_PLAYER_MON2; + + if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + gBattleBankFunc[0] = SetBankFuncToRecordedOpponentBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToRecordedOpponentBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_OPPONENT_MON2; + } + else + { + gBattleBankFunc[0] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_OPPONENT_MON2; + } + } + } + } +} + +static void SetControllersVariablesInLinkBattle(void) +{ + s32 i; + u8 multiplayerId; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + if (gBattleTypeFlags & BATTLE_TYPE_WILD) + { + gBattleMainFunc = BeginBattleIntro; + + gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gNoOfAllBanks = 2; + } + else + { + gBattleBankFunc[1] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[0] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1; + + gNoOfAllBanks = 2; + } + } + else if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (gBattleTypeFlags & BATTLE_TYPE_WILD) + { + gBattleMainFunc = BeginBattleIntro; + + gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[3] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + + gNoOfAllBanks = 4; + } + else + { + gBattleBankFunc[1] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[0] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[3] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[2] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_OPPONENT_MON2; + + gNoOfAllBanks = 4; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + { + if (gBattleTypeFlags & BATTLE_TYPE_WILD) + { + gBattleMainFunc = BeginBattleIntro; + + gBattleBankFunc[0] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToLinkPartnerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[3] = SetBankFuncToOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + + gNoOfAllBanks = 4; + } + else + { + gBattleBankFunc[0] = SetBankFuncToLinkPartnerBufferRunCommand; + gBanksByIdentity[0] = IDENTITY_PLAYER_MON1; + + gBattleBankFunc[1] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[1] = IDENTITY_OPPONENT_MON1; + + gBattleBankFunc[2] = SetBankFuncToPlayerBufferRunCommand; + gBanksByIdentity[2] = IDENTITY_PLAYER_MON2; + + gBattleBankFunc[3] = SetBankFuncToLinkOpponentBufferRunCommand; + gBanksByIdentity[3] = IDENTITY_OPPONENT_MON2; + + gNoOfAllBanks = 4; + } + + sub_81B8D64(0, 0); + sub_81B8D64(1, 0); + sub_81B8D64(2, 1); + sub_81B8D64(3, 1); + gBattlePartyID[0] = 0; + gBattlePartyID[1] = 0; + gBattlePartyID[2] = 3; + gBattlePartyID[3] = 3; + } + else + { + multiplayerId = GetMultiplayerId(); + + if (gBattleTypeFlags & BATTLE_TYPE_WILD) + gBattleMainFunc = BeginBattleIntro; + + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + sub_81B8D64(gLinkPlayers[i].lp_field_18, 0); + break; + case 1: + case 2: + sub_81B8D64(gLinkPlayers[i].lp_field_18, 1); + break; + } + + if (i == multiplayerId) + { + gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToPlayerBufferRunCommand; + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = 0; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 0; + break; + case 1: + case 2: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = 2; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 3; + break; + } + } + else + { + 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; + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = 0; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 0; + break; + case 1: + case 2: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = 2; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 3; + break; + } + } + else + { + gBattleBankFunc[gLinkPlayers[i].lp_field_18] = SetBankFuncToLinkOpponentBufferRunCommand; + switch (gLinkPlayers[i].lp_field_18) + { + case 0: + case 3: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = 1; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 0; + break; + case 1: + case 2: + gBanksByIdentity[gLinkPlayers[i].lp_field_18] = 3; + gBattlePartyID[gLinkPlayers[i].lp_field_18] = 3; + break; + } + } + } + } + + gNoOfAllBanks = 4; + } +} + +static void SetBattlePartyIds(void) +{ + s32 i, j; + + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + for (i = 0; i < gNoOfAllBanks; i++) + { + for (j = 0; j < 6; j++) + { + if (i < 2) + { + if (GET_BANK_SIDE2(i) == SIDE_PLAYER) + { + if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0 + && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES2) != SPECIES_EGG + && GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG) == 0) + { + gBattlePartyID[i] = j; + break; + } + } + else + { + if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0 + && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_EGG + && GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG) == 0) + { + gBattlePartyID[i] = j; + break; + } + } + } + else + { + if (GET_BANK_SIDE2(i) == SIDE_PLAYER) + { + if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0 + && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES) != SPECIES_NONE // Probably a typo by Game Freak. The rest use SPECIES2. + && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES2) != SPECIES_EGG + && GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG) == 0 + && gBattlePartyID[i - 2] != j) + { + gBattlePartyID[i] = j; + break; + } + } + else + { + if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0 + && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_EGG + && GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG) == 0 + && gBattlePartyID[i - 2] != j) + { + gBattlePartyID[i] = j; + break; + } + } + } + } + } + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + gBattlePartyID[1] = 0, gBattlePartyID[3] = 3; + } +} + +static void PrepareBufferDataTransfer(u8 bufferId, u8 *data, u16 size) +{ + s32 i; + + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + PrepareBufferDataTransferLink(bufferId, size, data); + } + else + { + switch (bufferId) + { + case 0: + for (i = 0; i < size; i++) + { + gBattleBufferA[gActiveBank][i] = *data; + data++; + } + break; + case 1: + for (i = 0; i < size; i++) + { + gBattleBufferB[gActiveBank][i] = *data; + data++; + } + break; + } + } +} + +static void CreateTasksForSendRecvLinkBuffers(void) +{ + gUnknown_02022D08 = CreateTask(Task_HandleSendLinkBuffersData, 0); + gTasks[gUnknown_02022D08].data[11] = 0; + gTasks[gUnknown_02022D08].data[12] = 0; + gTasks[gUnknown_02022D08].data[13] = 0; + gTasks[gUnknown_02022D08].data[14] = 0; + gTasks[gUnknown_02022D08].data[15] = 0; + + gUnknown_02022D09 = CreateTask(Task_HandleCopyReceivedLinkBuffersData, 0); + gTasks[gUnknown_02022D09].data[12] = 0; + gTasks[gUnknown_02022D09].data[13] = 0; + gTasks[gUnknown_02022D09].data[14] = 0; + gTasks[gUnknown_02022D09].data[15] = 0; + + gUnknown_02022D0A = 0; +} + +enum +{ + LINK_BUFF_BUFFER_ID, + LINK_BUFF_ACTIVE_BANK, + LINK_BUFF_ATTACKER, + LINK_BUFF_TARGET, + LINK_BUFF_SIZE_LO, + LINK_BUFF_SIZE_HI, + LINK_BUFF_ABSENT_BANK_FLAGS, + LINK_BUFF_EFFECT_BANK, + LINK_BUFF_DATA +}; + +void PrepareBufferDataTransferLink(u8 bufferId, u16 size, u8 *data) +{ + s32 alignedSize; + s32 i; + + alignedSize = size - size % 4 + 4; + if (gTasks[gUnknown_02022D08].data[14] + alignedSize + LINK_BUFF_DATA + 1 > BATTLE_BUFFER_LINK_SIZE) + { + gTasks[gUnknown_02022D08].data[12] = gTasks[gUnknown_02022D08].data[14]; + gTasks[gUnknown_02022D08].data[14] = 0; + } + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_BUFFER_ID] = bufferId; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_ACTIVE_BANK] = gActiveBank; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_ATTACKER] = gBankAttacker; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_TARGET] = gBankTarget; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_SIZE_LO] = alignedSize; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_SIZE_HI] = (alignedSize & 0x0000FF00) >> 8; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_ABSENT_BANK_FLAGS] = gAbsentBankFlags; + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_EFFECT_BANK] = gEffectBank; + + for (i = 0; i < size; i++) + gLinkBattleSendBuffer[gTasks[gUnknown_02022D08].data[14] + LINK_BUFF_DATA + i] = data[i]; + + gTasks[gUnknown_02022D08].data[14] = gTasks[gUnknown_02022D08].data[14] + alignedSize + LINK_BUFF_DATA; +} + +static void Task_HandleSendLinkBuffersData(u8 taskId) +{ + u16 var; + u16 blockSize; + + switch (gTasks[taskId].data[11]) + { + case 0: + gTasks[taskId].data[10] = 100; + gTasks[taskId].data[11]++; + break; + case 1: + gTasks[taskId].data[10]--; + if (gTasks[taskId].data[10] == 0) + gTasks[taskId].data[11]++; + break; + case 2: + if (gLinkVSyncDisabled) + { + gTasks[taskId].data[11]++; + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + var = 2; + else + var = (gBattleTypeFlags & BATTLE_TYPE_MULTI) ? 4 : 2; + + if (sub_800ABAC() >= var) + { + if (sub_800ABBC()) + { + sub_800A620(); + gTasks[taskId].data[11]++; + } + else + { + gTasks[taskId].data[11]++; + } + } + } + break; + case 3: + if (gTasks[taskId].data[15] != gTasks[taskId].data[14]) + { + if (gTasks[taskId].data[13] == 0) + { + if (gTasks[taskId].data[15] > gTasks[taskId].data[14] + && gTasks[taskId].data[15] == gTasks[taskId].data[12]) + { + gTasks[taskId].data[12] = 0; + gTasks[taskId].data[15] = 0; + } + blockSize = (gLinkBattleSendBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_LO] | (gLinkBattleSendBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_HI] << 8)) + LINK_BUFF_DATA; + SendBlock(bitmask_all_link_players_but_self(), &gLinkBattleSendBuffer[gTasks[taskId].data[15]], blockSize); + gTasks[taskId].data[11]++; + } + else + { + gTasks[taskId].data[13]--; + break; + } + } + break; + case 4: + if (sub_800A520()) + { + blockSize = gLinkBattleSendBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_LO] | (gLinkBattleSendBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_HI] << 8); + gTasks[taskId].data[13] = 1; + gTasks[taskId].data[15] = gTasks[taskId].data[15] + blockSize + LINK_BUFF_DATA; + gTasks[taskId].data[11] = 3; + } + break; + case 5: + gTasks[taskId].data[13]--; + if (gTasks[taskId].data[13] == 0) + { + gTasks[taskId].data[13] = 1; + gTasks[taskId].data[11] = 3; + } + break; + } +} + +// fix me +void sub_8033648(void) +{ + u8 i; + s32 j; + u16 r6; + u8 *recvBuffer; + u8 *dest; + u8 *src; + + if (gReceivedRemoteLinkPlayers != 0 && (gBattleTypeFlags & BATTLE_TYPE_20)) + { + sub_8011BD0(); + for (i = 0; i < GetLinkPlayerCount(); i++) + { + if (GetBlockReceivedStatus() & gBitTable[i]) + { + ResetBlockReceivedFlag(i); + recvBuffer = (u8 *)gBlockRecvBuffer[i]; + #ifndef NONMATCHING + asm(""); + recvBuffer = (u8 *)&gBlockRecvBuffer[i]; + #endif + r6 = gBlockRecvBuffer[i][2]; + + if (gTasks[gUnknown_02022D09].data[14] + 9 + r6 > 0x1000) + { + gTasks[gUnknown_02022D09].data[12] = gTasks[gUnknown_02022D09].data[14]; + gTasks[gUnknown_02022D09].data[14] = 0; + } + + dest = &gLinkBattleRecvBuffer[gTasks[gUnknown_02022D09].data[14]]; + src = recvBuffer; + + for (j = 0; j < r6 + 8; j++) + dest[j] = src[j]; + + gTasks[gUnknown_02022D09].data[14] = gTasks[gUnknown_02022D09].data[14] + r6 + 8; + } + } + } +} + +static void Task_HandleCopyReceivedLinkBuffersData(u8 taskId) +{ + u16 blockSize; + u8 bank; + u8 var; + + if (gTasks[taskId].data[15] != gTasks[taskId].data[14]) + { + if (gTasks[taskId].data[15] > gTasks[taskId].data[14] + && gTasks[taskId].data[15] == gTasks[taskId].data[12]) + { + gTasks[taskId].data[12] = 0; + gTasks[taskId].data[15] = 0; + } + bank = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + LINK_BUFF_ACTIVE_BANK]; + blockSize = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_LO] | (gLinkBattleRecvBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_HI] << 8); + + switch (gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 0]) + { + case 0: + if (gBattleExecBuffer & gBitTable[bank]) + return; + + memcpy(gBattleBufferA[bank], &gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 8], blockSize); + sub_803F850(bank); + + if (!(gBattleTypeFlags & BATTLE_TYPE_WILD)) + { + gBankAttacker = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 2]; + gBankTarget = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 3]; + gAbsentBankFlags = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 6]; + gEffectBank = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 7]; + } + break; + case 1: + memcpy(gBattleBufferB[bank], &gLinkBattleRecvBuffer[gTasks[taskId].data[15] + 8], blockSize); + break; + case 2: + var = gLinkBattleRecvBuffer[gTasks[taskId].data[15] + LINK_BUFF_DATA]; + gBattleExecBuffer &= ~(gBitTable[bank] << (var * 4)); + break; + } + + gTasks[taskId].data[15] = gTasks[taskId].data[15] + blockSize + LINK_BUFF_DATA; + } +} + +void EmitGetMonData(u8 bufferId, u8 arg1, u8 arg2) +{ + gBattleBuffersTransferData[0] = CONTROLLER_GETMONDATA; + gBattleBuffersTransferData[1] = arg1; + gBattleBuffersTransferData[2] = arg2; + gBattleBuffersTransferData[3] = 0; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitGetRawMonData(u8 bufferId, u8 monId, u8 bytes) +{ + gBattleBuffersTransferData[0] = CONTROLLER_GETRAWMONDATA; + gBattleBuffersTransferData[1] = monId; + gBattleBuffersTransferData[2] = bytes; + gBattleBuffersTransferData[3] = 0; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitSetMonData(u8 bufferId, u8 request, u8 c, u8 bytes, void *data) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_SETMONDATA; + gBattleBuffersTransferData[1] = request; + gBattleBuffersTransferData[2] = c; + for (i = 0; i < bytes; i++) + gBattleBuffersTransferData[3 + i] = *(u8*)(data++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 3 + bytes); +} + +void EmitSetRawMonData(u8 bufferId, u8 monId, u8 bytes, void *data) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_SETRAWMONDATA; + gBattleBuffersTransferData[1] = monId; + gBattleBuffersTransferData[2] = bytes; + for (i = 0; i < bytes; i++) + gBattleBuffersTransferData[3 + i] = *(u8*)(data++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, bytes + 3); +} + +void EmitLoadMonSprite(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_LOADMONSPRITE; + gBattleBuffersTransferData[1] = 4; + gBattleBuffersTransferData[2] = 4; + gBattleBuffersTransferData[3] = 4; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitSwitchInAnim(u8 bufferId, u8 partyId, bool8 dontClearSubstituteBit) +{ + gBattleBuffersTransferData[0] = CONTROLLER_SWITCHINANIM; + gBattleBuffersTransferData[1] = partyId; + gBattleBuffersTransferData[2] = dontClearSubstituteBit; + gBattleBuffersTransferData[3] = 5; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitReturnMonToBall(u8 bufferId, u8 arg1) +{ + gBattleBuffersTransferData[0] = CONTROLLER_RETURNMONTOBALL; + gBattleBuffersTransferData[1] = arg1; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2); +} + +void EmitDrawTrainerPic(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_DRAWTRAINERPIC; + gBattleBuffersTransferData[1] = 7; + gBattleBuffersTransferData[2] = 7; + gBattleBuffersTransferData[3] = 7; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitTrainerSlide(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_TRAINERSLIDE; + gBattleBuffersTransferData[1] = 8; + gBattleBuffersTransferData[2] = 8; + gBattleBuffersTransferData[3] = 8; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitTrainerSlideBack(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_TRAINERSLIDEBACK; + gBattleBuffersTransferData[1] = 9; + gBattleBuffersTransferData[2] = 9; + gBattleBuffersTransferData[3] = 9; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitFaintAnimation(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_FAINTANIMATION; + gBattleBuffersTransferData[1] = 10; + gBattleBuffersTransferData[2] = 10; + gBattleBuffersTransferData[3] = 10; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd11(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_11; + gBattleBuffersTransferData[1] = 11; + gBattleBuffersTransferData[2] = 11; + gBattleBuffersTransferData[3] = 11; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd12(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_12; + gBattleBuffersTransferData[1] = 12; + gBattleBuffersTransferData[2] = 12; + gBattleBuffersTransferData[3] = 12; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitBallThrow(u8 bufferId, u8 caseId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_BALLTHROW; + gBattleBuffersTransferData[1] = caseId; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2); +} + +void EmitPause(u8 bufferId, u8 toWait, void *data) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_PAUSE; + gBattleBuffersTransferData[1] = toWait; + for (i = 0; i < toWait * 3; i++) + gBattleBuffersTransferData[2 + i] = *(u8*)(data++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, toWait * 3 + 2); +} + +void EmitMoveAnimation(u8 bufferId, u16 move, u8 turnOfMove, u16 movePower, s32 dmg, u8 friendship, struct DisableStruct *disableStructPtr, u8 multihit) +{ + gBattleBuffersTransferData[0] = CONTROLLER_MOVEANIMATION; + gBattleBuffersTransferData[1] = move; + gBattleBuffersTransferData[2] = (move & 0xFF00) >> 8; + gBattleBuffersTransferData[3] = turnOfMove; + gBattleBuffersTransferData[4] = movePower; + gBattleBuffersTransferData[5] = (movePower & 0xFF00) >> 8; + gBattleBuffersTransferData[6] = dmg; + gBattleBuffersTransferData[7] = (dmg & 0x0000FF00) >> 8; + gBattleBuffersTransferData[8] = (dmg & 0x00FF0000) >> 16; + gBattleBuffersTransferData[9] = (dmg & 0xFF000000) >> 24; + gBattleBuffersTransferData[10] = friendship; + gBattleBuffersTransferData[11] = multihit; + if (WEATHER_HAS_EFFECT2) + { + gBattleBuffersTransferData[12] = gBattleWeather; + gBattleBuffersTransferData[13] = (gBattleWeather & 0xFF00) >> 8; + } + else + { + gBattleBuffersTransferData[12] = 0; + gBattleBuffersTransferData[13] = 0; + } + gBattleBuffersTransferData[14] = 0; + gBattleBuffersTransferData[15] = 0; + memcpy(&gBattleBuffersTransferData[16], disableStructPtr, sizeof(struct DisableStruct)); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 16 + sizeof(struct DisableStruct)); +} + +void EmitPrintString(u8 bufferId, u16 stringID) +{ + s32 i; + struct StringInfoBattle* stringInfo; + + gBattleBuffersTransferData[0] = CONTROLLER_PRINTSTRING; + gBattleBuffersTransferData[1] = gBattleOutcome; + gBattleBuffersTransferData[2] = stringID; + gBattleBuffersTransferData[3] = (stringID & 0xFF00) >> 8; + + stringInfo = (struct StringInfoBattle*)(&gBattleBuffersTransferData[4]); + stringInfo->currentMove = gCurrentMove; + stringInfo->lastMove = gLastUsedMove; + stringInfo->lastItem = gLastUsedItem; + stringInfo->lastAbility = gLastUsedAbility; + stringInfo->scrActive = gBattleScripting.bank; + stringInfo->unk1605E = gBattleStruct->field_52; + stringInfo->hpScale = gBattleStruct->hpScale; + stringInfo->StringBank = gStringBank; + stringInfo->moveType = gBattleMoves[gCurrentMove].type; + + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + stringInfo->abilities[i] = gBattleMons[i].ability; + for (i = 0; i < TEXT_BUFF_ARRAY_COUNT; i++) + { + stringInfo->textBuffs[0][i] = gBattleTextBuff1[i]; + stringInfo->textBuffs[1][i] = gBattleTextBuff2[i]; + stringInfo->textBuffs[2][i] = gBattleTextBuff3[i]; + } + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, sizeof(struct StringInfoBattle) + 4); +} + +void EmitPrintStringPlayerOnly(u8 bufferId, u16 stringID) +{ + s32 i; + struct StringInfoBattle* stringInfo; + + gBattleBuffersTransferData[0] = CONTROLLER_PRINTSTRINGPLAYERONLY; + gBattleBuffersTransferData[1] = 17; + gBattleBuffersTransferData[2] = stringID; + gBattleBuffersTransferData[3] = (stringID & 0xFF00) >> 8; + + stringInfo = (struct StringInfoBattle*)(&gBattleBuffersTransferData[4]); + stringInfo->currentMove = gCurrentMove; + stringInfo->lastMove = gLastUsedMove; + stringInfo->lastItem = gLastUsedItem; + stringInfo->lastAbility = gLastUsedAbility; + stringInfo->scrActive = gBattleScripting.bank; + stringInfo->unk1605E = gBattleStruct->field_52; + + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + stringInfo->abilities[i] = gBattleMons[i].ability; + for (i = 0; i < TEXT_BUFF_ARRAY_COUNT; i++) + { + stringInfo->textBuffs[0][i] = gBattleTextBuff1[i]; + stringInfo->textBuffs[1][i] = gBattleTextBuff2[i]; + stringInfo->textBuffs[2][i] = gBattleTextBuff3[i]; + } + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, sizeof(struct StringInfoBattle) + 4); +} + +void EmitChooseAction(u8 bufferId, u8 arg1, u16 arg2) +{ + gBattleBuffersTransferData[0] = CONTROLLER_CHOOSEACTION; + gBattleBuffersTransferData[1] = arg1; + gBattleBuffersTransferData[2] = arg2; + gBattleBuffersTransferData[3] = (arg2 & 0xFF00) >> 8; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd19(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_19; + gBattleBuffersTransferData[1] = 19; + gBattleBuffersTransferData[2] = 19; + gBattleBuffersTransferData[3] = 19; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitChooseMove(u8 bufferId, bool8 isDoubleBattle, bool8 NoPpNumber, struct ChooseMoveStruct *movePpData) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_CHOOSEMOVE; + gBattleBuffersTransferData[1] = isDoubleBattle; + gBattleBuffersTransferData[2] = NoPpNumber; + gBattleBuffersTransferData[3] = 0; + for (i = 0; i < sizeof(*movePpData); i++) + gBattleBuffersTransferData[4 + i] = *((u8*)(movePpData) + i); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, sizeof(*movePpData) + 4); +} + +void EmitOpenBag(u8 bufferId, u8 *arg1) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_OPENBAG; + for (i = 0; i < 3; i++) + gBattleBuffersTransferData[1 + i] = arg1[i]; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitChoosePokemon(u8 bufferId, u8 caseId, u8 arg2, u8 abilityId, u8* arg4) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_CHOOSEPOKEMON; + gBattleBuffersTransferData[1] = caseId; + gBattleBuffersTransferData[2] = arg2; + gBattleBuffersTransferData[3] = abilityId; + for (i = 0; i < 3; i++) + gBattleBuffersTransferData[4 + i] = arg4[i]; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 8); // but only 7 bytes were written +} + +void EmitCmd23(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_23; + gBattleBuffersTransferData[1] = 23; + gBattleBuffersTransferData[2] = 23; + gBattleBuffersTransferData[3] = 23; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +// why is the argument u16 if it's being cast to s16 anyway? +void EmitHealthBarUpdate(u8 bufferId, u16 hpValue) +{ + gBattleBuffersTransferData[0] = CONTROLLER_HEALTHBARUPDATE; + gBattleBuffersTransferData[1] = 0; + gBattleBuffersTransferData[2] = (s16)hpValue; + gBattleBuffersTransferData[3] = ((s16)hpValue & 0xFF00) >> 8; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +// why is the argument u16 if it's being cast to s16 anyway? +void EmitExpUpdate(u8 bufferId, u8 partyId, u16 expPoints) +{ + gBattleBuffersTransferData[0] = CONTROLLER_EXPUPDATE; + gBattleBuffersTransferData[1] = partyId; + gBattleBuffersTransferData[2] = (s16)expPoints; + gBattleBuffersTransferData[3] = ((s16)expPoints & 0xFF00) >> 8; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitStatusIconUpdate(u8 bufferId, u32 status1, u32 status2) +{ + gBattleBuffersTransferData[0] = CONTROLLER_STATUSICONUPDATE; + gBattleBuffersTransferData[1] = status1; + gBattleBuffersTransferData[2] = (status1 & 0x0000FF00) >> 8; + gBattleBuffersTransferData[3] = (status1 & 0x00FF0000) >> 16; + gBattleBuffersTransferData[4] = (status1 & 0xFF000000) >> 24; + gBattleBuffersTransferData[5] = status2; + gBattleBuffersTransferData[6] = (status2 & 0x0000FF00) >> 8; + gBattleBuffersTransferData[7] = (status2 & 0x00FF0000) >> 16; + gBattleBuffersTransferData[8] = (status2 & 0xFF000000) >> 24; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 9); +} + +void EmitStatusAnimation(u8 bufferId, bool8 status2, u32 status) +{ + gBattleBuffersTransferData[0] = CONTROLLER_STATUSANIMATION; + gBattleBuffersTransferData[1] = status2; + gBattleBuffersTransferData[2] = status; + gBattleBuffersTransferData[3] = (status & 0x0000FF00) >> 8; + gBattleBuffersTransferData[4] = (status & 0x00FF0000) >> 16; + gBattleBuffersTransferData[5] = (status & 0xFF000000) >> 24; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 6); +} + +void EmitStatusXor(u8 bufferId, u8 b) +{ + gBattleBuffersTransferData[0] = CONTROLLER_STATUSXOR; + gBattleBuffersTransferData[1] = b; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2); +} + +void EmitDataTransfer(u8 bufferId, u16 size, void *data) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_DATATRANSFER; + gBattleBuffersTransferData[1] = 29; + gBattleBuffersTransferData[2] = size; + gBattleBuffersTransferData[3] = (size & 0xFF00) >> 8; + for (i = 0; i < size; i++) + gBattleBuffersTransferData[4 + i] = *(u8*)(data++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, size + 4); +} + +void EmitDMA3Transfer(u8 bufferId, void *dst, u16 size, void *data) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_DMA3TRANSFER; + gBattleBuffersTransferData[1] = (u32)(dst); + gBattleBuffersTransferData[2] = ((u32)(dst) & 0x0000FF00) >> 8; + gBattleBuffersTransferData[3] = ((u32)(dst) & 0x00FF0000) >> 16; + gBattleBuffersTransferData[4] = ((u32)(dst) & 0xFF000000) >> 24; + gBattleBuffersTransferData[5] = size; + gBattleBuffersTransferData[6] = (size & 0xFF00) >> 8; + for (i = 0; i < size; i++) + gBattleBuffersTransferData[7 + i] = *(u8*)(data++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, size + 7); +} + +void EmitPlayBGM(u8 bufferId, u16 songId, void *unusedDumbDataParameter) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_31; + gBattleBuffersTransferData[1] = songId; + gBattleBuffersTransferData[2] = (songId & 0xFF00) >> 8; + for (i = 0; i < songId; i++) // ???? + gBattleBuffersTransferData[3 + i] = *(u8*)(unusedDumbDataParameter++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, songId + 3); +} + +void EmitCmd32(u8 bufferId, u16 size, void *data) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_32; + gBattleBuffersTransferData[1] = size; + gBattleBuffersTransferData[2] = (size & 0xFF00) >> 8; + for (i = 0; i < size; i++) + gBattleBuffersTransferData[3 + i] = *(u8*)(data++); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, size + 3); +} + +void EmitCmd33(u8 bufferId, u8 arg1, u16 arg2) +{ + gBattleBuffersTransferData[0] = CONTROLLER_33; + gBattleBuffersTransferData[1] = arg1; + gBattleBuffersTransferData[2] = arg2; + gBattleBuffersTransferData[3] = (arg2 & 0xFF00) >> 8; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd34(u8 bufferId, u8 b, u8 *c) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_34; + gBattleBuffersTransferData[1] = b; + for (i = 0; i < 3; i++) + gBattleBuffersTransferData[2 + i] = c[i]; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 5); +} + +void EmitCmd35(u8 bufferId, u16 b) +{ + gBattleBuffersTransferData[0] = CONTROLLER_35; + gBattleBuffersTransferData[1] = b; + gBattleBuffersTransferData[2] = (b & 0xFF00) >> 8; + gBattleBuffersTransferData[3] = 0; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd36(u8 bufferId, u16 b) +{ + gBattleBuffersTransferData[0] = CONTROLLER_36; + gBattleBuffersTransferData[1] = b; + gBattleBuffersTransferData[2] = (b & 0xFF00) >> 8; + gBattleBuffersTransferData[3] = 0; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd37(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_37; + gBattleBuffersTransferData[1] = 37; + gBattleBuffersTransferData[2] = 37; + gBattleBuffersTransferData[3] = 37; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd38(u8 bufferId, u8 b) +{ + gBattleBuffersTransferData[0] = CONTROLLER_38; + gBattleBuffersTransferData[1] = b; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2); +} + +void EmitCmd39(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_39; + gBattleBuffersTransferData[1] = 39; + gBattleBuffersTransferData[2] = 39; + gBattleBuffersTransferData[3] = 39; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd40(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_40; + gBattleBuffersTransferData[1] = 40; + gBattleBuffersTransferData[2] = 40; + gBattleBuffersTransferData[3] = 40; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitHitAnimation(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_HITANIMATION; + gBattleBuffersTransferData[1] = 41; + gBattleBuffersTransferData[2] = 41; + gBattleBuffersTransferData[3] = 41; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd42(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_42; + gBattleBuffersTransferData[1] = 42; + gBattleBuffersTransferData[2] = 42; + gBattleBuffersTransferData[3] = 42; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitEffectivenessSound(u8 bufferId, u16 songId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_EFFECTIVENESSSOUND; + gBattleBuffersTransferData[1] = songId; + gBattleBuffersTransferData[2] = (songId & 0xFF00) >> 8; + gBattleBuffersTransferData[3] = 0; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitPlayFanfareOrBGM(u8 bufferId, u16 songId, bool8 playBGM) +{ + gBattleBuffersTransferData[0] = CONTROLLER_PLAYFANFAREORBGM; + gBattleBuffersTransferData[1] = songId; + gBattleBuffersTransferData[2] = (songId & 0xFF00) >> 8; + gBattleBuffersTransferData[3] = playBGM; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitFaintingCry(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_FAINTINGCRY; + gBattleBuffersTransferData[1] = 45; + gBattleBuffersTransferData[2] = 45; + gBattleBuffersTransferData[3] = 45; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitIntroSlide(u8 bufferId, u8 terrainId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_INTROSLIDE; + gBattleBuffersTransferData[1] = terrainId; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2); +} + +void EmitIntroTrainerBallThrow(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_INTROTRAINERBALLTHROW; + gBattleBuffersTransferData[1] = 47; + gBattleBuffersTransferData[2] = 47; + gBattleBuffersTransferData[3] = 47; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitDrawPartyStatusSummary(u8 bufferId, struct HpAndStatus* hpAndStatus, u8 arg2) +{ + s32 i; + + gBattleBuffersTransferData[0] = CONTROLLER_DRAWPARTYSTATUSSUMMARY; + gBattleBuffersTransferData[1] = arg2 & 0x7F; + gBattleBuffersTransferData[2] = (arg2 & 0x80) >> 7; + gBattleBuffersTransferData[3] = 48; + for (i = 0; i < (s32)(sizeof(struct HpAndStatus) * 6); i++) + gBattleBuffersTransferData[4 + i] = *(i + (u8*)(hpAndStatus)); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, sizeof(struct HpAndStatus) * 6 + 4); +} + +void EmitCmd49(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_49; + gBattleBuffersTransferData[1] = 49; + gBattleBuffersTransferData[2] = 49; + gBattleBuffersTransferData[3] = 49; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitCmd50(u8 bufferId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_50; + gBattleBuffersTransferData[1] = 50; + gBattleBuffersTransferData[2] = 50; + gBattleBuffersTransferData[3] = 50; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitSpriteInvisibility(u8 bufferId, bool8 isInvisible) +{ + gBattleBuffersTransferData[0] = CONTROLLER_SPRITEINVISIBILITY; + gBattleBuffersTransferData[1] = isInvisible; + gBattleBuffersTransferData[2] = 51; + gBattleBuffersTransferData[3] = 51; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitBattleAnimation(u8 bufferId, u8 animationId, u16 argument) +{ + gBattleBuffersTransferData[0] = CONTROLLER_BATTLEANIMATION; + gBattleBuffersTransferData[1] = animationId; + gBattleBuffersTransferData[2] = argument; + gBattleBuffersTransferData[3] = (argument & 0xFF00) >> 8; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 4); +} + +void EmitLinkStandbyMsg(u8 bufferId, u8 arg1, bool32 arg2) +{ + bool8 arg2_ = arg2; + gBattleBuffersTransferData[0] = CONTROLLER_LINKSTANDBYMSG; + gBattleBuffersTransferData[1] = arg1; + + if (arg2_) + gBattleBuffersTransferData[3] = gBattleBuffersTransferData[2] = sub_81850DC(&gBattleBuffersTransferData[4]); + else + gBattleBuffersTransferData[3] = gBattleBuffersTransferData[2] = 0; + + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, gBattleBuffersTransferData[2] + 4); +} + +void EmitResetActionMoveSelection(u8 bufferId, u8 caseId) +{ + gBattleBuffersTransferData[0] = CONTROLLER_RESETACTIONMOVESELECTION; + gBattleBuffersTransferData[1] = caseId; + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, 2); +} + +void EmitCmd55(u8 bufferId, u8 arg1) +{ + gBattleBuffersTransferData[0] = CONTROLLER_55; + gBattleBuffersTransferData[1] = arg1; + gBattleBuffersTransferData[2] = gSaveBlock2Ptr->field_CA9_b; + gBattleBuffersTransferData[3] = gSaveBlock2Ptr->field_CA9_b; + gBattleBuffersTransferData[5] = gBattleBuffersTransferData[4] = sub_81850DC(&gBattleBuffersTransferData[6]); + PrepareBufferDataTransfer(bufferId, gBattleBuffersTransferData, gBattleBuffersTransferData[4] + 6); +} diff --git a/src/battle_interface.c b/src/battle_interface.c new file mode 100644 index 000000000..9241db1d9 --- /dev/null +++ b/src/battle_interface.c @@ -0,0 +1,2632 @@ +#include "global.h" +#include "battle.h" +#include "pokemon.h" +#include "battle_controllers.h" +#include "battle_interface.h" +#include "sprite.h" +#include "window.h" +#include "string_util.h" +#include "text.h" +#include "sound.h" +#include "songs.h" +#include "decompress.h" +#include "task.h" +#include "util.h" +#include "gpu_regs.h" +#include "battle_message.h" +#include "species.h" +#include "pokedex.h" +#include "palette.h" +#include "international_string_util.h" +#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; + u32 unkC_0:5; + u32 unk10; +}; + +enum +{ + HEALTHBOX_GFX_0, + HEALTHBOX_GFX_1, + HEALTHBOX_GFX_2, + HEALTHBOX_GFX_3, + HEALTHBOX_GFX_4, + HEALTHBOX_GFX_5, + HEALTHBOX_GFX_6, + HEALTHBOX_GFX_7, + HEALTHBOX_GFX_8, + HEALTHBOX_GFX_9, + HEALTHBOX_GFX_10, + HEALTHBOX_GFX_11, + HEALTHBOX_GFX_12, + HEALTHBOX_GFX_13, + HEALTHBOX_GFX_14, + HEALTHBOX_GFX_15, + HEALTHBOX_GFX_16, + HEALTHBOX_GFX_17, + HEALTHBOX_GFX_18, + HEALTHBOX_GFX_19, + HEALTHBOX_GFX_20, + HEALTHBOX_GFX_STATUS_PSN_BANK0, + HEALTHBOX_GFX_22, + HEALTHBOX_GFX_23, + HEALTHBOX_GFX_STATUS_PRZ_BANK0, + HEALTHBOX_GFX_25, + HEALTHBOX_GFX_26, + HEALTHBOX_GFX_STATUS_SLP_BANK0, + HEALTHBOX_GFX_28, + HEALTHBOX_GFX_29, + HEALTHBOX_GFX_STATUS_FRZ_BANK0, + HEALTHBOX_GFX_31, + HEALTHBOX_GFX_32, + HEALTHBOX_GFX_STATUS_BRN_BANK0, + HEALTHBOX_GFX_34, + HEALTHBOX_GFX_35, + HEALTHBOX_GFX_36, + HEALTHBOX_GFX_37, + HEALTHBOX_GFX_38, + HEALTHBOX_GFX_39, + HEALTHBOX_GFX_40, + HEALTHBOX_GFX_41, + HEALTHBOX_GFX_42, + HEALTHBOX_GFX_43, + HEALTHBOX_GFX_44, + HEALTHBOX_GFX_45, + HEALTHBOX_GFX_46, + HEALTHBOX_GFX_47, + HEALTHBOX_GFX_48, + HEALTHBOX_GFX_49, + HEALTHBOX_GFX_50, + HEALTHBOX_GFX_51, + HEALTHBOX_GFX_52, + HEALTHBOX_GFX_53, + HEALTHBOX_GFX_54, + HEALTHBOX_GFX_55, + HEALTHBOX_GFX_56, + HEALTHBOX_GFX_57, + HEALTHBOX_GFX_58, + HEALTHBOX_GFX_59, + HEALTHBOX_GFX_60, + HEALTHBOX_GFX_61, + HEALTHBOX_GFX_62, + HEALTHBOX_GFX_63, + HEALTHBOX_GFX_64, + HEALTHBOX_GFX_65, + HEALTHBOX_GFX_66, + HEALTHBOX_GFX_67, + HEALTHBOX_GFX_68, + HEALTHBOX_GFX_69, + HEALTHBOX_GFX_70, + HEALTHBOX_GFX_STATUS_PSN_BANK1, + HEALTHBOX_GFX_72, + HEALTHBOX_GFX_73, + HEALTHBOX_GFX_STATUS_PRZ_BANK1, + HEALTHBOX_GFX_75, + HEALTHBOX_GFX_76, + HEALTHBOX_GFX_STATUS_SLP_BANK1, + HEALTHBOX_GFX_78, + HEALTHBOX_GFX_79, + HEALTHBOX_GFX_STATUS_FRZ_BANK1, + HEALTHBOX_GFX_81, + HEALTHBOX_GFX_82, + HEALTHBOX_GFX_STATUS_BRN_BANK1, + HEALTHBOX_GFX_84, + HEALTHBOX_GFX_85, + HEALTHBOX_GFX_STATUS_PSN_BANK2, + HEALTHBOX_GFX_87, + HEALTHBOX_GFX_88, + HEALTHBOX_GFX_STATUS_PRZ_BANK2, + HEALTHBOX_GFX_90, + HEALTHBOX_GFX_91, + HEALTHBOX_GFX_STATUS_SLP_BANK2, + HEALTHBOX_GFX_93, + HEALTHBOX_GFX_94, + HEALTHBOX_GFX_STATUS_FRZ_BANK2, + HEALTHBOX_GFX_96, + HEALTHBOX_GFX_97, + HEALTHBOX_GFX_STATUS_BRN_BANK2, + HEALTHBOX_GFX_99, + HEALTHBOX_GFX_100, + HEALTHBOX_GFX_STATUS_PSN_BANK3, + HEALTHBOX_GFX_102, + HEALTHBOX_GFX_103, + HEALTHBOX_GFX_STATUS_PRZ_BANK3, + HEALTHBOX_GFX_105, + HEALTHBOX_GFX_106, + HEALTHBOX_GFX_STATUS_SLP_BANK3, + HEALTHBOX_GFX_108, + HEALTHBOX_GFX_109, + HEALTHBOX_GFX_STATUS_FRZ_BANK3, + HEALTHBOX_GFX_111, + HEALTHBOX_GFX_112, + HEALTHBOX_GFX_STATUS_BRN_BANK3, + HEALTHBOX_GFX_114, + HEALTHBOX_GFX_115, + HEALTHBOX_GFX_116, + HEALTHBOX_GFX_117, +}; + +extern u8 gBanksByIdentity[BATTLE_BANKS_COUNT]; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gNoOfAllBanks; +extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT]; + +extern const u8 * const gNatureNamePointers[]; +extern const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1]; + +// strings +extern const u8 gText_Slash[]; +extern const u8 gText_HighlightDarkGrey[]; +extern const u8 gText_DynColor2[]; +extern const u8 gText_DynColor2Male[]; +extern const u8 gText_DynColor1Female[]; +extern const u8 gText_SafariBalls[]; +extern const u8 gText_SafariBallLeft[]; + +// graphics +extern const u8 gBattleInterface_BallStatusBarGfx[]; +extern const u8 gBattleInterface_BallDisplayGfx[]; +extern const u16 gBattleInterface_BallStatusBarPal[]; +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); + +// this file's functions + +static const u8 *GetHealthboxElementGfxPtr(u8 elementId); +static u8* AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 arg3, u32 *windowId); + +static void RemoveWindowOnHealthbox(u32 windowId); +static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent); +static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId); + +static void sub_8075198(void *dest, u8 *windowTileData, s32 arg2); +static void sub_80751E4(void *dest, u8 *windowTileData, u32 arg2); +static void sub_8075170(void *dest, u8 *windowTileData, u32 arg2); +static void sub_807513C(void *dest, u32 arg1, u32 arg2); + +static void sub_8073E08(u8 taskId); +static void sub_8073F98(u8 taskId); +static void sub_8073E64(u8 taskId); + +static void sub_8072924(struct Sprite *sprite); +static void sub_80728B4(struct Sprite *sprite); +static void sub_8074158(struct Sprite *sprite); +static void sub_8074090(struct Sprite *sprite); +static void SpriteCB_StatusSummaryBar(struct Sprite *sprite); +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 void sub_8074B9C(u8 bank, u8 whichBar); +static u8 sub_8074E8C(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 *arg4, u8 arg5); +static void sub_8074F88(struct TestingBar *barInfo, s32 *arg1, u16 *arg2); + +// const rom data +static const struct OamData sUnknown_0832C138 = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 1, + .x = 0, + .matrixNum = 0, + .size = 3, + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteTemplate sHealthboxPlayerSpriteTemplates[2] = +{ + { + .tileTag = TAG_HEALTHBOX_PLAYER1_TILE, + .paletteTag = TAG_HEALTHBOX_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + }, + { + .tileTag = TAG_HEALTHBOX_PLAYER2_TILE, + .paletteTag = TAG_HEALTHBOX_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + } +}; + +static const struct SpriteTemplate sHealthboxOpponentSpriteTemplates[2] = +{ + { + .tileTag = TAG_HEALTHBOX_OPPONENT1_TILE, + .paletteTag = TAG_HEALTHBOX_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + }, + { + .tileTag = TAG_HEALTHBOX_OPPONENT2_TILE, + .paletteTag = TAG_HEALTHBOX_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + } +}; + +static const struct SpriteTemplate sHealthboxSafariSpriteTemplate = +{ + .tileTag = TAG_HEALTHBOX_SAFARI_TILE, + .paletteTag = TAG_HEALTHBOX_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy +}; + +static const struct OamData sUnknown_0832C1B8 = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 1, + .x = 0, + .matrixNum = 0, + .size = 1, + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteTemplate sUnknown_0832C1C0[4] = +{ + { + .tileTag = 0xd704, + .paletteTag = 0xd704, + .oam = &sUnknown_0832C1B8, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = sub_80728B4 + }, + { + .tileTag = 0xd705, + .paletteTag = 0xd704, + .oam = &sUnknown_0832C1B8, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = sub_80728B4 + }, + { + .tileTag = 0xd706, + .paletteTag = 0xd704, + .oam = &sUnknown_0832C1B8, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = sub_80728B4 + }, + { + .tileTag = 0xd707, + .paletteTag = 0xd704, + .oam = &sUnknown_0832C1B8, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = sub_80728B4 + } +}; + +static const struct Subsprite sUnknown_0832C220[] = +{ + {240, 0, 1, 3, 0, 1}, + {48, 0, 0, 2, 32, 1}, + {240, 32, 1, 1, 48, 1}, + {16, 32, 1, 1, 52, 1}, + {48, 32, 1, 1, 56, 1} +}; + +static const struct Subsprite sUnknown_0832C234[] = +{ + {240, 0, 1, 3, 64, 1}, + {48, 0, 0, 2, 96, 1}, + {240, 32, 1, 1, 112, 1}, + {16, 32, 1, 1, 116, 1}, + {48, 32, 1, 1, 120, 1} +}; + +static const struct Subsprite sUnknown_0832C248[] = +{ + {240, 0, 1, 3, 0, 1}, + {48, 0, 0, 2, 32, 1} +}; + +static const struct Subsprite sUnknown_0832C250[] = +{ + {240, 0, 1, 3, 0, 1}, + {48, 0, 0, 2, 32, 1} +}; + +static const struct Subsprite sUnknown_0832C258[] = +{ + {240, 0, 1, 1, 0, 1}, + {16, 0, 1, 1, 4, 1} +}; + +static const struct Subsprite sUnknown_0832C260[] = +{ + {240, 0, 1, 1, 0, 1}, + {16, 0, 1, 1, 4, 1}, + {224, 0, 0, 0, 8, 1} +}; + +// unused subsprite table +static const struct SubspriteTable sUnknown_0832C26C[] = +{ + {ARRAY_COUNT(sUnknown_0832C220), sUnknown_0832C220}, + {ARRAY_COUNT(sUnknown_0832C248), sUnknown_0832C248}, + {ARRAY_COUNT(sUnknown_0832C234), sUnknown_0832C234}, + {ARRAY_COUNT(sUnknown_0832C250), sUnknown_0832C250} +}; + +static const struct SubspriteTable sUnknown_0832C28C[] = +{ + {ARRAY_COUNT(sUnknown_0832C258), sUnknown_0832C258}, + {ARRAY_COUNT(sUnknown_0832C260), sUnknown_0832C260} +}; + +static const struct Subsprite sStatusSummaryBar_Subsprites_0[] = +{ + {160, 0, 1, 1, 0, 1}, + {192, 0, 1, 1, 4, 1}, + {224, 0, 1, 1, 8, 1}, + {0, 0, 1, 1, 12, 1} +}; + +static const struct Subsprite sUnknown_0832C2AC[] = +{ + {160, 0, 1, 1, 0, 1}, + {192, 0, 1, 1, 4, 1}, + {224, 0, 1, 1, 8, 1}, + {0, 0, 1, 1, 8, 1}, + {32, 0, 1, 1, 8, 1}, + {64, 0, 1, 1, 12, 1} +}; + +static const struct SubspriteTable sStatusSummaryBar_SubspriteTable[] = +{ + {ARRAY_COUNT(sStatusSummaryBar_Subsprites_0), sStatusSummaryBar_Subsprites_0} +}; + +static const struct SubspriteTable sUnknown_0832C2CC[] = +{ + {ARRAY_COUNT(sUnknown_0832C2AC), sUnknown_0832C2AC} +}; + +// unused unknown image +static const u8 sUnknown_0832C2D4[] = INCBIN_U8("graphics/battle_interface/unknown_32C2D4.4bpp"); + +static const struct CompressedSpriteSheet sStatusSummaryBarSpriteSheet = +{ + gBattleInterface_BallStatusBarGfx, 0x200, TAG_STATUS_SUMMARY_BAR_TILE +}; + +static const struct SpritePalette sStatusSummaryBarSpritePal = +{ + gBattleInterface_BallStatusBarPal, TAG_STATUS_SUMMARY_BAR_PAL +}; + +static const struct SpritePalette sStatusSummaryBallsSpritePal = +{ + gBattleInterface_BallDisplayPal, TAG_STATUS_SUMMARY_BALLS_PAL +}; + +static const struct SpriteSheet sStatusSummaryBallsSpriteSheet = +{ + gBattleInterface_BallDisplayGfx, 0x80, TAG_STATUS_SUMMARY_BALLS_TILE +}; + +// unused oam data +static const struct OamData sUnknown_0832C354 = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 1, + .x = 0, + .matrixNum = 0, + .size = 3, + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct OamData sOamData_StatusSummaryBalls = +{ + .y = 0, + .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 struct SpriteTemplate sStatusSummaryBarSpriteTemplates[2] = +{ + { + .tileTag = TAG_STATUS_SUMMARY_BAR_TILE, + .paletteTag = TAG_STATUS_SUMMARY_BAR_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_StatusSummaryBar + }, + { + .tileTag = TAG_STATUS_SUMMARY_BAR_TILE, + .paletteTag = TAG_STATUS_SUMMARY_BAR_PAL, + .oam = &sUnknown_0832C138, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_StatusSummaryBar + } +}; + +static const struct SpriteTemplate sStatusSummaryBallsSpriteTemplates[2] = +{ + { + .tileTag = TAG_STATUS_SUMMARY_BALLS_TILE, + .paletteTag = TAG_STATUS_SUMMARY_BALLS_PAL, + .oam = &sOamData_StatusSummaryBalls, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_StatusSummaryBallsOnBattleStart + }, + { + .tileTag = TAG_STATUS_SUMMARY_BALLS_TILE, + .paletteTag = TAG_STATUS_SUMMARY_BALLS_PAL, + .oam = &sOamData_StatusSummaryBalls, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_StatusSummaryBallsOnBattleStart + } +}; + +// possibly text +static const u8 sUnknown_0832C3C4[] = +{ + 0xfc, 0x01, 0x01, 0xfc, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +// possibly text +static const u8 sUnknown_0832C3D8[] = +{ + 0xfc, 0x01, 0x01, 0xfc, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +enum +{ + PAL_STATUS_PSN, + PAL_STATUS_PAR, + PAL_STATUS_SLP, + PAL_STATUS_FRZ, + PAL_STATUS_BRN +}; + +static const u16 sStatusIconPalettes[] = +{ + 0x6198, // PAL_STATUS_PSN + 0xEF7, // PAL_STATUS_PAR + 0x4694, // PAL_STATUS_SLP + 0x72D1, // PAL_STATUS_FRZ + 0x29DC // PAL_STATUS_BRN +}; + +static const struct WindowTemplate sHealthboxWindowTemplate = {0, 0, 0, 8, 2, 0, 0}; // width = 8, height = 2 + +// code + +static s32 DummiedOutFunction(s16 unused1, s16 unused2, s32 unused3) +{ + return 9; +} + +#ifdef NONMATCHING +static void sub_8072308(s16 arg0, u16 *arg1, u8 arg2) +{ + s8 i, j; + u8 array[4]; + u8 *arrayPtr; + s32 r9, vaaa; + + for (i = 0; i < 4; i++) + array[i] = 0; + + i = 3; + r9 = -1; + arrayPtr = array; + while (1) + { + if (arg0 > 0) + { + array[i] = arg0 % 10; + arg0 = arg0 / 10; + i--; + } + else + { + break; + } + } + + for (; i > -1; i--) + { + array[i] = 0xFF; + } + + if (arrayPtr[3] == 0xFF) + arrayPtr[3] = 0; + + if (arg2 == 0) + { + for (i = 0, j = 0; i < 4; i++) + { + if (array[j] == 0xFF) + { + arg1[j] &= 0xFC00; + arg1[j] |= 0x1E; + + arg1[i + 0x20] &= 0xFC00; + arg1[i + 0x20] |= 0x1E; + } + else + { + arg1[j] &= 0xFC00; + arg1[j] |= array[j] + 0x14; + + arg1[i + 0x20] &= 0xFC00; + arg1[i + 0x20] |= array[i] + 0x34; + } + j++; + } + } + else + { + for (i = 0; i < 4; i++) + { + if (array[i] == 0xFF) + { + arg1[i] &= 0xFC00; + arg1[i] |= 0x1E; + + arg1[i + 0x20] &= 0xFC00; + arg1[i + 0x20] |= 0x1E; + } + else + { + arg1[i] &= 0xFC00; + arg1[i] |= array[i] + 0x14; + + arg1[i + 0x20] &= 0xFC00; + arg1[i + 0x20] |= array[i] + 0x34; + } + } + } +} + +#else +__attribute__((naked)) +static void sub_8072308(s16 arg0, u16 *arg1, u8 arg2) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x4\n\ + adds r7, r1, 0\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ + lsls r2, 24\n\ + lsrs r2, 24\n\ + mov r10, r2\n\ + movs r3, 0\n\ + movs r2, 0\n\ +_08072324:\n\ + lsls r0, r3, 24\n\ + asrs r0, 24\n\ + mov r3, sp\n\ + adds r1, r3, r0\n\ + strb r2, [r1]\n\ + adds r0, 0x1\n\ + lsls r0, 24\n\ + lsrs r3, r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0x3\n\ + ble _08072324\n\ + movs r3, 0x3\n\ + movs r0, 0x1\n\ + negs r0, r0\n\ + mov r9, r0\n\ + mov r8, sp\n\ +_08072344:\n\ + lsls r0, r5, 16\n\ + asrs r6, r0, 16\n\ + cmp r6, 0\n\ + ble _08072372\n\ + lsls r4, r3, 24\n\ + asrs r4, 24\n\ + mov r1, sp\n\ + adds r5, r1, r4\n\ + adds r0, r6, 0\n\ + movs r1, 0xA\n\ + bl __modsi3\n\ + strb r0, [r5]\n\ + adds r0, r6, 0\n\ + movs r1, 0xA\n\ + bl __divsi3\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ + subs r4, 0x1\n\ + lsls r4, 24\n\ + lsrs r3, r4, 24\n\ + b _08072344\n\ +_08072372:\n\ + lsls r1, r3, 24\n\ + asrs r0, r1, 24\n\ + cmp r0, r9\n\ + ble _08072396\n\ + movs r4, 0xFF\n\ + movs r3, 0x1\n\ + negs r3, r3\n\ +_08072380:\n\ + asrs r2, r1, 24\n\ + mov r5, sp\n\ + adds r1, r5, r2\n\ + ldrb r0, [r1]\n\ + orrs r0, r4\n\ + strb r0, [r1]\n\ + subs r2, 0x1\n\ + lsls r1, r2, 24\n\ + asrs r0, r1, 24\n\ + cmp r0, r3\n\ + bgt _08072380\n\ +_08072396:\n\ + mov r1, r8\n\ + ldrb r0, [r1, 0x3]\n\ + cmp r0, 0xFF\n\ + bne _080723A2\n\ + movs r0, 0\n\ + strb r0, [r1, 0x3]\n\ +_080723A2:\n\ + mov r2, r10\n\ + cmp r2, 0\n\ + bne _08072432\n\ + movs r3, 0\n\ + movs r1, 0\n\ + movs r6, 0xFC\n\ + lsls r6, 8\n\ + movs r5, 0x1E\n\ + mov r12, r5\n\ +_080723B4:\n\ + lsls r1, 24\n\ + asrs r2, r1, 24\n\ + mov r0, sp\n\ + adds r5, r0, r2\n\ + ldrb r0, [r5]\n\ + mov r8, r1\n\ + cmp r0, 0xFF\n\ + bne _080723EA\n\ + lsls r1, r2, 1\n\ + adds r1, r7\n\ + ldrh r2, [r1]\n\ + adds r0, r6, 0\n\ + ands r0, r2\n\ + mov r2, r12\n\ + orrs r0, r2\n\ + strh r0, [r1]\n\ + lsls r3, 24\n\ + asrs r1, r3, 23\n\ + adds r1, r7\n\ + adds r1, 0x40\n\ + ldrh r2, [r1]\n\ + adds r0, r6, 0\n\ + ands r0, r2\n\ + mov r5, r12\n\ + orrs r0, r5\n\ + strh r0, [r1]\n\ + b _0807241A\n\ +_080723EA:\n\ + lsls r2, 1\n\ + adds r2, r7\n\ + ldrh r0, [r2]\n\ + adds r1, r6, 0\n\ + ands r1, r0\n\ + ldrb r0, [r5]\n\ + adds r0, 0x14\n\ + orrs r1, r0\n\ + strh r1, [r2]\n\ + lsls r4, r3, 24\n\ + asrs r3, r4, 24\n\ + lsls r2, r3, 1\n\ + adds r2, r7\n\ + adds r2, 0x40\n\ + ldrh r0, [r2]\n\ + adds r1, r6, 0\n\ + ands r1, r0\n\ + mov r5, sp\n\ + adds r0, r5, r3\n\ + ldrb r0, [r0]\n\ + adds r0, 0x34\n\ + orrs r1, r0\n\ + strh r1, [r2]\n\ + adds r3, r4, 0\n\ +_0807241A:\n\ + movs r0, 0x80\n\ + lsls r0, 17\n\ + add r0, r8\n\ + lsrs r1, r0, 24\n\ + movs r2, 0x80\n\ + lsls r2, 17\n\ + adds r0, r3, r2\n\ + lsrs r3, r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0x3\n\ + ble _080723B4\n\ + b _08072496\n\ +_08072432:\n\ + movs r3, 0\n\ + movs r4, 0xFC\n\ + lsls r4, 8\n\ + movs r6, 0x1E\n\ +_0807243A:\n\ + lsls r1, r3, 24\n\ + asrs r2, r1, 24\n\ + mov r3, sp\n\ + adds r5, r3, r2\n\ + ldrb r0, [r5]\n\ + adds r3, r1, 0\n\ + cmp r0, 0xFF\n\ + bne _08072466\n\ + lsls r1, r2, 1\n\ + adds r1, r7\n\ + ldrh r2, [r1]\n\ + adds r0, r4, 0\n\ + ands r0, r2\n\ + orrs r0, r6\n\ + strh r0, [r1]\n\ + adds r1, 0x40\n\ + ldrh r2, [r1]\n\ + adds r0, r4, 0\n\ + ands r0, r2\n\ + orrs r0, r6\n\ + strh r0, [r1]\n\ + b _08072488\n\ +_08072466:\n\ + lsls r2, 1\n\ + adds r2, r7\n\ + ldrh r0, [r2]\n\ + adds r1, r4, 0\n\ + ands r1, r0\n\ + ldrb r0, [r5]\n\ + adds r0, 0x14\n\ + orrs r1, r0\n\ + strh r1, [r2]\n\ + adds r2, 0x40\n\ + ldrh r0, [r2]\n\ + adds r1, r4, 0\n\ + ands r1, r0\n\ + ldrb r0, [r5]\n\ + adds r0, 0x34\n\ + orrs r1, r0\n\ + strh r1, [r2]\n\ +_08072488:\n\ + movs r5, 0x80\n\ + lsls r5, 17\n\ + adds r0, r3, r5\n\ + lsrs r3, r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0x3\n\ + ble _0807243A\n\ +_08072496:\n\ + add sp, 0x4\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +void sub_80724A8(s16 arg0, s16 arg1, u16 *arg2) +{ + arg2[4] = 0x1E; + sub_8072308(arg1, arg2, 0); + sub_8072308(arg0, arg2 + 5, 1); +} + +// because the healthbox is too large to fit into one sprite, it is divided into two sprites +// healthboxSpriteId_1 or healthboxSpriteId refers to the 'main' healthbox +// healthboxSpriteId_2 refers to the other part +// there's also one other sprite that appears to be a black square? dont fully understand its role + +u8 CreateBankHealthboxSprites(u8 bank) +{ + s16 data6 = 0; + u8 healthboxSpriteId_1, healthboxSpriteId_2; + u8 unkSpriteId; + struct Sprite *unkSpritePtr; + + if (!IsDoubleBattle()) + { + if (GetBankSide(bank) == SIDE_PLAYER) + { + healthboxSpriteId_1 = CreateSprite(&sHealthboxPlayerSpriteTemplates[0], 240, 160, 1); + healthboxSpriteId_2 = CreateSpriteAtEnd(&sHealthboxPlayerSpriteTemplates[0], 240, 160, 1); + + gSprites[healthboxSpriteId_1].oam.shape = 0; + + gSprites[healthboxSpriteId_2].oam.shape = 0; + gSprites[healthboxSpriteId_2].oam.tileNum += 64; + } + else + { + healthboxSpriteId_1 = CreateSprite(&sHealthboxOpponentSpriteTemplates[0], 240, 160, 1); + healthboxSpriteId_2 = CreateSpriteAtEnd(&sHealthboxOpponentSpriteTemplates[0], 240, 160, 1); + + gSprites[healthboxSpriteId_2].oam.tileNum += 32; + + data6 = 2; + } + gSprites[healthboxSpriteId_1].oam.affineParam = healthboxSpriteId_2; + gSprites[healthboxSpriteId_2].data5 = healthboxSpriteId_1; + gSprites[healthboxSpriteId_2].callback = sub_8072924; + } + else + { + if (GetBankSide(bank) == SIDE_PLAYER) + { + healthboxSpriteId_1 = CreateSprite(&sHealthboxPlayerSpriteTemplates[GetBankIdentity(bank) / 2], 240, 160, 1); + healthboxSpriteId_2 = CreateSpriteAtEnd(&sHealthboxPlayerSpriteTemplates[GetBankIdentity(bank) / 2], 240, 160, 1); + + gSprites[healthboxSpriteId_1].oam.affineParam = healthboxSpriteId_2; + + gSprites[healthboxSpriteId_2].data5 = healthboxSpriteId_1; + gSprites[healthboxSpriteId_2].oam.tileNum += 32; + gSprites[healthboxSpriteId_2].callback = sub_8072924; + + data6 = 1; + } + else + { + healthboxSpriteId_1 = CreateSprite(&sHealthboxOpponentSpriteTemplates[GetBankIdentity(bank) / 2], 240, 160, 1); + healthboxSpriteId_2 = CreateSpriteAtEnd(&sHealthboxOpponentSpriteTemplates[GetBankIdentity(bank) / 2], 240, 160, 1); + + gSprites[healthboxSpriteId_1].oam.affineParam = healthboxSpriteId_2; + + gSprites[healthboxSpriteId_2].data5 = healthboxSpriteId_1; + gSprites[healthboxSpriteId_2].oam.tileNum += 32; + gSprites[healthboxSpriteId_2].callback = sub_8072924; + + data6 = 2; + } + } + + unkSpriteId = CreateSpriteAtEnd(&sUnknown_0832C1C0[gBanksByIdentity[bank]], 140, 60, 0); + unkSpritePtr = &gSprites[unkSpriteId]; + SetSubspriteTables(unkSpritePtr, &sUnknown_0832C28C[GetBankSide(bank)]); + unkSpritePtr->subspriteMode = 2; + unkSpritePtr->oam.priority = 1; + + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_1), (void*)(OBJ_VRAM0 + unkSpritePtr->oam.tileNum * 32), 64); + + gSprites[healthboxSpriteId_1].data5 = unkSpriteId; + gSprites[healthboxSpriteId_1].data6 = bank; + gSprites[healthboxSpriteId_1].invisible = 1; + + gSprites[healthboxSpriteId_2].invisible = 1; + + unkSpritePtr->data5 = healthboxSpriteId_1; + unkSpritePtr->data6 = data6; + unkSpritePtr->invisible = 1; + + return healthboxSpriteId_1; +} + +u8 CreateSafariPlayerHealthboxSprites(void) +{ + u8 healthboxSpriteId_1, healthboxSpriteId_2; + + healthboxSpriteId_1 = CreateSprite(&sHealthboxSafariSpriteTemplate, 240, 160, 1); + healthboxSpriteId_2 = CreateSpriteAtEnd(&sHealthboxSafariSpriteTemplate, 240, 160, 1); + + gSprites[healthboxSpriteId_1].oam.shape = 0; + gSprites[healthboxSpriteId_2].oam.shape = 0; + + gSprites[healthboxSpriteId_2].oam.tileNum += 64; + + gSprites[healthboxSpriteId_1].oam.affineParam = healthboxSpriteId_2; + gSprites[healthboxSpriteId_2].data5 = healthboxSpriteId_1; + + gSprites[healthboxSpriteId_2].callback = sub_8072924; + + return healthboxSpriteId_1; +} + +static const u8 *GetHealthboxElementGfxPtr(u8 elementId) +{ + return gHealthboxElementsGfxTable[elementId]; +} + +static void sub_80728B4(struct Sprite *sprite) +{ + u8 var = sprite->data5; + + switch (sprite->data6) + { + case 0: + sprite->pos1.x = gSprites[var].pos1.x + 16; + sprite->pos1.y = gSprites[var].pos1.y; + break; + case 1: + sprite->pos1.x = gSprites[var].pos1.x + 16; + sprite->pos1.y = gSprites[var].pos1.y; + break; + case 2: + default: + sprite->pos1.x = gSprites[var].pos1.x + 8; + sprite->pos1.y = gSprites[var].pos1.y; + break; + } + + sprite->pos2.x = gSprites[var].pos2.x; + sprite->pos2.y = gSprites[var].pos2.y; +} + +static void sub_8072924(struct Sprite *sprite) +{ + u8 otherSpriteId = sprite->data5; + + sprite->pos1.x = gSprites[otherSpriteId].pos1.x + 64; + sprite->pos1.y = gSprites[otherSpriteId].pos1.y; + + sprite->pos2.x = gSprites[otherSpriteId].pos2.x; + sprite->pos2.y = gSprites[otherSpriteId].pos2.y; +} + +void SetBattleBarStruct(u8 bank, u8 healthboxSpriteId, s32 maxVal, s32 currVal, s32 field_C) +{ + 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].field_10 = -32768; +} + +void SetHealthboxSpriteInvisible(u8 healthboxSpriteId) +{ + gSprites[healthboxSpriteId].invisible = 1; + gSprites[gSprites[healthboxSpriteId].data5].invisible = 1; + gSprites[gSprites[healthboxSpriteId].oam.affineParam].invisible = 1; +} + +void SetHealthboxSpriteVisible(u8 healthboxSpriteId) +{ + gSprites[healthboxSpriteId].invisible = 0; + gSprites[gSprites[healthboxSpriteId].data5].invisible = 0; + gSprites[gSprites[healthboxSpriteId].oam.affineParam].invisible = 0; +} + +static void UpdateSpritePos(u8 spriteId, s16 x, s16 y) +{ + gSprites[spriteId].pos1.x = x; + gSprites[spriteId].pos1.y = y; +} + +void DestoryHealthboxSprite(u8 healthboxSpriteId) +{ + DestroySprite(&gSprites[gSprites[healthboxSpriteId].oam.affineParam]); + DestroySprite(&gSprites[gSprites[healthboxSpriteId].data5]); + DestroySprite(&gSprites[healthboxSpriteId]); +} + +void DummyBattleInterfaceFunc(u8 healthboxSpriteId, bool8 isDoubleBattleBankOnly) +{ + +} + +void UpdateOamPriorityInAllHealthboxes(u8 priority) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + u8 healthboxSpriteId_1 = gHealthBoxesIds[i]; + u8 healthboxSpriteId_2 = gSprites[gHealthBoxesIds[i]].oam.affineParam; + u8 healthboxSpriteId_3 = gSprites[gHealthBoxesIds[i]].data5; + + gSprites[healthboxSpriteId_1].oam.priority = priority; + gSprites[healthboxSpriteId_2].oam.priority = priority; + gSprites[healthboxSpriteId_3].oam.priority = priority; + } +} + +void SetBankHealthboxSpritePos(u8 bank) +{ + s16 x = 0, y = 0; + + if (!IsDoubleBattle()) + { + if (GetBankSide(bank) != SIDE_PLAYER) + x = 44, y = 30; + else + x = 158, y = 88; + } + else + { + switch (GetBankIdentity(bank)) + { + case IDENTITY_PLAYER_MON1: + x = 159, y = 76; + break; + case IDENTITY_PLAYER_MON2: + x = 171, y = 101; + break; + case IDENTITY_OPPONENT_MON1: + x = 44, y = 19; + break; + case IDENTITY_OPPONENT_MON2: + x = 32, y = 44; + break; + } + } + + UpdateSpritePos(gHealthBoxesIds[bank], x, y); +} + +static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl) +{ + u32 windowId, spriteTileNum; + u8 *windowTileData; + u8 text[16]; + u32 xPos, var1; + void *objVram; + + text[0] = 0xF9; + text[1] = 5; + + xPos = (u32) ConvertIntToDecimalStringN(text + 2, lvl, STR_CONV_MODE_LEFT_ALIGN, 3); + // Alright, that part was unmatchable. It's basically doing: + // xPos = 5 * (3 - (u32)(&text[2])); + xPos--; + xPos--; + xPos -= ((u32)(text)); + var1 = (3 - xPos); + xPos = 4 * var1; + xPos += var1; + + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, xPos, 3, 2, &windowId); + spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * 32; + + if (GetBankSide(gSprites[healthboxSpriteId].data6) == SIDE_PLAYER) + { + objVram = (void*)(OBJ_VRAM0); + if (!IsDoubleBattle()) + objVram += spriteTileNum + 0x820; + else + objVram += spriteTileNum + 0x420; + } + else + { + objVram = (void*)(OBJ_VRAM0); + objVram += spriteTileNum + 0x400; + } + sub_8075198(objVram, windowTileData, 3); + RemoveWindowOnHealthbox(windowId); +} + +void UpdateHpTextInHealthbox(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent) +{ + u32 windowId, spriteTileNum; + u8 *windowTileData; + u8 text[32]; + void *objVram; + + if (GetBankSide(gSprites[healthboxSpriteId].data6) == SIDE_PLAYER && !IsDoubleBattle()) + { + spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * 32; + if (maxOrCurrent != HP_CURRENT) // singles, max + { + ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 0, 5, 2, &windowId); + objVram = (void*)(OBJ_VRAM0); + objVram += spriteTileNum + 0xB40; + sub_8075170(objVram, windowTileData, 2); + RemoveWindowOnHealthbox(windowId); + } + else // singles, current + { + ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + text[3] = CHAR_SLASH; + text[4] = EOS; + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 4, 5, 2, &windowId); + objVram = (void*)(OBJ_VRAM0); + objVram += spriteTileNum + 0x3E0; + sub_8075170(objVram, windowTileData, 1); + objVram = (void*)(OBJ_VRAM0); + objVram += spriteTileNum + 0xB00; + sub_8075170(objVram, windowTileData + 0x20, 2); + RemoveWindowOnHealthbox(windowId); + } + + } + else + { + u8 bank; + + memcpy(text, sUnknown_0832C3C4, sizeof(sUnknown_0832C3C4)); + bank = gSprites[healthboxSpriteId].data6; + if (IsDoubleBattle() == TRUE || GetBankSide(bank) == SIDE_OPPONENT) + { + UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, value, maxOrCurrent); + } + else + { + u32 var; + u8 i; + + if (GetBankSide(gSprites[healthboxSpriteId].data6) == SIDE_PLAYER) + { + if (maxOrCurrent == HP_CURRENT) + var = 29; + else + var = 89; + } + else + { + if (maxOrCurrent == HP_CURRENT) + var = 20; + else + var = 48; + } + + ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + RenderTextFont9(gMonSpritesGfxPtr->fontPixels, 9, text); + + for (i = 0; i < 3; i++) + { + CpuCopy32(&gMonSpritesGfxPtr->fontPixels[i * 64 + 32], + (void*)((OBJ_VRAM0) + 32 * (gSprites[healthboxSpriteId].oam.tileNum + var + i)), + 0x20); + } + } + } +} + +static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent) +{ + u32 windowId, spriteTileNum; + u8 *windowTileData; + u8 text[32]; + void *objVram; + + if (GetBankSide(gSprites[healthboxSpriteId].data6) == SIDE_PLAYER) + { + if (gBattleSpritesDataPtr->bankData[gSprites[healthboxSpriteId].data6].hpNumbersNoBars) // don't print text if only bars are visible + { + spriteTileNum = gSprites[gSprites[healthboxSpriteId].data5].oam.tileNum * 32; + objVram = (void*)(OBJ_VRAM0) + spriteTileNum; + + if (maxOrCurrent != HP_CURRENT) // doubles, max hp + { + ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 0, 5, 0, &windowId); + sub_8075170((void*)(OBJ_VRAM0) + spriteTileNum + 0xC0, windowTileData, 2); + RemoveWindowOnHealthbox(windowId); + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_116), + (void*)(OBJ_VRAM0 + 0x680) + (gSprites[healthboxSpriteId].oam.tileNum * 32), + 0x20); + } + else + { + ConvertIntToDecimalStringN(text, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + text[3] = CHAR_SLASH; + text[4] = EOS; + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, 4, 5, 0, &windowId); + sub_807513C(objVram, 0, 3); + sub_8075170((void*)(OBJ_VRAM0 + 0x60) + spriteTileNum, windowTileData, 3); + RemoveWindowOnHealthbox(windowId); + } + } + } + else + { + u8 bank; + + memcpy(text, sUnknown_0832C3D8, sizeof(sUnknown_0832C3D8)); + bank = gSprites[healthboxSpriteId].data6; + + if (gBattleSpritesDataPtr->bankData[bank].hpNumbersNoBars) // don't print text if only bars are visible + { + u8 var = 4; + u8 r7; + u8 *txtPtr; + u8 i; + + if (maxOrCurrent == HP_CURRENT) + var = 0; + + r7 = gSprites[healthboxSpriteId].data5; + txtPtr = ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + if (!maxOrCurrent) + StringCopy(txtPtr, gText_Slash); + RenderTextFont9(gMonSpritesGfxPtr->fontPixels, 9, text); + + for (i = var; i < var + 3; i++) + { + if (i < 3) + { + CpuCopy32(&gMonSpritesGfxPtr->fontPixels[((i - var) * 64) + 32], + (void*)((OBJ_VRAM0) + 32 * (1 + gSprites[r7].oam.tileNum + i)), + 0x20); + } + else + { + CpuCopy32(&gMonSpritesGfxPtr->fontPixels[((i - var) * 64) + 32], + (void*)((OBJ_VRAM0 + 0x20) + 32 * (i + gSprites[r7].oam.tileNum)), + 0x20); + } + } + + if (maxOrCurrent == HP_CURRENT) + { + CpuCopy32(&gMonSpritesGfxPtr->fontPixels[224], + (void*)((OBJ_VRAM0) + ((gSprites[r7].oam.tileNum + 4) * 32)), + 0x20); + CpuFill32(0, (void*)((OBJ_VRAM0) + (gSprites[r7].oam.tileNum * 32)), 0x20); + } + else + { + if (GetBankSide(bank) == SIDE_PLAYER) // impossible to reach part, because the bank is from the opponent's side + { + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_116), + (void*)(OBJ_VRAM0) + ((gSprites[healthboxSpriteId].oam.tileNum + 52) * 32), + 0x20); + } + } + } + } +} + +static void sub_80730D4(u8 healthboxSpriteId, struct Pokemon *mon) +{ + u8 text[20]; + s32 j, var2; + u8 *fontPixels; + u8 i, var, nature, healthboxSpriteId_2; + + memcpy(text, sUnknown_0832C3C4, sizeof(sUnknown_0832C3C4)); + fontPixels = &gMonSpritesGfxPtr->fontPixels[0x520 + (GetBankIdentity(gSprites[healthboxSpriteId].data6) * 384)]; + var = 5; + nature = GetNature(mon); + StringCopy(text + 6, gNatureNamePointers[nature]); + RenderTextFont9(fontPixels, 9, text); + + for (j = 6, i = 0; i < var; i++, j++) + { + u8 elementId; + + if ((text[j] >= 55 && text[j] <= 74) || (text[j] >= 135 && text[j] <= 154)) + elementId = 44; + else if ((text[j] >= 75 && text[j] <= 79) || (text[j] >= 155 && text[j] <= 159)) + elementId = 45; + else + elementId = 43; + + CpuCopy32(GetHealthboxElementGfxPtr(elementId), fontPixels + (i * 64), 0x20); + } + + for (j = 1; j < var + 1; j++) + { + var2 = (gSprites[healthboxSpriteId].oam.tileNum + (j - (j / 8 * 8)) + (j / 8 * 64)) * 32; + CpuCopy32(fontPixels, (void*)(OBJ_VRAM0) + (var2), 0x20); + fontPixels += 0x20; + + var2 = (8 + gSprites[healthboxSpriteId].oam.tileNum + (j - (j / 8 * 8)) + (j / 8 * 64)) * 32; + CpuCopy32(fontPixels, (void*)(OBJ_VRAM0) + (var2), 0x20); + fontPixels += 0x20; + } + + healthboxSpriteId_2 = gSprites[healthboxSpriteId].data5; + ConvertIntToDecimalStringN(text + 6, gBattleStruct->field_7C, STR_CONV_MODE_RIGHT_ALIGN, 2); + ConvertIntToDecimalStringN(text + 9, gBattleStruct->field_7B, STR_CONV_MODE_RIGHT_ALIGN, 2); + text[5] = CHAR_SPACE; + text[8] = CHAR_SLASH; + RenderTextFont9(gMonSpritesGfxPtr->fontPixels, 9, text); + + j = healthboxSpriteId_2; // needed to match for some reason + for (j = 0; j < 5; j++) + { + if (j <= 1) + { + CpuCopy32(&gMonSpritesGfxPtr->fontPixels[0x40 * j + 0x20], + (void*)(OBJ_VRAM0) + (gSprites[healthboxSpriteId_2].oam.tileNum + 2 + j) * 32, + 32); + } + else + { + CpuCopy32(&gMonSpritesGfxPtr->fontPixels[0x40 * j + 0x20], + (void*)(OBJ_VRAM0 + 0xC0) + (j + gSprites[healthboxSpriteId_2].oam.tileNum) * 32, + 32); + } + } +} + +void SwapHpBarsWithHpText(void) +{ + s32 i; + u8 spriteId; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gSprites[gHealthBoxesIds[i]].callback == SpriteCallbackDummy + && GetBankSide(i) != SIDE_OPPONENT + && (IsDoubleBattle() || GetBankSide(i) != SIDE_PLAYER)) + { + bool8 noBars; + + gBattleSpritesDataPtr->bankData[i].hpNumbersNoBars ^= 1; + noBars = gBattleSpritesDataPtr->bankData[i].hpNumbersNoBars; + if (GetBankSide(i) == SIDE_PLAYER) + { + if (!IsDoubleBattle()) + continue; + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + continue; + + if (noBars == TRUE) // bars to text + { + spriteId = gSprites[gHealthBoxesIds[i]].data5; + + CpuFill32(0, (void*)(OBJ_VRAM0 + gSprites[spriteId].oam.tileNum * 32), 0x100); + UpdateHpTextInHealthboxInDoubles(gHealthBoxesIds[i], GetMonData(&gPlayerParty[gBattlePartyID[i]], MON_DATA_HP), HP_CURRENT); + UpdateHpTextInHealthboxInDoubles(gHealthBoxesIds[i], GetMonData(&gPlayerParty[gBattlePartyID[i]], MON_DATA_MAX_HP), HP_MAX); + } + else // text to bars + { + UpdateStatusIconInHealthbox(gHealthBoxesIds[i]); + UpdateHealthboxAttribute(gHealthBoxesIds[i], &gPlayerParty[gBattlePartyID[i]], HEALTHBOX_HEALTH_BAR); + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_117), (void*)(OBJ_VRAM0 + 0x680 + gSprites[gHealthBoxesIds[i]].oam.tileNum * 32), 32); + } + } + else + { + if (noBars == TRUE) // bars to text + { + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + { + sub_80730D4(gHealthBoxesIds[i], &gEnemyParty[gBattlePartyID[i]]); + } + else + { + spriteId = gSprites[gHealthBoxesIds[i]].data5; + + CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[spriteId].oam.tileNum * 32), 0x100); + UpdateHpTextInHealthboxInDoubles(gHealthBoxesIds[i], GetMonData(&gEnemyParty[gBattlePartyID[i]], MON_DATA_HP), HP_CURRENT); + UpdateHpTextInHealthboxInDoubles(gHealthBoxesIds[i], GetMonData(&gEnemyParty[gBattlePartyID[i]], MON_DATA_MAX_HP), HP_MAX); + } + } + else // text to bars + { + UpdateStatusIconInHealthbox(gHealthBoxesIds[i]); + UpdateHealthboxAttribute(gHealthBoxesIds[i], &gEnemyParty[gBattlePartyID[i]], HEALTHBOX_HEALTH_BAR); + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + UpdateHealthboxAttribute(gHealthBoxesIds[i], &gEnemyParty[gBattlePartyID[i]], HEALTHBOX_NICK); + } + } + gSprites[gHealthBoxesIds[i]].data7 ^= 1; + } + } +} + +u8 CreatePartyStatusSummarySprites(u8 bank, struct HpAndStatus *partyInfo, u8 arg2, bool8 isBattleStart) +{ + bool8 isOpponent; + s16 bar_X, bar_Y, bar_pos2_X, bar_data0; + s32 i, j, var; + u8 barSpriteId; + u8 ballIconSpritesIds[6]; + u8 taskId; + + if (!arg2 || GetBankIdentity(bank) != IDENTITY_OPPONENT_MON2) + { + if (GetBankSide(bank) == SIDE_PLAYER) + { + isOpponent = FALSE; + bar_X = 136, bar_Y = 96; + bar_pos2_X = 100; + bar_data0 = -5; + } + else + { + isOpponent = TRUE; + + if (!arg2 || !IsDoubleBattle()) + bar_X = 104, bar_Y = 40; + else + bar_X = 104, bar_Y = 16; + + bar_pos2_X = -100; + bar_data0 = 5; + } + } + else + { + isOpponent = TRUE; + bar_X = 104, bar_Y = 40; + bar_pos2_X = -100; + bar_data0 = 5; + } + + LoadCompressedObjectPicUsingHeap(&sStatusSummaryBarSpriteSheet); + LoadSpriteSheet(&sStatusSummaryBallsSpriteSheet); + LoadSpritePalette(&sStatusSummaryBarSpritePal); + LoadSpritePalette(&sStatusSummaryBallsSpritePal); + + barSpriteId = CreateSprite(&sStatusSummaryBarSpriteTemplates[isOpponent], bar_X, bar_Y, 10); + SetSubspriteTables(&gSprites[barSpriteId], sStatusSummaryBar_SubspriteTable); + gSprites[barSpriteId].pos2.x = bar_pos2_X; + gSprites[barSpriteId].data0 = bar_data0; + + if (isOpponent) + { + gSprites[barSpriteId].pos1.x -= 96; + gSprites[barSpriteId].oam.matrixNum = 8; + } + else + { + gSprites[barSpriteId].pos1.x += 96; + } + + for (i = 0; i < 6; i++) + { + ballIconSpritesIds[i] = CreateSpriteAtEnd(&sStatusSummaryBallsSpriteTemplates[isOpponent], bar_X, bar_Y - 4, 9); + + if (!isBattleStart) + gSprites[ballIconSpritesIds[i]].callback = SpriteCB_StatusSummaryBallsOnSwitchout; + + if (!isOpponent) + { + gSprites[ballIconSpritesIds[i]].pos2.x = 0; + gSprites[ballIconSpritesIds[i]].pos2.y = 0; + } + + gSprites[ballIconSpritesIds[i]].data0 = barSpriteId; + + if (!isOpponent) + { + gSprites[ballIconSpritesIds[i]].pos1.x += 10 * i + 24; + gSprites[ballIconSpritesIds[i]].data1 = i * 7 + 10; + gSprites[ballIconSpritesIds[i]].pos2.x = 120; + } + else + { + gSprites[ballIconSpritesIds[i]].pos1.x -= 10 * (5 - i) + 24; + gSprites[ballIconSpritesIds[i]].data1 = (6 - i) * 7 + 10; + gSprites[ballIconSpritesIds[i]].pos2.x = -120; + } + + gSprites[ballIconSpritesIds[i]].data2 = isOpponent; + } + + if (GetBankSide(bank) == SIDE_PLAYER) + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + for (i = 0; i < 6; i++) + { + if (partyInfo[i].hp == 0xFFFF) // empty slot or an egg + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 1; + gSprites[ballIconSpritesIds[i]].data7 = 1; + } + else if (partyInfo[i].hp == 0) // fainted mon + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 3; + } + else if (partyInfo[i].status != 0) // mon with major status + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 2; + } + } + } + else + { + for (i = 0, var = 5, j = 0; j < 6; j++) + { + if (partyInfo[j].hp == 0xFFFF) // empty slot or an egg + { + gSprites[ballIconSpritesIds[var]].oam.tileNum += 1; + gSprites[ballIconSpritesIds[var]].data7 = 1; + var--; + continue; + } + else if (partyInfo[j].hp == 0) // fainted mon + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 3; + } + else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->field_2A0 & gBitTable[j]) // hmm...? + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 3; + } + else if (partyInfo[j].status != 0) // mon with major status + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 2; + } + i++; + } + } + } + else + { + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS)) + { + for (var = 5, i = 0; i < 6; i++) + { + if (partyInfo[i].hp == 0xFFFF) // empty slot or an egg + { + gSprites[ballIconSpritesIds[var]].oam.tileNum += 1; + gSprites[ballIconSpritesIds[var]].data7 = 1; + } + else if (partyInfo[i].hp == 0) // fainted mon + { + gSprites[ballIconSpritesIds[var]].oam.tileNum += 3; + } + else if (partyInfo[i].status != 0) // mon with major status + { + gSprites[ballIconSpritesIds[var]].oam.tileNum += 2; + } + var--; + } + } + else + { + for (var = 0, i = 0, j = 0; j < 6; j++) + { + if (partyInfo[j].hp == 0xFFFF) // empty slot or an egg + { + gSprites[ballIconSpritesIds[i]].oam.tileNum += 1; + gSprites[ballIconSpritesIds[i]].data7 = 1; + i++; + continue; + } + else if (partyInfo[j].hp == 0) // fainted mon + { + gSprites[ballIconSpritesIds[5 - var]].oam.tileNum += 3; + } + else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->field_2A1 & gBitTable[j]) // hmm...? + { + gSprites[ballIconSpritesIds[5 - var]].oam.tileNum += 3; + } + else if (partyInfo[j].status != 0) // mon with major status + { + gSprites[ballIconSpritesIds[5 - var]].oam.tileNum += 2; + } + var++; + } + } + } + + taskId = CreateTask(TaskDummy, 5); + gTasks[taskId].data[0] = bank; + gTasks[taskId].data[1] = barSpriteId; + + for (i = 0; i < 6; i++) + gTasks[taskId].data[3 + i] = ballIconSpritesIds[i]; + + gTasks[taskId].data[10] = isBattleStart; + + if (isBattleStart) + { + gBattleSpritesDataPtr->animationData->field_9_x1C++; + } + + PlaySE12WithPanning(SE_TB_START, 0); + return taskId; +} + +void sub_8073C30(u8 taskId) +{ + u8 sp[6]; + u8 r7; + u8 r10; + u8 bank; + s32 i; + + r7 = gTasks[taskId].data[10]; + r10 = gTasks[taskId].data[1]; + bank = gTasks[taskId].data[0]; + + for (i = 0; i < 6; i++) + sp[i] = gTasks[taskId].data[3 + i]; + + SetGpuReg(REG_OFFSET_BLDCNT, 0x3F40); + SetGpuReg(REG_OFFSET_BLDALPHA, 0x10); + + gTasks[taskId].data[15] = 16; + + for (i = 0; i < 6; i++) + gSprites[sp[i]].oam.objMode = 1; + + gSprites[r10].oam.objMode = 1; + + if (r7 != 0) + { + for (i = 0; i < 6; i++) + { + if (GetBankSide(bank) != SIDE_PLAYER) + { + gSprites[sp[5 - i]].data1 = 7 * i; + gSprites[sp[5 - i]].data3 = 0; + gSprites[sp[5 - i]].data4 = 0; + gSprites[sp[5 - i]].callback = sub_8074158; + } + else + { + gSprites[sp[i]].data1 = 7 * i; + gSprites[sp[i]].data3 = 0; + gSprites[sp[i]].data4 = 0; + gSprites[sp[i]].callback = sub_8074158; + } + } + gSprites[r10].data0 /= 2; + gSprites[r10].data1 = 0; + gSprites[r10].callback = sub_8074090; + SetSubspriteTables(&gSprites[r10], sUnknown_0832C2CC); + gTasks[taskId].func = sub_8073E08; + } + else + { + gTasks[taskId].func = sub_8073F98; + } +} + +static void sub_8073E08(u8 taskId) +{ + u16 temp = gTasks[taskId].data[11]++; + + if (!(temp & 1)) + { + gTasks[taskId].data[15]--; + if (gTasks[taskId].data[15] < 0) + return; + + SetGpuReg(REG_OFFSET_BLDALPHA, (gTasks[taskId].data[15]) | ((16 - gTasks[taskId].data[15]) << 8)); + } + if (gTasks[taskId].data[15] == 0) + gTasks[taskId].func = sub_8073E64; +} + +static void sub_8073E64(u8 taskId) +{ + u8 sp[6]; + s32 i; + + u8 bank = gTasks[taskId].data[0]; + gTasks[taskId].data[15]--; + if (gTasks[taskId].data[15] == -1) + { + u8 var = gTasks[taskId].data[1]; + + for (i = 0; i < 6; i++) + sp[i] = gTasks[taskId].data[3 + i]; + + gBattleSpritesDataPtr->animationData->field_9_x1C--; + if (!gBattleSpritesDataPtr->animationData->field_9_x1C) + { + DestroySpriteAndFreeResources(&gSprites[var]); + DestroySpriteAndFreeResources(&gSprites[sp[0]]); + } + else + { + FreeSpriteOamMatrix(&gSprites[var]); + DestroySprite(&gSprites[var]); + FreeSpriteOamMatrix(&gSprites[sp[0]]); + DestroySprite(&gSprites[sp[0]]); + } + + for (i = 1; i < 6; i++) + DestroySprite(&gSprites[sp[i]]); + } + else if (gTasks[taskId].data[15] == -3) + { + gBattleSpritesDataPtr->healthBoxesData[bank].flag_x1 = 0; + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + DestroyTask(taskId); + } +} + +static void sub_8073F98(u8 taskId) +{ + u8 sp[6]; + s32 i; + + u8 bank = gTasks[taskId].data[0]; + gTasks[taskId].data[15]--; + if (gTasks[taskId].data[15] >= 0) + { + SetGpuReg(REG_OFFSET_BLDALPHA, (gTasks[taskId].data[15]) | ((16 - gTasks[taskId].data[15]) << 8)); + } + else if (gTasks[taskId].data[15] == -1) + { + u8 var = gTasks[taskId].data[1]; + + for (i = 0; i < 6; i++) + sp[i] = gTasks[taskId].data[3 + i]; + + DestroySpriteAndFreeResources(&gSprites[var]); + DestroySpriteAndFreeResources(&gSprites[sp[0]]); + + for (i = 1; i < 6; i++) + DestroySprite(&gSprites[sp[i]]); + } + else if (gTasks[taskId].data[15] == -3) + { + gBattleSpritesDataPtr->healthBoxesData[bank].flag_x1 = 0; + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + DestroyTask(taskId); + } +} + +static void SpriteCB_StatusSummaryBar(struct Sprite *sprite) +{ + if (sprite->pos2.x != 0) + sprite->pos2.x += sprite->data0; +} + +static void sub_8074090(struct Sprite *sprite) +{ + sprite->data1 += 32; + if (sprite->data0 > 0) + sprite->pos2.x += sprite->data1 >> 4; + else + sprite->pos2.x -= sprite->data1 >> 4; + sprite->data1 &= 0xF; +} + +static void SpriteCB_StatusSummaryBallsOnBattleStart(struct Sprite *sprite) +{ + u8 var1; + u16 var2; + s8 pan; + + if (sprite->data1 > 0) + { + sprite->data1--; + return; + } + + var1 = sprite->data2; + var2 = sprite->data3; + var2 += 56; + sprite->data3 = var2 & 0xFFF0; + + if (var1 != 0) + { + sprite->pos2.x += var2 >> 4; + if (sprite->pos2.x > 0) + sprite->pos2.x = 0; + } + else + { + sprite->pos2.x -= var2 >> 4; + if (sprite->pos2.x < 0) + sprite->pos2.x = 0; + } + + if (sprite->pos2.x == 0) + { + pan = PAN_SIDE_OPPONENT; + if (var1 != 0) + pan = PAN_SIDE_PLAYER; + + if (sprite->data7 != 0) + PlaySE2WithPanning(SE_TB_KARA, pan); + else + PlaySE1WithPanning(SE_TB_KON, pan); + + sprite->callback = SpriteCallbackDummy; + } +} + +static void sub_8074158(struct Sprite *sprite) +{ + u8 var1; + u16 var2; + + if (sprite->data1 > 0) + { + sprite->data1--; + return; + } + var1 = sprite->data2; + var2 = sprite->data3; + var2 += 56; + sprite->data3 = var2 & 0xFFF0; + if (var1 != 0) + sprite->pos2.x += var2 >> 4; + else + sprite->pos2.x -= var2 >> 4; + if (sprite->pos2.x + sprite->pos1.x > 248 + || sprite->pos2.x + sprite->pos1.x < -8) + { + sprite->invisible = TRUE; + sprite->callback = SpriteCallbackDummy; + } +} + +static void SpriteCB_StatusSummaryBallsOnSwitchout(struct Sprite *sprite) +{ + u8 barSpriteId = sprite->data0; + + sprite->pos2.x = gSprites[barSpriteId].pos2.x; + sprite->pos2.y = gSprites[barSpriteId].pos2.y; +} + +static void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon) +{ + u8 nickname[POKEMON_NAME_LENGTH + 1]; + void *ptr; + const u8 *genderTxt; + u32 windowId, spriteTileNum; + u8 *windowTileData; + u16 species; + u8 gender; + + StringCopy(gDisplayedStringBattle, gText_HighlightDarkGrey); + GetMonData(mon, MON_DATA_NICKNAME, nickname); + StringGetEnd10(nickname); + ptr = StringAppend(gDisplayedStringBattle, nickname); + + gender = GetMonGender(mon); + species = GetMonData(mon, MON_DATA_SPECIES); + + if ((species == SPECIES_NIDORAN_F || species == SPECIES_NIDORAN_M) && StringCompare(nickname, gSpeciesNames[species]) == 0) + gender = 100; + + // AddTextPrinterAndCreateWindowOnHealthbox's arguments are the same in all 3 cases. + // It's possible they may have been different in early development phases. + switch (gender) + { + default: + StringCopy(ptr, gText_DynColor2); + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId); + break; + case MON_MALE: + StringCopy(ptr, gText_DynColor2Male); + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId); + break; + case MON_FEMALE: + StringCopy(ptr, gText_DynColor1Female); + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId); + break; + } + + spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * 32; + + if (GetBankSide(gSprites[healthboxSpriteId].data6) == SIDE_PLAYER) + { + sub_8075198((void*)(0x6010040 + spriteTileNum), windowTileData, 6); + ptr = (void*)(OBJ_VRAM0); + if (!IsDoubleBattle()) + ptr += spriteTileNum + 0x800; + else + ptr += spriteTileNum + 0x400; + sub_8075198(ptr, windowTileData + 0xC0, 1); + } + else + { + sub_8075198((void*)(0x6010020 + spriteTileNum), windowTileData, 7); + } + + RemoveWindowOnHealthbox(windowId); +} + +static void TryAddPokeballIconToHealthbox(u8 healthboxSpriteId, bool8 noStatus) +{ + u8 bank, healthboxSpriteId_2; + + if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) + return; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + return; + + bank = gSprites[healthboxSpriteId].data6; + if (GetBankSide(bank) == SIDE_PLAYER) + return; + if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_SPECIES)), FLAG_GET_CAUGHT)) + return; + + healthboxSpriteId_2 = gSprites[healthboxSpriteId].data5; + + if (noStatus) + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_70), (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId_2].oam.tileNum + 8) * 32), 32); + else + CpuFill32(0, (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId_2].oam.tileNum + 8) * 32), 32); +} + +static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId) +{ + s32 i; + u8 bank, healthboxSpriteId_2; + u32 status, pltAdder; + const u8 *statusGfxPtr; + s16 tileNumAdder; + u8 statusPalId; + + bank = gSprites[healthboxSpriteId].data6; + healthboxSpriteId_2 = gSprites[healthboxSpriteId].data5; + if (GetBankSide(bank) == SIDE_PLAYER) + { + status = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_STATUS); + if (!IsDoubleBattle()) + tileNumAdder = 0x1A; + else + tileNumAdder = 0x12; + } + else + { + status = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_STATUS); + tileNumAdder = 0x11; + } + + if (status & STATUS_SLEEP) + { + statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBankId(HEALTHBOX_GFX_STATUS_SLP_BANK0, bank)); + statusPalId = PAL_STATUS_SLP; + } + else if (status & STATUS_PSN_ANY) + { + statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBankId(HEALTHBOX_GFX_STATUS_PSN_BANK0, bank)); + statusPalId = PAL_STATUS_PSN; + } + else if (status & STATUS_BURN) + { + statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBankId(HEALTHBOX_GFX_STATUS_BRN_BANK0, bank)); + statusPalId = PAL_STATUS_BRN; + } + else if (status & STATUS_FREEZE) + { + statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBankId(HEALTHBOX_GFX_STATUS_FRZ_BANK0, bank)); + statusPalId = PAL_STATUS_FRZ; + } + else if (status & STATUS_PARALYSIS) + { + statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBankId(HEALTHBOX_GFX_STATUS_PRZ_BANK0, bank)); + statusPalId = PAL_STATUS_PAR; + } + else + { + statusGfxPtr = GetHealthboxElementGfxPtr(HEALTHBOX_GFX_39); + + for (i = 0; i < 3; i++) + CpuCopy32(statusGfxPtr, (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder + i) * 32), 32); + + if (!gBattleSpritesDataPtr->bankData[bank].hpNumbersNoBars) + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_1), (void *)(OBJ_VRAM0 + gSprites[healthboxSpriteId_2].oam.tileNum * 32), 64); + + TryAddPokeballIconToHealthbox(healthboxSpriteId, TRUE); + return; + } + + pltAdder = gSprites[healthboxSpriteId].oam.paletteNum * 16; + pltAdder += bank + 12; + + FillPalette(sStatusIconPalettes[statusPalId], pltAdder + 0x100, 2); + CpuCopy16(gPlttBufferUnfaded + 0x100 + pltAdder, (void*)(OBJ_PLTT + pltAdder * 2), 2); + CpuCopy32(statusGfxPtr, (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder) * 32), 96); + if (IsDoubleBattle() == TRUE || GetBankSide(bank) == SIDE_OPPONENT) + { + if (!gBattleSpritesDataPtr->bankData[bank].hpNumbersNoBars) + { + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_0), (void*)(OBJ_VRAM0 + gSprites[healthboxSpriteId_2].oam.tileNum * 32), 32); + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_65), (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId_2].oam.tileNum + 1) * 32), 32); + } + } + TryAddPokeballIconToHealthbox(healthboxSpriteId, FALSE); +} + +static u8 GetStatusIconForBankId(u8 statusElementId, u8 bank) +{ + u8 ret = statusElementId; + + switch (statusElementId) + { + case HEALTHBOX_GFX_STATUS_PSN_BANK0: + if (bank == 0) + ret = HEALTHBOX_GFX_STATUS_PSN_BANK0; + else if (bank == 1) + ret = HEALTHBOX_GFX_STATUS_PSN_BANK1; + else if (bank == 2) + ret = HEALTHBOX_GFX_STATUS_PSN_BANK2; + else + ret = HEALTHBOX_GFX_STATUS_PSN_BANK3; + break; + case HEALTHBOX_GFX_STATUS_PRZ_BANK0: + if (bank == 0) + ret = HEALTHBOX_GFX_STATUS_PRZ_BANK0; + else if (bank == 1) + ret = HEALTHBOX_GFX_STATUS_PRZ_BANK1; + else if (bank == 2) + ret = HEALTHBOX_GFX_STATUS_PRZ_BANK2; + else + ret = HEALTHBOX_GFX_STATUS_PRZ_BANK3; + break; + case HEALTHBOX_GFX_STATUS_SLP_BANK0: + if (bank == 0) + ret = HEALTHBOX_GFX_STATUS_SLP_BANK0; + else if (bank == 1) + ret = HEALTHBOX_GFX_STATUS_SLP_BANK1; + else if (bank == 2) + ret = HEALTHBOX_GFX_STATUS_SLP_BANK2; + else + ret = HEALTHBOX_GFX_STATUS_SLP_BANK3; + break; + case HEALTHBOX_GFX_STATUS_FRZ_BANK0: + if (bank == 0) + ret = HEALTHBOX_GFX_STATUS_FRZ_BANK0; + else if (bank == 1) + ret = HEALTHBOX_GFX_STATUS_FRZ_BANK1; + else if (bank == 2) + ret = HEALTHBOX_GFX_STATUS_FRZ_BANK2; + else + ret = HEALTHBOX_GFX_STATUS_FRZ_BANK3; + break; + case HEALTHBOX_GFX_STATUS_BRN_BANK0: + if (bank == 0) + ret = HEALTHBOX_GFX_STATUS_BRN_BANK0; + else if (bank == 1) + ret = HEALTHBOX_GFX_STATUS_BRN_BANK1; + else if (bank == 2) + ret = HEALTHBOX_GFX_STATUS_BRN_BANK2; + else + ret = HEALTHBOX_GFX_STATUS_BRN_BANK3; + break; + } + return ret; +} + +static void UpdateSafariBallsTextOnHealthbox(u8 healthboxSpriteId) +{ + u32 windowId, spriteTileNum; + u8 *windowTileData; + + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gText_SafariBalls, 0, 3, 2, &windowId); + spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * 32; + sub_8075198((void*)(OBJ_VRAM0 + 0x40) + spriteTileNum, windowTileData, 6); + sub_8075198((void*)(OBJ_VRAM0 + 0x800) + spriteTileNum, windowTileData + 0xC0, 2); + RemoveWindowOnHealthbox(windowId); +} + +static void UpdateLeftNoOfBallsTextOnHealthbox(u8 healthboxSpriteId) +{ + u8 text[16]; + u8 *txtPtr; + u32 windowId, spriteTileNum; + u8 *windowTileData; + + txtPtr = StringCopy(text, gText_SafariBallLeft); + ConvertIntToDecimalStringN(txtPtr, gNumSafariBalls, STR_CONV_MODE_LEFT_ALIGN, 2); + + windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, GetStringRightAlignXOffset(0, text, 0x2F), 3, 2, &windowId); + spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * 32; + sub_80751E4((void*)(OBJ_VRAM0 + 0x2C0) + spriteTileNum, windowTileData, 2); + sub_80751E4((void*)(OBJ_VRAM0 + 0xA00) + spriteTileNum, windowTileData + 0x40, 4); + RemoveWindowOnHealthbox(windowId); +} + +void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elementId) +{ + s32 maxHp, currHp; + u8 bank = gSprites[healthboxSpriteId].data6; + + if (elementId == HEALTHBOX_ALL && !IsDoubleBattle()) + GetBankSide(bank); // pointless function call + + if (GetBankSide(gSprites[healthboxSpriteId].data6) == SIDE_PLAYER) + { + u8 isDoubles; + + if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL) + UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL)); + if (elementId == HEALTHBOX_CURRENT_HP || elementId == HEALTHBOX_ALL) + UpdateHpTextInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_HP), HP_CURRENT); + if (elementId == HEALTHBOX_MAX_HP || elementId == HEALTHBOX_ALL) + UpdateHpTextInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_MAX_HP), HP_MAX); + if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL) + { + LoadBattleBarGfx(0); + maxHp = GetMonData(mon, MON_DATA_MAX_HP); + currHp = GetMonData(mon, MON_DATA_HP); + SetBattleBarStruct(bank, healthboxSpriteId, maxHp, currHp, 0); + sub_8074AA0(bank, healthboxSpriteId, HEALTH_BAR, 0); + } + isDoubles = IsDoubleBattle(); + if (!isDoubles && (elementId == HEALTHBOX_EXP_BAR || elementId == HEALTHBOX_ALL)) + { + u16 species; + u32 exp, currLevelExp; + s32 currExpBarValue, maxExpBarValue; + u8 level; + + LoadBattleBarGfx(3); + species = GetMonData(mon, MON_DATA_SPECIES); + level = GetMonData(mon, MON_DATA_LEVEL); + exp = GetMonData(mon, MON_DATA_EXP); + currLevelExp = gExperienceTables[gBaseStats[species].growthRate][level]; + currExpBarValue = exp - currLevelExp; + maxExpBarValue = gExperienceTables[gBaseStats[species].growthRate][level + 1] - currLevelExp; + SetBattleBarStruct(bank, healthboxSpriteId, maxExpBarValue, currExpBarValue, isDoubles); + sub_8074AA0(bank, healthboxSpriteId, EXP_BAR, 0); + } + if (elementId == HEALTHBOX_NICK || elementId == HEALTHBOX_ALL) + UpdateNickInHealthbox(healthboxSpriteId, mon); + if (elementId == HEALTHBOX_STATUS_ICON || elementId == HEALTHBOX_ALL) + UpdateStatusIconInHealthbox(healthboxSpriteId); + if (elementId == HEALTHBOX_SAFARI_ALL_TEXT) + UpdateSafariBallsTextOnHealthbox(healthboxSpriteId); + if (elementId == HEALTHBOX_SAFARI_ALL_TEXT || elementId == HEALTHBOX_SAFARI_BALLS_TEXT) + UpdateLeftNoOfBallsTextOnHealthbox(healthboxSpriteId); + } + else + { + if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL) + UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL)); + if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL) + { + LoadBattleBarGfx(0); + maxHp = GetMonData(mon, MON_DATA_MAX_HP); + currHp = GetMonData(mon, MON_DATA_HP); + SetBattleBarStruct(bank, healthboxSpriteId, maxHp, currHp, 0); + sub_8074AA0(bank, healthboxSpriteId, HEALTH_BAR, 0); + } + if (elementId == HEALTHBOX_NICK || elementId == HEALTHBOX_ALL) + UpdateNickInHealthbox(healthboxSpriteId, mon); + if (elementId == HEALTHBOX_STATUS_ICON || elementId == HEALTHBOX_ALL) + UpdateStatusIconInHealthbox(healthboxSpriteId); + } +} + +s32 sub_8074AA0(u8 bank, u8 healthboxSpriteId, u8 whichBar, u8 arg3) +{ + s32 var; + + if (whichBar == HEALTH_BAR) // health bar + { + var = sub_8074DB8(gBattleSpritesDataPtr->battleBars[bank].maxValue, + gBattleSpritesDataPtr->battleBars[bank].currentValue, + gBattleSpritesDataPtr->battleBars[bank].field_C, + &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].maxValue, 8); + if (expFraction == 0) + expFraction = 1; + expFraction = abs(gBattleSpritesDataPtr->battleBars[bank].field_C / expFraction); + + var = sub_8074DB8(gBattleSpritesDataPtr->battleBars[bank].maxValue, + gBattleSpritesDataPtr->battleBars[bank].currentValue, + gBattleSpritesDataPtr->battleBars[bank].field_C, + &gBattleSpritesDataPtr->battleBars[bank].field_10, + 8, expFraction); + } + + if (whichBar == EXP_BAR || (whichBar == HEALTH_BAR && !gBattleSpritesDataPtr->bankData[bank].hpNumbersNoBars)) + sub_8074B9C(bank, whichBar); + + if (var == -1) + gBattleSpritesDataPtr->battleBars[bank].field_10 = 0; + + return var; +} + +static void sub_8074B9C(u8 bank, u8 whichBar) +{ + u8 array[7]; + u8 subRet, level; + u8 barElementId; + u8 i; + + switch (whichBar) + { + case HEALTH_BAR: + subRet = sub_8074E8C(gBattleSpritesDataPtr->battleBars[bank].maxValue, + gBattleSpritesDataPtr->battleBars[bank].currentValue, + gBattleSpritesDataPtr->battleBars[bank].field_C, + &gBattleSpritesDataPtr->battleBars[bank].field_10, + array, 6); + barElementId = 3; + if (subRet <= 0x18) + { + barElementId = 0x38; + if (subRet > 9) + barElementId = 0x2F; + } + for (i = 0; i < 6; i++) + { + u8 healthboxSpriteId_2 = gSprites[gBattleSpritesDataPtr->battleBars[bank].healthboxSpriteId].data5; + if (i < 2) + CpuCopy32(GetHealthboxElementGfxPtr(barElementId) + array[i] * 32, + (void*)(OBJ_VRAM0 + (gSprites[healthboxSpriteId_2].oam.tileNum + 2 + i) * 32), 32); + else + CpuCopy32(GetHealthboxElementGfxPtr(barElementId) + array[i] * 32, + (void*)(OBJ_VRAM0 + 64 + (i + gSprites[healthboxSpriteId_2].oam.tileNum) * 32), 32); + } + break; + case EXP_BAR: + sub_8074E8C(gBattleSpritesDataPtr->battleBars[bank].maxValue, + gBattleSpritesDataPtr->battleBars[bank].currentValue, + gBattleSpritesDataPtr->battleBars[bank].field_C, + &gBattleSpritesDataPtr->battleBars[bank].field_10, + array, 8); + level = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_LEVEL); + if (level == MAX_MON_LEVEL) + { + for (i = 0; i < 8; i++) + array[i] = 0; + } + for (i = 0; i < 8; i++) + { + if (i < 4) + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_12) + array[i] * 32, + (void*)(OBJ_VRAM0 + (gSprites[gBattleSpritesDataPtr->battleBars[bank].healthboxSpriteId].oam.tileNum + 0x24 + i) * 32), 32); + else + CpuCopy32(GetHealthboxElementGfxPtr(HEALTHBOX_GFX_12) + array[i] * 32, + (void*)(OBJ_VRAM0 + 0xB80 + (i + gSprites[gBattleSpritesDataPtr->battleBars[bank].healthboxSpriteId].oam.tileNum) * 32), 32); + } + break; + } +} + +static s32 sub_8074DB8(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 arg4, u16 arg5) +{ + s32 r6; + s32 ret; + arg4 <<= 3; + + if (*arg3 == -32768) + { + if (maxValue < arg4) + *arg3 = currValue << 8; + else + *arg3 = currValue; + } + + currValue -= arg2; + if (currValue < 0) + currValue = 0; + else if (currValue > maxValue) + currValue = maxValue; + + if (maxValue < arg4) + { + s32 var = *arg3 >> 8; + + r6 = *arg3; + if (currValue == var && (r6 & 0xFF) == 0) + return -1; + } + else + { + r6 = *arg3; + if (currValue == r6) + return -1; + } + + if (maxValue < arg4) + { + s32 var = (maxValue << 8) / arg4; + + if (arg2 < 0) + { + *arg3 = r6 + var; + ret = *arg3 >> 8; + if (ret >= currValue) + { + *arg3 = currValue << 8; + ret = currValue; + } + } + else + { + *arg3 = r6 - var; + ret = *arg3 >> 8; + if ((*arg3 & 0xFF) > 0) + ret++; + if (ret <= currValue) + { + *arg3 = currValue << 8; + ret = currValue; + } + } + } + else + { + if (arg2 < 0) + { + *arg3 += arg5; + if (*arg3 > currValue) + *arg3 = currValue; + ret = *arg3; + } + else + { + *arg3 -= arg5; + if (*arg3 < currValue) + *arg3 = currValue; + ret = *arg3; + } + } + + return ret; +} + +static u8 sub_8074E8C(s32 maxValue, s32 currValue, s32 arg2, s32 *arg3, u8 *arg4, u8 arg5) +{ + s32 r5 = currValue - arg2; + u8 ret; + u8 i; + u8 r2; + + if (r5 < 0) + r5 = 0; + else if (r5 > maxValue) + r5 = maxValue; + + ret = arg5 << 3; + + for (i = 0; i < arg5; i++) + arg4[i] = 0; + + if (maxValue < ret) + r2 = (*arg3 * ret / maxValue) >> 8; + else + r2 = *arg3 * ret / maxValue; + + ret = r2; + + if (ret == 0 && r5 > 0) + { + arg4[0] = 1; + ret = 1; + } + else + { + for (i = 0; i < arg5; i++) + { + if (r2 >= 8) + { + arg4[i] = 8; + } + else + { + arg4[i] = r2; + break; + } + r2 -= 8; + } + } + + return ret; +} + +static s16 sub_8074F28(struct TestingBar *barInfo, s32 *arg1, u16 *arg2, s32 arg3) +{ + s16 ret, var; + + ret = sub_8074DB8(barInfo->maxValue, + barInfo->currValue, + barInfo->field_8, + arg1, 6, 1); + sub_8074F88(barInfo, arg1, arg2); + + if (barInfo->maxValue < 0x30) + var = *arg1 >> 8; + else + var = *arg1; + + DummiedOutFunction(barInfo->maxValue, var, arg3); + + return ret; +} + +static void sub_8074F88(struct TestingBar *barInfo, s32 *arg1, u16 *arg2) +{ + u8 sp8[6]; + u16 sp10[6]; + u8 i; + + sub_8074E8C(barInfo->maxValue, barInfo->currValue, + barInfo->field_8, arg1, sp8, 6); + + for (i = 0; i < 6; i++) + sp10[i] = (barInfo->unkC_0 << 12) | (barInfo->unk10 + sp8[i]); + + CpuCopy16(sp10, arg2, sizeof(sp10)); +} + +static u8 GetScaledExpFraction(s32 currValue, s32 arg1, s32 maxValue, u8 scale) +{ + s32 r5, result; + s8 r4, r0; + + scale *= 8; + r5 = currValue - arg1; + + if (r5 < 0) + r5 = 0; + else if (r5 > maxValue) + r5 = maxValue; + + r4 = currValue * scale / maxValue; + r0 = r5 * scale / maxValue; + result = r4 - r0; + + return abs(result); +} + +u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale) +{ + u8 result = hp * scale / maxhp; + + if (result == 0 && hp > 0) + return 1; + + return result; +} + +u8 GetHPBarLevel(s16 hp, s16 maxhp) +{ + s32 result; + + if (hp == maxhp) + { + result = 4; + } + else + { + u8 fraction = GetScaledHPFraction(hp, maxhp, 48); + if (fraction > 24) + result = 3; + else if (fraction > 9) + result = 2; + else if (fraction > 0) + result = 1; + else + result = 0; + } + + return result; +} + +static u8* AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 arg3, u32 *windowId) +{ + u16 winId; + struct TextColor color; + struct WindowTemplate winTemplate = sHealthboxWindowTemplate; + + winId = AddWindow(&winTemplate); + FillWindowPixelBuffer(winId, (arg3 << 4) | (arg3)); + + color.fgColor = arg3; + color.bgColor = 1; + color.shadowColor = 3; + + AddTextPrinterParametrized2(winId, 0, x, y, 0, 0, &color, -1, str); + + *windowId = winId; + return (u8*)(GetWindowAttribute(winId, WINDOW_TILE_DATA)); +} + +static void RemoveWindowOnHealthbox(u32 windowId) +{ + RemoveWindow(windowId); +} + +static void sub_807513C(void *dest, u32 arg1, u32 arg2) +{ + CpuFill32(0x11111111 * arg1, dest, arg2 * 32); +} + +static void sub_8075170(void *dest, u8 *windowTileData, u32 arg2) +{ + CpuCopy32(windowTileData + 256, dest, arg2 * 32); +} + +static void sub_8075198(void *dest, u8 *windowTileData, s32 arg2) +{ + CpuCopy32(windowTileData + 256, dest + 256, arg2 * 32); + + if (arg2 > 0) + { + do + { + CpuCopy32(windowTileData + 20, dest + 20, 12); + dest += 32, windowTileData+= 32; + arg2--; + } while (arg2 != 0); + } +} + +static void sub_80751E4(void *dest, u8 *windowTileData, u32 arg2) +{ + CpuCopy32(windowTileData, dest, arg2 * 32); + CpuCopy32(windowTileData + 256, dest + 256, arg2 * 32); +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index fb6a8272b..a1e5767ad 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -349,7 +349,7 @@ static void atk51_switch_handle_order(void); static void atk52_switch_in_effects(void); static void atk53_trainer_slide(void); static void atk54_effectiveness_sound(void); -static void atk55_play_sound(void); +static void atk55_play_fanfare(void); static void atk56_fainting_cry(void); static void atk57(void); static void atk58_return_to_ball(void); @@ -601,7 +601,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk52_switch_in_effects, atk53_trainer_slide, atk54_effectiveness_sound, - atk55_play_sound, + atk55_play_fanfare, atk56_fainting_cry, atk57, atk58_return_to_ball, @@ -5308,7 +5308,7 @@ static void atk4B_return_atk_to_ball(void) gActiveBank = gBankAttacker; if (!(gHitMarker & HITMARKER_FAINTED(gActiveBank))) { - EmitReturnPokeToBall(0, 0); + EmitReturnMonToBall(0, 0); MarkBufferBankForExecution(gActiveBank); } gBattlescriptCurrInstr++; @@ -5627,7 +5627,7 @@ static void atk50_openpartyscreen(void) { gAbsentBankFlags |= gBitTable[gActiveBank]; gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); + EmitCmd42(0); MarkBufferBankForExecution(gActiveBank); } else if (!gSpecialStatuses[gActiveBank].flag40) @@ -5649,7 +5649,7 @@ static void atk50_openpartyscreen(void) { gAbsentBankFlags |= gBitTable[gActiveBank]; gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); + EmitCmd42(0); MarkBufferBankForExecution(gActiveBank); } else if (!gSpecialStatuses[gActiveBank].flag40) @@ -5670,7 +5670,7 @@ static void atk50_openpartyscreen(void) { gAbsentBankFlags |= gBitTable[gActiveBank]; gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); + EmitCmd42(0); MarkBufferBankForExecution(gActiveBank); } else if (!gSpecialStatuses[gActiveBank].flag40) @@ -5692,7 +5692,7 @@ static void atk50_openpartyscreen(void) { gAbsentBankFlags |= gBitTable[gActiveBank]; gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); + EmitCmd42(0); MarkBufferBankForExecution(gActiveBank); } else if (!gSpecialStatuses[gActiveBank].flag40) @@ -5755,7 +5755,7 @@ static void atk50_openpartyscreen(void) { gAbsentBankFlags |= gBitTable[gActiveBank]; gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); + EmitCmd42(0); MarkBufferBankForExecution(gActiveBank); } else if (!gSpecialStatuses[gActiveBank].flag40) @@ -5771,7 +5771,7 @@ static void atk50_openpartyscreen(void) { gAbsentBankFlags |= gBitTable[gActiveBank]; gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); + EmitCmd42(0); MarkBufferBankForExecution(gActiveBank); } else if (!gSpecialStatuses[gActiveBank].flag40) @@ -6031,10 +6031,10 @@ static void atk54_effectiveness_sound(void) gBattlescriptCurrInstr += 3; } -static void atk55_play_sound(void) +static void atk55_play_fanfare(void) { gActiveBank = gBankAttacker; - EmitPlaySound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), 0); + EmitPlayFanfareOrBGM(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), FALSE); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 3; @@ -6052,7 +6052,7 @@ static void atk56_fainting_cry(void) static void atk57(void) { gActiveBank = GetBankByIdentity(0); - Emit_x37(0, gBattleOutcome); + EmitCmd55(0, gBattleOutcome); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 1; @@ -6061,7 +6061,7 @@ static void atk57(void) static void atk58_return_to_ball(void) { gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitReturnPokeToBall(0, 1); + EmitReturnMonToBall(0, 1); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; @@ -7137,7 +7137,7 @@ static void atk76_various(void) gDisableStructs[1].truantUnknownBit = 1; break; case 13: - EmitCmd13(0); + EmitCmd19(0); MarkBufferBankForExecution(gActiveBank); break; case 14: @@ -7162,7 +7162,7 @@ static void atk76_various(void) gActiveBank = 1; if (gBattleMons[gActiveBank].hp != 0) { - EmitReturnPokeToBall(0, 0); + EmitReturnMonToBall(0, 0); MarkBufferBankForExecution(gActiveBank); } break; @@ -7172,7 +7172,7 @@ static void atk76_various(void) gActiveBank = 3; if (gBattleMons[gActiveBank].hp != 0) { - EmitReturnPokeToBall(0, 0); + EmitReturnMonToBall(0, 0); MarkBufferBankForExecution(gActiveBank); } } @@ -7197,7 +7197,7 @@ static void atk76_various(void) gBattleOutcome = BATTLE_OPPONENT_TELEPORTED; break; case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC: - EmitPlaySound(0, BGM_KACHI1, 1); + EmitPlayFanfareOrBGM(0, BGM_KACHI1, TRUE); MarkBufferBankForExecution(gActiveBank); break; } diff --git a/src/braille_puzzles.c b/src/braille_puzzles.c index 83d32b56c..9a6f0371c 100755 --- a/src/braille_puzzles.c +++ b/src/braille_puzzles.c @@ -220,7 +220,7 @@ bool8 ShouldDoBrailleStrengthEffect(void) void sub_8179834(void) { - gFieldEffectSpawnParams[0] = brm_get_pokemon_selection(); + gFieldEffectArguments[0] = brm_get_pokemon_selection(); FieldEffectStart(FLDEFF_USE_FLY_ANCIENT_TOMB); } @@ -256,7 +256,7 @@ bool8 ShouldDoBrailleFlyEffect(void) void sub_8179918(void) { - gFieldEffectSpawnParams[0] = brm_get_pokemon_selection(); + gFieldEffectArguments[0] = brm_get_pokemon_selection(); FieldEffectStart(FLDEFF_USE_FLY_ANCIENT_TOMB); } @@ -417,7 +417,7 @@ bool8 ShouldDoBrailleRegicePuzzle(void) } // TODO: Find what flags 2 and 3 are. FlagSet(3); - FlagReset(2); + FlagClear(2); return FALSE; } #else @@ -568,7 +568,7 @@ _08179B44:\n\ movs r0, 0x3\n\ bl FlagSet\n\ movs r0, 0x2\n\ - bl FlagReset\n\ + bl FlagClear\n\ _08179B5A:\n\ movs r0, 0\n\ _08179B5C:\n\ diff --git a/src/coins.c b/src/coins.c index 4ee601b22..e1694b29c 100644 --- a/src/coins.c +++ b/src/coins.c @@ -5,12 +5,12 @@ #include "text_window.h" #include "string_util.h" #include "menu.h" +#include "international_string_util.h" #define MAX_COINS 9999 EWRAM_DATA u8 sCoinsWindowId = 0; -extern s32 GetStringRightAlignXOffset(u8 fontId, u8 *str, s32 totalWidth); extern void sub_819746C(u8 windowId, bool8 copyToVram); extern const u8 gText_Coins[]; @@ -54,7 +54,7 @@ void SetCoins(u16 coinAmount) } /* Can't match it lol -bool8 AddCoins(u16 toAdd) +bool8 GiveCoins(u16 toAdd) { u16 newAmount; u16 ownedCoins = GetCoins(); diff --git a/src/decompress.c b/src/decompress.c index 2863ff1f5..9210799ec 100644 --- a/src/decompress.c +++ b/src/decompress.c @@ -465,7 +465,7 @@ u32 sub_8034974(void* ptr) return (ptr_[3] << 16) | (ptr_[2] << 8) | (ptr_[1]); } -bool8 LoadCompressedObjectPicUsingHeap(struct CompressedSpriteSheet* src) +bool8 LoadCompressedObjectPicUsingHeap(const struct CompressedSpriteSheet* src) { struct SpriteSheet dest; void* buffer; diff --git a/src/egg_hatch.c b/src/egg_hatch.c index a1f187b85..589e8901d 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -462,7 +462,7 @@ static void VBlankCB_EggHatch(void) TransferPlttBuffer(); } -static void EggHatch(void) +void EggHatch(void) { ScriptContext2_Enable(); CreateTask(Task_EggHatch, 10); diff --git a/src/event_data.c b/src/event_data.c index fb2edb063..19a310db5 100644 --- a/src/event_data.c +++ b/src/event_data.c @@ -40,11 +40,11 @@ void ClearTempFieldEventData(void) { memset(gSaveBlock1Ptr->flags, 0, TEMP_FLAGS_SIZE); memset(gSaveBlock1Ptr->vars, 0, TEMP_VARS_SIZE); - FlagReset(SYS_ENC_UP_ITEM); - FlagReset(SYS_ENC_DOWN_ITEM); - FlagReset(SYS_USE_STRENGTH); - FlagReset(SYS_CTRL_OBJ_DELETE); - FlagReset(SYS_UNKNOWN_880); + FlagClear(SYS_ENC_UP_ITEM); + FlagClear(SYS_ENC_DOWN_ITEM); + FlagClear(SYS_USE_STRENGTH); + FlagClear(SYS_CTRL_OBJ_DELETE); + FlagClear(SYS_UNKNOWN_880); } // probably had different flag splits at one point. @@ -58,7 +58,7 @@ void DisableNationalPokedex(void) u16 *nationalDexVar = GetVarPointer(VAR_NATIONAL_DEX); gSaveBlock2Ptr->pokedex.nationalMagic = 0; *nationalDexVar = 0; - FlagReset(SYS_NATIONAL_DEX); + FlagClear(SYS_NATIONAL_DEX); } void EnableNationalPokedex(void) @@ -82,7 +82,7 @@ bool32 IsNationalPokedexEnabled(void) void DisableMysteryEvent(void) { - FlagReset(SYS_MYSTERY_EVENT_ENABLE); + FlagClear(SYS_MYSTERY_EVENT_ENABLE); } void EnableMysteryEvent(void) @@ -97,7 +97,7 @@ bool32 IsMysteryEventEnabled(void) void DisableMysteryGift(void) { - FlagReset(SYS_MYSTERY_GIFT_ENABLE); + FlagClear(SYS_MYSTERY_GIFT_ENABLE); } void EnableMysteryGift(void) @@ -112,22 +112,22 @@ bool32 IsMysteryGiftEnabled(void) void sub_809D4D8(void) { - FlagReset(0x1E4); - FlagReset(0x1E5); - FlagReset(0x1E6); - FlagReset(0x1E7); - FlagReset(0x1E8); - FlagReset(0x1E9); - FlagReset(0x1EA); - FlagReset(0x1EB); - FlagReset(0x1EC); - FlagReset(0x1ED); - FlagReset(0x1EE); - FlagReset(0x1EF); - FlagReset(0x1F0); - FlagReset(0x1F1); - FlagReset(0x1F2); - FlagReset(0x1F3); + FlagClear(0x1E4); + FlagClear(0x1E5); + FlagClear(0x1E6); + FlagClear(0x1E7); + FlagClear(0x1E8); + FlagClear(0x1E9); + FlagClear(0x1EA); + FlagClear(0x1EB); + FlagClear(0x1EC); + FlagClear(0x1ED); + FlagClear(0x1EE); + FlagClear(0x1EF); + FlagClear(0x1F0); + FlagClear(0x1F1); + FlagClear(0x1F2); + FlagClear(0x1F3); } void sub_809D570(void) @@ -145,7 +145,7 @@ void sub_809D570(void) void DisableResetRTC(void) { VarSet(VAR_RESET_RTC_ENABLE, 0); - FlagReset(SYS_RESET_RTC_ENABLE); + FlagClear(SYS_RESET_RTC_ENABLE); } void EnableResetRTC(void) @@ -214,7 +214,7 @@ u8 FlagSet(u16 id) return 0; } -u8 FlagReset(u16 id) +u8 FlagClear(u16 id) { u8 *ptr = GetFlagPointer(id); if (ptr) diff --git a/src/field_map_obj.c b/src/field_map_obj.c index e80e402c8..e822fc1ca 100755 --- a/src/field_map_obj.c +++ b/src/field_map_obj.c @@ -3,7 +3,7 @@ #include "global.h" #include "malloc.h" #include "sprite.h" -#include "rom4.h" +#include "overworld.h" #include "rng.h" #include "event_scripts.h" #include "berry.h" @@ -2386,10 +2386,10 @@ bool8 do_berry_tree_growth_sparkle_1 (struct MapObject *mapObject, struct Sprite { if (!(sprite->data7 & 0x0004) && sprite->animNum == 4) { - gFieldEffectSpawnParams[0] = mapObject->coords2.x; - gFieldEffectSpawnParams[1] = mapObject->coords2.y; - gFieldEffectSpawnParams[2] = sprite->subpriority - 1; - gFieldEffectSpawnParams[3] = sprite->oam.priority; + gFieldEffectArguments[0] = mapObject->coords2.x; + gFieldEffectArguments[1] = mapObject->coords2.y; + gFieldEffectArguments[2] = sprite->subpriority - 1; + gFieldEffectArguments[3] = sprite->oam.priority; FieldEffectStart(FLDEFF_BERRY_TREE_GROWTH_SPARKLE); sprite->animNum = berryStage; } @@ -2425,10 +2425,10 @@ bool8 do_berry_tree_growth_sparkle_2 (struct MapObject *mapObject, struct Sprite sprite->data1 = 3; sprite->data2 = 0; sprite->data7 |= 0x0002; - gFieldEffectSpawnParams[0] = mapObject->coords2.x; - gFieldEffectSpawnParams[1] = mapObject->coords2.y; - gFieldEffectSpawnParams[2] = sprite->subpriority - 1; - gFieldEffectSpawnParams[3] = sprite->oam.priority; + gFieldEffectArguments[0] = mapObject->coords2.x; + gFieldEffectArguments[1] = mapObject->coords2.y; + gFieldEffectArguments[2] = sprite->subpriority - 1; + gFieldEffectArguments[3] = sprite->oam.priority; FieldEffectStart(FLDEFF_BERRY_TREE_GROWTH_SPARKLE); return TRUE; } @@ -3425,7 +3425,7 @@ void FieldObjectCB_TreeDisguise(struct Sprite *sprite) mapObject = &gMapObjects[sprite->data0]; if (mapObject->mapobj_unk_21 == 0 || (mapObject->mapobj_unk_21 == 1 && !sprite->data7)) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectSpawnParams[0], (u8 *)&gFieldEffectSpawnParams[1], (u8 *)&gFieldEffectSpawnParams[2]); + FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); mapObject->mapobj_unk_1A = FieldEffectStart(FLDEFF_TREE_DISGUISE); mapObject->mapobj_unk_21 = 1; sprite->data7 ++; @@ -3446,7 +3446,7 @@ void FieldObjectCB_MountainDisguise(struct Sprite *sprite) mapObject = &gMapObjects[sprite->data0]; if (mapObject->mapobj_unk_21 == 0 || (mapObject->mapobj_unk_21 == 1 && !sprite->data7)) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectSpawnParams[0], (u8 *)&gFieldEffectSpawnParams[1], (u8 *)&gFieldEffectSpawnParams[2]); + FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); mapObject->mapobj_unk_1A = FieldEffectStart(FLDEFF_MOUNTAIN_DISGUISE); mapObject->mapobj_unk_21 = 1; sprite->data7 ++; @@ -4693,7 +4693,7 @@ bool8 sub_80954CC(struct MapObject *mapObject, struct Sprite *sprite) bool8 do_exclamation_mark_bubble_1(struct MapObject *mapObject, struct Sprite *sprite) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectSpawnParams[0], (u8 *)&gFieldEffectSpawnParams[1], (u8 *)&gFieldEffectSpawnParams[2]); + FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); FieldEffectStart(FLDEFF_EXCLAMATION_MARK_ICON_1); sprite->data2 = 1; return TRUE; @@ -4701,7 +4701,7 @@ bool8 do_exclamation_mark_bubble_1(struct MapObject *mapObject, struct Sprite *s bool8 do_exclamation_mark_bubble_2(struct MapObject *mapObject, struct Sprite *sprite) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectSpawnParams[0], (u8 *)&gFieldEffectSpawnParams[1], (u8 *)&gFieldEffectSpawnParams[2]); + FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); FieldEffectStart(FLDEFF_EXCLAMATION_MARK_ICON_2); sprite->data2 = 1; return TRUE; @@ -4709,7 +4709,7 @@ bool8 do_exclamation_mark_bubble_2(struct MapObject *mapObject, struct Sprite *s bool8 do_heart_bubble(struct MapObject *mapObject, struct Sprite *sprite) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectSpawnParams[0], (u8 *)&gFieldEffectSpawnParams[1], (u8 *)&gFieldEffectSpawnParams[2]); + FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); FieldEffectStart(FLDEFF_HEART_ICON); sprite->data2 = 1; return TRUE; diff --git a/src/field_special_scene.c b/src/field_special_scene.c index 9c35a33da..54c1d8144 100755 --- a/src/field_special_scene.c +++ b/src/field_special_scene.c @@ -13,10 +13,10 @@ #define SECONDS(value) ((signed) (60.0 * value + 0.5)) extern u8 GetSSTidalLocation(s8 *, s8 *, s16 *, s16 *); // should be in field_specials.h -extern void warp1_set(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y); -extern bool8 sub_80D3340(u8, u8, u8); +extern void Overworld_SetWarpDestination(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y); +extern bool8 ScriptMovement_IsObjectMovementFinished(u8, u8, u8); extern bool32 CountSSTidalStep(u16); -extern bool8 exec_movement(u8, u8, u8, u8 *); +extern bool8 ScriptMovement_StartObjectMovementScript(u8, u8, u8, u8 *); extern void copy_saved_warp2_bank_and_enter_x_to_warp1(u8 unused); extern void sp13E_warp_to_last_warp(void); extern void saved_warp2_set(int unused, s8 mapGroup, s8 mapNum, s8 warpId); @@ -264,7 +264,7 @@ bool8 sub_80FB59C(void) } else { - warp1_set(mapGroup, mapNum, -1, x, y); + Overworld_SetWarpDestination(mapGroup, mapNum, -1, x, y); return TRUE; } } @@ -287,7 +287,7 @@ void Task_HandlePorthole(u8 taskId) case IDLE_CHECK: // idle and move. if (gMain.newKeys & A_BUTTON) data[1] = 1; - if (!sub_80D3340(0xFF, location->mapNum, location->mapGroup)) + if (!ScriptMovement_IsObjectMovementFinished(0xFF, location->mapNum, location->mapGroup)) return; if (CountSSTidalStep(1) == TRUE) { @@ -308,18 +308,18 @@ void Task_HandlePorthole(u8 taskId) // run this once. if (*var == 2) // which direction? { - exec_movement(0xFF, location->mapNum, location->mapGroup, gUnknown_0858E8AB); + ScriptMovement_StartObjectMovementScript(0xFF, location->mapNum, location->mapGroup, gUnknown_0858E8AB); data[0] = IDLE_CHECK; // run case 1. } else { - exec_movement(0xFF, location->mapNum, location->mapGroup, gUnknown_0858E8AD); + ScriptMovement_StartObjectMovementScript(0xFF, location->mapNum, location->mapGroup, gUnknown_0858E8AD); data[0] = IDLE_CHECK; // run case 1. } break; case EXIT_PORTHOLE: // exit porthole. - FlagReset(0x4001); - FlagReset(0x4000); + FlagClear(0x4001); + FlagClear(0x4000); copy_saved_warp2_bank_and_enter_x_to_warp1(0); sp13E_warp_to_last_warp(); DestroyTask(taskId); diff --git a/src/international_string_util.c b/src/international_string_util.c new file mode 100644 index 000000000..c77b4f8ff --- /dev/null +++ b/src/international_string_util.c @@ -0,0 +1,57 @@ +#include "global.h" +#include "international_string_util.h" +#include "text.h" + +extern s32 convert_pixel_width_to_tile_width(s32 a0); // script menu + +s32 GetStringCenterAlignXOffset(s32 fontId, const u8 *str, s32 totalWidth) +{ + return GetStringCenterAlignXOffsetWithLetterSpacing(fontId, str, totalWidth, 0); +} + +s32 GetStringRightAlignXOffset(s32 fontId, const u8 *str, s32 totalWidth) +{ + return GetStringWidthDifference(fontId, str, totalWidth, 0); +} + +s32 GetStringCenterAlignXOffsetWithLetterSpacing(s32 fontId, const u8 *str, s32 totalWidth, s32 letterSpacing) +{ + return GetStringWidthDifference(fontId, str, totalWidth, letterSpacing) / 2; +} + +s32 GetStringWidthDifference(s32 fontId, const u8 *str, s32 totalWidth, s32 letterSpacing) +{ + s32 stringWidth = GetStringWidth(fontId, str, letterSpacing); + if (totalWidth > stringWidth) + return totalWidth - stringWidth; + else + return 0; +} + +s32 GetMaxWidthInMenuTable(const u8 **str, s32 arg1) +{ + s32 i, var; + + for (var = 0, i = 0; i < arg1; i++) + { + s32 stringWidth = GetStringWidth(1, str[i * 2], 0); + if (stringWidth > var) + var = stringWidth; + } + + return convert_pixel_width_to_tile_width(var); +} + +s32 sub_81DB3D8(const u8 **str, u8* arg1, s32 arg2) +{ + s32 i, var; + + for (var = 0, i = 0; i < arg2; i++) + { + s32 stringWidth = GetStringWidth(1, str[arg1[i] * 2], 0); + if (stringWidth > var) + var = stringWidth; + } + + return convert_pixel_width_to_tile_width(var); +} diff --git a/src/lilycove_lady.c b/src/lilycove_lady.c index 9f38824f9..3b7ae49f2 100644 --- a/src/lilycove_lady.c +++ b/src/lilycove_lady.c @@ -4,7 +4,7 @@ #include "global.h" #include "main.h" -#include "rom4.h" +#include "overworld.h" #include "rom6.h" #include "event_data.h" #include "script.h" diff --git a/src/mail.c b/src/mail.c new file mode 100644 index 000000000..1060d73bd --- /dev/null +++ b/src/mail.c @@ -0,0 +1,577 @@ + +// Includes +#include "global.h" +#include "main.h" +#include "overworld.h" +#include "task.h" +#include "unknown_task.h" +#include "palette.h" +#include "menu.h" +#include "menu_helpers.h" +#include "text.h" +#include "text_window.h" +#include "string_util.h" +#include "international_string_util.h" +#include "strings.h" +#include "gpu_regs.h" +#include "bg.h" +#include "pokemon_icon.h" +#include "species.h" +#include "malloc.h" +#include "easy_chat.h" +#include "mail_data.h" +#include "mail.h" + +// Static type declarations + +struct UnkMailStruct +{ + u32 numEasyChatWords:2; + u32 xOffset:6; + u32 lineHeight:8; +}; + +struct MailLayout +{ + u8 numSubStructs; + u8 signatureYPos; + u8 signatureWidth; + u8 wordsXPos; + u8 wordsYPos; + const struct UnkMailStruct *var8; +}; + +struct MailGraphics +{ + const u16 *palette; + const u8 *tiles; + const u8 *tileMap; + u16 var0C; + u16 var0E; + u16 color10; + u16 color12; +}; + +// Static RAM declarations + +static EWRAM_DATA struct +{ + /*0x0000*/ u8 strbuf[8][64]; + /*0x0200*/ u8 playerName[12]; + /*0x020C*/ MainCallback callback; + /*0x0210*/ MainCallback callback2; + /*0x0214*/ struct MailStruct *mail; + /*0x0218*/ bool8 flag; + /*0x0219*/ u8 signatureWidth; + /*0x021a*/ u8 mailType; + /*0x021b*/ u8 animsActive; + /*0x021c*/ u8 monIconSprite; + /*0x021d*/ u8 language; + /*0x021e*/ bool8 playerIsSender; + /*0x0220*/ void (*parserSingle)(u8 *dest, u16 word); + /*0x0224*/ void (*parserMultiple)(u8 *dest, const u16 *src, u16 length1, u16 length2); + /*0x0228*/ const struct MailLayout *layout; + /*0x022c*/ u8 bg1TilemapBuffer[0x1000]; + /*0x122c*/ u8 bg2TilemapBuffer[0x1000]; +} *gUnknown_0203A134 = NULL; + +// Static ROM declarations + +void sub_81219F0(void); +void sub_8121A1C(void); +void sub_8121B1C(void); +void sub_8121C50(void); +void sub_8121C64(void); +void sub_8121C98(void); +void sub_8121CC0(void); +void sub_8121D00(void); + +// .rodata + +const struct BgTemplate gUnknown_0859F290[] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .priority = 0 + }, { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .priority = 1 + }, { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 29, + .priority = 2 + } +}; + +const struct WindowTemplate gUnknown_0859F29C[] = { + { + .priority = 0, + .tilemapLeft = 2, + .tilemapTop = 3, + .width = 26, + .height = 15, + .paletteNum = 15, + .baseBlock = 1 + }, + DUMMY_WIN_TEMPLATE +}; + +const u8 gUnknown_0859F2AC[] = { + 0, + 10, + 11 +}; + +const u16 gUnknown_0859F2B0[][2] = { + { 0x6ACD, 0x51A5 }, + { 0x45FC, 0x38D4 } +}; + +extern const u16 gUnknown_08DBE818[]; +extern const u16 gUnknown_08DBE838[]; +extern const u16 gUnknown_08DBE858[]; +extern const u16 gUnknown_08DBE878[]; +extern const u16 gUnknown_08DBE898[]; +extern const u16 gUnknown_08DBE8B8[]; +extern const u16 gUnknown_08DBE8D8[]; +extern const u16 gUnknown_08DBE8F8[]; +extern const u16 gUnknown_08DBE918[]; +extern const u16 gUnknown_08DBE938[]; +extern const u16 gUnknown_08DBE958[]; +extern const u16 gUnknown_08DBE978[]; +extern const u8 gUnknown_08DBE998[]; +extern const u8 gUnknown_08DBFBA4[]; +extern const u8 gUnknown_08DBEB38[]; +extern const u8 gUnknown_08DBFC7C[]; +extern const u8 gUnknown_08DBEC74[]; +extern const u8 gUnknown_08DBFD5C[]; +extern const u8 gUnknown_08DBEE84[]; +extern const u8 gUnknown_08DBFE68[]; +extern const u8 gUnknown_08DBEF5C[]; +extern const u8 gUnknown_08DBFF44[]; +extern const u8 gUnknown_08DBF154[]; +extern const u8 gUnknown_08DC0034[]; +extern const u8 gUnknown_08DBF2D4[]; +extern const u8 gUnknown_08DC0114[]; +extern const u8 gUnknown_08DBF37C[]; +extern const u8 gUnknown_08DC01F4[]; +extern const u8 gUnknown_08DBF50C[]; +extern const u8 gUnknown_08DC0300[]; +extern const u8 gUnknown_08DBF64C[]; +extern const u8 gUnknown_08DC03F0[]; +extern const u8 gUnknown_08DBF7B4[]; +extern const u8 gUnknown_08DC04E8[]; +extern const u8 gUnknown_08DBF904[]; +extern const u8 gUnknown_08DC0600[]; + +const struct MailGraphics gUnknown_0859F2B8[] = { + { + gUnknown_08DBE818, gUnknown_08DBE998, gUnknown_08DBFBA4, 0x02c0, 0x0000, 0x294a, 0x6739 + }, { + gUnknown_08DBE838, gUnknown_08DBEB38, gUnknown_08DBFC7C, 0x02e0, 0x0000, 0x7fff, 0x4631 + }, { + gUnknown_08DBE858, gUnknown_08DBEC74, gUnknown_08DBFD5C, 0x0400, 0x0000, 0x294a, 0x6739 + }, { + gUnknown_08DBE878, gUnknown_08DBEE84, gUnknown_08DBFE68, 0x01e0, 0x0000, 0x7fff, 0x4631 + }, { + gUnknown_08DBE898, gUnknown_08DBEF5C, gUnknown_08DBFF44, 0x02e0, 0x0000, 0x7fff, 0x4631 + }, { + gUnknown_08DBE8B8, gUnknown_08DBF154, gUnknown_08DC0034, 0x0300, 0x0000, 0x294a, 0x6739 + }, { + gUnknown_08DBE8D8, gUnknown_08DBF2D4, gUnknown_08DC0114, 0x0140, 0x0000, 0x7fff, 0x4631 + }, { + gUnknown_08DBE8F8, gUnknown_08DBF37C, gUnknown_08DC01F4, 0x0300, 0x0000, 0x7fff, 0x4631 + }, { + gUnknown_08DBE918, gUnknown_08DBF50C, gUnknown_08DC0300, 0x0220, 0x0000, 0x294a, 0x6739 + }, { + gUnknown_08DBE938, gUnknown_08DBF64C, gUnknown_08DC03F0, 0x0340, 0x0000, 0x294a, 0x6739 + }, { + gUnknown_08DBE958, gUnknown_08DBF7B4, gUnknown_08DC04E8, 0x02a0, 0x0000, 0x294a, 0x6739 + }, { + gUnknown_08DBE978, gUnknown_08DBF904, gUnknown_08DC0600, 0x0520, 0x0000, 0x294a, 0x6739 + } +}; + +const struct UnkMailStruct Unknown_0859F3A8[] = { + { .numEasyChatWords = 3, .lineHeight = 16 }, + { .numEasyChatWords = 3, .lineHeight = 16 }, + { .numEasyChatWords = 3, .lineHeight = 16 } +}; + +const struct MailLayout gUnknown_0859F3B4[] = { + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x08, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, + { 0x03, 0x00, 0x00, 0x02, 0x00, Unknown_0859F3A8 } +}; + +const struct UnkMailStruct Unknown_0859F444[] = { + { .numEasyChatWords = 2, .lineHeight = 16 }, + { .numEasyChatWords = 2, .lineHeight = 16 }, + { .numEasyChatWords = 2, .lineHeight = 16 }, + { .numEasyChatWords = 2, .lineHeight = 16 }, + { .numEasyChatWords = 1, .lineHeight = 16 } +}; + +const struct MailLayout gUnknown_0859F458[] = { + { 0x05, 0x07, 0x58, 0x0b, 0x1e, Unknown_0859F444 }, + { 0x05, 0x0a, 0x60, 0x09, 0x1e, Unknown_0859F444 }, + { 0x05, 0x0c, 0x68, 0x05, 0x1e, Unknown_0859F444 }, + { 0x05, 0x05, 0x60, 0x08, 0x1e, Unknown_0859F444 }, + { 0x05, 0x0a, 0x60, 0x09, 0x1e, Unknown_0859F444 }, + { 0x05, 0x09, 0x70, 0x05, 0x1e, Unknown_0859F444 }, + { 0x05, 0x0c, 0x68, 0x09, 0x1e, Unknown_0859F444 }, + { 0x05, 0x0d, 0x68, 0x0d, 0x1e, Unknown_0859F444 }, + { 0x05, 0x09, 0x60, 0x09, 0x1e, Unknown_0859F444 }, + { 0x05, 0x09, 0x60, 0x09, 0x1e, Unknown_0859F444 }, + { 0x05, 0x11, 0x68, 0x0f, 0x1e, Unknown_0859F444 }, + { 0x05, 0x09, 0x60, 0x05, 0x1e, Unknown_0859F444 } +}; + +// What the heck are these meant to be? Call them u16 for now. + +const u16 Unknown_0859F4E8[] = { + 0x00, 0x4000, 0x00, 0x00 +}; + +const u16 Unknown_0859F4F0[] = { + 0x00, 0x00, -1, 0x00 +}; + +const u16 Unknown_0859F4F8[] = { + 0x04, 0x00, -1, 0x00 +}; + +const u16 Unknown_0859F500[] = { + 0x00, 0x40, -1, 0x00 +}; + +const u16 *const gUnknown_0859F508[] = { + Unknown_0859F4F0, + Unknown_0859F4F8, + Unknown_0859F500 +}; + +// .text + +void sub_8121478(struct MailStruct *mail, MainCallback callback, bool8 flag) { + u16 buffer[2]; + u16 species; + + gUnknown_0203A134 = calloc(1, sizeof(*gUnknown_0203A134)); + gUnknown_0203A134->language = LANGUAGE_ENGLISH; + gUnknown_0203A134->playerIsSender = TRUE; + gUnknown_0203A134->parserSingle = CopyEasyChatWord; + gUnknown_0203A134->parserMultiple = ConvertEasyChatWordsToString; + if (mail->itemId >= ITEM_ORANGE_MAIL && mail->itemId <= ITEM_RETRO_MAIL) { + gUnknown_0203A134->mailType = mail->itemId - ITEM_ORANGE_MAIL; + } + else + { + gUnknown_0203A134->mailType = 0; + flag = FALSE; + } + switch (gUnknown_0203A134->playerIsSender) + { + case FALSE: + default: + gUnknown_0203A134->layout = &gUnknown_0859F3B4[gUnknown_0203A134->mailType]; + break; + case TRUE: + gUnknown_0203A134->layout = &gUnknown_0859F458[gUnknown_0203A134->mailType]; + break; + } + species = sub_80D45E8(mail->species, buffer); + if (species >= SPECIES_BULBASAUR && species < NUM_SPECIES) + { + switch (gUnknown_0203A134->mailType) + { + default: + gUnknown_0203A134->animsActive = 0; + break; + case ITEM_BEAD_MAIL - ITEM_ORANGE_MAIL: + gUnknown_0203A134->animsActive = 1; + break; + case ITEM_DREAM_MAIL - ITEM_ORANGE_MAIL: + gUnknown_0203A134->animsActive = 2; + break; + } + } + else + { + gUnknown_0203A134->animsActive = 0; + } + gUnknown_0203A134->mail = mail; + gUnknown_0203A134->callback = callback; + gUnknown_0203A134->flag = flag; + SetMainCallback2(sub_81219F0); +} + +bool8 sub_81215EC(void) +{ + u16 icon; + + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + remove_some_task(); + SetGpuReg(REG_OFFSET_DISPCNT, 0x0000); + break; + case 1: + CpuFill16(0, (void *)OAM, OAM_SIZE); + break; + case 2: + ResetPaletteFade(); + break; + case 3: + ResetTasks(); + break; + case 4: + ResetSpriteData(); + break; + case 5: + FreeAllSpritePalettes(); + reset_temp_tile_data_buffers(); + SetGpuReg(REG_OFFSET_BG0HOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG0VOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG1HOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG1VOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG2VOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG2HOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG3HOFS, 0x0000); + SetGpuReg(REG_OFFSET_BG3VOFS, 0x0000); + SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); + SetGpuReg(REG_OFFSET_BLDALPHA, 0x0000); + break; + case 6: + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_0859F290, 3); + SetBgTilemapBuffer(1, gUnknown_0203A134->bg1TilemapBuffer); + SetBgTilemapBuffer(2, gUnknown_0203A134->bg2TilemapBuffer); + break; + case 7: + InitWindows(gUnknown_0859F29C); + DeactivateAllTextPrinters(); + break; + case 8: + decompress_and_copy_tile_data_to_vram(1, gUnknown_0859F2B8[gUnknown_0203A134->mailType].tiles, 0, 0, 0); + break; + case 9: + if (free_temp_tile_data_buffers_if_possible()) + { + return FALSE; + } + break; + case 10: + FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 30, 20); + FillBgTilemapBufferRect_Palette0(2, 1, 0, 0, 30, 20); + CopyToBgTilemapBuffer(1, gUnknown_0859F2B8[gUnknown_0203A134->mailType].tileMap, 0, 0); + break; + case 11: + CopyBgTilemapBufferToVram(0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + break; + case 12: + LoadPalette(sub_8098C64(), 240, 32); + gPlttBufferUnfaded[250] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color10; + gPlttBufferFaded[250] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color10; + gPlttBufferUnfaded[251] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color12; + gPlttBufferFaded[251] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color12; + LoadPalette(gUnknown_0859F2B8[gUnknown_0203A134->mailType].palette, 0, 32); + gPlttBufferUnfaded[10] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; + gPlttBufferFaded[10] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; + gPlttBufferUnfaded[11] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; + gPlttBufferFaded[11] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; + break; + case 13: + if (gUnknown_0203A134->flag) + { + sub_8121A1C(); + } + break; + case 14: + if (gUnknown_0203A134->flag) + { + sub_8121B1C(); + RunTextPrinters(); + } + break; + case 15: + if (sub_8087598() == TRUE) + { + return FALSE; + } + break; + case 16: + SetVBlankCallback(sub_8121C50); + gPaletteFade.bufferTransferDisabled = TRUE; + break; + case 17: + icon = sub_80D2E84(gUnknown_0203A134->mail->species); + switch (gUnknown_0203A134->animsActive) + { + case 1: + sub_80D2F68(icon); + gUnknown_0203A134->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x60, 0x80, 0, 0); + break; + case 2: + sub_80D2F68(icon); + gUnknown_0203A134->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x28, 0x80, 0, 0); + break; + } + break; + case 18: + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + ShowBg(0); + ShowBg(1); + ShowBg(2); + BeginNormalPaletteFade(-1, 0, 16, 0, 0); + gPaletteFade.bufferTransferDisabled = FALSE; + gUnknown_0203A134->callback2 = sub_8121C98; + return TRUE; + default: + return FALSE; + } + gMain.state ++; + return FALSE; +} + +void sub_81219F0(void) +{ + do + { + if (sub_81215EC() == TRUE) + { + SetMainCallback2(sub_8121C64); + break; + } + } while (sub_81221AC() != TRUE); +} + +void sub_8121A1C(void) +{ + u16 i; + u8 total; + u8 *ptr; + + total = 0; + for (i = 0; i < gUnknown_0203A134->layout->numSubStructs; i ++) + { + ConvertEasyChatWordsToString(gUnknown_0203A134->strbuf[i], &gUnknown_0203A134->mail->words[total], gUnknown_0203A134->layout->var8[i].numEasyChatWords, 1); + total += gUnknown_0203A134->layout->var8[i].numEasyChatWords; + } + ptr = StringCopy(gUnknown_0203A134->playerName, gUnknown_0203A134->mail->playerName); + if (!gUnknown_0203A134->playerIsSender) + { + StringCopy(ptr, gText_FromSpace); + gUnknown_0203A134->signatureWidth = gUnknown_0203A134->layout->signatureWidth - (StringLength(gUnknown_0203A134->playerName) * 8 - 0x60); + } + else + { + sub_81DB52C(gUnknown_0203A134->playerName); + gUnknown_0203A134->signatureWidth = gUnknown_0203A134->layout->signatureWidth; + } +} + +void sub_8121B1C(void) +{ + u16 i; + u8 strbuf[0x20]; + u8 y; + u8 *bufptr; + s32 box_x; + s32 box_y; + + y = 0; + PutWindowTilemap(0); + PutWindowTilemap(1); + FillWindowPixelBuffer(0, 0); + FillWindowPixelBuffer(1, 0); + for (i = 0; i < gUnknown_0203A134->layout->numSubStructs; i ++) + { + if (gUnknown_0203A134->strbuf[i][0] == EOS || gUnknown_0203A134->strbuf[i][0] == CHAR_SPACE) + { + continue; + } + box_print(0, 1, gUnknown_0203A134->layout->var8[i].xOffset + gUnknown_0203A134->layout->wordsYPos, y + gUnknown_0203A134->layout->wordsXPos, gUnknown_0859F2AC, 0, gUnknown_0203A134->strbuf[i]); + y += gUnknown_0203A134->layout->var8[i].lineHeight; + } + bufptr = StringCopy(strbuf, gText_FromSpace); + StringCopy(bufptr, gUnknown_0203A134->playerName); + box_x = GetStringCenterAlignXOffset(1, strbuf, gUnknown_0203A134->signatureWidth) + 0x68; + box_y = gUnknown_0203A134->layout->signatureYPos + 0x58; + box_print(0, 1, box_x, box_y, gUnknown_0859F2AC, 0, strbuf); + CopyWindowToVram(0, 3); + CopyWindowToVram(1, 3); +} + +void sub_8121C50(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +void sub_8121C64(void) +{ + if (gUnknown_0203A134->animsActive != 0) + { + AnimateSprites(); + BuildOamBuffer(); + } + gUnknown_0203A134->callback2(); +} + +void sub_8121C98(void) +{ + if (!UpdatePaletteFade()) + { + gUnknown_0203A134->callback2 = sub_8121CC0; + } +} + +void sub_8121CC0(void) +{ + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gUnknown_0203A134->callback2 = sub_8121D00; + } +} + +void sub_8121D00(void) +{ + if (!UpdatePaletteFade()) + { + SetMainCallback2(gUnknown_0203A134->callback); + switch (gUnknown_0203A134->animsActive) + { + case 1: + case 2: + sub_80D2FF0(sub_80D2E84(gUnknown_0203A134->mail->species)); + sub_80D2EF8(&gSprites[gUnknown_0203A134->monIconSprite]); + } + memset(gUnknown_0203A134, 0, sizeof(*gUnknown_0203A134)); + ResetPaletteFade(); + UnsetBgTilemapBuffer(0); + UnsetBgTilemapBuffer(1); + ResetBgsAndClearDma3BusyFlags(0); + FreeAllWindowBuffers(); + free(gUnknown_0203A134); + gUnknown_0203A134 = NULL; + } +} diff --git a/src/money.c b/src/money.c index 65a45b158..98f25a42a 100644 --- a/src/money.c +++ b/src/money.c @@ -110,7 +110,7 @@ void AddMoney(u32* moneyPtr, u32 toAdd) SetMoney(moneyPtr, toSet); } -void SubtractMoney(u32* moneyPtr, u32 toSub) +void RemoveMoney(u32* moneyPtr, u32 toSub) { u32 toSet = GetMoney(moneyPtr); @@ -130,7 +130,7 @@ bool8 IsEnoughForCostInVar0x8005(void) void SubtractMoneyFromVar0x8005(void) { - SubtractMoney(&gSaveBlock1Ptr->money, gSpecialVar_0x8005); + RemoveMoney(&gSaveBlock1Ptr->money, gSpecialVar_0x8005); } void PrintMoneyAmountInMoneyBox(u8 windowId, int amount, u8 speed) diff --git a/src/new_game.c b/src/new_game.c index d01aa69d4..d0666dd71 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -29,7 +29,7 @@ extern u8 gUnknown_030060B0; // TODO: replace those declarations with file headers extern u16 GetGeneratedTrainerIdLower(void); extern void ClearContestWinnerPicsInContestHall(void); -extern void warp1_set(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPos, s8 yPos); +extern void Overworld_SetWarpDestination(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPos, s8 yPos); extern void warp_in(void); extern void sub_80BB358(void); extern void ResetBagScrollPositions(void); @@ -131,7 +131,7 @@ void sub_8084400(void) void WarpToTruck(void) { - warp1_set(25, 40, -1, -1, -1); // inside of truck + Overworld_SetWarpDestination(25, 40, -1, -1, -1); // inside of truck warp_in(); } diff --git a/src/palette.c b/src/palette.c index d60efdbc5..d4bb593da 100644 --- a/src/palette.c +++ b/src/palette.c @@ -53,13 +53,13 @@ static void UpdateBlendRegisters(void); static bool8 IsSoftwarePaletteFadeFinishing(void); static void sub_80A2D54(u8 taskId); -EWRAM_DATA u16 gPlttBufferUnfaded[0x200] = {0}; -EWRAM_DATA u16 gPlttBufferFaded[0x200] = {0}; +EWRAM_DATA u16 gPlttBufferUnfaded[PLTT_BUFFER_SIZE] = {0}; +EWRAM_DATA u16 gPlttBufferFaded[PLTT_BUFFER_SIZE] = {0}; EWRAM_DATA struct PaletteStruct sPaletteStructs[0x10] = {0}; EWRAM_DATA struct PaletteFadeControl gPaletteFade = {0}; static EWRAM_DATA u32 gFiller_2037FE0 = 0; static EWRAM_DATA u32 sPlttBufferTransferPending = 0; -EWRAM_DATA u8 gPaletteDecompressionBuffer[0x400] = {0}; +EWRAM_DATA u8 gPaletteDecompressionBuffer[PLTT_DECOMP_BUFFER_SIZE] = {0}; static const struct PaletteStructTemplate gDummyPaletteStructTemplate = { .uid = 0xFFFF, diff --git a/src/pokemon_2.c b/src/pokemon_2.c index ee54f0e4d..27441f952 100644 --- a/src/pokemon_2.c +++ b/src/pokemon_2.c @@ -1089,7 +1089,7 @@ u8 SendMonToPC(struct Pokemon* mon) gSpecialVar_0x8012 = boxNo; gSpecialVar_0x8013 = boxPos; if (get_unknown_box_id() != boxNo) - FlagReset(SYS_STORAGE_UNKNOWN_FLAG); + FlagClear(SYS_STORAGE_UNKNOWN_FLAG); VarSet(VAR_STORAGE_UNKNOWN, boxNo); return MON_GIVEN_TO_PC; } diff --git a/src/reset_save_heap.c b/src/reset_save_heap.c index b786ff9f8..d4dbc5f42 100644 --- a/src/reset_save_heap.c +++ b/src/reset_save_heap.c @@ -5,7 +5,7 @@ #include "load_save.h" #include "save.h" #include "new_game.h" -#include "rom4.h" +#include "overworld.h" #include "malloc.h" void sub_81700F8(void) diff --git a/src/reshow_battle_screen.c b/src/reshow_battle_screen.c index 25c2ca658..343ddb9c0 100644 --- a/src/reshow_battle_screen.c +++ b/src/reshow_battle_screen.c @@ -336,9 +336,9 @@ static void CreateHealthboxSprite(u8 bank) UpdateHealthboxAttribute(gHealthBoxesIds[bank], &gPlayerParty[gBattlePartyID[bank]], HEALTHBOX_ALL); if (GetBankIdentity(bank) == IDENTITY_OPPONENT_MON2 || GetBankIdentity(bank) == IDENTITY_PLAYER_MON2) - nullsub_30(gHealthBoxesIds[bank], TRUE); + DummyBattleInterfaceFunc(gHealthBoxesIds[bank], TRUE); else - nullsub_30(gHealthBoxesIds[bank], FALSE); + DummyBattleInterfaceFunc(gHealthBoxesIds[bank], FALSE); if (GetBankSide(bank) != SIDE_PLAYER) { diff --git a/src/safari_zone.c b/src/safari_zone.c index f7ef28577..77c6bbd61 100644 --- a/src/safari_zone.c +++ b/src/safari_zone.c @@ -60,7 +60,7 @@ void SetSafariZoneFlag(void) void ResetSafariZoneFlag(void) { - FlagReset(SYS_SAFARI_MODE); + FlagClear(SYS_SAFARI_MODE); } void EnterSafariMode(void) @@ -139,7 +139,7 @@ static void ClearAllPokeblockFeeders(void) memset(sPokeblockFeeders, 0, sizeof(sPokeblockFeeders)); } -static void GetPokeblockFeederInFront(void) +void GetPokeblockFeederInFront(void) { s16 x, y; u16 i; diff --git a/src/scrcmd.c b/src/scrcmd.c index b56a53caf..af314609c 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -1,15 +1,2452 @@ - -// Includes #include "global.h" +#include "battle_frontier_2.h" +#include "battle_setup.h" +#include "berry.h" +#include "clock.h" +#include "coins.h" +#include "contest_link_80F57C4.h" +#include "contest_painting.h" +#include "data2.h" +#include "decoration.h" +#include "decoration_inventory.h" +#include "event_data.h" +#include "field_door.h" +#include "field_effect.h" +#include "field_fadetransition.h" +#include "field_map_obj.h" +#include "field_map_obj_helpers.h" +#include "field_message_box.h" +#include "field_player_avatar.h" +#include "field_screen_effect.h" +#include "field_specials.h" +#include "field_tasks.h" +#include "field_weather.h" +#include "fieldmap.h" +#include "item.h" +#include "lilycove_lady.h" +#include "main.h" +#include "map_obj_lock.h" +#include "menu.h" +#include "money.h" +#include "mystery_event_script.h" +#include "new_menu_helpers.h" +#include "palette.h" +#include "party_menu.h" +#include "pokemon_3.h" +#include "pokemon_storage_system.h" +#include "rng.h" +#include "overworld.h" +#include "rtc.h" +#include "script.h" +#include "script_menu.h" +#include "script_movement.h" +#include "script_pokemon_80F8.h" +#include "script_pokemon_81B9.h" +#include "shop.h" +#include "slot_machine.h" +#include "sound.h" +#include "string_util.h" +#include "text.h" +#include "text_window.h" +#include "trainer_see.h" +#include "tv.h" +#include "window.h" + +typedef u16 (*SpecialFunc)(void); +typedef void (*NativeFunc)(void); + +extern u32 gUnknown_020375C0; + +static EWRAM_DATA u32 gUnknown_020375C4 = 0; +static EWRAM_DATA u16 sPauseCounter = 0; +static EWRAM_DATA u16 sMovingNpcId = 0; +static EWRAM_DATA u16 sMovingNpcMapBank = 0; +static EWRAM_DATA u16 sMovingNpcMapId = 0; +static EWRAM_DATA u16 sFieldEffectScriptId = 0; -// Static type declarations +extern u16 gSpecialVar_0x8000; +extern u16 gSpecialVar_0x8001; +extern u16 gSpecialVar_0x8002; +extern u16 gSpecialVar_0x8004; -// Static RAM declarations +extern u16 gScriptResult; + +extern u16 gScriptContestCategory; IWRAM_DATA u8 gUnknown_03000F30; -// Static ROM declarations +extern const SpecialFunc gSpecials[]; +extern const u8 *gStdScripts[]; +extern const u8 *gStdScripts_End[]; + +void sub_809BDB4(void); + +// This is defined in here so the optimizer can't see its value when compiling +// script.c. +void * const gNullScriptPtr = NULL; + +static const u8 sScriptConditionTable[6][3] = +{ +// < = > + 1, 0, 0, // < + 0, 1, 0, // = + 0, 0, 1, // > + 1, 1, 0, // <= + 0, 1, 1, // >= + 1, 0, 1, // != +}; + +static u8 * const sScriptStringVars[] = +{ + gStringVar1, + gStringVar2, + gStringVar3, +}; + +bool8 ScrCmd_nop(struct ScriptContext *ctx) +{ + return FALSE; +} + +bool8 ScrCmd_nop1(struct ScriptContext *ctx) +{ + return FALSE; +} + +bool8 ScrCmd_end(struct ScriptContext *ctx) +{ + StopScript(ctx); + return FALSE; +} + +bool8 ScrCmd_gotonative(struct ScriptContext *ctx) +{ + bool8 (*addr)(void) = (bool8 (*)(void))ScriptReadWord(ctx); + + SetupNativeScript(ctx, addr); + return TRUE; +} + +bool8 ScrCmd_special(struct ScriptContext *ctx) +{ + u16 index = ScriptReadHalfword(ctx); + + gSpecials[index](); + return FALSE; +} + +bool8 ScrCmd_specialvar(struct ScriptContext *ctx) +{ + u16 *var = GetVarPointer(ScriptReadHalfword(ctx)); + + *var = gSpecials[ScriptReadHalfword(ctx)](); + return FALSE; +} + +bool8 ScrCmd_callnative(struct ScriptContext *ctx) +{ + NativeFunc func = (NativeFunc)ScriptReadWord(ctx); + + func(); + return FALSE; +} + +bool8 ScrCmd_waitstate(struct ScriptContext *ctx) +{ + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_goto(struct ScriptContext *ctx) +{ + const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + + ScriptJump(ctx, ptr); + return FALSE; +} + +bool8 ScrCmd_return(struct ScriptContext *ctx) +{ + ScriptReturn(ctx); + return FALSE; +} + +bool8 ScrCmd_call(struct ScriptContext *ctx) +{ + const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + + ScriptCall(ctx, ptr); + return FALSE; +} + +bool8 ScrCmd_goto_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptJump(ctx, ptr); + return FALSE; +} + +bool8 ScrCmd_call_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptCall(ctx, ptr); + return FALSE; +} + +bool8 ScrCmd_setvaddress(struct ScriptContext *ctx) +{ + u32 addr1 = (u32)ctx->scriptPtr - 1; + u32 addr2 = ScriptReadWord(ctx); + + gUnknown_020375C4 = addr2 - addr1; + return FALSE; +} + +bool8 ScrCmd_vgoto(struct ScriptContext *ctx) +{ + u32 addr = ScriptReadWord(ctx); + + ScriptJump(ctx, (u8 *)(addr - gUnknown_020375C4)); + return FALSE; +} + +bool8 ScrCmd_vcall(struct ScriptContext *ctx) +{ + u32 addr = ScriptReadWord(ctx); + + ScriptCall(ctx, (u8 *)(addr - gUnknown_020375C4)); + return FALSE; +} + +bool8 ScrCmd_vgoto_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 *ptr = (const u8 *)(ScriptReadWord(ctx) - gUnknown_020375C4); + + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptJump(ctx, ptr); + return FALSE; +} + +bool8 ScrCmd_vcall_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 *ptr = (const u8 *)(ScriptReadWord(ctx) - gUnknown_020375C4); + + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptCall(ctx, ptr); + return FALSE; +} + +bool8 ScrCmd_gotostd(struct ScriptContext *ctx) +{ + u8 index = ScriptReadByte(ctx); + const u8 **ptr = &gStdScripts[index]; + + if (ptr < gStdScripts_End) + ScriptJump(ctx, *ptr); + return FALSE; +} + +bool8 ScrCmd_callstd(struct ScriptContext *ctx) +{ + u8 index = ScriptReadByte(ctx); + const u8 **ptr = &gStdScripts[index]; + + if (ptr < gStdScripts_End) + ScriptCall(ctx, *ptr); + return FALSE; +} + +bool8 ScrCmd_gotostd_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + u8 index = ScriptReadByte(ctx); + + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + { + const u8 **ptr = &gStdScripts[index]; + if (ptr < gStdScripts_End) + ScriptJump(ctx, *ptr); + } + return FALSE; +} + +bool8 ScrCmd_callstd_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + u8 index = ScriptReadByte(ctx); + + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + { + const u8 **ptr = &gStdScripts[index]; + if (ptr < gStdScripts_End) + ScriptCall(ctx, *ptr); + } + return FALSE; +} + +bool8 ScrCmd_gotoram(struct ScriptContext *ctx) +{ + ScriptJump(ctx, (const u8 *)gUnknown_020375C0); + return FALSE; +} + +bool8 ScrCmd_killscript(struct ScriptContext *ctx) +{ + ClearRamScript(); + StopScript(ctx); + return TRUE; +} + +bool8 ScrCmd_setmysteryeventstatus(struct ScriptContext *ctx) +{ + u8 value = ScriptReadByte(ctx); + + SetMysteryEventScriptStatus(value); + return FALSE; +} + +bool8 ScrCmd_loadword(struct ScriptContext *ctx) +{ + u8 index = ScriptReadByte(ctx); + + ctx->data[index] = ScriptReadWord(ctx); + return FALSE; +} + +bool8 ScrCmd_loadbytefromaddr(struct ScriptContext *ctx) +{ + u8 index = ScriptReadByte(ctx); + + ctx->data[index] = *(const u8 *)ScriptReadWord(ctx); + return FALSE; +} + +bool8 ScrCmd_writebytetoaddr(struct ScriptContext *ctx) +{ + u8 value = ScriptReadByte(ctx); + + *(u8 *)ScriptReadWord(ctx) = value; + return FALSE; +} + +bool8 ScrCmd_loadbyte(struct ScriptContext *ctx) +{ + u8 index = ScriptReadByte(ctx); + + ctx->data[index] = ScriptReadByte(ctx); + return FALSE; +} + +bool8 ScrCmd_setptrbyte(struct ScriptContext *ctx) +{ + u8 index = ScriptReadByte(ctx); + + *(u8 *)ScriptReadWord(ctx) = ctx->data[index]; + return FALSE; +} + +bool8 ScrCmd_copylocal(struct ScriptContext *ctx) +{ + u8 destIndex = ScriptReadByte(ctx); + u8 srcIndex = ScriptReadByte(ctx); + + ctx->data[destIndex] = ctx->data[srcIndex]; + return FALSE; +} + +bool8 ScrCmd_copybyte(struct ScriptContext *ctx) +{ + u8 *ptr = (u8 *)ScriptReadWord(ctx); + *ptr = *(const u8 *)ScriptReadWord(ctx); + return FALSE; +} + +bool8 ScrCmd_setvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr = ScriptReadHalfword(ctx); + return FALSE; +} + +bool8 ScrCmd_copyvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr = *GetVarPointer(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_setorcopyvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr = VarGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +u8 compare_012(u16 a1, u16 a2) +{ + if (a1 < a2) + return 0; + if (a1 == a2) + return 1; + return 2; +} + +// comparelocaltolocal +bool8 ScrCmd_compare_local_to_local(struct ScriptContext *ctx) +{ + const u8 value1 = ctx->data[ScriptReadByte(ctx)]; + const u8 value2 = ctx->data[ScriptReadByte(ctx)]; + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +// comparelocaltoimm +bool8 ScrCmd_compare_local_to_value(struct ScriptContext *ctx) +{ + const u8 value1 = ctx->data[ScriptReadByte(ctx)]; + const u8 value2 = ScriptReadByte(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_local_to_addr(struct ScriptContext *ctx) +{ + const u8 value1 = ctx->data[ScriptReadByte(ctx)]; + const u8 value2 = *(const u8 *)ScriptReadWord(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_addr_to_local(struct ScriptContext *ctx) +{ + const u8 value1 = *(const u8 *)ScriptReadWord(ctx); + const u8 value2 = ctx->data[ScriptReadByte(ctx)]; + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_addr_to_value(struct ScriptContext *ctx) +{ + const u8 value1 = *(const u8 *)ScriptReadWord(ctx); + const u8 value2 = ScriptReadByte(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_addr_to_addr(struct ScriptContext *ctx) +{ + const u8 value1 = *(const u8 *)ScriptReadWord(ctx); + const u8 value2 = *(const u8 *)ScriptReadWord(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_var_to_value(struct ScriptContext *ctx) +{ + const u16 value1 = *GetVarPointer(ScriptReadHalfword(ctx)); + const u16 value2 = ScriptReadHalfword(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_var_to_var(struct ScriptContext *ctx) +{ + const u16 *ptr1 = GetVarPointer(ScriptReadHalfword(ctx)); + const u16 *ptr2 = GetVarPointer(ScriptReadHalfword(ctx)); + + ctx->comparisonResult = compare_012(*ptr1, *ptr2); + return FALSE; +} + +bool8 ScrCmd_addvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr += ScriptReadHalfword(ctx); + return FALSE; +} + +bool8 ScrCmd_subvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr -= VarGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_random(struct ScriptContext *ctx) +{ + u16 max = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = Random() % max; + return FALSE; +} + +bool8 ScrCmd_additem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = AddBagItem(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_removeitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = RemoveBagItem(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_checkitemspace(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = CheckBagHasSpace(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_checkitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = CheckBagHasItem(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_checkitemtype(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = GetPocketByItemId(itemId); + return FALSE; +} + +bool8 ScrCmd_addpcitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u16 quantity = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = AddPCItem(itemId, quantity); + return FALSE; +} + +bool8 ScrCmd_checkpcitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u16 quantity = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = CheckPCHasItem(itemId, quantity); + return FALSE; +} + +bool8 ScrCmd_adddecor(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = DecorationAdd(decorId); + return FALSE; +} + +bool8 ScrCmd_removedecor(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = DecorationRemove(decorId); + return FALSE; +} + +bool8 ScrCmd_checkdecor(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = DecorationCheckSpace(decorId); + return FALSE; +} + +bool8 ScrCmd_hasdecor(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = CheckHasDecoration(decorId); + return FALSE; +} + +bool8 ScrCmd_setflag(struct ScriptContext *ctx) +{ + FlagSet(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_clearflag(struct ScriptContext *ctx) +{ + FlagClear(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_checkflag(struct ScriptContext *ctx) +{ + ctx->comparisonResult = FlagGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_incrementgamestat(struct ScriptContext *ctx) +{ + IncrementGameStat(ScriptReadByte(ctx)); + return FALSE; +} + +bool8 ScrCmd_animdarklevel(struct ScriptContext *ctx) +{ + sub_80B009C(ScriptReadByte(ctx)); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_setdarklevel(struct ScriptContext *ctx) +{ + u16 flashLevel = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetFlashLevel(flashLevel); + return FALSE; +} + +static bool8 IsPaletteNotActive(void) +{ + if (!gPaletteFade.active) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_fadescreen(struct ScriptContext *ctx) +{ + fade_screen(ScriptReadByte(ctx), 0); + SetupNativeScript(ctx, IsPaletteNotActive); + return TRUE; +} + +bool8 ScrCmd_fadescreendelay(struct ScriptContext *ctx) +{ + u8 mode = ScriptReadByte(ctx); + u8 delay = ScriptReadByte(ctx); + + fade_screen(mode, delay); + SetupNativeScript(ctx, IsPaletteNotActive); + return TRUE; +} + +bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx) +{ + u8 mode = ScriptReadByte(ctx); + + switch (mode) + { + case 1: + default: + CpuCopy32(gPlttBufferUnfaded, gPaletteDecompressionBuffer, PLTT_DECOMP_BUFFER_SIZE); + fade_screen(mode, 0); + break; + case 0: + case 2: + CpuCopy32(gPaletteDecompressionBuffer, gPlttBufferUnfaded, PLTT_DECOMP_BUFFER_SIZE); + fade_screen(mode, 0); + break; + } + + SetupNativeScript(ctx, IsPaletteNotActive); + return TRUE; +} + +static bool8 RunPauseTimer(void) +{ + sPauseCounter--; + + if (sPauseCounter == 0) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_delay(struct ScriptContext *ctx) +{ + sPauseCounter = ScriptReadHalfword(ctx); + SetupNativeScript(ctx, RunPauseTimer); + return TRUE; +} + +bool8 ScrCmd_initclock(struct ScriptContext *ctx) +{ + u8 hour = VarGet(ScriptReadHalfword(ctx)); + u8 minute = VarGet(ScriptReadHalfword(ctx)); + + RtcInitLocalTimeOffset(hour, minute); + return FALSE; +} + +bool8 ScrCmd_dodailyevents(struct ScriptContext *ctx) +{ + DoTimeBasedEvents(); + return FALSE; +} + +bool8 ScrCmd_gettime(struct ScriptContext *ctx) +{ + RtcCalcLocalTime(); + gSpecialVar_0x8000 = gLocalTime.hours; + gSpecialVar_0x8001 = gLocalTime.minutes; + gSpecialVar_0x8002 = gLocalTime.seconds; + return FALSE; +} + +bool8 ScrCmd_setweather(struct ScriptContext *ctx) +{ + u16 weather = VarGet(ScriptReadHalfword(ctx)); + + SetSav1Weather(weather); + return FALSE; +} + +bool8 ScrCmd_resetweather(struct ScriptContext *ctx) +{ + sub_80AEDBC(); + return FALSE; +} + +bool8 ScrCmd_doweather(struct ScriptContext *ctx) +{ + DoCurrentWeather(); + return FALSE; +} + +bool8 ScrCmd_tileeffect(struct ScriptContext *ctx) +{ + ActivatePerStepCallback(ScriptReadByte(ctx)); + return FALSE; +} + +bool8 ScrCmd_setmaplayoutindex(struct ScriptContext *ctx) +{ + u16 value = VarGet(ScriptReadHalfword(ctx)); + + sub_8085524(value); + return FALSE; +} + +bool8 ScrCmd_warp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_80AF734(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_warpsilent(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sp13E_warp_to_last_warp(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_warpdoor(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_80AF7D0(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_warphole(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u16 x; + u16 y; + + PlayerGetDestCoords(&x, &y); + if (mapGroup == 0xFF && mapNum == 0xFF) + sub_8084EBC(x - 7, y - 7); + else + Overworld_SetWarpDestination(mapGroup, mapNum, -1, x - 7, y - 7); + sp13F_fall_to_last_warp(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_warpteleport(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_80AF848(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_warpD7(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_80AF87C(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_setwarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setdynamicwarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + saved_warp2_set_2(0, mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setdivewarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + sub_8084E2C(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setholewarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + sub_8084E80(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setescapewarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + sub_8084DD4(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_getplayerxy(struct ScriptContext *ctx) +{ + u16 *pX = GetVarPointer(ScriptReadHalfword(ctx)); + u16 *pY = GetVarPointer(ScriptReadHalfword(ctx)); + + *pX = gSaveBlock1Ptr->pos.x; + *pY = gSaveBlock1Ptr->pos.y; + return FALSE; +} + +bool8 ScrCmd_countpokemon(struct ScriptContext *ctx) +{ + gScriptResult = CalculatePlayerPartyCount(); + return FALSE; +} + +bool8 ScrCmd_playse(struct ScriptContext *ctx) +{ + PlaySE(ScriptReadHalfword(ctx)); + return FALSE; +} + +static bool8 WaitForSoundEffectFinish(void) +{ + if (!IsSEPlaying()) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_waitse(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, WaitForSoundEffectFinish); + return TRUE; +} + +bool8 ScrCmd_playfanfare(struct ScriptContext *ctx) +{ + PlayFanfare(ScriptReadHalfword(ctx)); + return FALSE; +} + +static bool8 WaitForFanfareFinish(void) +{ + return IsFanfareTaskInactive(); +} + +bool8 ScrCmd_waitfanfare(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, WaitForFanfareFinish); + return TRUE; +} + +bool8 ScrCmd_playbgm(struct ScriptContext *ctx) +{ + u16 songId = ScriptReadHalfword(ctx); + bool8 val = ScriptReadByte(ctx); + + if (val == TRUE) + Overworld_SetSavedMusic(songId); + PlayNewMapMusic(songId); + return FALSE; +} + +bool8 ScrCmd_savebgm(struct ScriptContext *ctx) +{ + Overworld_SetSavedMusic(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_fadedefaultbgm(struct ScriptContext *ctx) +{ + Overworld_ChangeMusicToDefault(); + return FALSE; +} + +bool8 ScrCmd_fadenewbgm(struct ScriptContext *ctx) +{ + Overworld_ChangeMusicTo(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_fadeoutbgm(struct ScriptContext *ctx) +{ + u8 speed = ScriptReadByte(ctx); + + if (speed != 0) + FadeOutBGMTemporarily(4 * speed); + else + FadeOutBGMTemporarily(4); + SetupNativeScript(ctx, IsBGMPausedOrStopped); + return TRUE; +} + +bool8 ScrCmd_fadeinbgm(struct ScriptContext *ctx) +{ + u8 speed = ScriptReadByte(ctx); + + if (speed != 0) + FadeInBGM(4 * speed); + else + FadeInBGM(4); + return FALSE; +} + +bool8 ScrCmd_applymovement(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + const void *movementScript = (const void *)ScriptReadWord(ctx); + + ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript); + sMovingNpcId = localId; + return FALSE; +} + +bool8 ScrCmd_applymovement_at(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + const void *movementScript = (const void *)ScriptReadWord(ctx); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + ScriptMovement_StartObjectMovementScript(localId, mapNum, mapGroup, movementScript); + sMovingNpcId = localId; + return FALSE; +} + +static bool8 WaitForMovementFinish(void) +{ + return ScriptMovement_IsObjectMovementFinished(sMovingNpcId, sMovingNpcMapId, sMovingNpcMapBank); +} + +bool8 ScrCmd_waitmovement(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + + if (localId != 0) + sMovingNpcId = localId; + sMovingNpcMapBank = gSaveBlock1Ptr->location.mapGroup; + sMovingNpcMapId = gSaveBlock1Ptr->location.mapNum; + SetupNativeScript(ctx, WaitForMovementFinish); + return TRUE; +} + +bool8 ScrCmd_waitmovement_at(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapBank; + u8 mapId; + + if (localId != 0) + sMovingNpcId = localId; + mapBank = ScriptReadByte(ctx); + mapId = ScriptReadByte(ctx); + sMovingNpcMapBank = mapBank; + sMovingNpcMapId = mapId; + SetupNativeScript(ctx, WaitForMovementFinish); + return TRUE; +} + +bool8 ScrCmd_removeobject(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + + RemoveFieldObjectByLocalIdAndMap(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + return FALSE; +} + +bool8 ScrCmd_removeobject_at(struct ScriptContext *ctx) +{ + u16 objectId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + RemoveFieldObjectByLocalIdAndMap(objectId, mapNum, mapGroup); + return FALSE; +} + +bool8 ScrCmd_addobject(struct ScriptContext *ctx) +{ + u16 objectId = VarGet(ScriptReadHalfword(ctx)); + + show_sprite(objectId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + return FALSE; +} + +bool8 ScrCmd_addobject_at(struct ScriptContext *ctx) +{ + u16 objectId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + show_sprite(objectId, mapNum, mapGroup); + return FALSE; +} + +bool8 ScrCmd_setobjectxy(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + sub_808EBA8(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, x, y); + return FALSE; +} + +bool8 ScrCmd_setobjectxyperm(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetMapObjTemplateCoords(localId, x, y); + return FALSE; +} + +bool8 ScrCmd_moveobjectoffscreen(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + + sub_808F254(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + return FALSE; +} + +bool8 ScrCmd_showobject(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + npc_by_local_id_and_map_set_field_1_bit_x20(localId, mapNum, mapGroup, 0); + return FALSE; +} + +bool8 ScrCmd_hideobject(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + npc_by_local_id_and_map_set_field_1_bit_x20(localId, mapNum, mapGroup, 1); + return FALSE; +} + +bool8 ScrCmd_setobjectpriority(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 priority = ScriptReadByte(ctx); + + sub_808E78C(localId, mapNum, mapGroup, priority + 83); + return FALSE; +} + +bool8 ScrCmd_resetobjectpriority(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + sub_808E7E4(localId, mapNum, mapGroup); + return FALSE; +} + +bool8 ScrCmd_faceplayer(struct ScriptContext *ctx) +{ + if (gMapObjects[gSelectedMapObject].active) + { + FieldObjectFaceOppositeDirection(&gMapObjects[gSelectedMapObject], + player_get_direction_lower_nybble()); + } + return FALSE; +} + +bool8 ScrCmd_turnobject(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 direction = ScriptReadByte(ctx); + + FieldObjectTurnByLocalIdAndMap(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, direction); + return FALSE; +} + +bool8 ScrCmd_setobjectmovementtype(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 movementType = ScriptReadByte(ctx); + + Overworld_SetMapObjTemplateMovementType(localId, movementType); + return FALSE; +} + +bool8 ScrCmd_createvobject(struct ScriptContext *ctx) +{ + u8 graphicsId = ScriptReadByte(ctx); + u8 v2 = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u32 y = VarGet(ScriptReadHalfword(ctx)); + u8 elevation = ScriptReadByte(ctx); + u8 direction = ScriptReadByte(ctx); + + sprite_new(graphicsId, v2, x, y, elevation, direction); + return FALSE; +} + +bool8 ScrCmd_turnvobject(struct ScriptContext *ctx) +{ + u8 v1 = ScriptReadByte(ctx); + u8 direction = ScriptReadByte(ctx); + + sub_8097B78(v1, direction); + return FALSE; +} + +bool8 ScrCmd_lockall(struct ScriptContext *ctx) +{ + if (is_c1_link_related_active()) + { + return FALSE; + } + else + { + ScriptFreezeMapObjects(); + SetupNativeScript(ctx, sub_80983C4); + return TRUE; + } +} + +bool8 ScrCmd_lock(struct ScriptContext *ctx) +{ + if (is_c1_link_related_active()) + { + return FALSE; + } + else + { + if (gMapObjects[gSelectedMapObject].active) + { + LockSelectedMapObject(); + SetupNativeScript(ctx, sub_809847C); + } + else + { + ScriptFreezeMapObjects(); + SetupNativeScript(ctx, sub_80983C4); + } + return TRUE; + } +} + +bool8 ScrCmd_releaseall(struct ScriptContext *ctx) +{ + u8 objectId; + + HideFieldMessageBox(); + objectId = GetFieldObjectIdByLocalIdAndMap(0xFF, 0, 0); + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[objectId]); + sub_80D338C(); + UnfreezeMapObjects(); + return FALSE; +} + +bool8 ScrCmd_release(struct ScriptContext *ctx) +{ + u8 objectId; + + HideFieldMessageBox(); + if (gMapObjects[gSelectedMapObject].active) + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[gSelectedMapObject]); + objectId = GetFieldObjectIdByLocalIdAndMap(0xFF, 0, 0); + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[objectId]); + sub_80D338C(); + UnfreezeMapObjects(); + return FALSE; +} + +bool8 ScrCmd_message(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + ShowFieldMessage(msg); + return FALSE; +} + +bool8 ScrCmd_pokenavcall(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + sub_8098238(msg); + return FALSE; +} + +bool8 ScrCmd_messageautoscroll(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + gTextFlags.flag_2 = TRUE; + gTextFlags.flag_3 = TRUE; + ShowFieldAutoScrollMessage(msg); + return FALSE; +} + +bool8 ScrCmd_cmdDB(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + sub_81973A4(); + sub_81973C4(0, 1); + PrintTextOnWindow(0, 1, msg, 0, 1, 0, 0); + return FALSE; +} + +bool8 ScrCmd_waitmessage(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, IsFieldMessageBoxHidden); + return TRUE; +} + +bool8 ScrCmd_closemessage(struct ScriptContext *ctx) +{ + HideFieldMessageBox(); + return FALSE; +} + +static bool8 WaitForAorBPress(void) +{ + if (gMain.newKeys & A_BUTTON) + return TRUE; + if (gMain.newKeys & B_BUTTON) + return TRUE; + return FALSE; +} + +bool8 ScrCmd_waitbutton(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, WaitForAorBPress); + return TRUE; +} + +bool8 ScrCmd_yesnobox(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + + if (ScriptMenu_YesNo(left, top) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_multichoice(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + if (ScriptMenu_Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_multichoicedefault(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 defaultChoice = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + if (ScriptMenu_MultichoiceWithDefault(left, top, multichoiceId, ignoreBPress, defaultChoice) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_drawbox(struct ScriptContext *ctx) +{ + /*u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 right = ScriptReadByte(ctx); + u8 bottom = ScriptReadByte(ctx); + + MenuDrawTextWindow(left, top, right, bottom);*/ + return FALSE; +} + +bool8 ScrCmd_multichoicegrid(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 numColumns = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + if (ScriptMenu_MultichoiceGrid(left, top, multichoiceId, ignoreBPress, numColumns) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_erasebox(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 right = ScriptReadByte(ctx); + u8 bottom = ScriptReadByte(ctx); + + // MenuZeroFillWindowRect(left, top, right, bottom); + return FALSE; +} + +bool8 ScrCmd_drawboxtext(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + /*if (Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + }*/ + return FALSE; +} + +bool8 ScrCmd_drawpokepic(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + ScriptMenu_ShowPokemonPic(species, x, y); + return FALSE; +} + +bool8 ScrCmd_erasepokepic(struct ScriptContext *ctx) +{ + bool8 (*func)(void) = ScriptMenu_GetPicboxWaitFunc(); + + if (func == NULL) + return FALSE; + SetupNativeScript(ctx, func); + return TRUE; +} + +bool8 ScrCmd_drawcontestwinner(struct ScriptContext *ctx) +{ + u8 v1 = ScriptReadByte(ctx); + + if (v1) + sub_812FDA8(v1); + ShowContestWinner(); + ScriptContext1_Stop(); + return TRUE; +} + +// Lots of math, can't figure it out. +/* +bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) +{ + u8 *ptr = (u8 *)ScriptReadWord(ctx); + struct WindowTemplate template1; + struct WindowTemplate template2; + int i; + u8 width; + u8 height; + int temp1; + int temp2; + u8 x; + u8 y; + + StringExpandPlaceholders(gStringVar4, ptr + 6); + + width = GetStringWidth(6, gStringVar4, -1) / 8; + + if (width > 0x1C) + width = 0x1C; + + for (i = 0, height = 4; gStringVar4[i] != 0xFF;) + { + if (gStringVar4[i++] == 0xFE) + height += 3; + } + + if (height > 0x12) + height = 0x12; + + x = width + 2; + temp1 = (0x1E - x) / 2; + x = temp1 + 1; + temp1 = ((x - temp1 - 1) * 8 + 3); + + y = height + 2; + temp2 = (0x14 - y) / 2; + y = temp2 + 2; + temp2 = ((y - temp2 - 1) * 8); + + sub_8198A50(&template1, 0, x, y, width, height, 0xF, 0x1); + template2 = template1; + gUnknown_03000F30 = AddWindow(&template2); + sub_809882C(gUnknown_03000F30, 0x214, 0xE0); + sub_81973FC(gUnknown_03000F30, 0); + PutWindowTilemap(gUnknown_03000F30); + FillWindowPixelBuffer(gUnknown_03000F30, 0x11); + PrintTextOnWindow(gUnknown_03000F30, 6, gStringVar4, temp1, temp2, 0xFF, 0x0); + CopyWindowToVram(gUnknown_03000F30, 3); + return FALSE; +}*/ +__attribute__((naked)) +bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) +{ + asm("push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + sub sp, #0x20\n\ + bl ScriptReadWord\n\ + add r1, r0, #0\n\ + ldr r4, =gStringVar4\n\ + add r1, #0x6\n\ + add r0, r4, #0\n\ + bl StringExpandPlaceholders\n\ + mov r2, #0x1\n\ + neg r2, r2\n\ + mov r0, #0x6\n\ + add r1, r4, #0\n\ + bl GetStringWidth\n\ + lsr r0, #3\n\ + lsl r0, #24\n\ + lsr r7, r0, #24\n\ + cmp r7, #0x1C\n\ + bls _0809AE9C\n\ + mov r7, #0x1C\n\ +_0809AE9C:\n\ + mov r5, #0x4\n\ + ldrb r0, [r4]\n\ + add r2, r7, #0x2\n\ + add r1, sp, #0x18\n\ + mov r8, r1\n\ + cmp r0, #0xFF\n\ + beq _0809AEC0\n\ + add r1, r4, #0\n\ +_0809AEAC:\n\ + ldrb r0, [r1]\n\ + add r1, #0x1\n\ + cmp r0, #0xFE\n\ + bne _0809AEBA\n\ + add r0, r5, #0x3\n\ + lsl r0, #24\n\ + lsr r5, r0, #24\n\ +_0809AEBA:\n\ + ldrb r0, [r1]\n\ + cmp r0, #0xFF\n\ + bne _0809AEAC\n\ +_0809AEC0:\n\ + cmp r5, #0x12\n\ + bls _0809AEC6\n\ + mov r5, #0x12\n\ +_0809AEC6:\n\ + lsl r0, r2, #24\n\ + lsr r0, #24\n\ + mov r2, #0x1E\n\ + sub r2, r0\n\ + lsr r0, r2, #31\n\ + add r2, r0\n\ + asr r2, #1\n\ + lsl r2, #24\n\ + add r0, r5, #0x2\n\ + lsl r0, #24\n\ + lsr r0, #24\n\ + mov r4, #0x14\n\ + sub r4, r0\n\ + lsr r0, r4, #31\n\ + add r4, r0\n\ + asr r4, #1\n\ + lsl r4, #24\n\ + lsr r6, r2, #24\n\ + mov r0, #0x80\n\ + lsl r0, #17\n\ + add r2, r0\n\ + lsr r2, #24\n\ + lsr r3, r4, #24\n\ + mov r1, #0x80\n\ + lsl r1, #18\n\ + add r4, r1\n\ + lsr r4, #24\n\ + sub r6, r2, r6\n\ + sub r6, #0x1\n\ + lsl r6, #3\n\ + add r6, #0x3\n\ + lsl r6, #24\n\ + lsr r6, #24\n\ + sub r4, r3\n\ + sub r4, #0x1\n\ + lsl r4, #27\n\ + lsr r4, #24\n\ + add r3, #0x1\n\ + lsl r3, #24\n\ + lsr r3, #24\n\ + str r7, [sp]\n\ + str r5, [sp, #0x4]\n\ + mov r0, #0xF\n\ + str r0, [sp, #0x8]\n\ + mov r0, #0x1\n\ + str r0, [sp, #0xC]\n\ + add r0, sp, #0x10\n\ + mov r1, #0\n\ + bl sub_8198A50\n\ + ldr r0, [sp, #0x10]\n\ + ldr r1, [sp, #0x14]\n\ + str r0, [sp, #0x18]\n\ + str r1, [sp, #0x1C]\n\ + ldr r5, =gUnknown_03000F30\n\ + mov r0, r8\n\ + bl AddWindow\n\ + strb r0, [r5]\n\ + ldrb r0, [r5]\n\ + mov r1, #0x85\n\ + lsl r1, #2\n\ + mov r2, #0xE0\n\ + bl sub_809882C\n\ + ldrb r0, [r5]\n\ + mov r1, #0\n\ + bl sub_81973FC\n\ + ldrb r0, [r5]\n\ + bl PutWindowTilemap\n\ + ldrb r0, [r5]\n\ + mov r1, #0x11\n\ + bl FillWindowPixelBuffer\n\ + ldrb r0, [r5]\n\ + ldr r2, =gStringVar4\n\ + str r4, [sp]\n\ + mov r1, #0xFF\n\ + str r1, [sp, #0x4]\n\ + mov r1, #0\n\ + str r1, [sp, #0x8]\n\ + mov r1, #0x6\n\ + add r3, r6, #0\n\ + bl PrintTextOnWindow\n\ + ldrb r0, [r5]\n\ + mov r1, #0x3\n\ + bl CopyWindowToVram\n\ + mov r0, #0\n\ + add sp, #0x20\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r1}\n\ + bx r1\n\ + .pool"); +} + +bool8 ScrCmd_cmdDA(struct ScriptContext *ctx) +{ + sub_809BDB4(); + return FALSE; +} + +bool8 ScrCmd_vmessage(struct ScriptContext *ctx) +{ + u32 v1 = ScriptReadWord(ctx); + + ShowFieldMessage((u8 *)(v1 - gUnknown_020375C4)); + return FALSE; +} + +bool8 ScrCmd_getspeciesname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 species = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gSpeciesNames[species]); + return FALSE; +} + +bool8 ScrCmd_getfirstpartypokename(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + + u8 *dest = sScriptStringVars[stringVarIndex]; + u8 partyIndex = GetLeadMonIndex(); + u32 species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES, NULL); + StringCopy(dest, gSpeciesNames[species]); + return FALSE; +} + +bool8 ScrCmd_getpartypokename(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + GetMonData(&gPlayerParty[partyIndex], MON_DATA_NICKNAME, sScriptStringVars[stringVarIndex]); + StringGetEnd10(sScriptStringVars[stringVarIndex]); + return FALSE; +} + +bool8 ScrCmd_getitemname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + + CopyItemName(itemId, sScriptStringVars[stringVarIndex]); + return FALSE; +} + +bool8 ScrCmd_getitemnameplural(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u16 quantity = VarGet(ScriptReadHalfword(ctx)); + + CopyItemNameHandlePlural(itemId, sScriptStringVars[stringVarIndex], quantity); + return FALSE; +} + +bool8 ScrCmd_getdecorname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 decorId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gDecorations[decorId].name); + return FALSE; +} + +bool8 ScrCmd_getmovename(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 moveId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gMoveNames[moveId]); + return FALSE; +} + +bool8 ScrCmd_getnumberstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 v1 = VarGet(ScriptReadHalfword(ctx)); + u8 v2 = sub_80EF370(v1); + + ConvertIntToDecimalStringN(sScriptStringVars[stringVarIndex], v1, 0, v2); + return FALSE; +} + +bool8 ScrCmd_getstdstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 index = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gUnknown_0858BAF0[index]); + return FALSE; +} + +bool8 ScrCmd_getcontesttype(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 index = VarGet(ScriptReadHalfword(ctx)); + + sub_818E868(sScriptStringVars[stringVarIndex], index); + return FALSE; +} + +bool8 ScrCmd_getstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + const u8 *text = (u8 *)ScriptReadWord(ctx); + + StringCopy(sScriptStringVars[stringVarIndex], text); + return FALSE; +} + +bool8 ScrCmd_vloadword(struct ScriptContext *ctx) +{ + const u8 *ptr = (u8 *)(ScriptReadWord(ctx) - gUnknown_020375C4); + + StringExpandPlaceholders(gStringVar4, ptr); + return FALSE; +} + +bool8 ScrCmd_vgetstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u32 addr = ScriptReadWord(ctx); + + const u8 *src = (u8 *)(addr - gUnknown_020375C4); + u8 *dest = sScriptStringVars[stringVarIndex]; + StringCopy(dest, src); + return FALSE; +} + +bool8 ScrCmd_getboxname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 boxId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], GetBoxNamePtr(boxId)); + return FALSE; +} + +bool8 ScrCmd_givepoke(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u8 level = ScriptReadByte(ctx); + u16 item = VarGet(ScriptReadHalfword(ctx)); + u32 unkParam1 = ScriptReadWord(ctx); + u32 unkParam2 = ScriptReadWord(ctx); + u8 unkParam3 = ScriptReadByte(ctx); + + gScriptResult = ScriptGiveMon(species, level, item, unkParam1, unkParam2, unkParam3); + return FALSE; +} + +bool8 ScrCmd_giveegg(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = ScriptGiveEgg(species); + return FALSE; +} + +bool8 ScrCmd_setpokemove(struct ScriptContext *ctx) +{ + u8 partyIndex = ScriptReadByte(ctx); + u8 slot = ScriptReadByte(ctx); + u16 move = ScriptReadHalfword(ctx); + + ScriptSetMonMoveSlot(partyIndex, move, slot); + return FALSE; +} + +bool8 ScrCmd_checkpokemove(struct ScriptContext *ctx) +{ + u8 i; + u16 moveId = ScriptReadHalfword(ctx); + + gScriptResult = 6; + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL); + if (!species) + break; + // UB: GetMonData() arguments don't match function definition + if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) && pokemon_has_move(&gPlayerParty[i], moveId) == TRUE) + { + gScriptResult = i; + gSpecialVar_0x8004 = species; + break; + } + } + return FALSE; +} + +bool8 ScrCmd_givemoney(struct ScriptContext *ctx) +{ + u32 amount = ScriptReadWord(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + AddMoney(&gSaveBlock1Ptr->money, amount); + return FALSE; +} + +bool8 ScrCmd_takemoney(struct ScriptContext *ctx) +{ + u32 amount = ScriptReadWord(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + RemoveMoney(&gSaveBlock1Ptr->money, amount); + return FALSE; +} + +bool8 ScrCmd_checkmoney(struct ScriptContext *ctx) +{ + u32 amount = ScriptReadWord(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + gScriptResult = IsEnoughMoney(&gSaveBlock1Ptr->money, amount); + return FALSE; +} + +bool8 ScrCmd_showmoneybox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + DrawMoneyBox(GetMoney(&gSaveBlock1Ptr->money), x, y); + return FALSE; +} + +bool8 ScrCmd_hidemoneybox(struct ScriptContext *ctx) +{ + /*u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx);*/ + + HideMoneyBox(); + return FALSE; +} + +bool8 ScrCmd_updatemoneybox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + ChangeAmountInMoneyBox(GetMoney(&gSaveBlock1Ptr->money)); + return FALSE; +} + +bool8 ScrCmd_showcoinsbox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + ShowCoinsWindow(GetCoins(), x, y); + return FALSE; +} + +bool8 ScrCmd_hidecoinsbox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + HideCoinsWindow(); + return FALSE; +} + +bool8 ScrCmd_updatecoinsbox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + PrintCoinsString(GetCoins()); + return FALSE; +} + +bool8 ScrCmd_trainerbattle(struct ScriptContext *ctx) +{ + ctx->scriptPtr = BattleSetup_ConfigureTrainerBattle(ctx->scriptPtr); + return FALSE; +} + +bool8 ScrCmd_battlebegin(struct ScriptContext *ctx) +{ + BattleSetup_StartTrainerBattle(); + return TRUE; +} + +bool8 ScrCmd_ontrainerbattleend(struct ScriptContext *ctx) +{ + ctx->scriptPtr = BattleSetup_GetScriptAddrAfterBattle(); + return FALSE; +} + +bool8 ScrCmd_ontrainerbattleendgoto(struct ScriptContext *ctx) +{ + ctx->scriptPtr = BattleSetup_GetTrainerPostBattleScript(); + return FALSE; +} + +bool8 ScrCmd_checktrainerflag(struct ScriptContext *ctx) +{ + u16 index = VarGet(ScriptReadHalfword(ctx)); + + ctx->comparisonResult = HasTrainerAlreadyBeenFought(index); + return FALSE; +} + +bool8 ScrCmd_settrainerflag(struct ScriptContext *ctx) +{ + u16 index = VarGet(ScriptReadHalfword(ctx)); + + trainer_flag_set(index); + return FALSE; +} + +bool8 ScrCmd_cleartrainerflag(struct ScriptContext *ctx) +{ + u16 index = VarGet(ScriptReadHalfword(ctx)); + + trainer_flag_clear(index); + return FALSE; +} + +bool8 ScrCmd_setwildbattle(struct ScriptContext *ctx) +{ + u16 species = ScriptReadHalfword(ctx); + u8 level = ScriptReadByte(ctx); + u16 item = ScriptReadHalfword(ctx); + + CreateScriptedWildMon(species, level, item); + return FALSE; +} + +bool8 ScrCmd_dowildbattle(struct ScriptContext *ctx) +{ + BattleSetup_StartScriptedWildBattle(); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_pokemart(struct ScriptContext *ctx) +{ + const void *ptr = (void *)ScriptReadWord(ctx); + + CreatePokemartMenu(ptr); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_pokemartdecor(struct ScriptContext *ctx) +{ + const void *ptr = (void *)ScriptReadWord(ctx); + + CreateDecorationShop1Menu(ptr); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_pokemartbp(struct ScriptContext *ctx) +{ + const void *ptr = (void *)ScriptReadWord(ctx); + + CreateDecorationShop2Menu(ptr); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_playslotmachine(struct ScriptContext *ctx) +{ + u8 slotMachineIndex = VarGet(ScriptReadHalfword(ctx)); + + PlaySlotMachine(slotMachineIndex, c2_exit_to_overworld_1_continue_scripts_restart_music); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_plantberrytree(struct ScriptContext *ctx) +{ + u8 treeId = ScriptReadByte(ctx); + u8 berry = ScriptReadByte(ctx); + u8 growthStage = ScriptReadByte(ctx); + + if (berry == 0) + PlantBerryTree(treeId, 0, growthStage, FALSE); + else + PlantBerryTree(treeId, berry, growthStage, FALSE); + return FALSE; +} + +bool8 ScrCmd_getpricereduction(struct ScriptContext *ctx) +{ + u16 value = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = GetPriceReduction(value); + return FALSE; +} + +bool8 ScrCmd_choosecontestpkmn(struct ScriptContext *ctx) +{ + sub_81B9404(); + ScriptContext1_Stop(); + return TRUE; +} + + +bool8 ScrCmd_startcontest(struct ScriptContext *ctx) +{ + sub_80F840C(); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_showcontestresults(struct ScriptContext *ctx) +{ + sub_80F8484(); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_contestlinktransfer(struct ScriptContext *ctx) +{ + sub_80F84C4(gScriptContestCategory); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_dofieldeffect(struct ScriptContext *ctx) +{ + u16 effectId = VarGet(ScriptReadHalfword(ctx)); + + sFieldEffectScriptId = effectId; + FieldEffectStart(sFieldEffectScriptId); + return FALSE; +} + +bool8 ScrCmd_setfieldeffect(struct ScriptContext *ctx) +{ + u8 argNum = ScriptReadByte(ctx); + + gFieldEffectArguments[argNum] = (s16)VarGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +static bool8 WaitForFieldEffectFinish(void) +{ + if (!FieldEffectActiveListContains(sFieldEffectScriptId)) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_waitfieldeffect(struct ScriptContext *ctx) +{ + sFieldEffectScriptId = VarGet(ScriptReadHalfword(ctx)); + SetupNativeScript(ctx, WaitForFieldEffectFinish); + return TRUE; +} + +bool8 ScrCmd_sethealplace(struct ScriptContext *ctx) +{ + u16 healLocationId = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetHealLocationWarp(healLocationId); + return FALSE; +} + +bool8 ScrCmd_checkplayergender(struct ScriptContext *ctx) +{ + gScriptResult = gSaveBlock2Ptr->playerGender; + return FALSE; +} + +bool8 ScrCmd_playpokecry(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u16 mode = VarGet(ScriptReadHalfword(ctx)); + + PlayCry5(species, mode); + return FALSE; +} + +bool8 ScrCmd_waitpokecry(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, IsCryFinished); + return TRUE; +} + +bool8 ScrCmd_setmaptile(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + u16 tileId = VarGet(ScriptReadHalfword(ctx)); + u16 v8 = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + if (!v8) + MapGridSetMetatileIdAt(x, y, tileId); + else + MapGridSetMetatileIdAt(x, y, tileId | 0xC00); + return FALSE; +} + +bool8 ScrCmd_opendoor(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + PlaySE(GetDoorSoundEffect(x, y)); + FieldAnimateDoorOpen(x, y); + return FALSE; +} + +bool8 ScrCmd_closedoor(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + FieldAnimateDoorClose(x, y); + return FALSE; +} + +static bool8 IsDoorAnimationStopped(void) +{ + if (!FieldIsDoorAnimationRunning()) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_waitdooranim(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, IsDoorAnimationStopped); + return TRUE; +} + +bool8 ScrCmd_setdooropen(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + FieldSetDoorOpened(x, y); + return FALSE; +} + +bool8 ScrCmd_setdoorclosed(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + FieldSetDoorClosed(x, y); + return FALSE; +} + +bool8 ScrCmd_addelevmenuitem(struct ScriptContext *ctx) +{ + u8 v3 = ScriptReadByte(ctx); + u16 v5 = VarGet(ScriptReadHalfword(ctx)); + u16 v7 = VarGet(ScriptReadHalfword(ctx)); + u16 v9 = VarGet(ScriptReadHalfword(ctx)); + + //ScriptAddElevatorMenuItem(v3, v5, v7, v9); + return FALSE; +} + +bool8 ScrCmd_showelevmenu(struct ScriptContext *ctx) +{ + /*ScriptShowElevatorMenu(); + ScriptContext1_Stop(); + return TRUE;*/ + return FALSE; +} + +bool8 ScrCmd_checkcoins(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr = GetCoins(); + return FALSE; +} + +bool8 ScrCmd_givecoins(struct ScriptContext *ctx) +{ + u16 coins = VarGet(ScriptReadHalfword(ctx)); + + if (GiveCoins(coins) == TRUE) + gScriptResult = 0; + else + gScriptResult = 1; + return FALSE; +} + +bool8 ScrCmd_takecoins(struct ScriptContext *ctx) +{ + u16 coins = VarGet(ScriptReadHalfword(ctx)); + + if (TakeCoins(coins) == TRUE) + gScriptResult = 0; + else + gScriptResult = 1; + return FALSE; +} + +bool8 ScrCmd_mossdeepgym1(struct ScriptContext *ctx) +{ + u16 v1 = VarGet(ScriptReadHalfword(ctx)); + + sMovingNpcId = sub_81A89A0(v1); + return FALSE; +} + +bool8 ScrCmd_mossdeepgym2(struct ScriptContext *ctx) +{ + sub_81A8AF8(); + return FALSE; +} + +bool8 ScrCmd_mossdeepgym3(struct ScriptContext *ctx) +{ + u16 v1 = VarGet(ScriptReadHalfword(ctx)); + + sub_81A8934(v1); + return FALSE; +} + +bool8 ScrCmd_mossdeepgym4(struct ScriptContext *ctx) +{ + sub_81A895C(); + return FALSE; +} + +bool8 ScrCmd_cmdD8(struct ScriptContext *ctx) +{ + gSelectedMapObject = sub_80B47BC(); + return FALSE; +} + +bool8 ScrCmd_cmdD9(struct ScriptContext *ctx) +{ + if (is_c1_link_related_active()) + { + return FALSE; + } + else + { + if (gMapObjects[gSelectedMapObject].active) + { + sub_8098630(); + SetupNativeScript(ctx, sub_8098734); + } + return TRUE; + } +} + +// This command will force the Pokémon to be obedient, you don't get to choose which value to set its obedience to +bool8 ScrCmd_setpokeobedient(struct ScriptContext *ctx) +{ + bool8 obedient = TRUE; + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + SetMonData(&gPlayerParty[partyIndex], MON_DATA_OBEDIENCE, &obedient); + return FALSE; +} + +bool8 ScrCmd_checkpokeobedience(struct ScriptContext *ctx) +{ + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + gScriptResult = GetMonData(&gPlayerParty[partyIndex], MON_DATA_OBEDIENCE, NULL); + return FALSE; +} + +bool8 ScrCmd_cmdCF(struct ScriptContext *ctx) +{ + const u8* v1 = sub_8099244(); + + if (v1) + { + ((u8*)gUnknown_020375C0) = ctx->scriptPtr; + ScriptJump(ctx, v1); + } + return FALSE; +} + +bool8 ScrCmd_warpD1(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_808D074(player_get_direction_lower_nybble()); + sub_80B0244(); + player_avatar_init_params_reset(); + return TRUE; +} + +bool8 ScrCmd_setpokemetlocation(struct ScriptContext *ctx) +{ + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + u8 location = ScriptReadByte(ctx); + + if (partyIndex < PARTY_SIZE) + SetMonData(&gPlayerParty[partyIndex], MON_DATA_MET_LOCATION, &location); + return FALSE; +} + +void sub_809BDB4(void) +{ + sub_819746C(gUnknown_03000F30, 1); + RemoveWindow(gUnknown_03000F30); +} + +bool8 ScrCmd_gettrainerclass(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 trainerClassId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], GetTrainerClassNameFromId(trainerClassId)); + return FALSE; +} + +bool8 ScrCmd_gettrainername(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 trainerClassId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], GetTrainerNameFromId(trainerClassId)); + return FALSE; +} + +void sub_809BE48(u16 npcId) +{ + sMovingNpcId = npcId; +} -// .rodata +bool8 ScrCmd_warpE0(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); -// .text + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_80AF79C(); + player_avatar_init_params_reset(); + return TRUE; +} diff --git a/src/script.c b/src/script.c index b2809a137..5a1c5daa9 100644 --- a/src/script.c +++ b/src/script.c @@ -134,12 +134,12 @@ const u8 *ScriptPop(struct ScriptContext *ctx) return ctx->stack[ctx->stackDepth]; } -void ScriptJump(struct ScriptContext *ctx, u8 *ptr) +void ScriptJump(struct ScriptContext *ctx, const u8 *ptr) { ctx->scriptPtr = ptr; } -void ScriptCall(struct ScriptContext *ctx, u8 *ptr) +void ScriptCall(struct ScriptContext *ctx, const u8 *ptr) { ScriptPush(ctx, ctx->scriptPtr); ctx->scriptPtr = ptr; diff --git a/src/sprite.c b/src/sprite.c index 17b0f181a..daa019019 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -594,7 +594,7 @@ u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, return index; } -u8 CreateSpriteAndAnimate(struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) { u8 i; diff --git a/src/text.c b/src/text.c index 7cc46cd92..8108a6867 100644 --- a/src/text.c +++ b/src/text.c @@ -145,7 +145,7 @@ void DeactivateAllTextPrinters (void) gTextPrinters[printer].sub_union.sub.active = 0; } -u16 PrintTextOnWindow(u8 windowId, u8 fontId, u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextSubPrinter *, u16)) +u16 PrintTextOnWindow(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextSubPrinter *, u16)) { struct TextSubPrinter subPrinter; @@ -2,7 +2,7 @@ // Includes #include "global.h" #include "rtc.h" -#include "rom4.h" +#include "overworld.h" #include "map_constants.h" #include "rng.h" #include "event_data.h" @@ -838,7 +838,7 @@ void UpdateTVScreensOnMap(int width, int height) } else if (FlagGet(SYS_TV_START) && (FindAnyTVShowOnTheAir() != 0xff || FindAnyTVNewsOnTheAir() != 0xff || IsTVShowInSearchOfTrainersAiring())) { - FlagReset(SYS_TV_WATCH); + FlagClear(SYS_TV_WATCH); SetTVMetatilesOnMap(width, height, 0x3); } break; @@ -1263,7 +1263,7 @@ void InterviewAfter_ContestLiveUpdates(void) show2->contestLiveUpdates.kind = TVSHOW_CONTEST_LIVE_UPDATES; show2->contestLiveUpdates.active = TRUE; StringCopy(show2->contestLiveUpdates.playerName, gSaveBlock2Ptr->playerName); - show2->contestLiveUpdates.category = gUnknown_02039F2C; + show2->contestLiveUpdates.category = gScriptContestCategory; show2->contestLiveUpdates.species = GetMonData(&gPlayerParty[gUnknown_02039F24], MON_DATA_SPECIES, NULL); show2->contestLiveUpdates.winningSpecies = show->contestLiveUpdates.winningSpecies; show2->contestLiveUpdates.appealFlags2 = show->contestLiveUpdates.appealFlags2; @@ -1527,7 +1527,7 @@ void BravoTrainerPokemonProfile_BeforeInterview2(u8 a0) if (sCurTVShowSlot != -1) { show->bravoTrainer.contestResult = a0; - show->bravoTrainer.contestCategory = gUnknown_02039F2C; + show->bravoTrainer.contestCategory = gScriptContestCategory; show->bravoTrainer.contestRank = gUnknown_02039F2E; show->bravoTrainer.species = GetMonData(&gPlayerParty[gUnknown_02039F24], MON_DATA_SPECIES, NULL); GetMonData(&gPlayerParty[gUnknown_02039F24], MON_DATA_NICKNAME, show->bravoTrainer.pokemonNickname); @@ -1675,7 +1675,7 @@ void InterviewAfter_FanClubLetter(void) show->fanclubLetter.kind = TVSHOW_FAN_CLUB_LETTER; show->fanclubLetter.active = TRUE; StringCopy(show->fanclubLetter.playerName, gSaveBlock2Ptr->playerName); - show->fanclubLetter.species = GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_SPECIES, NULL); + show->fanclubLetter.species = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL); tv_store_id_2x(show); show->fanclubLetter.language = gGameLanguage; } @@ -1700,21 +1700,21 @@ void InterviewAfter_PkmnFanClubOpinions(void) show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; show->fanclubOpinions.kind = TVSHOW_PKMN_FAN_CLUB_OPINIONS; show->fanclubOpinions.active = TRUE; - show->fanclubOpinions.friendshipHighNybble = GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_FRIENDSHIP, NULL) >> 4; + show->fanclubOpinions.friendshipHighNybble = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_FRIENDSHIP, NULL) >> 4; show->fanclubOpinions.questionAsked = gSpecialVar_0x8007; StringCopy(show->fanclubOpinions.playerName, gSaveBlock2Ptr->playerName); - GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_NICKNAME, show->fanclubOpinions.nickname); + GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_NICKNAME, show->fanclubOpinions.nickname); StripExtCtrlCodes(show->fanclubOpinions.nickname); - show->fanclubOpinions.species = GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_SPECIES, NULL); + show->fanclubOpinions.species = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL); tv_store_id_2x(show); show->fanclubOpinions.language = gGameLanguage; - if (gGameLanguage == LANGUAGE_JAPANESE || GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_LANGUAGE) == LANGUAGE_JAPANESE) + if (gGameLanguage == LANGUAGE_JAPANESE || GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_LANGUAGE) == LANGUAGE_JAPANESE) { show->fanclubOpinions.pokemonNameLanguage = LANGUAGE_JAPANESE; } else { - show->fanclubOpinions.pokemonNameLanguage = GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_LANGUAGE); + show->fanclubOpinions.pokemonNameLanguage = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_LANGUAGE); } } @@ -3073,7 +3073,7 @@ void TV_PrintIntToStringVar(u8 varIdx, int value) ConvertIntToDecimalStringN(gTVStringVarPtrs[varIdx], value, STR_CONV_MODE_LEFT_ALIGN, nDigits); } -int sub_80EF370(int value) +size_t sub_80EF370(int value) { if (value / 10 == 0) { @@ -3246,7 +3246,7 @@ void InterviewBefore_FanClubLetter(void) FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_FAN_CLUB_LETTER); if (!gScriptResult) { - StringCopy(gStringVar1, gSpeciesNames[GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_SPECIES, NULL)]); + StringCopy(gStringVar1, gSpeciesNames[GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL)]); InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].fanclubLetter.words, 6); } } @@ -3265,8 +3265,8 @@ void InterviewBefore_PkmnFanClubOpinions(void) FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_PKMN_FAN_CLUB_OPINIONS); if (!gScriptResult) { - StringCopy(gStringVar1, gSpeciesNames[GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_SPECIES, NULL)]); - GetMonData(&gPlayerParty[GetIdxOfFirstPartyMemberThatIsNotAnEgg()], MON_DATA_NICKNAME, gStringVar2); + StringCopy(gStringVar1, gSpeciesNames[GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL)]); + GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_NICKNAME, gStringVar2); StringGetEnd10(gStringVar2); InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].fanclubOpinions.words, 2); } @@ -3336,7 +3336,7 @@ bool8 sub_80EF88C(u8 monIdx) bool8 sub_80EF8F8(void) { - return sub_80EF88C(GetIdxOfFirstPartyMemberThatIsNotAnEgg()); + return sub_80EF88C(GetLeadMonIndex()); } void DeleteTVShowInArrayByIdx(TVShow *shows, u8 idx) diff --git a/src/walda_phrase.c b/src/walda_phrase.c new file mode 100644 index 000000000..7e06d1319 --- /dev/null +++ b/src/walda_phrase.c @@ -0,0 +1,257 @@ +#include "global.h" +#include "walda_phrase.h" +#include "string_util.h" +#include "event_data.h" +#include "naming_screen.h" +#include "main.h" +#include "text.h" +#include "new_game.h" + +extern void (*gFieldCallback)(void); + +extern const u8 gText_Peekaboo[]; + +extern u8 *GetWaldaPhrasePtr(void); +extern bool32 IsWaldaPhraseEmpty(void); +extern void sub_80AF168(void); +extern void c2_exit_to_overworld_2_switch(void); +extern void SetWaldaPhrase(const u8 *src); +extern void SetWaldaWallpaperPatternId(u8 patternId); +extern void SetWaldaWallpaperIconId(u8 iconId); +extern void SetWaldaWallpaperColors(u16 backgroundColor, u16 foregroundColor); +extern void SetWaldaWallpaperLockedOrUnlocked(bool32 unlocked); + +// this file's functions +static void CB2_HandleGivenWaldaPhrase(void); +static u32 GetWaldaPhraseInputCase(u8 *inputPtr); +static bool32 TryCalculateWallpaper(u16* backgroundClr, u16 *foregroundClr, u8 *iconId, u8 *patternId, u16 trainerId, u8 *phrase); +static void sub_81D9D5C(u8 *array, u8 *letterTableIds, u32 arg2, u32 arg3, u32 loopCount); +static u32 sub_81D9DAC(u8 *array, u32 arg1, u32 loopCount); +static void sub_81D9C90(u8 *array, s32 arg1, s32 arg2); +static void sub_81D9CDC(u8 *array, u32 loopCount, u8 arg2); + +// only consonants are allowed, no vowels, some lowercase letters are missing +static const u8 sWaldaLettersTable[] = +{ + CHAR_B, CHAR_C, CHAR_D, CHAR_F, CHAR_G, CHAR_H, CHAR_J, CHAR_K, CHAR_L, CHAR_M, CHAR_N, CHAR_P, CHAR_Q, CHAR_R, CHAR_S, CHAR_T, CHAR_V, CHAR_W, CHAR_Z, + CHAR_b, CHAR_c, CHAR_d, CHAR_f, CHAR_g, CHAR_h, CHAR_j, CHAR_k, CHAR_m, CHAR_n, CHAR_p, CHAR_q, CHAR_s +}; + +enum +{ + PHRASE_GIVEN_NEW, + PHRASE_NO_CHANGE, + PHRASE_FIRST_ATTEMPT +}; + +u16 TryBufferWaldaPhrase(void) +{ + if (IsWaldaPhraseEmpty()) + return FALSE; + + StringCopy(gStringVar1, GetWaldaPhrasePtr()); + return TRUE; +} + +void DoWaldaNamingScreen(void) +{ + StringCopy(gStringVar2, GetWaldaPhrasePtr()); + DoNamingScreen(NAMING_SCREEN_WALDA, gStringVar2, 0, 0, 0, CB2_HandleGivenWaldaPhrase); +} + +static void CB2_HandleGivenWaldaPhrase(void) +{ + gSpecialVar_0x8004 = GetWaldaPhraseInputCase(gStringVar2); + + switch (gSpecialVar_0x8004) + { + case PHRASE_FIRST_ATTEMPT: + if (IsWaldaPhraseEmpty()) + SetWaldaPhrase(gText_Peekaboo); + else + gSpecialVar_0x8004 = PHRASE_NO_CHANGE; + break; + case PHRASE_GIVEN_NEW: + SetWaldaPhrase(gStringVar2); + break; + case PHRASE_NO_CHANGE: + break; + } + + StringCopy(gStringVar1, GetWaldaPhrasePtr()); + gFieldCallback = sub_80AF168; + SetMainCallback2(c2_exit_to_overworld_2_switch); +} + +static u32 GetWaldaPhraseInputCase(u8 *inputPtr) +{ + if (inputPtr[0] == EOS) + return PHRASE_FIRST_ATTEMPT; + if (StringCompare(inputPtr, GetWaldaPhrasePtr()) == 0) + return PHRASE_NO_CHANGE; + + return PHRASE_GIVEN_NEW; +} + +u16 TryGetWallpaperWithWaldaPhrase(void) +{ + u16 backgroundClr, foregroundClr; + u8 patternId, iconId; + u16 trainerId = ReadUnalignedWord(gSaveBlock2Ptr->playerTrainerId); + gScriptResult = TryCalculateWallpaper(&backgroundClr, &foregroundClr, &iconId, &patternId, trainerId, GetWaldaPhrasePtr()); + + if (gScriptResult) + { + SetWaldaWallpaperPatternId(patternId); + SetWaldaWallpaperIconId(iconId); + SetWaldaWallpaperColors(backgroundClr, foregroundClr); + } + + SetWaldaWallpaperLockedOrUnlocked(gScriptResult); + return (bool8)(gScriptResult); +} + +static u8 GetLetterTableId(u8 letter) +{ + s32 i; + + for (i = 0; i < ARRAY_COUNT(sWaldaLettersTable); i++) + { + if (sWaldaLettersTable[i] == letter) + return i; + } + + return ARRAY_COUNT(sWaldaLettersTable); +} + +static bool32 TryCalculateWallpaper(u16* backgroundClr, u16 *foregroundClr, u8 *iconId, u8 *patternId, u16 trainerId, u8 *phrase) +{ + s32 i; + ALIGNED(2) u8 array[12]; + u8 charsByTableId[16]; + u16 *ptr; + + if (StringLength(phrase) != 15) + return FALSE; + + for (i = 0; i < 15; i++) + { + charsByTableId[i] = GetLetterTableId(phrase[i]); + if (charsByTableId[i] == ARRAY_COUNT(sWaldaLettersTable)) + return FALSE; + } + + for (i = 0; i < 14; i++) + { + sub_81D9D5C(array, charsByTableId, (5 * i), 3 + (8 * i), 5); + } + + sub_81D9D5C(array, charsByTableId, 70, 115, 2); + + if (sub_81D9DAC(array, 0, 3) != sub_81D9DAC(charsByTableId, 117, 3)) + return FALSE; + + sub_81D9C90(array, 9, 21); + sub_81D9C90(array, 8, array[8] & 0xF); + sub_81D9CDC(array, 8, array[8] >> 4); + + if (array[6] != (array[0] ^ array[2] ^ array[4] ^ (trainerId >> 8))) + return FALSE; + + if (array[7] != (array[1] ^ array[3] ^ array[5] ^ (trainerId & 0xFF))) + return FALSE; + + ptr = (u16*)(&array[0]); + *backgroundClr = *ptr; + + ptr = (u16*)(&array[2]); + *foregroundClr = *ptr; + + *iconId = array[4]; + *patternId = array[5]; + + return TRUE; +} + +static void sub_81D9C90(u8 *array, s32 arg1, s32 arg2) +{ + s32 i, j; + u8 var1, var2; + + for (i = arg2 - 1; i != -1; i--) + { + var1 = (array[0] & 0x80) >> 7; + + var1++; var1--; // needed to match + + for (j = arg1 - 1; j >= 0; j--) + { + var2 = array[j] & 0x80; + array[j] <<= 1; + array[j] |= var1; + var1 = var2 >> 7; + } + } +} + +static void sub_81D9CDC(u8 *array, u32 loopCount, u8 arg2) +{ + u32 i; + + arg2 |= (arg2 << 4); + + for (i = 0; i < loopCount; i++) + { + array[i] ^= arg2; + } +} + +static bool8 sub_81D9D0C(u8 *array, u32 arg1) +{ + u32 arrayId = arg1 >> 3; + u32 bits = 0x80 >> (7 & arg1); + + return ((array[arrayId] & bits) != 0); +} + +static void sub_81D9D28(u8 *array, u32 arg1) +{ + u32 arrayId = arg1 >> 3; + u8 bits = 0x80 >> (7 & arg1); + + array[arrayId] |= bits; +} + +static void sub_81D9D40(u8 *array, u32 arg1) +{ + u32 arrayId = arg1 >> 3; + u8 bits = ~(0x80 >> (7 & arg1)); + + array[arrayId] &= bits; +} + +static void sub_81D9D5C(u8 *array, u8 *letterTableIds, u32 arg2, u32 arg3, u32 loopCount) +{ + u32 i; + + for (i = 0; i < loopCount; i++) + { + if (sub_81D9D0C(letterTableIds, arg3 + i)) + sub_81D9D28(array, arg2 + i); + else + sub_81D9D40(array, arg2 + i); + } +} + +static u32 sub_81D9DAC(u8 *array, u32 arg1, u32 loopCount) +{ + u32 ret, i; + + for (ret = 0, i = 0; i < loopCount; i++) + { + ret <<= 1; + ret |= sub_81D9D0C(array, arg1 + i); + } + + return ret; +} |