diff options
Diffstat (limited to 'src')
73 files changed, 52034 insertions, 4991 deletions
diff --git a/src/battle_1.c b/src/battle_1.c new file mode 100644 index 000000000..5e4ef5583 --- /dev/null +++ b/src/battle_1.c @@ -0,0 +1,17 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u32 gUnknown_03000DD4; +IWRAM_DATA u32 gUnknown_03000DD8; +IWRAM_DATA u32 gUnknown_03000DDC; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/battle_2.c b/src/battle_2.c new file mode 100644 index 000000000..16c07114a --- /dev/null +++ b/src/battle_2.c @@ -0,0 +1,5646 @@ +#include "global.h" +#include "battle.h" +#include "recorded_battle.h" +#include "main.h" +#include "load_save.h" +#include "gpu_regs.h" +#include "unknown_task.h" +#include "battle_setup.h" +#include "pokemon.h" +#include "palette.h" +#include "task.h" +#include "event_data.h" +#include "species.h" +#include "berry.h" +#include "text.h" +#include "item.h" +#include "items.h" +#include "hold_effects.h" +#include "link.h" +#include "bg.h" +#include "dma3.h" +#include "string_util.h" +#include "malloc.h" +#include "event_data.h" +#include "m4a.h" +#include "window.h" +#include "rng.h" +#include "songs.h" +#include "sound.h" +#include "battle_message.h" +#include "sprite.h" +#include "util.h" +#include "trig.h" +#include "battle_ai_script_commands.h" +#include "battle_move_effects.h" +#include "battle_controllers.h" +#include "pokedex.h" +#include "abilities.h" +#include "moves.h" +#include "trainer_classes.h" +#include "evolution_scene.h" +#include "roamer.h" +#include "tv.h" +#include "safari_zone.h" +#include "battle_string_ids.h" + +struct UnknownStruct6 +{ + u16 unk0[0xA0]; + u8 fillerA0[0x640]; + u16 unk780[0xA0]; +}; + +struct UnknownPokemonStruct2 +{ + /*0x00*/ u16 species; + /*0x02*/ u16 heldItem; + /*0x04*/ u8 nickname[POKEMON_NAME_LENGTH + 1]; + /*0x0F*/ u8 level; + /*0x10*/ u16 hp; + /*0x12*/ u16 maxhp; + /*0x14*/ u32 status; + /*0x18*/ u32 personality; + /*0x1C*/ u8 gender; + /*0x1D*/ u8 language; +}; + +extern u8 gBattleCommunication[]; +extern u8 gBattleTerrain; +extern u16 gBattle_BG0_X; +extern u16 gBattle_BG0_Y; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattle_BG3_X; +extern u16 gBattle_BG3_Y; +extern u16 gPartnerTrainerId; +extern u16 gBattle_WIN0H; +extern u16 gBattle_WIN0V; +extern u16 gBattle_WIN1H; +extern u16 gBattle_WIN1V; +extern u16 gTrainerBattleOpponent_A; +extern u16 gTrainerBattleOpponent_B; +extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT]; +extern void (*gPreBattleCallback1)(void); +extern void (*gBattleMainFunc)(void); +extern void (*gUnknown_030061E8)(void); +extern struct UnknownPokemonStruct2 gUnknown_02022FF8[3]; // what is it used for? +extern struct UnknownPokemonStruct2* gUnknown_02023058; // what is it used for? +extern u8 gUnknown_02039B28[]; // possibly a struct? +extern struct UnknownStruct6 gUnknown_02038C28; // todo: identify & document +extern struct MusicPlayerInfo gMPlay_SE1; +extern struct MusicPlayerInfo gMPlay_SE2; +extern u8 gDecompressionBuffer[]; +extern u16 gUnknown_020243FC; +extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT]; +extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void); +extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200]; +extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; +extern u8 gStringBank; +extern u32 gUnknown_02022F88; +extern u32 gHitMarker; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gBattleMonForms[BATTLE_BANKS_COUNT]; +extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT]; +extern u16 gPaydayMoney; +extern u16 gBattleWeather; +extern u16 gPauseCounterBattle; +extern u16 gRandomTurnNumber; +extern u8 gActiveBank; +extern u8 gNoOfAllBanks; +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern u8 gLeveledUpInBattle; +extern u8 gAbsentBankFlags; +extern u32 gBattleExecBuffer; +extern u8 gMultiHitCounter; +extern u8 gBattleMoveFlags; +extern s32 gBattleMoveDamage; +extern const u8* gUnknown_02024230[BATTLE_BANKS_COUNT]; +extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; +extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gUnknown_02024250[BATTLE_BANKS_COUNT]; +extern u16 gUnknown_02024258[BATTLE_BANKS_COUNT]; +extern u16 gUnknown_02024260[BATTLE_BANKS_COUNT]; +extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_02024270[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_02024284[BATTLE_BANKS_COUNT]; +extern u32 gStatuses3[BATTLE_BANKS_COUNT]; +extern u16 gSideAffecting[2]; +extern u16 gCurrentMove; +extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT]; +extern u8 gMoveSelectionCursor[BATTLE_BANKS_COUNT]; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; +extern u8 gBanksByTurnOrder[BATTLE_BANKS_COUNT]; +extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; +extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT]; +extern u8 gCurrentActionFuncId; +extern u8 gLastUsedAbility; +extern u8 gUnknown_0203CF00[]; +extern const u8* gBattlescriptPtrsForSelection[BATTLE_BANKS_COUNT]; +extern const u8* gBattlescriptCurrInstr; +extern u32 gBattlePalaceMoveSelectionRngValue; +extern u8 gActionsByTurnOrder[BATTLE_BANKS_COUNT]; +extern u8 gCurrentTurnActionNumber; +extern u16 gDynamicBasePower; +extern u8 gCritMultiplier; +extern u8 gCurrMovePos; +extern u8 gUnknown_020241E9; +extern u16 gLastUsedMove; + +extern const struct BattleMove gBattleMoves[]; +extern const u16 gUnknown_08C004E0[]; // battle textbox palette +extern const struct BgTemplate gUnknown_0831AA08[]; +extern const struct WindowTemplate * const gUnknown_0831ABA0[]; +extern const u8 gUnknown_0831ACE0[]; +extern const u8 gStatStageRatios[][2]; +extern const u8 * const gBattleScriptsForMoveEffects[]; +extern const u8 * const gBattlescriptsForBallThrow[]; +extern const u8 * const gBattlescriptsForRunningByItem[]; +extern const u8 * const gUnknown_082DBD3C[]; +extern const u8 * const gBattlescriptsForSafariActions[]; + +// strings +extern const u8 gText_LinkStandby3[]; +extern const u8 gText_RecordBattleToPass[]; +extern const u8 gText_BattleYesNoChoice[]; +extern const u8 gText_BattleRecordCouldntBeSaved[]; +extern const u8 gText_BattleRecordedOnPass[]; +extern const u8 gText_ShedinjaJapaneseName[]; +extern const u8 gText_EmptyString3[]; +extern const u8 gText_Poison[]; +extern const u8 gText_Sleep[]; +extern const u8 gText_Paralysis[]; +extern const u8 gText_Burn[]; +extern const u8 gText_Ice[]; +extern const u8 gText_Confusion[]; +extern const u8 gText_Love[]; + +// battlescripts +extern const u8 gUnknown_082DB8BE[]; +extern const u8 gUnknown_082DB881[]; +extern const u8 BattleScript_ActionSelectionItemsCantBeUsed[]; +extern const u8 gUnknown_082DAB11[]; +extern const u8 gUnknown_082DB9BA[]; +extern const u8 gUnknown_082DAAFE[]; +extern const u8 gUnknown_082DAB0B[]; +extern const u8 BattleScript_FocusPunchSetUp[]; +extern const u8 BattleScript_LinkBattleWonOrLost[]; +extern const u8 BattleScript_FrontierTrainerBattleWon[]; +extern const u8 BattleScript_LocalTrainerBattleWon[]; +extern const u8 BattleScript_PayDayMoneyAndPickUpItems[]; +extern const u8 BattleScript_LocalBattleLost[]; +extern const u8 gUnknown_082DB9C8[]; +extern const u8 gUnknown_082DAA0B[]; +extern const u8 gUnknown_082DB9C1[]; +extern const u8 BattleScript_RanAwayUsingMonAbility[]; +extern const u8 BattleScript_SmokeBallEscape[]; +extern const u8 BattleScript_GotAwaySafely[]; +extern const u8 BattleScript_WildMonFled[]; +extern const u8 BattleScript_MoveUsedLoafingAround[]; +extern const u8 BattleScript_ActionSwitch[]; +extern const u8 BattleScript_PrintFailedToRunString[]; + +// functions +extern void dp12_8087EA4(void); +extern void sub_80356D0(void); +extern void GetFrontierTrainerName(u8* dst, u16 trainerId); // battle tower +extern void sub_8166188(void); // battle tower, sets link battle mons level but why? +extern void sub_8165B88(u8* dst, u16 trainerId); // battle tower, gets language +extern void sub_81DB4DC(u8* dst, u8 arg2); // +extern void sub_81B9150(void); +extern void sub_800AC34(void); +extern void sub_80B3AF8(u8 taskId); // cable club +extern void sub_8076918(u8 bank); +extern void SetHealthboxSpriteVisible(u8 healthoxSpriteId); +extern void sub_81A56B4(void); // battle frontier 2 +extern u8 sub_81A9E28(void); // battle frontier 2 +extern void sub_81A56E8(u8 bank); // battle frontier 2 +extern void sub_81B8FB0(u8, u8); // party menu +extern u8 pokemon_order_func(u8); // party menu +extern bool8 InBattlePyramid(void); + +// this file's functions +static void CB2_InitBattleInternal(void); +static void CB2_PreInitMultiBattle(void); +static void CB2_PreInitIngamePlayerPartnerBattle(void); +static void CB2_HandleStartMultiPartnerBattle(void); +static void CB2_HandleStartMultiBattle(void); +static void CB2_HandleStartBattle(void); +static void TryCorrectShedinjaLanguage(struct Pokemon *mon); +static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer); +static void BattleMainCB1(void); +static void sub_8038538(struct Sprite *sprite); +static void sub_8038F14(void); +static void sub_8038F34(void); +static void sub_80392A8(void); +static void sub_803937C(void); +static void sub_803939C(void); +void oac_poke_opponent(struct Sprite *sprite); +static void sub_803980C(struct Sprite *sprite); +static void sub_8039838(struct Sprite *sprite); +static void sub_8039894(struct Sprite *sprite); +static void sub_80398D0(struct Sprite *sprite); +static void sub_8039A48(struct Sprite *sprite); +static void sub_8039AF4(struct Sprite *sprite); +static void SpriteCallbackDummy_3(struct Sprite *sprite); +static void oac_poke_ally_(struct Sprite *sprite); +static void SpecialStatusesClear(void); +static void TurnValuesCleanUp(bool8 var0); +static void SpriteCB_HealthBoxBounce(struct Sprite *sprite); +static void BattleStartClearSetData(void); +static void BattleIntroGetMonsData(void); +static void BattleIntroPrepareBackgroundSlide(void); +static void BattleIntroDrawTrainersOrMonsSprites(void); +static void BattleIntroDrawPartySummaryScreens(void); +static void BattleIntroPrintTrainerWantsToBattle(void); +static void BattleIntroPrintWildMonAttacked(void); +static void BattleIntroPrintOpponentSendsOut(void); +static void BattleIntroPrintPlayerSendsOut(void); +static void BattleIntroOpponent1SendsOutMonAnimation(void); +static void BattleIntroOpponent2SendsOutMonAnimation(void); +static void BattleIntroRecordMonsToDex(void); +static void BattleIntroPlayer1SendsOutMonAnimation(void); +static void TryDoEventsBeforeFirstTurn(void); +static void HandleTurnActionSelectionState(void); +static void RunTurnActionsFunctions(void); +static void SetActionsAndBanksTurnOrder(void); +static void sub_803CDF8(void); +static bool8 sub_803CDB8(void); +static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void); +static void FreeResetData_ReturnToOvOrDoEvolutions(void); +static void ReturnFromBattleToOverworld(void); +static void TryEvolvePokemon(void); +static void WaitForEvoSceneToFinish(void); +static void HandleEndTurn_ContinueBattle(void); +static void HandleEndTurn_BattleWon(void); +static void HandleEndTurn_BattleLost(void); +static void HandleEndTurn_RanFromBattle(void); +static void HandleEndTurn_MonFled(void); +static void HandleEndTurn_FinishBattle(void); +static void HandleAction_UseMove(void); +static void HandleAction_Switch(void); +static void HandleAction_UseItem(void); +static void HandleAction_Run(void); +static void HandleAction_WatchesCarefully(void); +static void HandleAction_SafariZoneBallThrow(void); +static void HandleAction_ThrowPokeblock(void); +static void HandleAction_GoNear(void); +static void HandleAction_SafriZoneRun(void); +static void HandleAction_Action9(void); +static void HandleAction_Action11(void); +static void HandleAction_NothingIsFainted(void); +static void HandleAction_ActionFinished(void); + +// rom const data +static void (* const sTurnActionsFuncsTable[])(void) = +{ + HandleAction_UseMove, // ACTION_USE_MOVE + HandleAction_UseItem, // ACTION_USE_ITEM + HandleAction_Switch, // ACTION_SWITCH + HandleAction_Run, // ACTION_RUN + HandleAction_WatchesCarefully, // ACTION_WATCHES_CAREFULLY + HandleAction_SafariZoneBallThrow, // ACTION_SAFARI_ZONE_BALL + HandleAction_ThrowPokeblock, // ACTION_POKEBLOCK_CASE + HandleAction_GoNear, // ACTION_GO_NEAR + HandleAction_SafriZoneRun, // ACTION_SAFARI_ZONE_RUN + HandleAction_Action9, // ACTION_9 + HandleAction_RunBattleScript, // ACTION_RUN_BATTLESCRIPT + HandleAction_Action11, // not sure about this one + HandleAction_ActionFinished, // ACTION_FINISHED + HandleAction_NothingIsFainted, // ACTION_NOTHING_FAINTED +}; + +static void (* const sEndTurnFuncsTable[])(void) = +{ + HandleEndTurn_ContinueBattle, // battle outcome 0 + HandleEndTurn_BattleWon, // BATTLE_WON + HandleEndTurn_BattleLost, // BATTLE_LOST + HandleEndTurn_BattleLost, // BATTLE_DREW + HandleEndTurn_RanFromBattle, // BATTLE_RAN + HandleEndTurn_FinishBattle, // BATTLE_PLAYER_TELEPORTED + HandleEndTurn_MonFled, // BATTLE_POKE_FLED + HandleEndTurn_FinishBattle, // BATTLE_CAUGHT + HandleEndTurn_FinishBattle, // battle outcome 8 + HandleEndTurn_FinishBattle, // BATTLE_FORFEITED + HandleEndTurn_FinishBattle, // BATTLE_OPPONENT_TELEPORTED +}; + +const u8 gStatusConditionString_PoisonJpn[8] = _("どく$$$$$"); +const u8 gStatusConditionString_SleepJpn[8] = _("ねむり$$$$"); +const u8 gStatusConditionString_ParalysisJpn[8] = _("まひ$$$$$"); +const u8 gStatusConditionString_BurnJpn[8] = _("やけど$$$$"); +const u8 gStatusConditionString_IceJpn[8] = _("こおり$$$$"); +const u8 gStatusConditionString_ConfusionJpn[8] = _("こんらん$$$"); +const u8 gStatusConditionString_LoveJpn[8] = _("メロメロ$$$"); + +const u8 * const gStatusConditionStringsTable[7][2] = +{ + {gStatusConditionString_PoisonJpn, gText_Poison}, + {gStatusConditionString_SleepJpn, gText_Sleep}, + {gStatusConditionString_ParalysisJpn, gText_Paralysis}, + {gStatusConditionString_BurnJpn, gText_Burn}, + {gStatusConditionString_IceJpn, gText_Ice}, + {gStatusConditionString_ConfusionJpn, gText_Confusion}, + {gStatusConditionString_LoveJpn, gText_Love} +}; + +static const u8 sUnknown_0831BCE0[][3] = {{0, 0, 0}, {3, 5, 0}, {2, 3, 0}, {1, 2, 0}, {1, 1, 0}}; +static const u8 sUnknown_0831BCEF[] = {4, 3, 2, 1}; +static const u8 sUnknown_0831BCF3[] = {4, 4, 4, 4}; + +void CB2_InitBattle(void) +{ + MoveSaveBlocks_ResetHeap(); + AllocateBattleResrouces(); + AllocateBattleSpritesData(); + AllocateMonSpritesGfx(); + sub_8185F84(); + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + { + CB2_InitBattleInternal(); + } + else if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) + { + HandleLinkBattleSetup(); + SetMainCallback2(CB2_PreInitMultiBattle); + } + else + { + SetMainCallback2(CB2_PreInitIngamePlayerPartnerBattle); + } + gBattleCommunication[MULTIUSE_STATE] = 0; + } + else + { + CB2_InitBattleInternal(); + } +} + +static void CB2_InitBattleInternal(void) +{ + s32 i; + + SetHBlankCallback(NULL); + SetVBlankCallback(NULL); + + CpuFill32(0, (void*)(VRAM), VRAM_SIZE); + + SetGpuReg(REG_OFFSET_MOSAIC, 0); + SetGpuReg(REG_OFFSET_WIN0H, 240); + SetGpuReg(REG_OFFSET_WIN0V, 0x5051); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + + gBattle_WIN0H = 240; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != STEVEN_PARTNER_ID) + { + gBattle_WIN0V = 159; + gBattle_WIN1H = 240; + gBattle_WIN1V = 32; + } + else + { + gBattle_WIN0V = 0x5051; + dp12_8087EA4(); + + for (i = 0; i < 80; i++) + { + gUnknown_02038C28.unk0[i] = 0xF0; + gUnknown_02038C28.unk780[i] = 0xF0; + } + for (i = 80; i < 160; i++) + { + #ifndef NONMATCHING + asm(""::"r"(i)); // needed to match + #endif // NONMATCHING + + gUnknown_02038C28.unk0[i] = 0xFF10; + gUnknown_02038C28.unk780[i] = 0xFF10; + } + + sub_80BA038(gUnknown_0831AC70); + } + + ResetPaletteFade(); + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + gBattle_BG3_X = 0; + gBattle_BG3_Y = 0; + + gBattleTerrain = BattleSetup_GetTerrainId(); + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + gBattleTerrain = BATTLE_TERRAIN_INSIDE; + + sub_80356D0(); + LoadBattleTextboxAndBackground(); + ResetSpriteData(); + ResetTasks(); + LoadBattleEntryBackground(); + FreeAllSpritePalettes(); + gReservedSpritePaletteCount = 4; + SetVBlankCallback(VBlankCB_Battle); + SetUpBattleVarsAndBirchZigzagoon(); + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + SetMainCallback2(CB2_HandleStartMultiPartnerBattle); + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + SetMainCallback2(CB2_HandleStartMultiPartnerBattle); + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + SetMainCallback2(CB2_HandleStartMultiBattle); + else + SetMainCallback2(CB2_HandleStartBattle); + + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED))) + { + CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, TRUE); + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + CreateNPCTrainerParty(&gEnemyParty[3], gTrainerBattleOpponent_B, FALSE); + SetWildMonHeldItem(); + } + + gMain.inBattle = TRUE; + gSaveBlock2Ptr->field_CA9_b = 0; + + for (i = 0; i < 6; i++) + AdjustFriendship(&gPlayerParty[i], 3); + + gBattleCommunication[MULTIUSE_STATE] = 0; +} + +static void sub_8036A5C(void) +{ + u16 r6 = 0; + u16 species = 0; + u16 hp = 0; + u32 status = 0; + s32 i; + + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp != 0 && status == 0) + r6 |= 1 << i * 2; + + if (species == SPECIES_NONE) + continue; + if (hp != 0 && (species == SPECIES_EGG || status != 0)) + r6 |= 2 << i * 2; + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp == 0) + r6 |= 3 << i * 2; + } + + gBattleStruct->field_182 = r6; + *(&gBattleStruct->field_183) = r6 >> 8; + gBattleStruct->field_183 |= FlagGet(SYS_FRONTIER_PASS) << 7; +} + +static void SetPlayerBerryDataInBattleStruct(void) +{ + s32 i; + struct BattleStruct *battleStruct = gBattleStruct; + struct BattleEnigmaBerry *battleBerry = &battleStruct->battleEnigmaBerry; + + if (IsEnigmaBerryValid() == TRUE) + { + for (i = 0; i < BERRY_NAME_COUNT - 1; i++) + battleBerry->name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i]; + battleBerry->name[i] = EOS; + + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++) + battleBerry->itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i]; + + battleBerry->holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + battleBerry->holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam; + } + else + { + const struct Berry* berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY)); + + for (i = 0; i < BERRY_NAME_COUNT - 1; i++) + battleBerry->name[i] = berryData->name[i]; + battleBerry->name[i] = EOS; + + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++) + battleBerry->itemEffect[i] = 0; + + battleBerry->holdEffect = HOLD_EFFECT_NONE; + battleBerry->holdEffectParam = 0; + } +} + +static void SetAllPlayersBerryData(void) +{ + s32 i; + s32 j; + + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + if (IsEnigmaBerryValid() == TRUE) + { + for (i = 0; i < BERRY_NAME_COUNT - 1; i++) + { + gEnigmaBerries[0].name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i]; + gEnigmaBerries[2].name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i]; + } + gEnigmaBerries[0].name[i] = EOS; + gEnigmaBerries[2].name[i] = EOS; + + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++) + { + gEnigmaBerries[0].itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i]; + gEnigmaBerries[2].itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i]; + } + + gEnigmaBerries[0].holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + gEnigmaBerries[2].holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + gEnigmaBerries[0].holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam; + gEnigmaBerries[2].holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam; + } + else + { + const struct Berry* berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY)); + + for (i = 0; i < BERRY_NAME_COUNT - 1; i++) + { + gEnigmaBerries[0].name[i] = berryData->name[i]; + gEnigmaBerries[2].name[i] = berryData->name[i]; + } + gEnigmaBerries[0].name[i] = EOS; + gEnigmaBerries[2].name[i] = EOS; + + for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++) + { + gEnigmaBerries[0].itemEffect[i] = 0; + gEnigmaBerries[2].itemEffect[i] = 0; + } + + gEnigmaBerries[0].holdEffect = 0; + gEnigmaBerries[2].holdEffect = 0; + gEnigmaBerries[0].holdEffectParam = 0; + gEnigmaBerries[2].holdEffectParam = 0; + } + } + else + { + s32 numPlayers; + struct BattleEnigmaBerry *src; + u8 r4; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + numPlayers = 2; + else + numPlayers = 4; + + for (i = 0; i < numPlayers; i++) + { + src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2); + r4 = gLinkPlayers[i].lp_field_18; + + for (j = 0; j < BERRY_NAME_COUNT - 1; j++) + gEnigmaBerries[r4].name[j] = src->name[j]; + gEnigmaBerries[r4].name[j] = EOS; + + for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; j++) + gEnigmaBerries[r4].itemEffect[j] = src->itemEffect[j]; + + gEnigmaBerries[r4].holdEffect = src->holdEffect; + gEnigmaBerries[r4].holdEffectParam = src->holdEffectParam; + } + } + else + { + for (i = 0; i < 2; i++) + { + src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2); + + for (j = 0; j < BERRY_NAME_COUNT - 1; j++) + { + gEnigmaBerries[i].name[j] = src->name[j]; + gEnigmaBerries[i + 2].name[j] = src->name[j]; + } + gEnigmaBerries[i].name[j] = EOS; + gEnigmaBerries[i + 2].name[j] = EOS; + + for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; j++) + { + gEnigmaBerries[i].itemEffect[j] = src->itemEffect[j]; + gEnigmaBerries[i + 2].itemEffect[j] = src->itemEffect[j]; + } + + gEnigmaBerries[i].holdEffect = src->holdEffect; + gEnigmaBerries[i + 2].holdEffect = src->holdEffect; + gEnigmaBerries[i].holdEffectParam = src->holdEffectParam; + gEnigmaBerries[i + 2].holdEffectParam = src->holdEffectParam; + } + } + } +} + +static void sub_8036EB8(u8 arg0, u8 arg1) +{ + u8 var = 0; + + if (gBlockRecvBuffer[0][0] == 256) + { + if (arg1 == 0) + gBattleTypeFlags |= BATTLE_TYPE_WILD | BATTLE_TYPE_TRAINER; + else + gBattleTypeFlags |= BATTLE_TYPE_TRAINER; + var++; + } + + if (var == 0) + { + s32 i; + + for (i = 0; i < arg0; i++) + { + if (gBlockRecvBuffer[0][0] != gBlockRecvBuffer[i][0]) + break; + } + + if (i == arg0) + { + if (arg1 == 0) + gBattleTypeFlags |= BATTLE_TYPE_WILD | BATTLE_TYPE_TRAINER; + else + gBattleTypeFlags |= BATTLE_TYPE_TRAINER; + var++; + } + + if (var == 0) + { + for (i = 0; i < arg0; i++) + { + if (gBlockRecvBuffer[i][0] == 0x300) + { + if (i != arg1 && i < arg1) + break; + } + if (gBlockRecvBuffer[i][0] > 0x300 && i != arg1) + break; + } + + if (i == arg0) + gBattleTypeFlags |= BATTLE_TYPE_WILD | BATTLE_TYPE_TRAINER; + else + gBattleTypeFlags |= BATTLE_TYPE_TRAINER; + } + } +} + +static void CB2_HandleStartBattle(void) +{ + u8 playerMultiplayerId; + u8 enemyMultiplayerId; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + + playerMultiplayerId = GetMultiplayerId(); + gBattleScripting.multiplayerId = playerMultiplayerId; + enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE; + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (!IsDma3ManagerBusyWithBgCopy()) + { + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + sub_805EF14(); + gBattleCommunication[MULTIUSE_STATE] = 1; + } + if (gLinkVSyncDisabled) + sub_800E0E8(); + break; + case 1: + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + if (gReceivedRemoteLinkPlayers != 0) + { + if (sub_800A520()) + { + *(&gBattleStruct->field_180) = 0; + *(&gBattleStruct->field_181) = 3; + sub_8036A5C(); + SetPlayerBerryDataInBattleStruct(); + + if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + { + gLinkPlayers[0].lp_field_18 = 0; + gLinkPlayers[1].lp_field_18 = 1; + } + + SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_180, 32); + gBattleCommunication[MULTIUSE_STATE] = 2; + } + if (gLinkVSyncDisabled) + sub_800DFB4(0, 0); + } + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + gBattleTypeFlags |= BATTLE_TYPE_WILD; + gBattleCommunication[MULTIUSE_STATE] = 15; + SetAllPlayersBerryData(); + } + break; + case 2: + if ((GetBlockReceivedStatus() & 3) == 3) + { + u8 taskId; + + ResetBlockReceivedFlags(); + sub_8036EB8(2, playerMultiplayerId); + SetAllPlayersBerryData(); + taskId = CreateTask(task00_0800F6FC, 0); + gTasks[taskId].data[1] = 0x10E; + gTasks[taskId].data[2] = 0x5A; + gTasks[taskId].data[5] = 0; + gTasks[taskId].data[3] = gBattleStruct->field_182 | (gBattleStruct->field_183 << 8); + gTasks[taskId].data[4] = gBlockRecvBuffer[enemyMultiplayerId][1]; + sub_8185F90(gBlockRecvBuffer[playerMultiplayerId][1]); + sub_8185F90(gBlockRecvBuffer[enemyMultiplayerId][1]); + sub_8068AA4(); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 3: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 4: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + memcpy(gEnemyParty, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 7: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 8: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + memcpy(gEnemyParty + 2, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 11: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 4, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 12: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + memcpy(gEnemyParty + 4, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + TryCorrectShedinjaLanguage(&gEnemyParty[0]); + TryCorrectShedinjaLanguage(&gEnemyParty[1]); + TryCorrectShedinjaLanguage(&gEnemyParty[2]); + TryCorrectShedinjaLanguage(&gEnemyParty[3]); + TryCorrectShedinjaLanguage(&gEnemyParty[4]); + TryCorrectShedinjaLanguage(&gEnemyParty[5]); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 15: + sub_8032768(); + sub_8184E58(); + gBattleCommunication[SPRITES_INIT_STATE1] = 0; + gBattleCommunication[SPRITES_INIT_STATE2] = 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + s32 i; + + for (i = 0; i < 2 && (gLinkPlayers[i].version & 0xFF) == VERSION_EMERALD; i++); + + if (i == 2) + gBattleCommunication[MULTIUSE_STATE] = 16; + else + gBattleCommunication[MULTIUSE_STATE] = 18; + } + else + { + gBattleCommunication[MULTIUSE_STATE] = 18; + } + break; + case 16: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed)); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 17: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (!(gBattleTypeFlags & BATTLE_TYPE_WILD)) + memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[enemyMultiplayerId], sizeof(gRecordedBattleRngSeed)); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 18: + if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2])) + { + gPreBattleCallback1 = gMain.callback1; + gMain.callback1 = BattleMainCB1; + SetMainCallback2(BattleMainCB2); + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleTypeFlags |= BATTLE_TYPE_20; + } + } + break; + case 5: + case 9: + case 13: + gBattleCommunication[MULTIUSE_STATE]++; + gBattleCommunication[1] = 1; + case 6: + case 10: + case 14: + if (--gBattleCommunication[1] == 0) + gBattleCommunication[MULTIUSE_STATE]++; + break; + } +} + +static void CB2_HandleStartMultiPartnerBattle(void) +{ + u8 playerMultiplayerId; + u8 enemyMultiplayerId; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + + playerMultiplayerId = GetMultiplayerId(); + gBattleScripting.multiplayerId = playerMultiplayerId; + enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE; + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (!IsDma3ManagerBusyWithBgCopy()) + { + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + sub_805EF14(); + gBattleCommunication[MULTIUSE_STATE] = 1; + } + if (gLinkVSyncDisabled) + sub_800E0E8(); + // fall through + case 1: + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + if (gReceivedRemoteLinkPlayers != 0) + { + u8 language; + + gLinkPlayers[0].lp_field_18 = 0; + gLinkPlayers[1].lp_field_18 = 2; + gLinkPlayers[2].lp_field_18 = 1; + gLinkPlayers[3].lp_field_18 = 3; + GetFrontierTrainerName(gLinkPlayers[2].name, gTrainerBattleOpponent_A); + GetFrontierTrainerName(gLinkPlayers[3].name, gTrainerBattleOpponent_B); + sub_8165B88(&language, gTrainerBattleOpponent_A); + gLinkPlayers[2].language = language; + sub_8165B88(&language, gTrainerBattleOpponent_B); + gLinkPlayers[3].language = language; + + if (sub_800A520()) + { + *(&gBattleStruct->field_180) = 0; + *(&gBattleStruct->field_181) = 3; + sub_8036A5C(); + SetPlayerBerryDataInBattleStruct(); + SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_180, 32); + gBattleCommunication[MULTIUSE_STATE] = 2; + } + + if (gLinkVSyncDisabled) + sub_800DFB4(0, 0); + } + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + gBattleTypeFlags |= BATTLE_TYPE_WILD; + gBattleCommunication[MULTIUSE_STATE] = 13; + SetAllPlayersBerryData(); + } + break; + case 2: + if ((GetBlockReceivedStatus() & 3) == 3) + { + u8 taskId; + + ResetBlockReceivedFlags(); + sub_8036EB8(2, playerMultiplayerId); + SetAllPlayersBerryData(); + taskId = CreateTask(task00_0800F6FC, 0); + gTasks[taskId].data[1] = 0x10E; + gTasks[taskId].data[2] = 0x5A; + gTasks[taskId].data[5] = 0; + gTasks[taskId].data[3] = 0x145; + gTasks[taskId].data[4] = 0x145; + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 3: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 4: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (gLinkPlayers[playerMultiplayerId].lp_field_18 != 0) + { + memcpy(gPlayerParty, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + memcpy(gPlayerParty + 3, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2); + } + else + { + memcpy(gPlayerParty, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2); + memcpy(gPlayerParty + 3, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2); + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 5: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon)); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 6: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (gLinkPlayers[playerMultiplayerId].lp_field_18 != 0) + { + memcpy(gPlayerParty + 2, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon)); + memcpy(gPlayerParty + 5, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon)); + } + else + { + memcpy(gPlayerParty + 2, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon)); + memcpy(gPlayerParty + 5, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon)); + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 7: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gEnemyParty, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 8: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (GetMultiplayerId() != 0) + { + memcpy(gEnemyParty, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2); + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 9: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gEnemyParty + 2, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 10: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (GetMultiplayerId() != 0) + { + memcpy(gEnemyParty + 2, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2); + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 11: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gEnemyParty + 4, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 12: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (GetMultiplayerId() != 0) + memcpy(gEnemyParty + 4, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2); + TryCorrectShedinjaLanguage(&gPlayerParty[0]); + TryCorrectShedinjaLanguage(&gPlayerParty[1]); + TryCorrectShedinjaLanguage(&gPlayerParty[2]); + TryCorrectShedinjaLanguage(&gPlayerParty[3]); + TryCorrectShedinjaLanguage(&gPlayerParty[4]); + TryCorrectShedinjaLanguage(&gPlayerParty[5]); + TryCorrectShedinjaLanguage(&gEnemyParty[0]); + TryCorrectShedinjaLanguage(&gEnemyParty[1]); + TryCorrectShedinjaLanguage(&gEnemyParty[2]); + TryCorrectShedinjaLanguage(&gEnemyParty[3]); + TryCorrectShedinjaLanguage(&gEnemyParty[4]); + TryCorrectShedinjaLanguage(&gEnemyParty[5]); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 13: + sub_8032768(); + sub_8184E58(); + gBattleCommunication[SPRITES_INIT_STATE1] = 0; + gBattleCommunication[SPRITES_INIT_STATE2] = 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleCommunication[MULTIUSE_STATE] = 14; + } + else + { + gBattleCommunication[MULTIUSE_STATE] = 16; + } + break; + case 14: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed)); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 15: + if ((GetBlockReceivedStatus() & 3) == 3) + { + ResetBlockReceivedFlags(); + if (!(gBattleTypeFlags & BATTLE_TYPE_WILD)) + memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[enemyMultiplayerId], sizeof(gRecordedBattleRngSeed)); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 16: + if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2])) + { + sub_8166188(); + gPreBattleCallback1 = gMain.callback1; + gMain.callback1 = BattleMainCB1; + SetMainCallback2(BattleMainCB2); + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleTypeFlags |= BATTLE_TYPE_20; + } + } + break; + } +} + +static void sub_80379F8(u8 arrayIdPlus) +{ + s32 i; + + for (i = 0; i < 3; i++) + { + gUnknown_02022FF8[i].species = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_SPECIES); + gUnknown_02022FF8[i].heldItem = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_HELD_ITEM); + GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_NICKNAME, gUnknown_02022FF8[i].nickname); + gUnknown_02022FF8[i].level = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_LEVEL); + gUnknown_02022FF8[i].hp = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_HP); + gUnknown_02022FF8[i].maxhp = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_MAX_HP); + gUnknown_02022FF8[i].status = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_STATUS); + gUnknown_02022FF8[i].personality = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_PERSONALITY); + gUnknown_02022FF8[i].gender = GetMonGender(&gPlayerParty[arrayIdPlus + i]); + StripExtCtrlCodes(gUnknown_02022FF8[i].nickname); + if (GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE) + sub_81DB4DC(gUnknown_02022FF8[i].nickname, 0); + } + memcpy(gUnknown_02023058, gUnknown_02022FF8, sizeof(gUnknown_02022FF8)); +} + +static void CB2_PreInitMultiBattle(void) +{ + s32 i; + u8 playerMultiplierId; + s32 numPlayers = 4; + u8 r4 = 0xF; + u32* savedBattleTypeFlags; + void (**savedCallback)(void); + + if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + { + numPlayers = 2; + r4 = 3; + } + + playerMultiplierId = GetMultiplayerId(); + gBattleScripting.multiplayerId = playerMultiplierId; + savedCallback = &gBattleStruct->savedCallback; + savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (gReceivedRemoteLinkPlayers != 0 && sub_800A520()) + { + gUnknown_02023058 = Alloc(sizeof(struct UnknownPokemonStruct2) * 3); + sub_80379F8(0); + SendBlock(bitmask_all_link_players_but_self(), gUnknown_02023058, sizeof(struct UnknownPokemonStruct2) * 3); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 1: + if ((GetBlockReceivedStatus() & r4) == r4) + { + ResetBlockReceivedFlags(); + for (i = 0; i < numPlayers; i++) + { + if (i == playerMultiplierId) + continue; + + if (numPlayers == 4) + { + if ((!(gLinkPlayers[i].lp_field_18 & 1) && !(gLinkPlayers[playerMultiplierId].lp_field_18 & 1)) + || (gLinkPlayers[i].lp_field_18 & 1 && gLinkPlayers[playerMultiplierId].lp_field_18 & 1)) + { + memcpy(gUnknown_02022FF8, gBlockRecvBuffer[i], sizeof(struct UnknownPokemonStruct2) * 3); + } + } + else + { + memcpy(gUnknown_02022FF8, gBlockRecvBuffer[i], sizeof(struct UnknownPokemonStruct2) * 3); + } + } + gBattleCommunication[MULTIUSE_STATE]++; + *savedCallback = gMain.savedCallback; + *savedBattleTypeFlags = gBattleTypeFlags; + gMain.savedCallback = CB2_PreInitMultiBattle; + sub_81B9150(); + } + break; + case 2: + if (sub_800A520() && !gPaletteFade.active) + { + gBattleCommunication[MULTIUSE_STATE]++; + if (gLinkVSyncDisabled) + sub_800ADF8(); + else + sub_800AC34(); + } + break; + case 3: + if (gLinkVSyncDisabled) + { + if (sub_8010500()) + { + gBattleTypeFlags = *savedBattleTypeFlags; + gMain.savedCallback = *savedCallback; + SetMainCallback2(CB2_InitBattleInternal); + Free(gUnknown_02023058); + gUnknown_02023058 = NULL; + } + } + else if (gReceivedRemoteLinkPlayers == 0) + { + gBattleTypeFlags = *savedBattleTypeFlags; + gMain.savedCallback = *savedCallback; + SetMainCallback2(CB2_InitBattleInternal); + Free(gUnknown_02023058); + gUnknown_02023058 = NULL; + } + break; + } +} + +static void CB2_PreInitIngamePlayerPartnerBattle(void) +{ + u32* savedBattleTypeFlags; + void (**savedCallback)(void); + + savedCallback = &gBattleStruct->savedCallback; + savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + gUnknown_02023058 = Alloc(sizeof(struct UnknownPokemonStruct2) * 3); + sub_80379F8(3); + gBattleCommunication[MULTIUSE_STATE]++; + *savedCallback = gMain.savedCallback; + *savedBattleTypeFlags = gBattleTypeFlags; + gMain.savedCallback = CB2_PreInitIngamePlayerPartnerBattle; + sub_81B9150(); + break; + case 1: + if (!gPaletteFade.active) + { + gBattleCommunication[MULTIUSE_STATE] = 2; + gBattleTypeFlags = *savedBattleTypeFlags; + gMain.savedCallback = *savedCallback; + SetMainCallback2(CB2_InitBattleInternal); + Free(gUnknown_02023058); + gUnknown_02023058 = NULL; + } + break; + } +} + +static void CB2_HandleStartMultiBattle(void) +{ + u8 playerMultiplayerId; + s32 id; + u8 var; + + playerMultiplayerId = GetMultiplayerId(); + gBattleScripting.multiplayerId = playerMultiplayerId; + + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + if (!IsDma3ManagerBusyWithBgCopy()) + { + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + sub_805EF14(); + gBattleCommunication[MULTIUSE_STATE] = 1; + } + if (gLinkVSyncDisabled) + sub_800E0E8(); + break; + case 1: + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + if (gReceivedRemoteLinkPlayers != 0) + { + if (sub_800A520()) + { + *(&gBattleStruct->field_180) = 0; + *(&gBattleStruct->field_181) = 3; + sub_8036A5C(); + SetPlayerBerryDataInBattleStruct(); + + SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_180, 32); + gBattleCommunication[MULTIUSE_STATE]++; + } + if (gLinkVSyncDisabled) + sub_800DFB4(0, 0); + } + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + gBattleTypeFlags |= BATTLE_TYPE_WILD; + gBattleCommunication[MULTIUSE_STATE] = 7; + SetAllPlayersBerryData(); + } + break; + case 2: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + sub_8036EB8(4, playerMultiplayerId); + SetAllPlayersBerryData(); + sub_8068AA4(); + var = CreateTask(task00_0800F6FC, 0); + gTasks[var].data[1] = 0x10E; + gTasks[var].data[2] = 0x5A; + gTasks[var].data[5] = 0; + gTasks[var].data[3] = 0; + gTasks[var].data[4] = 0; + + for (id = 0; id < MAX_LINK_PLAYERS; id++) + { + sub_8185F90(gBlockRecvBuffer[id][1]); + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + gTasks[var].data[3] |= gBlockRecvBuffer[id][1] & 0x3F; + break; + case 1: + gTasks[var].data[4] |= gBlockRecvBuffer[id][1] & 0x3F; + break; + case 2: + gTasks[var].data[3] |= (gBlockRecvBuffer[id][1] & 0x3F) << 6; + break; + case 3: + gTasks[var].data[4] |= (gBlockRecvBuffer[id][1] & 0x3F) << 6; + break; + } + } + ZeroEnemyPartyMons(); + gBattleCommunication[MULTIUSE_STATE]++; + } + else + break; + // fall through + case 3: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 4: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + for (id = 0; id < MAX_LINK_PLAYERS; id++) + { + if (id == playerMultiplayerId) + { + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + case 3: + memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + case 1: + case 2: + memcpy(gPlayerParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + } + } + else + { + if ((!(gLinkPlayers[id].lp_field_18 & 1) && !(gLinkPlayers[playerMultiplayerId].lp_field_18 & 1)) + || ((gLinkPlayers[id].lp_field_18 & 1) && (gLinkPlayers[playerMultiplayerId].lp_field_18 & 1))) + { + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + case 3: + memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + case 1: + case 2: + memcpy(gPlayerParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + } + } + else + { + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + case 3: + memcpy(gEnemyParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + case 1: + case 2: + memcpy(gEnemyParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2); + break; + } + } + } + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 5: + if (sub_800A520()) + { + SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon)); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 6: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + for (id = 0; id < MAX_LINK_PLAYERS; id++) + { + if (id == playerMultiplayerId) + { + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + case 3: + memcpy(gPlayerParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + case 1: + case 2: + memcpy(gPlayerParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + } + } + else + { + if ((!(gLinkPlayers[id].lp_field_18 & 1) && !(gLinkPlayers[playerMultiplayerId].lp_field_18 & 1)) + || ((gLinkPlayers[id].lp_field_18 & 1) && (gLinkPlayers[playerMultiplayerId].lp_field_18 & 1))) + { + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + case 3: + memcpy(gPlayerParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + case 1: + case 2: + memcpy(gPlayerParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + } + } + else + { + switch (gLinkPlayers[id].lp_field_18) + { + case 0: + case 3: + memcpy(gEnemyParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + case 1: + case 2: + memcpy(gEnemyParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon)); + break; + } + } + } + } + TryCorrectShedinjaLanguage(&gPlayerParty[0]); + TryCorrectShedinjaLanguage(&gPlayerParty[1]); + TryCorrectShedinjaLanguage(&gPlayerParty[2]); + TryCorrectShedinjaLanguage(&gPlayerParty[3]); + TryCorrectShedinjaLanguage(&gPlayerParty[4]); + TryCorrectShedinjaLanguage(&gPlayerParty[5]); + + TryCorrectShedinjaLanguage(&gEnemyParty[0]); + TryCorrectShedinjaLanguage(&gEnemyParty[1]); + TryCorrectShedinjaLanguage(&gEnemyParty[2]); + TryCorrectShedinjaLanguage(&gEnemyParty[3]); + TryCorrectShedinjaLanguage(&gEnemyParty[4]); + TryCorrectShedinjaLanguage(&gEnemyParty[5]); + + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 7: + sub_8032768(); + sub_8184E58(); + gBattleCommunication[SPRITES_INIT_STATE1] = 0; + gBattleCommunication[SPRITES_INIT_STATE2] = 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + for (id = 0; id < 4 && (gLinkPlayers[id].version & 0xFF) == 3; id++); + + if (id == 4) + gBattleCommunication[MULTIUSE_STATE] = 8; + else + gBattleCommunication[MULTIUSE_STATE] = 10; + } + else + { + gBattleCommunication[MULTIUSE_STATE] = 10; + } + break; + case 8: + if (sub_800A520()) + { + u32* ptr = (u32*)(&gBattleStruct->field_180); + ptr[0] = gBattleTypeFlags; + ptr[1] = gRecordedBattleRngSeed; // UB: overwrites berry data + SendBlock(bitmask_all_link_players_but_self(), ptr, 8); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 9: + if ((GetBlockReceivedStatus() & 0xF) == 0xF) + { + ResetBlockReceivedFlags(); + for (var = 0; var < 4; var++) + { + u32 blockValue = gBlockRecvBuffer[var][0]; + if (blockValue & 4) + { + memcpy(&gRecordedBattleRngSeed, &gBlockRecvBuffer[var][2], sizeof(gRecordedBattleRngSeed)); + break; + } + } + + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 10: + if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2])) + { + gPreBattleCallback1 = gMain.callback1; + gMain.callback1 = BattleMainCB1; + SetMainCallback2(BattleMainCB2); + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gTrainerBattleOpponent_A = TRAINER_OPPONENT_800; + gBattleTypeFlags |= BATTLE_TYPE_20; + } + } + break; + } +} + +void BattleMainCB2(void) +{ + AnimateSprites(); + BuildOamBuffer(); + RunTextPrinters(); + UpdatePaletteFade(); + RunTasks(); + + if (gMain.heldKeys & B_BUTTON && gBattleTypeFlags & BATTLE_TYPE_RECORDED && sub_8186450()) + { + gScriptResult = gBattleOutcome = BATTLE_PLAYER_TELEPORTED; + ResetPaletteFadeControl(); + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + SetMainCallback2(CB2_QuitRecordedBattle); + } +} + +static void FreeRestoreBattleData(void) +{ + gMain.callback1 = gPreBattleCallback1; + gUnknown_02039B28[0x15] = 3; + gMain.inBattle = 0; + ZeroEnemyPartyMons(); + m4aSongNumStop(0x5A); + FreeMonSpritesGfx(); + FreeBattleSpritesData(); + FreeBattleResources(); +} + +void CB2_QuitRecordedBattle(void) +{ + UpdatePaletteFade(); + if (!gPaletteFade.active) + { + m4aMPlayStop(&gMPlay_SE1); + m4aMPlayStop(&gMPlay_SE2); + FreeRestoreBattleData(); + FreeAllWindowBuffers(); + SetMainCallback2(gMain.savedCallback); + } +} + +void sub_8038528(struct Sprite* sprite) +{ + sprite->data0 = 0; + sprite->callback = sub_8038538; +} + +static void sub_8038538(struct Sprite *sprite) +{ + u16 *arr = (u16*)(gDecompressionBuffer); + + switch (sprite->data0) + { + case 0: + sprite->data0++; + sprite->data1 = 0; + sprite->data2 = 0x281; + sprite->data3 = 0; + sprite->data4 = 1; + // fall through + case 1: + sprite->data4--; + if (sprite->data4 == 0) + { + s32 i; + s32 r2; + s32 r0; + + sprite->data4 = 2; + r2 = sprite->data1 + sprite->data3 * 32; + r0 = sprite->data2 - sprite->data3 * 32; + for (i = 0; i < 29; i += 2) + { + arr[r2 + i] = 0x3D; + arr[r0 + i] = 0x3D; + } + sprite->data3++; + if (sprite->data3 == 21) + { + sprite->data0++; + sprite->data1 = 32; + } + } + break; + case 2: + sprite->data1--; + if (sprite->data1 == 20) + SetMainCallback2(CB2_InitBattle); + break; + } +} + +static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer) +{ + u32 nameHash = 0; + u32 personalityValue; + u8 fixedIV; + s32 i, j; + u8 monsCount; + + if (trainerNum == SECRET_BASE_OPPONENT) + return 0; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_x4000000))) + { + if (firstTrainer == TRUE) + ZeroEnemyPartyMons(); + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (gTrainers[trainerNum].partySize > 3) + monsCount = 3; + else + monsCount = gTrainers[trainerNum].partySize; + } + else + { + monsCount = gTrainers[trainerNum].partySize; + } + + for (i = 0; i < monsCount; i++) + { + + if (gTrainers[trainerNum].doubleBattle == TRUE) + personalityValue = 0x80; + else if (gTrainers[trainerNum].encounterMusic_gender & 0x80) + personalityValue = 0x78; + else + personalityValue = 0x88; + + for (j = 0; gTrainers[trainerNum].trainerName[j] != 0xFF; j++) + nameHash += gTrainers[trainerNum].trainerName[j]; + + switch (gTrainers[trainerNum].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + nameHash += gSpeciesNames[partyData[i].species][j]; + + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); + break; + } + case PARTY_FLAG_CUSTOM_MOVES: + { + const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + nameHash += gSpeciesNames[partyData[i].species][j]; + + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, 2, 0); + + for (j = 0; j < 4; j++) + { + SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); + SetMonData(&party[i], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp); + } + break; + } + case PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + nameHash += gSpeciesNames[partyData[i].species][j]; + + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, 2, 0); + + SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); + break; + } + case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves; + + for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + nameHash += gSpeciesNames[partyData[i].species][j]; + + personalityValue += nameHash << 8; + fixedIV = partyData[i].iv * 31 / 255; + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, 2, 0); + + SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); + + for (j = 0; j < 4; j++) + { + SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); + SetMonData(&party[i], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp); + } + break; + } + } + } + + gBattleTypeFlags |= gTrainers[trainerNum].doubleBattle; + } + + return gTrainers[trainerNum].partySize; +} + +void sub_8038A04(void) // unused +{ + if (REG_VCOUNT < 0xA0 && REG_VCOUNT >= 0x6F) + SetGpuReg(REG_OFFSET_BG0CNT, 0x9800); +} + +void VBlankCB_Battle(void) +{ + // change gRngSeed every vblank unless the battle could be recorded + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_RECORDED))) + Random(); + + SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X); + SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y); + SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X); + SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y); + SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X); + SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y); + SetGpuReg(REG_OFFSET_BG3HOFS, gBattle_BG3_X); + SetGpuReg(REG_OFFSET_BG3VOFS, gBattle_BG3_Y); + SetGpuReg(REG_OFFSET_WIN0H, gBattle_WIN0H); + SetGpuReg(REG_OFFSET_WIN0V, gBattle_WIN0V); + SetGpuReg(REG_OFFSET_WIN1H, gBattle_WIN1H); + SetGpuReg(REG_OFFSET_WIN1V, gBattle_WIN1V); + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); + sub_80BA0A8(); +} + +void nullsub_17(void) +{ + +} + +static void sub_8038B04(struct Sprite *sprite) +{ + if (sprite->data0 != 0) + sprite->pos1.x = sprite->data1 + ((sprite->data2 & 0xFF00) >> 8); + else + sprite->pos1.x = sprite->data1 - ((sprite->data2 & 0xFF00) >> 8); + + sprite->data2 += 0x180; + + if (sprite->affineAnimEnded) + { + FreeSpriteTilesByTag(0x2710); + FreeSpritePaletteByTag(0x2710); + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); + } +} + +void sub_8038B74(struct Sprite *sprite) +{ + StartSpriteAffineAnim(sprite, 1); + sprite->callback = sub_8038B04; + PlaySE(SE_BT_START); +} + +static void sub_8038B94(u8 taskId) +{ + struct Pokemon *sp4 = NULL; + struct Pokemon *sp8 = NULL; + u8 r2 = gBattleScripting.multiplayerId; + u32 r7; + s32 i; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + switch (gLinkPlayers[r2].lp_field_18) + { + case 0: + case 2: + sp4 = gPlayerParty; + sp8 = gEnemyParty; + break; + case 1: + case 3: + sp4 = gEnemyParty; + sp8 = gPlayerParty; + break; + } + } + else + { + sp4 = gPlayerParty; + sp8 = gEnemyParty; + } + + r7 = 0; + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&sp4[i], MON_DATA_SPECIES2); + u16 hp = GetMonData(&sp4[i], MON_DATA_HP); + u32 status = GetMonData(&sp4[i], MON_DATA_STATUS); + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp != 0 && status == 0) + r7 |= 1 << i * 2; + + if (species == 0) + continue; + if (hp != 0 && (species == SPECIES_EGG || status != 0)) + r7 |= 2 << i * 2; + + if (species == 0) + continue; + if (species != SPECIES_EGG && hp == 0) + r7 |= 3 << i * 2; + } + gTasks[taskId].data[3] = r7; + + r7 = 0; + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&sp8[i], MON_DATA_SPECIES2); + u16 hp = GetMonData(&sp8[i], MON_DATA_HP); + u32 status = GetMonData(&sp8[i], MON_DATA_STATUS); + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp != 0 && status == 0) + r7 |= 1 << i * 2; + + if (species == SPECIES_NONE) + continue; + if (hp != 0 && (species == SPECIES_EGG || status != 0)) + r7 |= 2 << i * 2; + + if (species == SPECIES_NONE) + continue; + if (species != SPECIES_EGG && hp == 0) + r7 |= 3 << i * 2; + } + gTasks[taskId].data[4] = r7; +} + +void sub_8038D64(void) +{ + s32 i; + u8 taskId; + + SetHBlankCallback(NULL); + SetVBlankCallback(NULL); + gBattleTypeFlags &= ~(BATTLE_TYPE_20); + + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + SetMainCallback2(gMain.savedCallback); + FreeBattleResources(); + FreeBattleSpritesData(); + FreeMonSpritesGfx(); + } + else + { + CpuFill32(0, (void*)(VRAM), VRAM_SIZE); + SetGpuReg(REG_OFFSET_MOSAIC, 0); + SetGpuReg(REG_OFFSET_WIN0H, 0xF0); + SetGpuReg(REG_OFFSET_WIN0V, 0x5051); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + gBattle_WIN0H = 0xF0; + gBattle_WIN0V = 0x5051; + dp12_8087EA4(); + + for (i = 0; i < 80; i++) + { + gUnknown_02038C28.unk0[i] = 0xF0; + gUnknown_02038C28.unk780[i] = 0xF0; + } + for (i = 80; i < 160; i++) + { + asm(""::"r"(i)); // Needed to stop the compiler from optimizing out the loop counter + gUnknown_02038C28.unk0[i] = 0xFF10; + gUnknown_02038C28.unk780[i] = 0xFF10; + } + + ResetPaletteFade(); + + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + gBattle_BG3_X = 0; + gBattle_BG3_Y = 0; + + sub_80356D0(); + LoadCompressedPalette(gUnknown_08C004E0, 0, 64); + ApplyPlayerChosenFrameToBattleMenu(); + ResetSpriteData(); + ResetTasks(); + LoadBattleEntryBackground(); + SetGpuReg(REG_OFFSET_WINOUT, 0x37); + FreeAllSpritePalettes(); + gReservedSpritePaletteCount = 4; + SetVBlankCallback(VBlankCB_Battle); + + taskId = CreateTask(task00_0800F6FC, 0); + gTasks[taskId].data[1] = 0x10E; + gTasks[taskId].data[2] = 0x5A; + gTasks[taskId].data[5] = 1; + sub_8038B94(taskId); + SetMainCallback2(sub_8038F14); + gBattleCommunication[MULTIUSE_STATE] = 0; + } +} + +static void sub_8038F14(void) +{ + sub_8038F34(); + AnimateSprites(); + BuildOamBuffer(); + RunTextPrinters(); + UpdatePaletteFade(); + RunTasks(); +} + +static void sub_8038F34(void) +{ + s32 i; + + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + ShowBg(0); + ShowBg(1); + ShowBg(2); + gBattleCommunication[1] = 0xFF; + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 1: + if (--gBattleCommunication[1] == 0) + { + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 2: + if (!gPaletteFade.active) + { + u8 monsCount; + + gMain.field_439_x4 = sub_8185FAC(); + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + monsCount = 4; + else + monsCount = 2; + + for (i = 0; i < monsCount && (gLinkPlayers[i].version & 0xFF) == VERSION_EMERALD; i++); + + if (!gSaveBlock2Ptr->field_CA9_b && i == monsCount) + { + if (FlagGet(SYS_FRONTIER_PASS)) + { + FreeAllWindowBuffers(); + SetMainCallback2(sub_80392A8); + } + else if (!gMain.field_439_x4) + { + SetMainCallback2(gMain.savedCallback); + FreeBattleResources(); + FreeBattleSpritesData(); + FreeMonSpritesGfx(); + } + else if (gReceivedRemoteLinkPlayers == 0) + { + CreateTask(sub_80B3AF8, 5); + gBattleCommunication[MULTIUSE_STATE]++; + } + else + { + gBattleCommunication[MULTIUSE_STATE]++; + } + } + else + { + SetMainCallback2(gMain.savedCallback); + FreeBattleResources(); + FreeBattleSpritesData(); + FreeMonSpritesGfx(); + } + } + break; + case 3: + CpuFill32(0, (void*)(VRAM), VRAM_SIZE); + + for (i = 0; i < 2; i++) + LoadChosenBattleElement(i); + + BeginNormalPaletteFade(-1, 0, 0x10, 0, 0); + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 4: + if (!gPaletteFade.active) + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 5: + if (!FuncIsActiveTask(sub_80B3AF8)) + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 6: + if (sub_800A520() == TRUE) + { + sub_800ADF8(); + sub_814F9EC(gText_LinkStandby3, 0); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 7: + if (!IsTextPrinterActive(0)) + { + if (sub_800A520() == TRUE) + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 8: + if (!gLinkVSyncDisabled) + sub_800AC34(); + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 9: + if (!gMain.field_439_x4 || gLinkVSyncDisabled || gReceivedRemoteLinkPlayers != 1) + { + gMain.field_439_x4 = 0; + SetMainCallback2(gMain.savedCallback); + FreeBattleResources(); + FreeBattleSpritesData(); + FreeMonSpritesGfx(); + } + break; + } +} + +u32 sub_80391E0(u8 arrayId, u8 caseId) +{ + u32 ret = 0; + + switch (caseId) + { + case 0: + ret = gUnknown_0831AA08[arrayId].bg; + break; + case 1: + ret = gUnknown_0831AA08[arrayId].charBaseIndex; + break; + case 2: + ret = gUnknown_0831AA08[arrayId].mapBaseIndex; + break; + case 3: + ret = gUnknown_0831AA08[arrayId].screenSize; + break; + case 4: + ret = gUnknown_0831AA08[arrayId].paletteMode; + break; + case 5: + ret = gUnknown_0831AA08[arrayId].priority; + break; + case 6: + ret = gUnknown_0831AA08[arrayId].baseTile; + break; + } + + return ret; +} + +static void sub_80392A8(void) +{ + s32 i; + + SetHBlankCallback(NULL); + SetVBlankCallback(NULL); + CpuFill32(0, (void*)(VRAM), VRAM_SIZE); + ResetPaletteFade(); + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + gBattle_BG3_X = 0; + gBattle_BG3_Y = 0; + sub_80356D0(); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + ApplyPlayerChosenFrameToBattleMenu(); + + for (i = 0; i < 2; i++) + LoadChosenBattleElement(i); + + ResetSpriteData(); + ResetTasks(); + FreeAllSpritePalettes(); + gReservedSpritePaletteCount = 4; + SetVBlankCallback(VBlankCB_Battle); + SetMainCallback2(sub_803937C); + BeginNormalPaletteFade(-1, 0, 0x10, 0, 0); + gBattleCommunication[MULTIUSE_STATE] = 0; +} + +static void sub_803937C(void) +{ + sub_803939C(); + AnimateSprites(); + BuildOamBuffer(); + RunTextPrinters(); + UpdatePaletteFade(); + RunTasks(); +} + +static void sub_803939C(void) +{ + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + ShowBg(0); + ShowBg(1); + ShowBg(2); + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 1: + if (gMain.field_439_x4 && gReceivedRemoteLinkPlayers == 0) + CreateTask(sub_80B3AF8, 5); + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 2: + if (!FuncIsActiveTask(sub_80B3AF8)) + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 3: + if (!gPaletteFade.active) + { + sub_814F9EC(gText_RecordBattleToPass, 0); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 4: + if (!IsTextPrinterActive(0)) + { + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 5: + if (gMain.newKeys & DPAD_UP) + { + if (gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + } + else if (gMain.newKeys & DPAD_DOWN) + { + if (gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + } + else if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[CURSOR_POSITION] == 0) + { + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattleCommunication[1] = MoveRecordedBattleToSaveData(); + gBattleCommunication[MULTIUSE_STATE] = 10; + } + else + { + gBattleCommunication[MULTIUSE_STATE]++; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 6: + if (sub_800A520() == TRUE) + { + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + if (gMain.field_439_x4) + { + sub_800ADF8(); + sub_814F9EC(gText_LinkStandby3, 0); + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 8: + if (--gBattleCommunication[1] == 0) + { + if (gMain.field_439_x4 && !gLinkVSyncDisabled) + sub_800AC34(); + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 9: + if (!gMain.field_439_x4 || gLinkVSyncDisabled || gReceivedRemoteLinkPlayers != 1) + { + gMain.field_439_x4 = 0; + if (!gPaletteFade.active) + { + SetMainCallback2(gMain.savedCallback); + FreeBattleResources(); + FreeBattleSpritesData(); + FreeMonSpritesGfx(); + } + } + break; + case 10: + if (gBattleCommunication[1] == 1) + { + PlaySE(SE_SAVE); + BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordedOnPass); + sub_814F9EC(gDisplayedStringBattle, 0); + gBattleCommunication[1] = 0x80; + gBattleCommunication[MULTIUSE_STATE]++; + } + else + { + BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordCouldntBeSaved); + sub_814F9EC(gDisplayedStringBattle, 0); + gBattleCommunication[1] = 0x80; + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 11: + if (sub_800A520() == TRUE && !IsTextPrinterActive(0) && --gBattleCommunication[1] == 0) + { + if (gMain.field_439_x4) + { + sub_800ADF8(); + sub_814F9EC(gText_LinkStandby3, 0); + } + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 12: + case 7: + if (!IsTextPrinterActive(0)) + { + if (gMain.field_439_x4) + { + if (sub_800A520() == TRUE) + { + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleCommunication[1] = 0x20; + gBattleCommunication[MULTIUSE_STATE] = 8; + } + + } + else + { + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleCommunication[1] = 0x20; + gBattleCommunication[MULTIUSE_STATE] = 8; + } + } + break; + } +} + +static void TryCorrectShedinjaLanguage(struct Pokemon *mon) +{ + u8 nickname[POKEMON_NAME_LENGTH + 1]; + u8 language = LANGUAGE_JAPANESE; + + if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_SHEDINJA + && GetMonData(mon, MON_DATA_LANGUAGE) != language) + { + GetMonData(mon, MON_DATA_NICKNAME, nickname); + if (StringCompareWithoutExtCtrlCodes(nickname, gText_ShedinjaJapaneseName) == 0) + SetMonData(mon, MON_DATA_LANGUAGE, &language); + } +} + +u32 sub_80397C4(u32 setId, u32 tableId) +{ + return gUnknown_0831ABA0[setId][tableId].width * 8; +} + +#define tBank data0 +#define tSpeciesId data2 + +void oac_poke_opponent(struct Sprite *sprite) +{ + sprite->callback = sub_803980C; + StartSpriteAnimIfDifferent(sprite, 0); + BeginNormalPaletteFade(0x20000, 0, 10, 10, 0x2108); +} + +static void sub_803980C(struct Sprite *sprite) +{ + if ((gUnknown_020243FC & 1) == 0) + { + sprite->pos2.x += 2; + if (sprite->pos2.x == 0) + { + sprite->callback = sub_8039838; + } + } +} + +static void sub_8039838(struct Sprite *sprite) +{ + if (sprite->animEnded) + { + sub_8076918(sprite->tBank); + SetHealthboxSpriteVisible(gHealthBoxesIds[sprite->tBank]); + sprite->callback = sub_8039894; + StartSpriteAnimIfDifferent(sprite, 0); + BeginNormalPaletteFade(0x20000, 0, 10, 0, 0x2108); + } +} + +static void sub_8039894(struct Sprite *sprite) +{ + if (!gPaletteFade.active) + { + BattleAnimateFrontSprite(sprite, sprite->tSpeciesId, FALSE, 1); + } +} + +void SpriteCallbackDummy_2(struct Sprite *sprite) +{ + +} + +static void sub_80398BC(struct Sprite *sprite) // unused? +{ + sprite->data3 = 6; + sprite->data4 = 1; + sprite->callback = sub_80398D0; +} + +static void sub_80398D0(struct Sprite *sprite) +{ + sprite->data4--; + if (sprite->data4 == 0) + { + sprite->data4 = 8; + sprite->invisible ^= 1; + sprite->data3--; + if (sprite->data3 == 0) + { + sprite->invisible = FALSE; + sprite->callback = SpriteCallbackDummy_2; + gUnknown_02022F88 = 0; + } + } +} + +// to get rid of once the struct is declared in a header +struct MonCoords +{ + // This would use a bitfield, but sub_8079F44 + // uses it as a u8 and casting won't match. + u8 coords; // u8 x:4, y:4; + u8 y_offset; +}; + +extern const struct MonCoords gMonFrontPicCoords[]; +extern const struct MonCoords gCastformFrontSpriteCoords[]; + +void sub_8039934(struct Sprite *sprite) +{ + u8 bank = sprite->tBank; + u16 species; + u8 yOffset; + + if (gBattleSpritesDataPtr->bankData[bank].transformSpecies != 0) + species = gBattleSpritesDataPtr->bankData[bank].transformSpecies; + else + species = sprite->tSpeciesId; + + GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_PERSONALITY); // Unused return value + + if (species == SPECIES_UNOWN) + { + u32 personalityValue = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_PERSONALITY); + u16 unownForm = ((((personalityValue & 0x3000000) >> 18) | ((personalityValue & 0x30000) >> 12) | ((personalityValue & 0x300) >> 6) | (personalityValue & 3)) % 0x1C); + u16 unownSpecies; + + if (unownForm == 0) + unownSpecies = SPECIES_UNOWN; // Use the A Unown form + else + unownSpecies = NUM_SPECIES + unownForm; // Use one of the other Unown letters + + yOffset = gMonFrontPicCoords[unownSpecies].y_offset; + } + else if (species == SPECIES_CASTFORM) + { + yOffset = gCastformFrontSpriteCoords[gBattleMonForms[bank]].y_offset; + } + else if (species > NUM_SPECIES) + { + yOffset = gMonFrontPicCoords[SPECIES_NONE].y_offset; + } + else + { + yOffset = gMonFrontPicCoords[species].y_offset; + } + + sprite->data3 = 8 - yOffset / 8; + sprite->data4 = 1; + sprite->callback = sub_8039A48; +} + +static void sub_8039A48(struct Sprite *sprite) +{ + s32 i; + + sprite->data4--; + if (sprite->data4 == 0) + { + sprite->data4 = 2; + sprite->pos2.y += 8; + sprite->data3--; + if (sprite->data3 < 0) + { + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); + } + else + { + u8 *dst = (u8 *)gMonSpritesGfxPtr->sprites[GetBankIdentity(sprite->tBank)] + (gBattleMonForms[sprite->tBank] << 11) + (sprite->data3 << 8); + + for (i = 0; i < 0x100; i++) + *(dst++) = 0; + + StartSpriteAnim(sprite, gBattleMonForms[sprite->tBank]); + } + } +} + +void sub_8039AD8(struct Sprite *sprite) +{ + sprite->data3 = 8; + sprite->data4 = sprite->invisible; + sprite->callback = sub_8039AF4; +} + +static void sub_8039AF4(struct Sprite *sprite) +{ + sprite->data3--; + if (sprite->data3 == 0) + { + sprite->invisible ^= 1; + sprite->data3 = 8; + } +} + +void sub_8039B2C(struct Sprite *sprite) +{ + sprite->invisible = sprite->data4; + sprite->data4 = FALSE; + sprite->callback = SpriteCallbackDummy_2; +} + +void sub_8039B58(struct Sprite *sprite) +{ + if (sprite->affineAnimEnded) + { + if (!(gHitMarker & HITMARKER_NO_ANIMATIONS) || gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + if (HasTwoFramesAnimation(sprite->tSpeciesId)) + StartSpriteAnim(sprite, 1); + } + BattleAnimateFrontSprite(sprite, sprite->tSpeciesId, TRUE, 1); + } +} + +void sub_8039BB4(struct Sprite *sprite) +{ + sprite->callback = oac_poke_ally_; +} + +static void oac_poke_ally_(struct Sprite *sprite) +{ + if ((gUnknown_020243FC & 1) == 0) + { + sprite->pos2.x -= 2; + if (sprite->pos2.x == 0) + { + sprite->callback = SpriteCallbackDummy_3; + sprite->data1 = 0; + } + } +} + +void sub_80105DC(struct Sprite *sprite) +{ + sprite->callback = SpriteCallbackDummy_3; +} + +static void SpriteCallbackDummy_3(struct Sprite *sprite) +{ +} + +void sub_8039C00(struct Sprite *sprite) +{ + if (!(gUnknown_020243FC & 1)) + { + sprite->pos2.x += sprite->data1; + sprite->pos2.y += sprite->data2; + } +} + +void dp11b_obj_instanciate(u8 bank, u8 b, s8 c, s8 d) +{ + u8 bounceHealthBoxSpriteId; + u8 spriteId2; + + if (b) + { + if (gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2) + return; + } + else + { + if (gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4) + return; + } + + bounceHealthBoxSpriteId = CreateInvisibleSpriteWithCallback(SpriteCB_HealthBoxBounce); + if (b == TRUE) + { + spriteId2 = gHealthBoxesIds[bank]; + gBattleSpritesDataPtr->healthBoxesData[bank].field_2 = bounceHealthBoxSpriteId; + gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2 = 1; + gSprites[bounceHealthBoxSpriteId].data0 = 0x80; + } + else + { + spriteId2 = gBankSpriteIds[bank]; + gBattleSpritesDataPtr->healthBoxesData[bank].field_3 = bounceHealthBoxSpriteId; + gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4 = 1; + gSprites[bounceHealthBoxSpriteId].data0 = 0xC0; + } + gSprites[bounceHealthBoxSpriteId].data1 = c; + gSprites[bounceHealthBoxSpriteId].data2 = d; + gSprites[bounceHealthBoxSpriteId].data3 = spriteId2; + gSprites[bounceHealthBoxSpriteId].data4 = b; + gSprites[spriteId2].pos2.x = 0; + gSprites[spriteId2].pos2.y = 0; +} + +void dp11b_obj_free(u8 bank, bool8 b) +{ + u8 r4; + + if (b == TRUE) + { + if (!gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2) + return; + + r4 = gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_2].data3; + DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_2]); + gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2 = 0; + } + else + { + if (!gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4) + return; + + r4 = gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_3].data3; + DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_3]); + gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4 = 0; + } + gSprites[r4].pos2.x = 0; + gSprites[r4].pos2.y = 0; +} + +static void SpriteCB_HealthBoxBounce(struct Sprite *sprite) +{ + u8 spriteId = sprite->data3; + s32 var; + + if (sprite->data4 == 1) + var = sprite->data0; + else + var = sprite->data0; + + gSprites[spriteId].pos2.y = Sin(var, sprite->data2) + sprite->data2; + sprite->data0 = (sprite->data0 + sprite->data1) & 0xFF; +} + +void sub_8039E44(struct Sprite *sprite) +{ + if (sprite->affineAnimEnded) + BattleAnimateBackSprite(sprite, sprite->tSpeciesId); +} + +void sub_8039E60(struct Sprite *sprite) +{ + sub_8039E9C(sprite); + if (sprite->animEnded) + sprite->callback = SpriteCallbackDummy_3; +} + +void sub_8039E84(struct Sprite *sprite) +{ + StartSpriteAnim(sprite, 1); + sprite->callback = sub_8039E60; +} + +void sub_8039E9C(struct Sprite *sprite) +{ + if (sprite->animDelayCounter == 0) + sprite->centerToCornerVecX = gUnknown_0831ACE0[sprite->animCmdIndex]; +} + +void nullsub_20(void) +{ + +} + +void BeginBattleIntro(void) +{ + BattleStartClearSetData(); + gBattleCommunication[1] = 0; + gBattleMainFunc = BattleIntroGetMonsData; +} + +static void BattleMainCB1(void) +{ + gBattleMainFunc(); + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + gBattleBankFunc[gActiveBank](); +} + +static void BattleStartClearSetData(void) +{ + s32 i; + u32 j; + u8 *dataPtr; + + TurnValuesCleanUp(FALSE); + SpecialStatusesClear(); + + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + gStatuses3[i] = 0; + + dataPtr = (u8 *)&gDisableStructs[i]; + for (j = 0; j < sizeof(struct DisableStruct); j++) + dataPtr[j] = 0; + + gDisableStructs[i].isFirstTurn= 2; + gUnknown_02024284[i] = 0; + gLastUsedMovesByBanks[i] = 0; + gUnknown_02024250[i] = 0; + gUnknown_02024258[i] = 0; + gUnknown_02024260[i] = 0; + gUnknown_02024270[i] = 0xFF; + gLockedMoves[i] = 0; + gUnknownMovesUsedByBanks[i] = 0; + gBattleResources->flags->flags[i] = 0; + gUnknown_02024230[i] = 0; + } + + for (i = 0; i < 2; i++) + { + gSideAffecting[i] = 0; + + dataPtr = (u8 *)&gSideTimers[i]; + for (j = 0; j < sizeof(struct SideTimer); j++) + dataPtr[j] = 0; + } + + gBankAttacker = 0; + gBankTarget = 0; + gBattleWeather = 0; + + dataPtr = (u8 *)&gWishFutureKnock; + for (i = 0; i < sizeof(struct WishFutureKnock); i++) + dataPtr[i] = 0; + + gHitMarker = 0; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) && gSaveBlock2Ptr->optionsBattleSceneOff == TRUE) + gHitMarker |= HITMARKER_NO_ANIMATIONS; + } + else if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && sub_8185FB8()) + gHitMarker |= HITMARKER_NO_ANIMATIONS; + + gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; + + gMultiHitCounter = 0; + gBattleOutcome = 0; + gBattleExecBuffer = 0; + gPaydayMoney = 0; + gBattleResources->battleScriptsStack->size = 0; + gBattleResources->battleCallbackStack->size = 0; + + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++) + gBattleCommunication[i] = 0; + + gPauseCounterBattle = 0; + gBattleMoveDamage = 0; + gUnknown_020243FC = 0; + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gLeveledUpInBattle = 0; + gAbsentBankFlags = 0; + gBattleStruct->runTries = 0; + gBattleStruct->field_79 = 0; + gBattleStruct->field_7A = 0; + *(&gBattleStruct->field_7C) = gBaseStats[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].catchRate * 100 / 1275; + gBattleStruct->field_7B = 3; + gBattleStruct->wildVictorySong = 0; + gBattleStruct->moneyMultiplier = 1; + + for (i = 0; i < 8; i++) + { + *((u8 *)gBattleStruct->mirrorMoves + i) = 0; + *((u8 *)gBattleStruct->usedHeldItems + i) = 0; + *((u8 *)gBattleStruct->choicedMove + i) = 0; + *((u8 *)gBattleStruct->changedItems + i) = 0; + *(i + 0 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(i + 1 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(i + 2 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(i + 3 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + } + + for (i = 0; i < 4; i++) + { + *(gBattleStruct->field_294 + i) = 6; + } + + gBattleStruct->field_DF = 0; + gBattleStruct->field_92 = 0; + + gRandomTurnNumber = Random(); + + dataPtr = (u8 *)(&gBattleResults); + for (i = 0; i < sizeof(struct BattleResults); i++) + dataPtr[i] = 0; + + gBattleResults.unk5_6 = IsMonShiny(&gEnemyParty[0]); + + gBattleStruct->field_2A0 = 0; + gBattleStruct->field_2A1 = 0; +} + +void SwitchInClearSetData(void) +{ + struct DisableStruct disableStructCopy = gDisableStructs[gActiveBank]; + s32 i; + u8 *ptr; + + if (gBattleMoves[gCurrentMove].effect != EFFECT_BATON_PASS) + { + for (i = 0; i < BATTLE_STATS_NO; i++) + gBattleMons[gActiveBank].statStages[i] = 6; + for (i = 0; i < gNoOfAllBanks; i++) + { + if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].bankPreventingEscape == gActiveBank) + gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; + if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].bankWithSureHit == gActiveBank) + { + gStatuses3[i] &= ~STATUS3_ALWAYS_HITS; + gDisableStructs[i].bankWithSureHit = 0; + } + } + } + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + gBattleMons[gActiveBank].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED); + gStatuses3[gActiveBank] &= (STATUS3_LEECHSEED_BANK | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED | STATUS3_MUDSPORT | STATUS3_WATERSPORT); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (GetBankSide(gActiveBank) != GetBankSide(i) + && (gStatuses3[i] & STATUS3_ALWAYS_HITS) != 0 + && (gDisableStructs[i].bankWithSureHit == gActiveBank)) + { + gStatuses3[i] &= ~STATUS3_ALWAYS_HITS; + gStatuses3[i] |= 0x10; + } + } + } + else + { + gBattleMons[gActiveBank].status2 = 0; + gStatuses3[gActiveBank] = 0; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBank)) + gBattleMons[i].status2 &= ~(STATUS2_INFATUATED_WITH(gActiveBank)); + if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBank) + gBattleMons[i].status2 &= ~(STATUS2_WRAPPED); + } + + gActionSelectionCursor[gActiveBank] = 0; + gMoveSelectionCursor[gActiveBank] = 0; + + ptr = (u8 *)&gDisableStructs[gActiveBank]; + for (i = 0; i < sizeof(struct DisableStruct); i++) + ptr[i] = 0; + + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + gDisableStructs[gActiveBank].substituteHP = disableStructCopy.substituteHP; + gDisableStructs[gActiveBank].bankWithSureHit = disableStructCopy.bankWithSureHit; + gDisableStructs[gActiveBank].perishSong1 = disableStructCopy.perishSong1; + gDisableStructs[gActiveBank].perishSong2 = disableStructCopy.perishSong2; + gDisableStructs[gActiveBank].bankPreventingEscape = disableStructCopy.bankPreventingEscape; + } + + gBattleMoveFlags = 0; + gDisableStructs[gActiveBank].isFirstTurn= 2; + gDisableStructs[gActiveBank].truantUnknownBit = disableStructCopy.truantUnknownBit; + gLastUsedMovesByBanks[gActiveBank] = 0; + gUnknown_02024250[gActiveBank] = 0; + gUnknown_02024258[gActiveBank] = 0; + gUnknown_02024260[gActiveBank] = 0; + gUnknownMovesUsedByBanks[gActiveBank] = 0; + gUnknown_02024270[gActiveBank] = 0xFF; + + *(gBattleStruct->mirrorMoves + gActiveBank * 2 + 0) = 0; + *(gBattleStruct->mirrorMoves + gActiveBank * 2 + 1) = 0; + *(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + *(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + *(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + *(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + + gBattleStruct->field_92 &= ~(gBitTable[gActiveBank]); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (i != gActiveBank && GetBankSide(i) != GetBankSide(gActiveBank)) + { + *(gBattleStruct->mirrorMoves + i * 2 + 0) = 0; + *(gBattleStruct->mirrorMoves + i * 2 + 1) = 0; + } + *(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + } + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 1) = 0; + + gBattleResources->flags->flags[gActiveBank] = 0; + gCurrentMove = 0; + gBattleStruct->field_DA = 0xFF; + + ClearBankMoveHistory(gActiveBank); + ClearBankAbilityHistory(gActiveBank); +} + +void FaintClearSetData(void) +{ + s32 i; + u8 *ptr; + + for (i = 0; i < BATTLE_STATS_NO; i++) + gBattleMons[gActiveBank].statStages[i] = 6; + + gBattleMons[gActiveBank].status2 = 0; + gStatuses3[gActiveBank] = 0; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].bankPreventingEscape == gActiveBank) + gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; + if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBank)) + gBattleMons[i].status2 &= ~(STATUS2_INFATUATED_WITH(gActiveBank)); + if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBank) + gBattleMons[i].status2 &= ~(STATUS2_WRAPPED); + } + + gActionSelectionCursor[gActiveBank] = 0; + gMoveSelectionCursor[gActiveBank] = 0; + + ptr = (u8 *)&gDisableStructs[gActiveBank]; + for (i = 0; i < sizeof(struct DisableStruct); i++) + ptr[i] = 0; + + gProtectStructs[gActiveBank].protected = 0; + gProtectStructs[gActiveBank].endured = 0; + gProtectStructs[gActiveBank].onlyStruggle = 0; + gProtectStructs[gActiveBank].helpingHand = 0; + gProtectStructs[gActiveBank].bounceMove = 0; + gProtectStructs[gActiveBank].stealMove = 0; + gProtectStructs[gActiveBank].flag0Unknown = 0; + gProtectStructs[gActiveBank].prlzImmobility = 0; + gProtectStructs[gActiveBank].confusionSelfDmg = 0; + gProtectStructs[gActiveBank].targetNotAffected = 0; + gProtectStructs[gActiveBank].chargingTurn = 0; + gProtectStructs[gActiveBank].fleeFlag = 0; + gProtectStructs[gActiveBank].usedImprisionedMove = 0; + gProtectStructs[gActiveBank].loveImmobility = 0; + gProtectStructs[gActiveBank].usedDisabledMove = 0; + gProtectStructs[gActiveBank].usedTauntedMove = 0; + gProtectStructs[gActiveBank].flag2Unknown = 0; + gProtectStructs[gActiveBank].flinchImmobility = 0; + gProtectStructs[gActiveBank].notFirstStrike = 0; + + gDisableStructs[gActiveBank].isFirstTurn = 2; + + gLastUsedMovesByBanks[gActiveBank] = 0; + gUnknown_02024250[gActiveBank] = 0; + gUnknown_02024258[gActiveBank] = 0; + gUnknown_02024260[gActiveBank] = 0; + gUnknownMovesUsedByBanks[gActiveBank] = 0; + gUnknown_02024270[gActiveBank] = 0xFF; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 1) = 0; + + *(gBattleStruct->mirrorMoves + gActiveBank * 2 + 0) = 0; + *(gBattleStruct->mirrorMoves + gActiveBank * 2 + 1) = 0; + *(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + *(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + *(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + *(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + + gBattleStruct->field_92 &= ~(gBitTable[gActiveBank]); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (i != gActiveBank && GetBankSide(i) != GetBankSide(gActiveBank)) + { + *(gBattleStruct->mirrorMoves + i * 2 + 0) = 0; + *(gBattleStruct->mirrorMoves + i * 2 + 1) = 0; + } + *(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0; + *(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0; + } + + gBattleResources->flags->flags[gActiveBank] = 0; + + gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1; + gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2; + + ClearBankMoveHistory(gActiveBank); + ClearBankAbilityHistory(gActiveBank); +} + +static void BattleIntroGetMonsData(void) +{ + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + gActiveBank = gBattleCommunication[1]; + EmitGetMonData(0, 0, 0); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[MULTIUSE_STATE]++; + break; + case 1: + if (gBattleExecBuffer == 0) + { + gBattleCommunication[1]++; + if (gBattleCommunication[1] == gNoOfAllBanks) + gBattleMainFunc = BattleIntroPrepareBackgroundSlide; + else + gBattleCommunication[MULTIUSE_STATE] = 0; + } + break; + } +} + +static void BattleIntroPrepareBackgroundSlide(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBankByIdentity(0); + EmitIntroSlide(0, gBattleTerrain); + MarkBufferBankForExecution(gActiveBank); + gBattleMainFunc = BattleIntroDrawTrainersOrMonsSprites; + gBattleCommunication[0] = 0; + gBattleCommunication[1] = 0; + } +} + +static void BattleIntroDrawTrainersOrMonsSprites(void) +{ + u8 *ptr; + s32 i; + + if (gBattleExecBuffer) + return; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) + && GetBankSide(gActiveBank) == SIDE_PLAYER) + { + ptr = (u8 *)&gBattleMons[gActiveBank]; + for (i = 0; i < sizeof(struct BattlePokemon); i++) + ptr[i] = 0; + } + else + { + u16* hpOnSwitchout; + + ptr = (u8 *)&gBattleMons[gActiveBank]; + for (i = 0; i < sizeof(struct BattlePokemon); i++) + ptr[i] = gBattleBufferB[gActiveBank][4 + i]; + + gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1; + gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2; + gBattleMons[gActiveBank].ability = GetAbilityBySpecies(gBattleMons[gActiveBank].species, gBattleMons[gActiveBank].altAbility); + hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(gActiveBank)]; + *hpOnSwitchout = gBattleMons[gActiveBank].hp; + for (i = 0; i < BATTLE_STATS_NO; i++) + gBattleMons[gActiveBank].statStages[i] = 6; + gBattleMons[gActiveBank].status2 = 0; + } + + if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON1) + { + EmitDrawTrainerPic(0); + MarkBufferBankForExecution(gActiveBank); + } + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON1) + { + EmitDrawTrainerPic(0); + MarkBufferBankForExecution(gActiveBank); + } + if (GetBankSide(gActiveBank) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000))) + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); + } + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000))) + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); + } + EmitLoadMonSprite(0); + MarkBufferBankForExecution(gActiveBank); + gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); + } + } + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON2 + || GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON2) + { + EmitDrawTrainerPic(0); + MarkBufferBankForExecution(gActiveBank); + } + } + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON2) + { + EmitDrawTrainerPic(0); + MarkBufferBankForExecution(gActiveBank); + } + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A56B4(); + } + gBattleMainFunc = BattleIntroDrawPartySummaryScreens; +} + +static void BattleIntroDrawPartySummaryScreens(void) +{ + s32 i; + struct HpAndStatus hpStatus[6]; + + if (gBattleExecBuffer) + return; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + for (i = 0; i < 6; i++) + { + if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatus[i].hp = 0xFFFF; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS); + } + } + gActiveBank = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + EmitDrawPartyStatusSummary(0, hpStatus, 0x80); + MarkBufferBankForExecution(gActiveBank); + + for (i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatus[i].hp = 0xFFFF; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + } + } + gActiveBank = GetBankByIdentity(IDENTITY_PLAYER_MON1); + EmitDrawPartyStatusSummary(0, hpStatus, 0x80); + MarkBufferBankForExecution(gActiveBank); + + gBattleMainFunc = BattleIntroPrintTrainerWantsToBattle; + } + else + { + // The struct gets set here, but nothing is ever done with it since + // wild battles don't show the party summary. + // Still, there's no point in having dead code. + + for (i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatus[i].hp = 0xFFFF; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + } + } + + gBattleMainFunc = BattleIntroPrintWildMonAttacked; + } + +} + +static void BattleIntroPrintTrainerWantsToBattle(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + PrepareStringBattle(STRINGID_INTROMSG, gActiveBank); + gBattleMainFunc = BattleIntroPrintOpponentSendsOut; + } +} + +static void BattleIntroPrintWildMonAttacked(void) +{ + if (gBattleExecBuffer == 0) + { + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; + PrepareStringBattle(STRINGID_INTROMSG, 0); + } +} + +static void BattleIntroPrintOpponentSendsOut(void) +{ + u32 identity; + + if (gBattleExecBuffer) + return; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + identity = IDENTITY_OPPONENT_MON1; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + identity = IDENTITY_OPPONENT_MON1; + else + identity = IDENTITY_PLAYER_MON1; + } + else + identity = IDENTITY_OPPONENT_MON1; + + PrepareStringBattle(STRINGID_INTROSENDOUT, GetBankByIdentity(identity)); + gBattleMainFunc = BattleIntroOpponent1SendsOutMonAnimation; +} + +static void BattleIntroOpponent2SendsOutMonAnimation(void) +{ + u32 identity; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + identity = IDENTITY_OPPONENT_MON2; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + identity = IDENTITY_OPPONENT_MON2; + else + identity = IDENTITY_PLAYER_MON2; + } + else + identity = IDENTITY_OPPONENT_MON2; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankIdentity(gActiveBank) == identity) + { + EmitIntroTrainerBallThrow(0); + MarkBufferBankForExecution(gActiveBank); + } + } + + gBattleMainFunc = BattleIntroRecordMonsToDex; +} + +#ifdef NONMATCHING +static void BattleIntroOpponent1SendsOutMonAnimation(void) +{ + u32 identity; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + identity = IDENTITY_OPPONENT_MON1; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + identity = IDENTITY_OPPONENT_MON1; + else + identity = IDENTITY_PLAYER_MON1; + } + else + identity = IDENTITY_OPPONENT_MON1; + + if (gBattleExecBuffer) + return; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankIdentity(gActiveBank) == identity) + { + EmitIntroTrainerBallThrow(0); + MarkBufferBankForExecution(gActiveBank); + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS)) + { + gBattleMainFunc = BattleIntroOpponent2SendsOutMonAnimation; + return; + } + } + } + + gBattleMainFunc = BattleIntroRecordMonsToDex; +} + +#else +__attribute__((naked)) +static void BattleIntroOpponent1SendsOutMonAnimation(void) +{ + asm(".syntax unified\n\ + push {r4-r6,lr}\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r2, [r0]\n\ + movs r0, 0x80\n\ + lsls r0, 17\n\ + ands r0, r2\n\ + cmp r0, 0\n\ + beq _0803B298\n\ + movs r0, 0x80\n\ + lsls r0, 18\n\ + ands r0, r2\n\ + cmp r0, 0\n\ + beq _0803B298\n\ + movs r1, 0x80\n\ + lsls r1, 24\n\ + ands r1, r2\n\ + negs r0, r1\n\ + orrs r0, r1\n\ + lsrs r5, r0, 31\n\ + b _0803B29A\n\ + .pool\n\ +_0803B288:\n\ + ldr r1, =gBattleMainFunc\n\ + ldr r0, =BattleIntroOpponent2SendsOutMonAnimation\n\ + b _0803B2F0\n\ + .pool\n\ +_0803B298:\n\ + movs r5, 0x1\n\ +_0803B29A:\n\ + ldr r0, =gBattleExecBuffer\n\ + ldr r2, [r0]\n\ + cmp r2, 0\n\ + bne _0803B2F2\n\ + ldr r0, =gActiveBank\n\ + strb r2, [r0]\n\ + ldr r1, =gNoOfAllBanks\n\ + adds r4, r0, 0\n\ + ldrb r1, [r1]\n\ + cmp r2, r1\n\ + bcs _0803B2EC\n\ + adds r6, r4, 0\n\ +_0803B2B2:\n\ + ldrb r0, [r4]\n\ + bl GetBankIdentity\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + cmp r0, r5\n\ + bne _0803B2D8\n\ + movs r0, 0\n\ + bl EmitIntroTrainerBallThrow\n\ + ldrb r0, [r4]\n\ + bl MarkBufferBankForExecution\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + ldr r1, =0x00008040\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + bne _0803B288\n\ +_0803B2D8:\n\ + ldrb r0, [r6]\n\ + adds r0, 0x1\n\ + strb r0, [r6]\n\ + ldr r1, =gNoOfAllBanks\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + ldr r4, =gActiveBank\n\ + ldrb r1, [r1]\n\ + cmp r0, r1\n\ + bcc _0803B2B2\n\ +_0803B2EC:\n\ + ldr r1, =gBattleMainFunc\n\ + ldr r0, =BattleIntroRecordMonsToDex\n\ +_0803B2F0:\n\ + str r0, [r1]\n\ +_0803B2F2:\n\ + pop {r4-r6}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +static void BattleIntroRecordMonsToDex(void) +{ + if (gBattleExecBuffer == 0) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000))) + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); + } + } + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; + } +} + +void sub_803B3AC(void) // unused +{ + if (gBattleExecBuffer == 0) + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; +} + +static void BattleIntroPrintPlayerSendsOut(void) +{ + if (gBattleExecBuffer == 0) + { + u8 identity; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + identity = IDENTITY_PLAYER_MON1; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + identity = IDENTITY_PLAYER_MON1; + else + identity = IDENTITY_OPPONENT_MON1; + } + else + identity = IDENTITY_PLAYER_MON1; + + if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) + PrepareStringBattle(STRINGID_INTROSENDOUT, GetBankByIdentity(identity)); + + gBattleMainFunc = BattleIntroPlayer1SendsOutMonAnimation; + } +} + +static void BattleIntroPlayer2SendsOutMonAnimation(void) +{ + u32 identity; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + identity = IDENTITY_PLAYER_MON2; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + identity = IDENTITY_PLAYER_MON2; + else + identity = IDENTITY_OPPONENT_MON2; + } + else + identity = IDENTITY_PLAYER_MON2; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankIdentity(gActiveBank) == identity) + { + EmitIntroTrainerBallThrow(0); + MarkBufferBankForExecution(gActiveBank); + } + } + + gBattleStruct->switchInAbilitiesCounter = 0; + gBattleStruct->switchInItemsCounter = 0; + gBattleStruct->overworldWeatherDone = FALSE; + + gBattleMainFunc = TryDoEventsBeforeFirstTurn; +} + +static void BattleIntroPlayer1SendsOutMonAnimation(void) +{ + u32 identity; + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + identity = IDENTITY_PLAYER_MON1; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) + identity = IDENTITY_PLAYER_MON1; + else + identity = IDENTITY_OPPONENT_MON1; + } + else + identity = IDENTITY_PLAYER_MON1; + + if (gBattleExecBuffer) + return; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankIdentity(gActiveBank) == identity) + { + EmitIntroTrainerBallThrow(0); + MarkBufferBankForExecution(gActiveBank); + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI)) + { + gBattleMainFunc = BattleIntroPlayer2SendsOutMonAnimation; + return; + } + } + } + + gBattleStruct->switchInAbilitiesCounter = 0; + gBattleStruct->switchInItemsCounter = 0; + gBattleStruct->overworldWeatherDone = FALSE; + + gBattleMainFunc = TryDoEventsBeforeFirstTurn; +} + +void sub_803B598(void) // unused +{ + if (gBattleExecBuffer == 0) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + EmitSwitchInAnim(0, gBattlePartyID[gActiveBank], FALSE); + MarkBufferBankForExecution(gActiveBank); + } + } + + gBattleStruct->switchInAbilitiesCounter = 0; + gBattleStruct->switchInItemsCounter = 0; + gBattleStruct->overworldWeatherDone = FALSE; + + gBattleMainFunc = TryDoEventsBeforeFirstTurn; + } +} + +static void TryDoEventsBeforeFirstTurn(void) +{ + s32 i; + s32 j; + u8 effect = 0; + + if (gBattleExecBuffer) + return; + + if (gBattleStruct->switchInAbilitiesCounter == 0) + { + for (i = 0; i < gNoOfAllBanks; i++) + gBanksByTurnOrder[i] = i; + for (i = 0; i < gNoOfAllBanks - 1; i++) + { + for (j = i + 1; j < gNoOfAllBanks; j++) + { + if (GetWhoStrikesFirst(gBanksByTurnOrder[i], gBanksByTurnOrder[j], TRUE) != 0) + SwapTurnOrder(i, j); + } + } + } + if (!gBattleStruct->overworldWeatherDone + && AbilityBattleEffects(0, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0) + { + gBattleStruct->overworldWeatherDone = TRUE; + return; + } + // check all switch in abilities happening from the fastest mon to slowest + while (gBattleStruct->switchInAbilitiesCounter < gNoOfAllBanks) + { + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBanksByTurnOrder[gBattleStruct->switchInAbilitiesCounter], 0, 0, 0) != 0) + effect++; + + gBattleStruct->switchInAbilitiesCounter++; + + if (effect) + return; + } + if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) != 0) + return; + if (AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) != 0) + return; + // check all switch in items having effect from the fastest mon to slowest + while (gBattleStruct->switchInItemsCounter < gNoOfAllBanks) + { + if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBanksByTurnOrder[gBattleStruct->switchInItemsCounter], 0) != 0) + effect++; + + gBattleStruct->switchInItemsCounter++; + + if (effect) + return; + } + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + *(gBattleStruct->field_5C + i) = 6; + gActionForBanks[i] = ACTION_INIT_VALUE; + gChosenMovesByBanks[i] = MOVE_NONE; + } + TurnValuesCleanUp(FALSE); + SpecialStatusesClear(); + *(&gBattleStruct->field_91) = gAbsentBankFlags; + sub_814F9EC(gText_EmptyString3, 0); + gBattleMainFunc = HandleTurnActionSelectionState; + ResetSentPokesToOpponentValue(); + + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++) + gBattleCommunication[i] = 0; + + for (i = 0; i < gNoOfAllBanks; i++) + gBattleMons[i].status2 &= ~(STATUS2_FLINCHED); + + *(&gBattleStruct->turnEffectsTracker) = 0; + *(&gBattleStruct->turnEffectsBank) = 0; + *(&gBattleStruct->field_1A0) = 0; + *(&gBattleStruct->field_1A1) = 0; + gBattleScripting.atk49_state = 0; + gBattleStruct->field_4D = 0; + gBattleStruct->turncountersTracker = 0; + gBattleMoveFlags = 0; + + gRandomTurnNumber = Random(); + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + { + StopCryAndClearCrySongs(); + BattleScriptExecute(gUnknown_082DB8BE); + } +} + +static void HandleEndTurn_ContinueBattle(void) +{ + s32 i; + + if (gBattleExecBuffer == 0) + { + gBattleMainFunc = BattleTurnPassed; + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++) + gBattleCommunication[i] = 0; + for (i = 0; i < gNoOfAllBanks; i++) + { + gBattleMons[i].status2 &= ~(STATUS2_FLINCHED); + if ((gBattleMons[i].status1 & STATUS_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS)) + CancelMultiTurnMoves(i); + } + gBattleStruct->turnEffectsTracker = 0; + gBattleStruct->turnEffectsBank = 0; + gBattleStruct->field_1A0 = 0; + gBattleStruct->field_1A1 = 0; + gBattleStruct->turncountersTracker = 0; + gBattleMoveFlags = 0; + } +} + +void BattleTurnPassed(void) +{ + s32 i; + + TurnValuesCleanUp(TRUE); + if (gBattleOutcome == 0) + { + if (UpdateTurnCounters() != 0) + return; + if (TurnBasedEffects() != 0) + return; + } + if (sub_8041728() != 0) + return; + gBattleStruct->field_4D = 0; + if (sub_8041364() != 0) + return; + + TurnValuesCleanUp(FALSE); + gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING); + gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE); + gHitMarker &= ~(HITMARKER_x400000); + gHitMarker &= ~(HITMARKER_x100000); + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gBattleScripting.atk49_state = 0; + gBattleMoveDamage = 0; + gBattleMoveFlags = 0; + + for (i = 0; i < 5; i++) + gBattleCommunication[i] = 0; + + if (gBattleOutcome != 0) + { + gCurrentActionFuncId = 12; + gBattleMainFunc = RunTurnActionsFunctions; + return; + } + + if (gBattleResults.battleTurnCounter < 0xFF) + { + gBattleResults.battleTurnCounter++; + gBattleStruct->field_DA++; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + gActionForBanks[i] = ACTION_INIT_VALUE; + gChosenMovesByBanks[i] = MOVE_NONE; + } + + for (i = 0; i < 4; i++) + *(gBattleStruct->field_5C + i) = 6; + + *(&gBattleStruct->field_91) = gAbsentBankFlags; + sub_814F9EC(gText_EmptyString3, 0); + gBattleMainFunc = HandleTurnActionSelectionState; + gRandomTurnNumber = Random(); + + if (gBattleTypeFlags & BATTLE_TYPE_PALACE) + BattleScriptExecute(gUnknown_082DB881); + else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->field_DA == 0) + BattleScriptExecute(gUnknown_082DB8BE); +} + +u8 IsRunningFromBattleImpossible(void) +{ + u8 holdEffect; + u8 side; + s32 i; + + if (gBattleMons[gActiveBank].item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[gActiveBank].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(gBattleMons[gActiveBank].item); + + gStringBank = gActiveBank; + + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + return 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + return 0; + if (gBattleMons[gActiveBank].ability == ABILITY_RUN_AWAY) + return 0; + + side = GetBankSide(gActiveBank); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (side != GetBankSide(i) + && gBattleMons[i].ability == ABILITY_SHADOW_TAG) + { + gBattleScripting.bank = i; + gLastUsedAbility = gBattleMons[i].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + return 2; + } + if (side != GetBankSide(i) + && gBattleMons[gActiveBank].ability != ABILITY_LEVITATE + && gBattleMons[gActiveBank].type1 != TYPE_FLYING + && gBattleMons[gActiveBank].type2 != TYPE_FLYING + && gBattleMons[i].ability == ABILITY_ARENA_TRAP) + { + gBattleScripting.bank = i; + gLastUsedAbility = gBattleMons[i].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + return 2; + } + } + i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BANK, gActiveBank, ABILITY_MAGNET_PULL, 0, 0); + if (i != 0 && (gBattleMons[gActiveBank].type1 == TYPE_STEEL || gBattleMons[gActiveBank].type2 == TYPE_STEEL)) + { + gBattleScripting.bank = i - 1; + gLastUsedAbility = gBattleMons[i - 1].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + return 2; + } + if ((gBattleMons[gActiveBank].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED)) + || (gStatuses3[gActiveBank] & STATUS3_ROOTED)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + return 1; + } + if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + return 1; + } + return 0; +} + +void sub_803BDA0(u8 bank) +{ + s32 i; + u8 r4; + u8 r1; + + // gBattleStruct->field_60[bank][i] + + for (i = 0; i < 3; i++) + gUnknown_0203CF00[i] = *(bank * 3 + i + (u8*)(gBattleStruct->field_60)); + + r4 = pokemon_order_func(gBattlePartyID[bank]); + r1 = pokemon_order_func(*(gBattleStruct->field_5C + bank)); + sub_81B8FB0(r4, r1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + for (i = 0; i < 3; i++) + { + *(bank * 3 + i + (u8*)(gBattleStruct->field_60)) = gUnknown_0203CF00[i]; + *((bank ^ BIT_MON) * 3 + i + (u8*)(gBattleStruct->field_60)) = gUnknown_0203CF00[i]; + } + } + else + { + for (i = 0; i < 3; i++) + { + *(bank * 3 + i + (u8*)(gBattleStruct->field_60)) = gUnknown_0203CF00[i]; + } + } +} + +enum +{ + STATE_TURN_START_RECORD, + STATE_BEFORE_ACTION_CHOSEN, + STATE_WAIT_ACTION_CHOSEN, + STATE_WAIT_ACTION_CASE_CHOSEN, + STATE_WAIT_ACTION_CONFIRMED_STANDBY, + STATE_WAIT_ACTION_CONFIRMED, + STATE_SELECTION_SCRIPT, + STATE_WAIT_SET_BEFORE_ACTION, + STATE_SELECTION_SCRIPT_MAY_RUN +}; + +static void HandleTurnActionSelectionState(void) +{ + s32 i; + + gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0; + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + u8 identity = GetBankIdentity(gActiveBank); + switch (gBattleCommunication[gActiveBank]) + { + case STATE_TURN_START_RECORD: // recorded battle related on start of every turn + sub_8185FD0(); + gBattleCommunication[gActiveBank] = STATE_BEFORE_ACTION_CHOSEN; + break; + case STATE_BEFORE_ACTION_CHOSEN: // choose an action + *(gBattleStruct->field_5C + gActiveBank) = 6; + if (gBattleTypeFlags & BATTLE_TYPE_MULTI + || !(identity & BIT_MON) + || gBattleStruct->field_91 & gBitTable[GetBankByIdentity(identity ^ BIT_MON)] + || gBattleCommunication[GetBankByIdentity(identity ^ BIT_MON)] == 5) + { + if (gBattleStruct->field_91 & gBitTable[gActiveBank]) + { + gActionForBanks[gActiveBank] = ACTION_NOTHING_FAINTED; + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED; + else + gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + } + else + { + if (gBattleMons[gActiveBank].status2 & STATUS2_MULTIPLETURNS + || gBattleMons[gActiveBank].status2 & STATUS2_RECHARGE) + { + gActionForBanks[gActiveBank] = ACTION_USE_MOVE; + gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + } + else + { + EmitChooseAction(0, gActionForBanks[0], gBattleBufferB[0][1] | (gBattleBufferB[0][2] << 8)); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[gActiveBank]++; + } + } + } + break; + case STATE_WAIT_ACTION_CHOSEN: // try to perform an action + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]); + gActionForBanks[gActiveBank] = gBattleBufferB[gActiveBank][1]; + + switch (gBattleBufferB[gActiveBank][1]) + { + case ACTION_USE_MOVE: + if (AreAllMovesUnusable()) + { + gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + *(gBattleStruct->moveTarget + gActiveBank) = gBattleBufferB[gActiveBank][3]; + return; + } + else if (gDisableStructs[gActiveBank].encoredMove != 0) + { + gChosenMovesByBanks[gActiveBank] = gDisableStructs[gActiveBank].encoredMove; + *(gBattleStruct->chosenMovePositions + gActiveBank) = gDisableStructs[gActiveBank].encoredMovePos; + gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + return; + } + else + { + struct ChooseMoveStruct moveInfo; + + moveInfo.species = gBattleMons[gActiveBank].species; + moveInfo.monType1 = gBattleMons[gActiveBank].type1; + moveInfo.monType2 = gBattleMons[gActiveBank].type2; + + for (i = 0; i < 4; i++) + { + moveInfo.moves[i] = gBattleMons[gActiveBank].moves[i]; + moveInfo.currentPp[i] = gBattleMons[gActiveBank].pp[i]; + moveInfo.maxPp[i] = CalculatePPWithBonus( + gBattleMons[gActiveBank].moves[i], + gBattleMons[gActiveBank].ppBonuses, + i); + } + + EmitChooseMove(0, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo); + MarkBufferBankForExecution(gActiveBank); + } + break; + case ACTION_USE_ITEM: + if (gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_FRONTIER_NO_PYRAMID + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_x2000000)) + { + RecordedBattle_ClearBankAction(gActiveBank, 1); + gBattlescriptPtrsForSelection[gActiveBank] = BattleScript_ActionSelectionItemsCantBeUsed; + gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + else + { + EmitOpenBag(0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); + } + break; + case ACTION_SWITCH: + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + if (gBattleMons[gActiveBank].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION) + || gBattleTypeFlags & BATTLE_TYPE_ARENA + || gStatuses3[gActiveBank] & STATUS3_ROOTED) + { + EmitChoosePokemon(0, 2, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBank]); + } + else if ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBank, ABILITY_SHADOW_TAG, 0, 0)) + || ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBank, ABILITY_ARENA_TRAP, 0, 0)) + && gBattleMons[gActiveBank].type1 != TYPE_FLYING + && gBattleMons[gActiveBank].type2 != TYPE_FLYING + && gBattleMons[gActiveBank].ability != ABILITY_LEVITATE) + || ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BANK, gActiveBank, ABILITY_MAGNET_PULL, 0, 0)) + && (gBattleMons[gActiveBank].type1 == TYPE_STEEL + || gBattleMons[gActiveBank].type2 == TYPE_STEEL))) + { + EmitChoosePokemon(0, ((i - 1) << 4) | 4, 6, gLastUsedAbility, gBattleStruct->field_60[gActiveBank]); + } + else + { + if (gActiveBank == 2 && gActionForBanks[0] == ACTION_SWITCH) + EmitChoosePokemon(0, 0, *(gBattleStruct->field_5C + 0), ABILITY_NONE, gBattleStruct->field_60[gActiveBank]); + else if (gActiveBank == 3 && gActionForBanks[1] == ACTION_SWITCH) + EmitChoosePokemon(0, 0, *(gBattleStruct->field_5C + 1), ABILITY_NONE, gBattleStruct->field_60[gActiveBank]); + else + EmitChoosePokemon(0, 0, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBank]); + } + MarkBufferBankForExecution(gActiveBank); + break; + case ACTION_SAFARI_ZONE_BALL: + if (IsPlayerPartyAndPokemonStorageFull()) + { + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DAB11; + gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + break; + case ACTION_POKEBLOCK_CASE: + EmitOpenBag(0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); + break; + case ACTION_CANCEL_PARTNER: + gBattleCommunication[gActiveBank] = 7; + gBattleCommunication[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] = 1; + RecordedBattle_ClearBankAction(gActiveBank, 1); + if (gBattleMons[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].status2 & STATUS2_MULTIPLETURNS + || gBattleMons[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].status2 & STATUS2_RECHARGE) + { + EmitCmd50(0); + MarkBufferBankForExecution(gActiveBank); + return; + } + else if (gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_SWITCH) + { + RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 2); + } + else if (gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_RUN) + { + RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 1); + } + else if (gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_USE_MOVE + && (gProtectStructs[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].onlyStruggle + || gDisableStructs[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].encoredMove)) + { + RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 1); + } + else if (gBattleTypeFlags & BATTLE_TYPE_PALACE + && gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_USE_MOVE) + { + gRngValue = gBattlePalaceMoveSelectionRngValue; + RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 1); + } + else + { + RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 3); + } + EmitCmd50(0); + MarkBufferBankForExecution(gActiveBank); + return; + } + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER + && gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_x4000000) + && gBattleBufferB[gActiveBank][1] == ACTION_RUN) + { + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB9BA; + gBattleCommunication[gActiveBank] = 8; + *(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + && gBattleBufferB[gActiveBank][1] == ACTION_RUN) + { + BattleScriptExecute(gUnknown_082DAAFE); + gBattleCommunication[gActiveBank] = 1; + } + else if (IsRunningFromBattleImpossible() != 0 + && gBattleBufferB[gActiveBank][1] == ACTION_RUN) + { + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DAB0B; + gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + else + { + gBattleCommunication[gActiveBank]++; + } + } + break; + case STATE_WAIT_ACTION_CASE_CHOSEN: + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + switch (gActionForBanks[gActiveBank]) + { + case ACTION_USE_MOVE: + switch (gBattleBufferB[gActiveBank][1]) + { + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + gActionForBanks[gActiveBank] = gBattleBufferB[gActiveBank][1]; + return; + case 15: + gActionForBanks[gActiveBank] = ACTION_SWITCH; + sub_803CDF8(); + return; + default: + sub_818603C(2); + if ((gBattleBufferB[gActiveBank][2] | (gBattleBufferB[gActiveBank][3] << 8)) == 0xFFFF) + { + gBattleCommunication[gActiveBank] = 1; + RecordedBattle_ClearBankAction(gActiveBank, 1); + } + else if (TrySetCantSelectMoveBattleScript()) + { + RecordedBattle_ClearBankAction(gActiveBank, 1); + gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE; + gBattleBufferB[gActiveBank][1] = 0; + *(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_WAIT_ACTION_CHOSEN; + return; + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_PALACE)) + { + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][2]); + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][3]); + } + *(gBattleStruct->chosenMovePositions + gActiveBank) = gBattleBufferB[gActiveBank][2]; + gChosenMovesByBanks[gActiveBank] = gBattleMons[gActiveBank].moves[*(gBattleStruct->chosenMovePositions + gActiveBank)]; + *(gBattleStruct->moveTarget + gActiveBank) = gBattleBufferB[gActiveBank][3]; + gBattleCommunication[gActiveBank]++; + } + break; + } + break; + case ACTION_USE_ITEM: + if ((gBattleBufferB[gActiveBank][1] | (gBattleBufferB[gActiveBank][2] << 8)) == 0) + { + gBattleCommunication[gActiveBank] = 1; + } + else + { + gLastUsedItem = (gBattleBufferB[gActiveBank][1] | (gBattleBufferB[gActiveBank][2] << 8)); + gBattleCommunication[gActiveBank]++; + } + break; + case ACTION_SWITCH: + if (gBattleBufferB[gActiveBank][1] == 6) + { + gBattleCommunication[gActiveBank] = 1; + RecordedBattle_ClearBankAction(gActiveBank, 1); + } + else + { + sub_803CDF8(); + gBattleCommunication[gActiveBank]++; + } + break; + case ACTION_RUN: + gHitMarker |= HITMARKER_RUN; + gBattleCommunication[gActiveBank]++; + break; + case ACTION_WATCHES_CAREFULLY: + gBattleCommunication[gActiveBank]++; + break; + case ACTION_SAFARI_ZONE_BALL: + gBattleCommunication[gActiveBank]++; + break; + case ACTION_POKEBLOCK_CASE: + if ((gBattleBufferB[gActiveBank][1] | (gBattleBufferB[gActiveBank][2] << 8)) != 0) + { + gBattleCommunication[gActiveBank]++; + } + else + { + gBattleCommunication[gActiveBank] = STATE_BEFORE_ACTION_CHOSEN; + } + break; + case ACTION_GO_NEAR: + gBattleCommunication[gActiveBank]++; + break; + case ACTION_SAFARI_ZONE_RUN: + gHitMarker |= HITMARKER_RUN; + gBattleCommunication[gActiveBank]++; + break; + case ACTION_9: + gBattleCommunication[gActiveBank]++; + break; + } + } + break; + case STATE_WAIT_ACTION_CONFIRMED_STANDBY: + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + i = (sub_803CDB8() != 0); + + if (((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_DOUBLE)) != BATTLE_TYPE_DOUBLE) + || (identity & BIT_MON) + || (*(&gBattleStruct->field_91) & gBitTable[GetBankByIdentity(identity ^ BIT_MON)])) + { + EmitLinkStandbyMsg(0, 0, i); + } + else + { + EmitLinkStandbyMsg(0, 1, i); + } + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[gActiveBank]++; + } + break; + case STATE_WAIT_ACTION_CONFIRMED: + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + gBattleCommunication[ACTIONS_CONFIRMED_COUNT]++; + } + break; + case STATE_SELECTION_SCRIPT: + if (*(gBattleStruct->selectionScriptFinished + gActiveBank)) + { + gBattleCommunication[gActiveBank] = *(gBattleStruct->stateIdAfterSelScript + gActiveBank); + } + else + { + gBankAttacker = gActiveBank; + gBattlescriptCurrInstr = gBattlescriptPtrsForSelection[gActiveBank]; + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + } + gBattlescriptPtrsForSelection[gActiveBank] = gBattlescriptCurrInstr; + } + break; + case STATE_WAIT_SET_BEFORE_ACTION: + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + gBattleCommunication[gActiveBank] = 1; + } + break; + case STATE_SELECTION_SCRIPT_MAY_RUN: + if (*(gBattleStruct->selectionScriptFinished + gActiveBank)) + { + if (gBattleBufferB[gActiveBank][1] == 13) + { + gHitMarker |= HITMARKER_RUN; + gActionForBanks[gActiveBank] = ACTION_RUN; + gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + } + else + { + RecordedBattle_ClearBankAction(gActiveBank, 1); + gBattleCommunication[gActiveBank] = *(gBattleStruct->stateIdAfterSelScript + gActiveBank); + } + } + else + { + gBankAttacker = gActiveBank; + gBattlescriptCurrInstr = gBattlescriptPtrsForSelection[gActiveBank]; + if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) + { + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + } + gBattlescriptPtrsForSelection[gActiveBank] = gBattlescriptCurrInstr; + } + break; + } + } + + // check if everyone chose actions + if (gBattleCommunication[ACTIONS_CONFIRMED_COUNT] == gNoOfAllBanks) + { + sub_818603C(1); + gBattleMainFunc = SetActionsAndBanksTurnOrder; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gActionForBanks[i] == ACTION_SWITCH) + sub_80571DC(i, *(gBattleStruct->field_5C + i)); + } + } + } +} + +static bool8 sub_803CDB8(void) +{ + s32 i, var; + + for (var = 0, i = 0; i < gNoOfAllBanks; i++) + { + if (gBattleCommunication[i] == 5) + var++; + } + + if (var + 1 == gNoOfAllBanks) + return TRUE; + else + return FALSE; +} + +static void sub_803CDF8(void) +{ + *(gBattleStruct->field_5C + gActiveBank) = gBattleBufferB[gActiveBank][1]; + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]); + + if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) &= 0xF; + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0); + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBank][3]; + + *((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0); + *((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4; + *((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBank][3]; + } +} + +void SwapTurnOrder(u8 id1, u8 id2) +{ + u32 temp = gActionsByTurnOrder[id1]; + gActionsByTurnOrder[id1] = gActionsByTurnOrder[id2]; + gActionsByTurnOrder[id2] = temp; + + temp = gBanksByTurnOrder[id1]; + gBanksByTurnOrder[id1] = gBanksByTurnOrder[id2]; + gBanksByTurnOrder[id2] = temp; +} + +u8 GetWhoStrikesFirst(u8 bank1, u8 bank2, bool8 ignoreChosenMoves) +{ + u8 strikesFirst = 0; + u8 speedMultiplierBank1 = 0, speedMultiplierBank2 = 0; + u32 speedBank1 = 0, speedBank2 = 0; + u8 holdEffect = 0; + u8 holdEffectParam = 0; + u16 moveBank1 = 0, moveBank2 = 0; + + if (WEATHER_HAS_EFFECT) + { + if ((gBattleMons[bank1].ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY) + || (gBattleMons[bank1].ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY)) + speedMultiplierBank1 = 2; + else + speedMultiplierBank1 = 1; + + if ((gBattleMons[bank2].ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY) + || (gBattleMons[bank2].ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY)) + speedMultiplierBank2 = 2; + else + speedMultiplierBank2 = 1; + } + else + { + speedMultiplierBank1 = 1; + speedMultiplierBank2 = 1; + } + + speedBank1 = (gBattleMons[bank1].speed * speedMultiplierBank1) + * (gStatStageRatios[gBattleMons[bank1].statStages[STAT_STAGE_SPEED]][0]) + / (gStatStageRatios[gBattleMons[bank1].statStages[STAT_STAGE_SPEED]][1]); + + if (gBattleMons[bank1].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[bank1].holdEffect; + holdEffectParam = gEnigmaBerries[bank1].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[bank1].item); + holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[bank1].item); + } + + // badge boost + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER)) + && FlagGet(BADGE03_GET) + && GetBankSide(bank1) == SIDE_PLAYER) + { + speedBank1 = (speedBank1 * 110) / 100; + } + + if (holdEffect == HOLD_EFFECT_MACHO_BRACE) + speedBank1 /= 2; + + if (gBattleMons[bank1].status1 & STATUS_PARALYSIS) + speedBank1 /= 4; + + if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100) + speedBank1 = UINT_MAX; + + // check second bank's speed + + speedBank2 = (gBattleMons[bank2].speed * speedMultiplierBank2) + * (gStatStageRatios[gBattleMons[bank2].statStages[STAT_STAGE_SPEED]][0]) + / (gStatStageRatios[gBattleMons[bank2].statStages[STAT_STAGE_SPEED]][1]); + + if (gBattleMons[bank2].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[bank2].holdEffect; + holdEffectParam = gEnigmaBerries[bank2].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[bank2].item); + holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[bank2].item); + } + + // badge boost + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER)) + && FlagGet(BADGE03_GET) + && GetBankSide(bank2) == SIDE_PLAYER) + { + speedBank2 = (speedBank2 * 110) / 100; + } + + if (holdEffect == HOLD_EFFECT_MACHO_BRACE) + speedBank2 /= 2; + + if (gBattleMons[bank2].status1 & STATUS_PARALYSIS) + speedBank2 /= 4; + + if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100) + speedBank2 = UINT_MAX; + + if (ignoreChosenMoves) + { + moveBank1 = MOVE_NONE; + moveBank2 = MOVE_NONE; + } + else + { + if (gActionForBanks[bank1] == ACTION_USE_MOVE) + { + if (gProtectStructs[bank1].onlyStruggle) + moveBank1 = MOVE_STRUGGLE; + else + moveBank1 = gBattleMons[bank1].moves[*(gBattleStruct->chosenMovePositions + bank1)]; + } + else + moveBank1 = MOVE_NONE; + + if (gActionForBanks[bank2] == ACTION_USE_MOVE) + { + if (gProtectStructs[bank2].onlyStruggle) + moveBank2 = MOVE_STRUGGLE; + else + moveBank2 = gBattleMons[bank2].moves[*(gBattleStruct->chosenMovePositions + bank2)]; + } + else + moveBank2 = MOVE_NONE; + } + + // both move priorities are different than 0 + if (gBattleMoves[moveBank1].priority != 0 || gBattleMoves[moveBank2].priority != 0) + { + // both priorities are the same + if (gBattleMoves[moveBank1].priority == gBattleMoves[moveBank2].priority) + { + if (speedBank1 == speedBank2 && Random() & 1) + strikesFirst = 2; // same speeds, same priorities + else if (speedBank1 < speedBank2) + strikesFirst = 1; // bank2 has more speed + + // else bank1 has more speed + } + else if (gBattleMoves[moveBank1].priority < gBattleMoves[moveBank2].priority) + strikesFirst = 1; // bank2's move has greater priority + + // else bank1's move has greater priority + } + // both priorities are equal to 0 + else + { + if (speedBank1 == speedBank2 && Random() & 1) + strikesFirst = 2; // same speeds, same priorities + else if (speedBank1 < speedBank2) + strikesFirst = 1; // bank2 has more speed + + // else bank1 has more speed + } + + return strikesFirst; +} + +static void SetActionsAndBanksTurnOrder(void) +{ + s32 var = 0; + s32 i, j; + + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + gActionsByTurnOrder[var] = gActionForBanks[gActiveBank]; + gBanksByTurnOrder[var] = gActiveBank; + var++; + } + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gActionForBanks[gActiveBank] == ACTION_RUN) + { + var = 5; + break; + } + } + } + else + { + if (gActionForBanks[0] == ACTION_RUN) + { + gActiveBank = 0; + var = 5; + } + if (gActionForBanks[2] == ACTION_RUN) + { + gActiveBank = 2; + var = 5; + } + } + + if (var == 5) + { + gActionsByTurnOrder[0] = gActionForBanks[gActiveBank]; + gBanksByTurnOrder[0] = gActiveBank; + var = 1; + for (i = 0; i < gNoOfAllBanks; i++) + { + if (i != gActiveBank) + { + gActionsByTurnOrder[var] = gActionForBanks[i]; + gBanksByTurnOrder[var] = i; + var++; + } + } + gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts; + gBattleStruct->focusPunchBank = 0; + return; + } + else + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gActionForBanks[gActiveBank] == ACTION_USE_ITEM || gActionForBanks[gActiveBank] == ACTION_SWITCH) + { + gActionsByTurnOrder[var] = gActionForBanks[gActiveBank]; + gBanksByTurnOrder[var] = gActiveBank; + var++; + } + } + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gActionForBanks[gActiveBank] != ACTION_USE_ITEM && gActionForBanks[gActiveBank] != ACTION_SWITCH) + { + gActionsByTurnOrder[var] = gActionForBanks[gActiveBank]; + gBanksByTurnOrder[var] = gActiveBank; + var++; + } + } + for (i = 0; i < gNoOfAllBanks - 1; i++) + { + for (j = i + 1; j < gNoOfAllBanks; j++) + { + u8 bank1 = gBanksByTurnOrder[i]; + u8 bank2 = gBanksByTurnOrder[j]; + if (gActionsByTurnOrder[i] != ACTION_USE_ITEM + && gActionsByTurnOrder[j] != ACTION_USE_ITEM + && gActionsByTurnOrder[i] != ACTION_SWITCH + && gActionsByTurnOrder[j] != ACTION_SWITCH) + { + if (GetWhoStrikesFirst(bank1, bank2, FALSE)) + SwapTurnOrder(i, j); + } + } + } + } + } + gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts; + gBattleStruct->focusPunchBank = 0; +} + +static void TurnValuesCleanUp(bool8 var0) +{ + s32 i; + u8 *dataPtr; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (var0) + { + gProtectStructs[gActiveBank].protected = 0; + gProtectStructs[gActiveBank].endured = 0; + } + else + { + dataPtr = (u8*)(&gProtectStructs[gActiveBank]); + for (i = 0; i < sizeof(struct ProtectStruct); i++) + dataPtr[i] = 0; + + if (gDisableStructs[gActiveBank].isFirstTurn) + gDisableStructs[gActiveBank].isFirstTurn--; + + if (gDisableStructs[gActiveBank].rechargeCounter) + { + gDisableStructs[gActiveBank].rechargeCounter--; + if (gDisableStructs[gActiveBank].rechargeCounter == 0) + gBattleMons[gActiveBank].status2 &= ~(STATUS2_RECHARGE); + } + } + + if (gDisableStructs[gActiveBank].substituteHP == 0) + gBattleMons[gActiveBank].status2 &= ~(STATUS2_SUBSTITUTE); + } + + gSideTimers[0].followmeTimer = 0; + gSideTimers[1].followmeTimer = 0; +} + +static void SpecialStatusesClear(void) +{ + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + s32 i; + u8 *dataPtr = (u8*)(&gSpecialStatuses[gActiveBank]); + + for (i = 0; i < sizeof(struct SpecialStatus); i++) + dataPtr[i] = 0; + } +} + +static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) +{ + if (!(gHitMarker & HITMARKER_RUN)) + { + while (gBattleStruct->focusPunchBank < gNoOfAllBanks) + { + gActiveBank = gBankAttacker = gBattleStruct->focusPunchBank; + gBattleStruct->focusPunchBank++; + if (gChosenMovesByBanks[gActiveBank] == MOVE_FOCUS_PUNCH + && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP) + && !(gDisableStructs[gBankAttacker].truantCounter) + && !(gProtectStructs[gActiveBank].onlyStruggle)) + { + BattleScriptExecute(BattleScript_FocusPunchSetUp); + return; + } + } + } + + TryClearRageStatuses(); + gCurrentTurnActionNumber = 0; +{ + // something stupid needed to match + u8 zero; + gCurrentActionFuncId = gActionsByTurnOrder[(zero = 0)]; +} + gDynamicBasePower = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleMainFunc = RunTurnActionsFunctions; + gBattleCommunication[3] = 0; + gBattleCommunication[4] = 0; + gBattleScripting.field_16 = 0; + gBattleResources->battleScriptsStack->size = 0; +} + +static void RunTurnActionsFunctions(void) +{ + if (gBattleOutcome != 0) + gCurrentActionFuncId = 12; + + *(&gBattleStruct->field_4B) = gCurrentTurnActionNumber; + sTurnActionsFuncsTable[gCurrentActionFuncId](); + + if (gCurrentTurnActionNumber >= gNoOfAllBanks) // everyone did their actions, turn finished + { + gHitMarker &= ~(HITMARKER_x100000); + gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F]; + } + else + { + if (gBattleStruct->field_4B != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another bank + { + gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING); + gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE); + } + } +} + +static void HandleEndTurn_BattleWon(void) +{ + gCurrentActionFuncId = 0; + + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + gScriptResult = gBattleOutcome; + gBattleTextBuff1[0] = gBattleOutcome; + gBankAttacker = GetBankByIdentity(IDENTITY_PLAYER_MON1); + gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost; + gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80); + } + else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER + && gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_x4000000 | BATTLE_TYPE_EREADER_TRAINER)) + { + BattleMusicStop(); + gBattlescriptCurrInstr = BattleScript_FrontierTrainerBattleWon; + + if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_3FE) + PlayBGM(BGM_KACHI3); + else + PlayBGM(BGM_KACHI1); + } + else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + BattleMusicStop(); + gBattlescriptCurrInstr = BattleScript_LocalTrainerBattleWon; + + switch (gTrainers[gTrainerBattleOpponent_A].trainerClass) + { + case CLASS_ELITE_FOUR: + case CLASS_CHAMPION: + PlayBGM(BGM_KACHI5); + break; + case CLASS_TEAM_AQUA: + case CLASS_TEAM_MAGMA: + case CLASS_AQUA_ADMIN: + case CLASS_AQUA_LEADER: + case CLASS_MAGMA_ADMIN: + case CLASS_MAGMA_LEADER: + PlayBGM(BGM_KACHI4); + break; + case CLASS_LEADER: + PlayBGM(BGM_KACHI3); + break; + default: + PlayBGM(BGM_KACHI1); + break; + } + } + else + { + gBattlescriptCurrInstr = BattleScript_PayDayMoneyAndPickUpItems; + } + + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_BattleLost(void) +{ + gCurrentActionFuncId = 0; + + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + if (gBattleOutcome & BATTLE_OUTCOME_BIT_x80) + { + gBattlescriptCurrInstr = gUnknown_082DB9C8; + gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80); + gSaveBlock2Ptr->field_CA9_b = 1; + } + else + { + gBattlescriptCurrInstr = gUnknown_082DAA0B; + gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80); + } + } + else + { + gBattleTextBuff1[0] = gBattleOutcome; + gBankAttacker = GetBankByIdentity(IDENTITY_PLAYER_MON1); + gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost; + gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80); + } + } + else + { + gBattlescriptCurrInstr = BattleScript_LocalBattleLost; + } + + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_RanFromBattle(void) +{ + gCurrentActionFuncId = 0; + + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER && gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + gBattlescriptCurrInstr = gUnknown_082DB9C1; + gBattleOutcome = BATTLE_FORFEITED; + gSaveBlock2Ptr->field_CA9_b = 1; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + gBattlescriptCurrInstr = gUnknown_082DB9C1; + gBattleOutcome = BATTLE_FORFEITED; + } + else + { + switch (gProtectStructs[gBankAttacker].fleeFlag) + { + default: + gBattlescriptCurrInstr = BattleScript_GotAwaySafely; + break; + case 1: + gBattlescriptCurrInstr = BattleScript_SmokeBallEscape; + break; + case 2: + gBattlescriptCurrInstr = BattleScript_RanAwayUsingMonAbility; + break; + } + } + + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_MonFled(void) +{ + gCurrentActionFuncId = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]); + gBattlescriptCurrInstr = BattleScript_WildMonFled; + + gBattleMainFunc = HandleEndTurn_FinishBattle; +} + +static void HandleEndTurn_FinishBattle(void) +{ + if (gCurrentActionFuncId == 0xB || gCurrentActionFuncId == 0xC) + { + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_FIRST_BATTLE + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_WALLY_TUTORIAL + | BATTLE_TYPE_FRONTIER))) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + if (gBattleResults.playerMon1Species == SPECIES_NONE) + { + gBattleResults.playerMon1Species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); + GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_NICKNAME, gBattleResults.playerMon1Name); + } + else + { + gBattleResults.playerMon2Species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); + GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_NICKNAME, gBattleResults.playerMon2Name); + } + } + } + PutPokemonTodayCaughtOnAir(); + } + + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_TRAINER + | BATTLE_TYPE_FIRST_BATTLE + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_WALLY_TUTORIAL)) + && gBattleResults.unk5_6) + { + sub_80EE184(); + } + + sub_8186444(); + BeginFastPaletteFade(3); + FadeOutMapMusic(5); + gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions; + gUnknown_030061E8 = BattleMainCB2; + } + else + { + if (gBattleExecBuffer == 0) + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + } +} + +static void FreeResetData_ReturnToOvOrDoEvolutions(void) +{ + if (!gPaletteFade.active) + { + ResetSpriteData(); + if (gLeveledUpInBattle == 0 || gBattleOutcome != BATTLE_WON) + { + gBattleMainFunc = ReturnFromBattleToOverworld; + return; + } + else + { + gBattleMainFunc = TryEvolvePokemon; + } + } + + FreeAllWindowBuffers(); + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + FreeMonSpritesGfx(); + FreeBattleResources(); + FreeBattleSpritesData(); + } +} + +static void TryEvolvePokemon(void) +{ + s32 i; + + while (gLeveledUpInBattle != 0) + { + for (i = 0; i < 6; i++) + { + if (gLeveledUpInBattle & gBitTable[i]) + { + u16 species; + u8 levelUpBits = gLeveledUpInBattle; + + levelUpBits &= ~(gBitTable[i]); + gLeveledUpInBattle = levelUpBits; + + species = GetEvolutionTargetSpecies(&gPlayerParty[i], 0, levelUpBits); + if (species != SPECIES_NONE) + { + FreeAllWindowBuffers(); + gBattleMainFunc = WaitForEvoSceneToFinish; + EvolutionScene(&gPlayerParty[i], species, TRUE, i); + return; + } + } + } + } + + gBattleMainFunc = ReturnFromBattleToOverworld; +} + +static void WaitForEvoSceneToFinish(void) +{ + if (gMain.callback2 == BattleMainCB2) + gBattleMainFunc = TryEvolvePokemon; +} + +static void ReturnFromBattleToOverworld(void) +{ + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + RandomlyGivePartyPokerus(gPlayerParty); + PartySpreadPokerus(gPlayerParty); + } + + if (gBattleTypeFlags & BATTLE_TYPE_LINK && gReceivedRemoteLinkPlayers != 0) + return; + + gScriptResult = gBattleOutcome; + gMain.inBattle = 0; + gMain.callback1 = gPreBattleCallback1; + + if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) + { + UpdateRoamerHPStatus(&gEnemyParty[0]); + if ((gBattleOutcome & BATTLE_WON) || gBattleOutcome == BATTLE_CAUGHT) + SetRoamerInactive(); + } + + m4aSongNumStop(0x5A); + SetMainCallback2(gMain.savedCallback); +} + +void RunBattleScriptCommands_PopCallbacksStack(void) +{ + if (gCurrentActionFuncId == 0xB || gCurrentActionFuncId == 0xC) + { + if (BATTLE_CALLBACKS_STACK->size != 0) + BATTLE_CALLBACKS_STACK->size--; + gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size]; + } + else + { + if (gBattleExecBuffer == 0) + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + } +} + +void RunBattleScriptCommands(void) +{ + if (gBattleExecBuffer == 0) + gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); +} + +static void HandleAction_UseMove(void) +{ + u8 side; + u8 var = 4; + + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + + if (*(&gBattleStruct->field_91) & gBitTable[gBankAttacker]) + { + gCurrentActionFuncId = ACTION_FINISHED; + return; + } + + gCritMultiplier = 1; + gBattleScripting.dmgMultiplier = 1; + gBattleStruct->atkCancellerTracker = 0; + gBattleMoveFlags = 0; + gMultiHitCounter = 0; + gBattleCommunication[6] = 0; + gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovePositions + gBankAttacker); + + // choose move + if (gProtectStructs[gBankAttacker].onlyStruggle) + { + gProtectStructs[gBankAttacker].onlyStruggle = 0; + gCurrentMove = gLastUsedMove = MOVE_STRUGGLE; + gHitMarker |= HITMARKER_NO_PPDEDUCT; + *(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(MOVE_STRUGGLE, 0); + } + else if (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBankAttacker].status2 & STATUS2_RECHARGE) + { + gCurrentMove = gLastUsedMove = gLockedMoves[gBankAttacker]; + } + // encore forces you to use the same move + else if (gDisableStructs[gBankAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBankAttacker].encoredMove == gBattleMons[gBankAttacker].moves[gDisableStructs[gBankAttacker].encoredMovePos]) + { + gCurrentMove = gLastUsedMove = gDisableStructs[gBankAttacker].encoredMove; + gCurrMovePos = gUnknown_020241E9 = gDisableStructs[gBankAttacker].encoredMovePos; + *(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0); + } + // check if the encored move wasn't overwritten + else if (gDisableStructs[gBankAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBankAttacker].encoredMove != gBattleMons[gBankAttacker].moves[gDisableStructs[gBankAttacker].encoredMovePos]) + { + gCurrMovePos = gUnknown_020241E9 = gDisableStructs[gBankAttacker].encoredMovePos; + gCurrentMove = gLastUsedMove = gBattleMons[gBankAttacker].moves[gCurrMovePos]; + gDisableStructs[gBankAttacker].encoredMove = MOVE_NONE; + gDisableStructs[gBankAttacker].encoredMovePos = 0; + gDisableStructs[gBankAttacker].encoreTimer1 = 0; + *(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0); + } + else if (gBattleMons[gBankAttacker].moves[gCurrMovePos] != gChosenMovesByBanks[gBankAttacker]) + { + gCurrentMove = gLastUsedMove = gBattleMons[gBankAttacker].moves[gCurrMovePos]; + *(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0); + } + else + { + gCurrentMove = gLastUsedMove = gBattleMons[gBankAttacker].moves[gCurrMovePos]; + } + + if (gBattleMons[gBankAttacker].hp != 0) + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBattleResults.lastUsedMovePlayer = gCurrentMove; + else + gBattleResults.lastUsedMoveOpponent = gCurrentMove; + } + + // choose target + side = GetBankSide(gBankAttacker) ^ BIT_SIDE; + if (gSideTimers[side].followmeTimer != 0 + && gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED + && GetBankSide(gBankAttacker) != GetBankSide(gSideTimers[side].followmeTarget) + && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + { + gBankTarget = gSideTimers[side].followmeTarget; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + && gSideTimers[side].followmeTimer == 0 + && (gBattleMoves[gCurrentMove].power != 0 + || gBattleMoves[gCurrentMove].target != MOVE_TARGET_x10) + && gBattleMons[*(gBattleStruct->moveTarget + gBankAttacker)].ability != ABILITY_LIGHTNING_ROD + && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + { + side = GetBankSide(gBankAttacker); + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (side != GetBankSide(gActiveBank) + && *(gBattleStruct->moveTarget + gBankAttacker) != gActiveBank + && gBattleMons[gActiveBank].ability == ABILITY_LIGHTNING_ROD + && BankGetTurnOrder(gActiveBank) < var) + { + var = BankGetTurnOrder(gActiveBank); + } + } + if (var == 4) + { + if (gBattleMoves[gLastUsedMove].target & MOVE_TARGET_RANDOM) + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + { + if (Random() & 1) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + } + else + { + if (Random() & 1) + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2); + } + } + else + { + gBankTarget = *(gBattleStruct->moveTarget + gBankAttacker); + } + + if (gAbsentBankFlags & gBitTable[gBankTarget]) + { + if (GetBankSide(gBankAttacker) != GetBankSide(gBankTarget)) + { + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + } + else + { + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_SIDE); + if (gAbsentBankFlags & gBitTable[gBankTarget]) + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + } + } + } + else + { + gActiveBank = gBanksByTurnOrder[var]; + RecordAbilityBattle(gActiveBank, gBattleMons[gActiveBank].ability); + gSpecialStatuses[gActiveBank].lightningRodRedirected = 1; + gBankTarget = gActiveBank; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattleMoves[gLastUsedMove].target & MOVE_TARGET_RANDOM) + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + { + if (Random() & 1) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + } + else + { + if (Random() & 1) + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2); + } + + if (gAbsentBankFlags & gBitTable[gBankTarget] + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget)) + { + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + } + } + else + { + gBankTarget = *(gBattleStruct->moveTarget + gBankAttacker); + if (gAbsentBankFlags & gBitTable[gBankTarget]) + { + if (GetBankSide(gBankAttacker) != GetBankSide(gBankTarget)) + { + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + } + else + { + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_SIDE); + if (gAbsentBankFlags & gBitTable[gBankTarget]) + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + } + } + } + + // choose battlescript + if (gBattleTypeFlags & BATTLE_TYPE_PALACE + && gProtectStructs[gBankAttacker].flag_x10) + { + if (gBattleMons[gBankAttacker].hp == 0) + { + gCurrentActionFuncId = 12; + return; + } + else if (gUnknown_02024230[gBankAttacker] != NULL) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = gUnknown_02024230[gBankAttacker]; + gUnknown_02024230[gBankAttacker] = NULL; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; + } + } + else + { + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A56E8(gBankAttacker); + + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; +} + +static void HandleAction_Switch(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gActionSelectionCursor[gBankAttacker] = 0; + gMoveSelectionCursor[gBankAttacker] = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, *(gBattleStruct->field_58 + gBankAttacker)) + + gBattleScripting.bank = gBankAttacker; + gBattlescriptCurrInstr = BattleScript_ActionSwitch; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; + + if (gBattleResults.playerSwitchesCounter < 255) + gBattleResults.playerSwitchesCounter++; +} + +static void HandleAction_UseItem(void) +{ + gBankAttacker = gBankTarget = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + ClearFuryCutterDestinyBondGrudge(gBankAttacker); + gLastUsedItem = gBattleBufferB[gBankAttacker][1] | (gBattleBufferB[gBankAttacker][2] << 8); + + if (gLastUsedItem <= ITEM_PREMIER_BALL) // is ball + { + gBattlescriptCurrInstr = gBattlescriptsForBallThrow[gLastUsedItem]; + } + else if (gLastUsedItem == ITEM_POKE_DOLL || gLastUsedItem == ITEM_FLUFFY_TAIL) + { + gBattlescriptCurrInstr = gBattlescriptsForRunningByItem[0]; + } + else if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + { + gBattlescriptCurrInstr = gUnknown_082DBD3C[0]; + } + else + { + gBattleScripting.bank = gBankAttacker; + + switch (*(gBattleStruct->AI_itemType + (gBankAttacker >> 1))) + { + case AI_ITEM_FULL_RESTORE: + case AI_ITEM_HEAL_HP: + break; + case AI_ITEM_CURE_CONDITION: + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + if (*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) & 1) + { + if (*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) & 0x3E) + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + while (!(*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) & 1)) + { + *(gBattleStruct->AI_itemFlags + gBankAttacker / 2) >>= 1; + gBattleCommunication[MULTISTRING_CHOOSER]++; + } + } + break; + case AI_ITEM_X_STAT: + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + if (*(gBattleStruct->AI_itemFlags + (gBankAttacker >> 1)) & 0x80) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK) + PREPARE_STRING_BUFFER(gBattleTextBuff2, 0xD2) + + while (!((*(gBattleStruct->AI_itemFlags + (gBankAttacker >> 1))) & 1)) + { + *(gBattleStruct->AI_itemFlags + gBankAttacker / 2) >>= 1; + gBattleTextBuff1[2]++; + } + + gBattleScripting.animArg1 = gBattleTextBuff1[2] + 14; + gBattleScripting.animArg2 = 0; + } + break; + case AI_ITEM_GUARD_SPECS: + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + break; + } + + gBattlescriptCurrInstr = gUnknown_082DBD3C[*(gBattleStruct->AI_itemType + gBankAttacker / 2)]; + } + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; +} + +bool8 TryRunFromBattle(u8 bank) +{ + bool8 effect = FALSE; + u8 holdEffect; + u8 pyramidMultiplier; + u8 speedVar; + + if (gBattleMons[bank].item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[bank].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(gBattleMons[bank].item); + + gStringBank = bank; + + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + { + gLastUsedItem = gBattleMons[bank].item ; + gProtectStructs[bank].fleeFlag = 1; + effect++; + } + else if (gBattleMons[bank].ability == ABILITY_RUN_AWAY) + { + if (InBattlePyramid()) + { + gBattleStruct->runTries++; + pyramidMultiplier = sub_81A9E28(); + speedVar = (gBattleMons[bank].speed * pyramidMultiplier) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + { + gLastUsedAbility = ABILITY_RUN_AWAY; + gProtectStructs[bank].fleeFlag = 2; + effect++; + } + } + else + { + gLastUsedAbility = ABILITY_RUN_AWAY; + gProtectStructs[bank].fleeFlag = 2; + effect++; + } + } + else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_x4000000) && gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + effect++; + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + if (InBattlePyramid()) + { + pyramidMultiplier = sub_81A9E28(); + speedVar = (gBattleMons[bank].speed * pyramidMultiplier) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + effect++; + } + else if (gBattleMons[bank].speed < gBattleMons[bank ^ BIT_SIDE].speed) + { + speedVar = (gBattleMons[bank].speed * 128) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + effect++; + } + else // same speed or faster + { + effect++; + } + } + + gBattleStruct->runTries++; + } + + if (effect) + { + gCurrentTurnActionNumber = gNoOfAllBanks; + gBattleOutcome = BATTLE_RAN; + } + + return effect; +} + +static void HandleAction_Run(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + gCurrentTurnActionNumber = gNoOfAllBanks; + + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + if (gActionForBanks[gActiveBank] == ACTION_RUN) + gBattleOutcome |= BATTLE_LOST; + } + else + { + if (gActionForBanks[gActiveBank] == ACTION_RUN) + gBattleOutcome |= BATTLE_WON; + } + } + + gBattleOutcome |= BATTLE_OUTCOME_BIT_x80; + gSaveBlock2Ptr->field_CA9_b = 1; + } + else + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + { + if (!TryRunFromBattle(gBankAttacker)) // failed to run away + { + ClearFuryCutterDestinyBondGrudge(gBankAttacker); + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; + } + } + else + { + if (gBattleMons[gBankAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; + } + else + { + gCurrentTurnActionNumber = gNoOfAllBanks; + gBattleOutcome = BATTLE_POKE_FLED; + } + } + } +} + +static void HandleAction_WatchesCarefully(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[0]; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; +} + +static void HandleAction_SafariZoneBallThrow(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gNumSafariBalls--; + gLastUsedItem = ITEM_SAFARI_BALL; + gBattlescriptCurrInstr = gBattlescriptsForBallThrow[ITEM_SAFARI_BALL]; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; +} + +static void HandleAction_ThrowPokeblock(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = gBattleBufferB[gBankAttacker][1] - 1; + gLastUsedItem = gBattleBufferB[gBankAttacker][2]; + + if (gBattleResults.field_1F < 0xFF) + gBattleResults.field_1F++; + if (gBattleStruct->field_7A < 3) + gBattleStruct->field_7A++; + if (gBattleStruct->field_7B > 1) + { + if (gBattleStruct->field_7B < sUnknown_0831BCE0[gBattleStruct->field_7A][gBattleCommunication[MULTISTRING_CHOOSER]]) + gBattleStruct->field_7B = 1; + else + gBattleStruct->field_7B -= sUnknown_0831BCE0[gBattleStruct->field_7A][gBattleCommunication[MULTISTRING_CHOOSER]]; + } + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[2]; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; +} + +static void HandleAction_GoNear(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + gBattleStruct->field_7C += sUnknown_0831BCEF[gBattleStruct->field_79]; + if (gBattleStruct->field_7C > 20) + gBattleStruct->field_7C = 20; + + gBattleStruct->field_7B +=sUnknown_0831BCF3[gBattleStruct->field_79]; + if (gBattleStruct->field_7B > 20) + gBattleStruct->field_7B = 20; + + if (gBattleStruct->field_79 < 3) + { + gBattleStruct->field_79++; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[1]; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; +} + +static void HandleAction_SafriZoneRun(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + PlaySE(SE_NIGERU); + gCurrentTurnActionNumber = gNoOfAllBanks; + gBattleOutcome = BATTLE_RAN; +} + +static void HandleAction_Action9(void) +{ + gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]) + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[3]; + gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT; + gActionsByTurnOrder[1] = ACTION_FINISHED; +} + +static void HandleAction_Action11(void) +{ + if (!sub_8041728()) + { + gBattleStruct->field_4D = 0; + gCurrentActionFuncId = ACTION_FINISHED; + } +} + +static void HandleAction_NothingIsFainted(void) +{ + gCurrentTurnActionNumber++; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR + | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000 + | HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_x8000000 | HITMARKER_x4000000); +} + +static void HandleAction_ActionFinished(void) +{ + *(gBattleStruct->field_5C + gBanksByTurnOrder[gCurrentTurnActionNumber]) = 6; + gCurrentTurnActionNumber++; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + SpecialStatusesClear(); + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR + | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000 + | HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_x8000000 | HITMARKER_x4000000); + + gCurrentMove = 0; + gBattleMoveDamage = 0; + gBattleMoveFlags = 0; + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gUnknown_02024250[gBankAttacker] = 0; + gUnknown_02024258[gBankAttacker] = 0; + gBattleStruct->dynamicMoveType = 0; + gDynamicBasePower = 0; + gBattleScripting.atk49_state = 0; + gBattleCommunication[3] = 0; + gBattleCommunication[4] = 0; + gBattleScripting.field_16 = 0; + gBattleResources->battleScriptsStack->size = 0; +} diff --git a/src/battle_4.c b/src/battle_4.c deleted file mode 100644 index 92561251f..000000000 --- a/src/battle_4.c +++ /dev/null @@ -1,601 +0,0 @@ -#include "global.h" -#include "battle.h" -#include "battle_move_effects.h" -#include "moves.h" -#include "abilities.h" -#include "item.h" -#include "items.h" -#include "hold_effects.h" - -void atk00_attackcanceler(void); -void atk01_accuracycheck(void); -void atk02_attackstring(void); -void atk03_ppreduce(void); -void atk04_critcalc(void); -void atk05_damagecalc1(void); -void atk06_typecalc(void); -void atk07_dmg_adjustment(void); -void atk08_dmg_adjustment2(void); -void atk09_attackanimation(void); -void atk0A_waitanimation(void); -void atk0B_healthbarupdate(void); -void atk0C_datahpupdate(void); -void atk0D_critmessage(void); -void atk0E_effectiveness_sound(void); -void atk0F_resultmessage(void); -void atk10_printstring(void); -void atk11_printstring_playeronly(void); -void atk12_waitmessage(void); -void atk13_printfromtable(void); -void atk14_printfromtable_playeronly(void); -void atk15_seteffectwithchancetarget(void); -void atk16_seteffectprimary(void); -void atk17_seteffectsecondary(void); -void atk18_status_effect_clear(void); -void atk19_faint_pokemon(void); -void atk1A_faint_animation(void); -void atk1B_faint_effects_clear(void); -void atk1C_jumpifstatus(void); -void atk1D_jumpifstatus2(void); -void atk1E_jumpifability(void); -void atk1F_jumpifsideaffecting(void); -void atk20_jumpifstat(void); -void atk21_jumpifstatus3(void); -void atk22_jumpiftype(void); -void atk23_getexp(void); -void atk24(void); -void atk25_move_values_cleanup(void); -void atk26_set_multihit(void); -void atk27_decrement_multihit(void); -void atk28_goto(void); -void atk29_jumpifbyte(void); -void atk2A_jumpifhalfword(void); -void atk2B_jumpifword(void); -void atk2C_jumpifarrayequal(void); -void atk2D_jumpifarraynotequal(void); -void atk2E_setbyte(void); -void atk2F_addbyte(void); -void atk30_subbyte(void); -void atk31_copyarray(void); -void atk32_copyarray_withindex(void); -void atk33_orbyte(void); -void atk34_orhalfword(void); -void atk35_orword(void); -void atk36_bicbyte(void); -void atk37_bichalfword(void); -void atk38_bicword(void); -void atk39_pause(void); -void atk3A_waitstate(void); -void atk3B_healthbar_update(void); -void atk3C_return(void); -void atk3D_end(void); -void atk3E_end2(void); -void atk3F_end3(void); -void atk40_jump_if_move_affected_by_protect(void); -void atk41_call(void); -void atk42_jumpiftype2(void); -void atk43_jumpifabilitypresent(void); -void atk44(void); -void atk45_playanimation(void); -void atk46_playanimation2(void); -void atk47_setgraphicalstatchangevalues(void); -void atk48_playstatchangeanimation(void); -void atk49_moveendturn(void); -void atk4A_typecalc2(void); -void atk4B_return_atk_to_ball(void); -void atk4C_copy_poke_data(void); -void atk4D_switch_data_update(void); -void atk4E_switchin_anim(void); -void atk4F_jump_if_cannot_switch(void); -void atk50_openpartyscreen(void); -void atk51_switch_handle_order(void); -void atk52_switch_in_effects(void); -void atk53_trainer_slide(void); -void atk54_effectiveness_sound(void); -void atk55_play_sound(void); -void atk56_fainting_cry(void); -void atk57(void); -void atk58_return_to_ball(void); -void atk59_learnmove_inbattle(void); -void atk5A(void); -void atk5B_80256E0(void); -void atk5C_hitanimation(void); -void atk5D_getmoneyreward(void); -void atk5E_8025A70(void); -void atk5F_8025B24(void); -void atk60_increment_gamestat(void); -void atk61_8025BA4(void); -void atk62_08025C6C(void); -void atk63_jumptorandomattack(void); -void atk64_statusanimation(void); -void atk65_status2animation(void); -void atk66_chosenstatusanimation(void); -void atk67_8025ECC(void); -void atk68_80246A0(void); -void atk69_dmg_adjustment2(void); -void atk6A_removeitem(void); -void atk6B_atknameinbuff1(void); -void atk6C_lvlbox_display(void); -void atk6D_set_sentpokes_values(void); -void atk6E_set_atk_to_player0(void); -void atk6F_set_visible(void); -void atk70_record_ability(void); -void atk71_buffer_move_to_learn(void); -void atk72_jump_if_can_run_frombattle(void); -void atk73_hp_thresholds(void); -void atk74_hp_thresholds2(void); -void atk75_8026A58(void); -void atk76_various(void); -void atk77_setprotect(void); -void atk78_faintifabilitynotdamp(void); -void atk79_setatkhptozero(void); -void atk7A_jumpwhiletargetvalid(void); -void atk7B_healhalfHP_if_possible(void); -void atk7C_8025508(void); -void atk7D_set_rain(void); -void atk7E_setreflect(void); -void atk7F_setseeded(void); -void atk80_manipulatedamage(void); -void atk81_setrest(void); -void atk82_jumpifnotfirstturn(void); -void atk83_nop(void); -void atk84_jump_if_cant_sleep(void); -void atk85_stockpile(void); -void atk86_stockpiletobasedamage(void); -void atk87_stockpiletohpheal(void); -void atk88_negativedamage(void); -void atk89_statbuffchange(void); -void atk8A_normalisebuffs(void); -void atk8B_setbide(void); -void atk8C_confuseifrepeatingattackends(void); -void atk8D_setmultihit_counter(void); -void atk8E_prepare_multihit(void); -void atk8F_forcerandomswitch(void); -void atk90_conversion_type_change(void); -void atk91_givepaydaymoney(void); -void atk92_setlightscreen(void); -void atk93_ko_move(void); -void atk94_gethalfcurrentenemyhp(void); -void atk95_setsandstorm(void); -void atk96_weatherdamage(void); -void atk97_try_infatuation(void); -void atk98_status_icon_update(void); -void atk99_setmist(void); -void atk9A_set_focusenergy(void); -void atk9B_transformdataexecution(void); -void atk9C_set_substitute(void); -void atk9D_copyattack(void); -void atk9E_metronome(void); -void atk9F_dmgtolevel(void); -void atkA0_psywavedamageeffect(void); -void atkA1_counterdamagecalculator(void); -void atkA2_mirrorcoatdamagecalculator(void); -void atkA3_disablelastusedattack(void); -void atkA4_setencore(void); -void atkA5_painsplitdmgcalc(void); -void atkA6_settypetorandomresistance(void); -void atkA7_setalwayshitflag(void); -void atkA8_copymovepermanently(void); -void atkA9_sleeptalk_choose_move(void); -void atkAA_set_destinybond(void); -void atkAB_DestinyBondFlagUpdate(void); -void atkAC_remaininghptopower(void); -void atkAD_spite_ppreduce(void); -void atkAE_heal_party_status(void); -void atkAF_cursetarget(void); -void atkB0_set_spikes(void); -void atkB1_set_foresight(void); -void atkB2_setperishsong(void); -void atkB3_rolloutdamagecalculation(void); -void atkB4_jumpifconfusedandstatmaxed(void); -void atkB5_furycuttercalc(void); -void atkB6_happinesstodamagecalculation(void); -void atkB7_presentdamagecalculation(void); -void atkB8_set_safeguard(void); -void atkB9_magnitudedamagecalculation(void); -void atkBA_jumpifnopursuitswitchdmg(void); -void atkBB_setsunny(void); -void atkBC_maxattackhalvehp(void); -void atkBD_copyfoestats(void); -void atkBE_breakfree(void); -void atkBF_set_defense_curl(void); -void atkC0_recoverbasedonsunlight(void); -void atkC1_hidden_power(void); -void atkC2_selectnexttarget(void); -void atkC3_setfutureattack(void); -void atkC4_beat_up(void); -void atkC5_hidepreattack(void); -void atkC6_unhidepostattack(void); -void atkC7_setminimize(void); -void atkC8_sethail(void); -void atkC9_jumpifattackandspecialattackcannotfall(void); -void atkCA_setforcedtarget(void); -void atkCB_setcharge(void); -void atkCC_callterrainattack(void); -void atkCD_cureifburnedparalysedorpoisoned(void); -void atkCE_settorment(void); -void atkCF_jumpifnodamage(void); -void atkD0_settaunt(void); -void atkD1_set_helpinghand(void); -void atkD2_swap_items(void); -void atkD3_copy_ability(void); -void atkD4_wish_effect(void); -void atkD5_setroots(void); -void atkD6_doubledamagedealtifdamaged(void); -void atkD7_setyawn(void); -void atkD8_setdamagetohealthdifference(void); -void atkD9_scaledamagebyhealthratio(void); -void atkDA_abilityswap(void); -void atkDB_imprisoneffect(void); -void atkDC_setgrudge(void); -void atkDD_weightdamagecalculation(void); -void atkDE_asistattackselect(void); -void atkDF_setmagiccoat(void); -void atkE0_setstealstatchange(void); -void atkE1_intimidate_string_loader(void); -void atkE2_switchout_abilities(void); -void atkE3_jumpiffainted(void); -void atkE4_getsecretpowereffect(void); -void atkE5_pickup(void); -void atkE6_castform_change_animation(void); -void atkE7_castform_data_change(void); -void atkE8_settypebasedhalvers(void); -void atkE9_setweatherballtype(void); -void atkEA_recycleitem(void); -void atkEB_settypetoterrain(void); -void atkEC_pursuit_sth(void); -void atkED_802B4B4(void); -void atkEE_removelightscreenreflect(void); -void atkEF_pokeball_catch_calculation(void); -void atkF0_copy_caught_poke(void); -void atkF1_setpoke_as_caught(void); -void atkF2_display_dex_info(void); -void atkF3_nickname_caught_poke(void); -void atkF4_802BEF0(void); -void atkF5_removeattackerstatus1(void); -void atkF6_802BF48(void); -void atkF7_802BF54(void); -void sub_8056EF8(void); - -void (* const gBattleScriptingCommandsTable[])(void) = -{ - atk00_attackcanceler, - atk01_accuracycheck, - atk02_attackstring, - atk03_ppreduce, - atk04_critcalc, - atk05_damagecalc1, - atk06_typecalc, - atk07_dmg_adjustment, - atk08_dmg_adjustment2, - atk09_attackanimation, - atk0A_waitanimation, - atk0B_healthbarupdate, - atk0C_datahpupdate, - atk0D_critmessage, - atk0E_effectiveness_sound, - atk0F_resultmessage, - atk10_printstring, - atk11_printstring_playeronly, - atk12_waitmessage, - atk13_printfromtable, - atk14_printfromtable_playeronly, - atk15_seteffectwithchancetarget, - atk16_seteffectprimary, - atk17_seteffectsecondary, - atk18_status_effect_clear, - atk19_faint_pokemon, - atk1A_faint_animation, - atk1B_faint_effects_clear, - atk1C_jumpifstatus, - atk1D_jumpifstatus2, - atk1E_jumpifability, - atk1F_jumpifsideaffecting, - atk20_jumpifstat, - atk21_jumpifstatus3, - atk22_jumpiftype, - atk23_getexp, - atk24, - atk25_move_values_cleanup, - atk26_set_multihit, - atk27_decrement_multihit, - atk28_goto, - atk29_jumpifbyte, - atk2A_jumpifhalfword, - atk2B_jumpifword, - atk2C_jumpifarrayequal, - atk2D_jumpifarraynotequal, - atk2E_setbyte, - atk2F_addbyte, - atk30_subbyte, - atk31_copyarray, - atk32_copyarray_withindex, - atk33_orbyte, - atk34_orhalfword, - atk35_orword, - atk36_bicbyte, - atk37_bichalfword, - atk38_bicword, - atk39_pause, - atk3A_waitstate, - atk3B_healthbar_update, - atk3C_return, - atk3D_end, - atk3E_end2, - atk3F_end3, - atk40_jump_if_move_affected_by_protect, - atk41_call, - atk42_jumpiftype2, - atk43_jumpifabilitypresent, - atk44, - atk45_playanimation, - atk46_playanimation2, - atk47_setgraphicalstatchangevalues, - atk48_playstatchangeanimation, - atk49_moveendturn, - atk4A_typecalc2, - atk4B_return_atk_to_ball, - atk4C_copy_poke_data, - atk4D_switch_data_update, - atk4E_switchin_anim, - atk4F_jump_if_cannot_switch, - atk50_openpartyscreen, - atk51_switch_handle_order, - atk52_switch_in_effects, - atk53_trainer_slide, - atk54_effectiveness_sound, - atk55_play_sound, - atk56_fainting_cry, - atk57, - atk58_return_to_ball, - atk59_learnmove_inbattle, - atk5A, - atk5B_80256E0, - atk5C_hitanimation, - atk5D_getmoneyreward, - atk5E_8025A70, - atk5F_8025B24, - atk60_increment_gamestat, - atk61_8025BA4, - atk62_08025C6C, - atk63_jumptorandomattack, - atk64_statusanimation, - atk65_status2animation, - atk66_chosenstatusanimation, - atk67_8025ECC, - atk68_80246A0, - atk69_dmg_adjustment2, - atk6A_removeitem, - atk6B_atknameinbuff1, - atk6C_lvlbox_display, - atk6D_set_sentpokes_values, - atk6E_set_atk_to_player0, - atk6F_set_visible, - atk70_record_ability, - atk71_buffer_move_to_learn, - atk72_jump_if_can_run_frombattle, - atk73_hp_thresholds, - atk74_hp_thresholds2, - atk75_8026A58, - atk76_various, - atk77_setprotect, - atk78_faintifabilitynotdamp, - atk79_setatkhptozero, - atk7A_jumpwhiletargetvalid, - atk7B_healhalfHP_if_possible, - atk7C_8025508, - atk7D_set_rain, - atk7E_setreflect, - atk7F_setseeded, - atk80_manipulatedamage, - atk81_setrest, - atk82_jumpifnotfirstturn, - atk83_nop, - atk84_jump_if_cant_sleep, - atk85_stockpile, - atk86_stockpiletobasedamage, - atk87_stockpiletohpheal, - atk88_negativedamage, - atk89_statbuffchange, - atk8A_normalisebuffs, - atk8B_setbide, - atk8C_confuseifrepeatingattackends, - atk8D_setmultihit_counter, - atk8E_prepare_multihit, - atk8F_forcerandomswitch, - atk90_conversion_type_change, - atk91_givepaydaymoney, - atk92_setlightscreen, - atk93_ko_move, - atk94_gethalfcurrentenemyhp, - atk95_setsandstorm, - atk96_weatherdamage, - atk97_try_infatuation, - atk98_status_icon_update, - atk99_setmist, - atk9A_set_focusenergy, - atk9B_transformdataexecution, - atk9C_set_substitute, - atk9D_copyattack, - atk9E_metronome, - atk9F_dmgtolevel, - atkA0_psywavedamageeffect, - atkA1_counterdamagecalculator, - atkA2_mirrorcoatdamagecalculator, - atkA3_disablelastusedattack, - atkA4_setencore, - atkA5_painsplitdmgcalc, - atkA6_settypetorandomresistance, - atkA7_setalwayshitflag, - atkA8_copymovepermanently, - atkA9_sleeptalk_choose_move, - atkAA_set_destinybond, - atkAB_DestinyBondFlagUpdate, - atkAC_remaininghptopower, - atkAD_spite_ppreduce, - atkAE_heal_party_status, - atkAF_cursetarget, - atkB0_set_spikes, - atkB1_set_foresight, - atkB2_setperishsong, - atkB3_rolloutdamagecalculation, - atkB4_jumpifconfusedandstatmaxed, - atkB5_furycuttercalc, - atkB6_happinesstodamagecalculation, - atkB7_presentdamagecalculation, - atkB8_set_safeguard, - atkB9_magnitudedamagecalculation, - atkBA_jumpifnopursuitswitchdmg, - atkBB_setsunny, - atkBC_maxattackhalvehp, - atkBD_copyfoestats, - atkBE_breakfree, - atkBF_set_defense_curl, - atkC0_recoverbasedonsunlight, - atkC1_hidden_power, - atkC2_selectnexttarget, - atkC3_setfutureattack, - atkC4_beat_up, - atkC5_hidepreattack, - atkC6_unhidepostattack, - atkC7_setminimize, - atkC8_sethail, - atkC9_jumpifattackandspecialattackcannotfall, - atkCA_setforcedtarget, - atkCB_setcharge, - atkCC_callterrainattack, - atkCD_cureifburnedparalysedorpoisoned, - atkCE_settorment, - atkCF_jumpifnodamage, - atkD0_settaunt, - atkD1_set_helpinghand, - atkD2_swap_items, - atkD3_copy_ability, - atkD4_wish_effect, - atkD5_setroots, - atkD6_doubledamagedealtifdamaged, - atkD7_setyawn, - atkD8_setdamagetohealthdifference, - atkD9_scaledamagebyhealthratio, - atkDA_abilityswap, - atkDB_imprisoneffect, - atkDC_setgrudge, - atkDD_weightdamagecalculation, - atkDE_asistattackselect, - atkDF_setmagiccoat, - atkE0_setstealstatchange, - atkE1_intimidate_string_loader, - atkE2_switchout_abilities, - atkE3_jumpiffainted, - atkE4_getsecretpowereffect, - atkE5_pickup, - atkE6_castform_change_animation, - atkE7_castform_data_change, - atkE8_settypebasedhalvers, - atkE9_setweatherballtype, - atkEA_recycleitem, - atkEB_settypetoterrain, - atkEC_pursuit_sth, - atkED_802B4B4, - atkEE_removelightscreenreflect, - atkEF_pokeball_catch_calculation, - atkF0_copy_caught_poke, - atkF1_setpoke_as_caught, - atkF2_display_dex_info, - atkF3_nickname_caught_poke, - atkF4_802BEF0, - atkF5_removeattackerstatus1, - atkF6_802BF48, - atkF7_802BF54, - sub_8056EF8 -}; - -struct statFractions -{ - u8 dividend; - u8 divisor; -}; - -const struct statFractions gAccuracyStageRatios[] = -{ - { 33, 100}, // -6 - { 36, 100}, // -5 - { 43, 100}, // -4 - { 50, 100}, // -3 - { 60, 100}, // -2 - { 75, 100}, // -1 - { 1, 1}, // 0 - {133, 100}, // +1 - {166, 100}, // +2 - { 2, 1}, // +3 - {233, 100}, // +4 - {133, 50}, // +5 - { 3, 1}, // +6 -}; - -// The chance is 1/N for each stage. -const u16 gCriticalHitChance[] = {16, 8, 4, 3, 2}; - -const u32 gStatusFlagsForMoveEffects[] = -{ - 0x00000000, - 0x00000007, - 0x00000008, - 0x00000010, - 0x00000020, - 0x00000040, - 0x00000080, - 0x00000007, - 0x00000008, - 0x00000000, - 0x00000070, - 0x00000000, - 0x00001000, - 0x0000E000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00400000, - 0x00000000, - 0x00000000, - 0x04000000, - 0x08000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000C00, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000 -}; diff --git a/src/battle_ai.c b/src/battle_ai_script_commands.c index 3b696b84e..24377eacc 100644 --- a/src/battle_ai.c +++ b/src/battle_ai_script_commands.c @@ -1,5 +1,5 @@ #include "global.h" -#include "battle_ai.h" +#include "battle_ai_script_commands.h" #include "pokemon.h" #include "battle.h" #include "species.h" @@ -7,11 +7,13 @@ #include "rng.h" #include "item.h" #include "battle_move_effects.h" +#include "moves.h" +#include "util.h" #define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) #define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8) #define AIScriptRead8(ptr) ((ptr)[0]) -#define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr) +#define AIScriptReadPtr(ptr) (const u8*) AIScriptRead32(ptr) #define AI_ACTION_DONE 0x0001 #define AI_ACTION_FLEE 0x0002 @@ -52,16 +54,16 @@ AI scripts. extern u32 gBattleTypeFlags; extern u8 gActiveBank; -extern struct BattlePokemon gBattleMons[4]; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; extern u16 gCurrentMove; extern u8 gBankTarget; extern u8 gAbsentBankFlags; -extern u16 gLastUsedMovesByBanks[4]; +extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; extern u16 gTrainerBattleOpponent_A; extern u16 gTrainerBattleOpponent_B; -extern u32 gStatuses3[4]; +extern u32 gStatuses3[BATTLE_BANKS_COUNT]; extern u16 gSideAffecting[2]; -extern u16 gBattlePartyID[4]; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; extern u16 gDynamicBasePower; extern u8 gBattleMoveFlags; extern s32 gBattleMoveDamage; @@ -70,16 +72,8 @@ extern u16 gBattleWeather; extern const struct BattleMove gBattleMoves[]; extern const struct BaseStats gBaseStats[]; -extern const u32 gBitTable[]; -extern u8 * const gBattleAI_ScriptsTable[]; +extern const u8 * const gBattleAI_ScriptsTable[]; -extern u8 GetBankIdentity(u8); -extern u8 b_first_side(u8, u8, u8); -extern u8 GetBankByPlayerAI(u8); -extern void TypeCalc(u16 move, u8 bankAtk, u8 bankDef); -extern void AI_CalcDmg(u8, u8); - -extern u8 CheckMoveLimitations(); extern u32 GetAiScriptsInRecordedBattle(); extern u32 GetAiScriptsInBattleFactory(); @@ -119,8 +113,8 @@ static void BattleAICmd_if_move(void); static void BattleAICmd_if_not_move(void); static void BattleAICmd_if_in_bytes(void); static void BattleAICmd_if_not_in_bytes(void); -static void BattleAICmd_if_in_words(void); -static void BattleAICmd_if_not_in_words(void); +static void BattleAICmd_if_in_hwords(void); +static void BattleAICmd_if_not_in_hwords(void); static void BattleAICmd_if_user_can_damage(void); static void BattleAICmd_if_user_cant_damage(void); static void BattleAICmd_get_turn_count(void); @@ -230,8 +224,8 @@ static const BattleAICmdFunc sBattleAICmdTable[] = BattleAICmd_if_not_move, // 0x1A BattleAICmd_if_in_bytes, // 0x1B BattleAICmd_if_not_in_bytes, // 0x1C - BattleAICmd_if_in_words, // 0x1D - BattleAICmd_if_not_in_words, // 0x1E + BattleAICmd_if_in_hwords, // 0x1D + BattleAICmd_if_not_in_hwords, // 0x1E BattleAICmd_if_user_can_damage, // 0x1F BattleAICmd_if_user_cant_damage, // 0x20 BattleAICmd_get_turn_count, // 0x21 @@ -337,7 +331,7 @@ void BattleAI_HandleItemUseBeforeAISetup(u8 defaultScoreMoves) { if (gTrainers[gTrainerBattleOpponent_A].items[i] != 0) { - gBattleResources->battleHistory->TrainerItems[gBattleResources->battleHistory->itemsNo] = gTrainers[gTrainerBattleOpponent_A].items[i]; + gBattleResources->battleHistory->trainerItems[gBattleResources->battleHistory->itemsNo] = gTrainers[gTrainerBattleOpponent_A].items[i]; gBattleResources->battleHistory->itemsNo++; } } @@ -475,13 +469,11 @@ static u8 BattleAI_ChooseMoveOrAction_Singles(void) return consideredMoveArray[Random() % numOfBestMoves]; } -#ifdef NONMATCHING static u8 BattleAI_ChooseMoveOrAction_Doubles(void) { s32 i; s32 j; s32 scriptsToRun; - s16 mostMovePoints; s16 bestMovePointsForTarget[4]; s8 mostViableTargetsArray[4]; u8 actionOrMoveIndex[4]; @@ -489,27 +481,27 @@ static u8 BattleAI_ChooseMoveOrAction_Doubles(void) u8 mostViableMovesIndices[4]; s32 mostViableTargetsNo; s32 mostViableMovesNo; + s16 mostMovePoints; - for (i = 0; i < 4; i++) //08130D14 + for (i = 0; i < 4; i++) { if (i == sBank_AI || gBattleMons[i].hp == 0) { - //_08130D2E actionOrMoveIndex[i] = -1; bestMovePointsForTarget[i] = -1; } - //_08130D48 else { if (gBattleTypeFlags & BATTLE_TYPE_PALACE) BattleAI_SetupAIData(gBattleStruct->field_92 >> 4); else BattleAI_SetupAIData(0xF); - //_08130D76 + gBankTarget = i; - if ((i & 1) != (sBank_AI & 1)) + + if ((i & BIT_SIDE) != (sBank_AI & BIT_SIDE)) RecordLastUsedMoveByTarget(); - //_08130D90 + AI_THINKING_STRUCT->aiLogicId = 0; AI_THINKING_STRUCT->movesetIndex = 0; scriptsToRun = AI_THINKING_STRUCT->aiFlags; @@ -524,14 +516,12 @@ static u8 BattleAI_ChooseMoveOrAction_Doubles(void) AI_THINKING_STRUCT->aiLogicId++; AI_THINKING_STRUCT->movesetIndex = 0; } - //_08130DD8 if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) actionOrMoveIndex[i] = 4; else if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) actionOrMoveIndex[i] = 5; else { - //_08130E10 mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; mostViableMovesIndices[0] = 0; mostViableMovesNo = 1; @@ -558,17 +548,20 @@ static u8 BattleAI_ChooseMoveOrAction_Doubles(void) bestMovePointsForTarget[i] = mostViableMovesScores[0]; // don't use a move against ally if it has less than 100 pts - if (i == (sBank_AI ^ 2) && bestMovePointsForTarget[i] < 100) + if (i == (sBank_AI ^ BIT_MON) && bestMovePointsForTarget[i] < 100) + { bestMovePointsForTarget[i] = -1; + mostViableMovesScores[0] = mostViableMovesScores[0]; // needed to match + } + } } - //_08130EAE } - //08130EC4 mostMovePoints = bestMovePointsForTarget[0]; mostViableTargetsArray[0] = 0; mostViableTargetsNo = 1; + for (i = 1; i < 4; i++) { //_08130EDA @@ -585,305 +578,10 @@ static u8 BattleAI_ChooseMoveOrAction_Doubles(void) mostViableTargetsNo = 1; } } + gBankTarget = mostViableTargetsArray[Random() % mostViableTargetsNo]; return actionOrMoveIndex[gBankTarget]; } -#else -__attribute__((naked)) -static u8 BattleAI_ChooseMoveOrAction_Doubles(void) -{ - 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, 0x24\n\ - movs r0, 0\n\ - mov r8, r0\n\ - mov r1, sp\n\ - adds r1, 0xC\n\ - str r1, [sp, 0x1C]\n\ - mov r2, sp\n\ - adds r2, 0x8\n\ - str r2, [sp, 0x18]\n\ - str r1, [sp, 0x20]\n\ - mov r10, sp\n\ -_08130D14:\n\ - ldr r0, =sBank_AI\n\ - ldrb r0, [r0]\n\ - cmp r8, r0\n\ - beq _08130D2E\n\ - movs r0, 0x58\n\ - mov r7, r8\n\ - muls r7, r0\n\ - adds r0, r7, 0\n\ - ldr r1, =gBattleMons\n\ - adds r0, r1\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _08130D48\n\ -_08130D2E:\n\ - movs r0, 0xFF\n\ - ldr r2, [sp, 0x20]\n\ - strb r0, [r2]\n\ - ldr r0, =0x0000ffff\n\ - mov r7, r10\n\ - strh r0, [r7]\n\ - b _08130EAE\n\ - .pool\n\ -_08130D48:\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 10\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08130D70\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - adds r0, 0x92\n\ - ldrb r0, [r0]\n\ - lsrs r0, 4\n\ - bl BattleAI_SetupAIData\n\ - b _08130D76\n\ - .pool\n\ -_08130D70:\n\ - movs r0, 0xF\n\ - bl BattleAI_SetupAIData\n\ -_08130D76:\n\ - ldr r0, =gBankTarget\n\ - mov r1, r8\n\ - strb r1, [r0]\n\ - movs r1, 0x1\n\ - mov r2, r8\n\ - ands r2, r1\n\ - ldr r0, =sBank_AI\n\ - ldrb r0, [r0]\n\ - ands r1, r0\n\ - cmp r2, r1\n\ - beq _08130D90\n\ - bl RecordLastUsedMoveByTarget\n\ -_08130D90:\n\ - ldr r2, =gBattleResources\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - movs r1, 0\n\ - strb r1, [r0, 0x11]\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - strb r1, [r0, 0x1]\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldr r4, [r0, 0xC]\n\ - mov r9, r2\n\ - cmp r4, 0\n\ - beq _08130DD8\n\ - mov r5, r9\n\ - movs r6, 0\n\ -_08130DB0:\n\ - movs r0, 0x1\n\ - ands r0, r4\n\ - cmp r0, 0\n\ - beq _08130DC2\n\ - ldr r0, [r5]\n\ - ldr r0, [r0, 0x14]\n\ - strb r6, [r0]\n\ - bl BattleAI_DoAIProcessing\n\ -_08130DC2:\n\ - asrs r4, 1\n\ - ldr r0, [r5]\n\ - ldr r1, [r0, 0x14]\n\ - ldrb r0, [r1, 0x11]\n\ - adds r0, 0x1\n\ - strb r0, [r1, 0x11]\n\ - ldr r0, [r5]\n\ - ldr r0, [r0, 0x14]\n\ - strb r6, [r0, 0x1]\n\ - cmp r4, 0\n\ - bne _08130DB0\n\ -_08130DD8:\n\ - mov r2, r9\n\ - ldr r0, [r2]\n\ - ldr r3, [r0, 0x14]\n\ - ldrb r1, [r3, 0x10]\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08130DFC\n\ - movs r0, 0x4\n\ - ldr r7, [sp, 0x20]\n\ - strb r0, [r7]\n\ - b _08130EAE\n\ - .pool\n\ -_08130DFC:\n\ - movs r0, 0x4\n\ - ands r0, r1\n\ - lsls r0, 24\n\ - lsrs r2, r0, 24\n\ - cmp r2, 0\n\ - beq _08130E10\n\ - movs r0, 0x5\n\ - ldr r1, [sp, 0x20]\n\ - strb r0, [r1]\n\ - b _08130EAE\n\ -_08130E10:\n\ - add r1, sp, 0x10\n\ - ldrb r0, [r3, 0x4]\n\ - strb r0, [r1]\n\ - add r0, sp, 0x14\n\ - strb r2, [r0]\n\ - movs r5, 0x1\n\ - movs r3, 0x1\n\ - adds r6, r1, 0\n\ - ldr r0, =sBank_AI\n\ - ldrb r1, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - ldr r2, =gBattleMons + 0xC\n\ - adds r0, r2\n\ - adds r4, r0, 0x2\n\ - add r7, sp, 0x14\n\ -_08130E30:\n\ - ldrh r0, [r4]\n\ - cmp r0, 0\n\ - beq _08130E72\n\ - ldrb r1, [r6]\n\ - mov r2, r9\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - adds r0, 0x4\n\ - adds r2, r0, r3\n\ - movs r0, 0\n\ - ldrsb r0, [r2, r0]\n\ - cmp r1, r0\n\ - bne _08130E56\n\ - adds r0, r6, r5\n\ - ldrb r1, [r2]\n\ - strb r1, [r0]\n\ - adds r0, r7, r5\n\ - strb r3, [r0]\n\ - adds r5, 0x1\n\ -_08130E56:\n\ - ldrb r1, [r6]\n\ - mov r2, r9\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - adds r0, 0x4\n\ - adds r2, r0, r3\n\ - movs r0, 0\n\ - ldrsb r0, [r2, r0]\n\ - cmp r1, r0\n\ - bge _08130E72\n\ - ldrb r0, [r2]\n\ - strb r0, [r6]\n\ - strb r3, [r7]\n\ - movs r5, 0x1\n\ -_08130E72:\n\ - adds r4, 0x2\n\ - adds r3, 0x1\n\ - cmp r3, 0x3\n\ - ble _08130E30\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - adds r1, r5, 0\n\ - bl __modsi3\n\ - add r0, sp\n\ - adds r0, 0x14\n\ - ldrb r0, [r0]\n\ - ldr r7, [sp, 0x20]\n\ - strb r0, [r7]\n\ - ldrb r2, [r6]\n\ - mov r0, r10\n\ - strh r2, [r0]\n\ - ldr r0, =sBank_AI\n\ - ldrb r1, [r0]\n\ - movs r0, 0x2\n\ - eors r0, r1\n\ - cmp r8, r0\n\ - bne _08130EAE\n\ - cmp r2, 0x63\n\ - bgt _08130EAE\n\ - ldr r0, =0x0000ffff\n\ - mov r1, r10\n\ - strh r0, [r1]\n\ -_08130EAE:\n\ - ldr r2, [sp, 0x20]\n\ - adds r2, 0x1\n\ - str r2, [sp, 0x20]\n\ - movs r7, 0x2\n\ - add r10, r7\n\ - movs r0, 0x1\n\ - add r8, r0\n\ - mov r1, r8\n\ - cmp r1, 0x3\n\ - bgt _08130EC4\n\ - b _08130D14\n\ -_08130EC4:\n\ - mov r0, sp\n\ - ldrh r5, [r0]\n\ - movs r0, 0\n\ - ldr r2, [sp, 0x18]\n\ - strb r0, [r2]\n\ - movs r4, 0x1\n\ - mov r8, r4\n\ - ldr r6, =gBankTarget\n\ - ldr r3, [sp, 0x18]\n\ - mov r1, sp\n\ - adds r1, 0x2\n\ -_08130EDA:\n\ - lsls r0, r5, 16\n\ - asrs r2, r0, 16\n\ - movs r7, 0\n\ - ldrsh r0, [r1, r7]\n\ - cmp r2, r0\n\ - bne _08130EEE\n\ - adds r0, r3, r4\n\ - mov r7, r8\n\ - strb r7, [r0]\n\ - adds r4, 0x1\n\ -_08130EEE:\n\ - movs r7, 0\n\ - ldrsh r0, [r1, r7]\n\ - cmp r2, r0\n\ - bge _08130EFE\n\ - ldrh r5, [r1]\n\ - mov r0, r8\n\ - strb r0, [r3]\n\ - movs r4, 0x1\n\ -_08130EFE:\n\ - adds r1, 0x2\n\ - movs r2, 0x1\n\ - add r8, r2\n\ - mov r7, r8\n\ - cmp r7, 0x3\n\ - ble _08130EDA\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - adds r1, r4, 0\n\ - bl __modsi3\n\ - ldr r1, [sp, 0x18]\n\ - adds r0, r1, r0\n\ - ldrb r0, [r0]\n\ - strb r0, [r6]\n\ - ldrb r0, [r6]\n\ - ldr r2, [sp, 0x1C]\n\ - adds r0, r2, r0\n\ - ldrb r0, [r0]\n\ - add sp, 0x24\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r1}\n\ - bx r1\n\ - .pool\n\ - .syntax divided\n"); -} -#endif static void BattleAI_DoAIProcessing(void) { @@ -891,7 +589,7 @@ static void BattleAI_DoAIProcessing(void) { switch (AI_THINKING_STRUCT->aiState) { - case AIState_DoNotProcess: //Needed to match. + case AIState_DoNotProcess: // Needed to match. break; case AIState_SettingUp: gAIScriptPtr = gBattleAI_ScriptsTable[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID. @@ -907,7 +605,7 @@ static void BattleAI_DoAIProcessing(void) break; case AIState_Processing: if (AI_THINKING_STRUCT->moveConsidered != 0) - sBattleAICmdTable[*gAIScriptPtr](); // run AI command. + sBattleAICmdTable[*gAIScriptPtr](); // Run AI command. else { AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; @@ -937,7 +635,7 @@ static void RecordLastUsedMoveByTarget(void) { if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) break; - if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] != gLastUsedMovesByBanks[gBankTarget] //HACK: This redundant condition is a hack to make the asm match. + if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] != gLastUsedMovesByBanks[gBankTarget] // HACK: This redundant condition is a hack to make the asm match. && gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == 0) { gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] = gLastUsedMovesByBanks[gBankTarget]; @@ -1264,7 +962,7 @@ static void BattleAICmd_if_not_equal(void) static void BattleAICmd_if_less_than_32(void) { - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + const u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); if (AI_THINKING_STRUCT->funcResult < *temp) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); @@ -1274,7 +972,7 @@ static void BattleAICmd_if_less_than_32(void) static void BattleAICmd_if_more_than_32(void) { - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + const u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); if (AI_THINKING_STRUCT->funcResult > *temp) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); @@ -1284,7 +982,7 @@ static void BattleAICmd_if_more_than_32(void) static void BattleAICmd_if_equal_32(void) { - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + const u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); if (AI_THINKING_STRUCT->funcResult == *temp) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); @@ -1294,7 +992,7 @@ static void BattleAICmd_if_equal_32(void) static void BattleAICmd_if_not_equal_32(void) { - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + const u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); if (AI_THINKING_STRUCT->funcResult != *temp) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); @@ -1324,7 +1022,7 @@ static void BattleAICmd_if_not_move(void) static void BattleAICmd_if_in_bytes(void) { - u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); + const u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); while (*ptr != 0xFF) { @@ -1340,7 +1038,7 @@ static void BattleAICmd_if_in_bytes(void) static void BattleAICmd_if_not_in_bytes(void) { - u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); + const u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); while (*ptr != 0xFF) { @@ -1354,9 +1052,9 @@ static void BattleAICmd_if_not_in_bytes(void) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); } -static void BattleAICmd_if_in_words(void) +static void BattleAICmd_if_in_hwords(void) { - u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); + const u16 *ptr = (const u16 *)AIScriptReadPtr(gAIScriptPtr + 1); while (*ptr != 0xFFFF) { @@ -1370,9 +1068,9 @@ static void BattleAICmd_if_in_words(void) gAIScriptPtr += 9; } -static void BattleAICmd_if_not_in_words(void) +static void BattleAICmd_if_not_in_hwords(void) { - u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); + const u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); while (*ptr != 0xFFFF) { @@ -1459,9 +1157,9 @@ static u8 BattleAI_GetWantedBank(u8 index) default: return gBankTarget; case AI_USER_PARTNER: - return sBank_AI ^ 2; + return sBank_AI ^ BIT_MON; case AI_TARGET_PARTNER: - return gBankTarget ^ 2; + return gBankTarget ^ BIT_MON; } } @@ -1487,248 +1185,68 @@ static void BattleAICmd_get_last_used_bank_move_power(void) gAIScriptPtr += 1; } -__attribute__((naked)) // not even going to try. if it doesnt match in ruby, it wont match in emerald (yet). static void BattleAICmd_is_most_powerful_move(void) { - 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, 0x14\n\ - movs r3, 0\n\ - ldr r0, =sDiscouragedPowerfulMoveEffects\n\ - ldrh r1, [r0]\n\ - ldr r5, =0x0000ffff\n\ - ldr r6, =gBattleMoves\n\ - ldr r2, =gBattleResources\n\ - cmp r1, r5\n\ - beq _08131F86\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldrh r1, [r0, 0x2]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r6\n\ - ldrb r4, [r0]\n\ - ldr r1, =sDiscouragedPowerfulMoveEffects\n\ -_08131F76:\n\ - ldrh r0, [r1]\n\ - cmp r4, r0\n\ - beq _08131F86\n\ - adds r1, 0x2\n\ - adds r3, 0x1\n\ - ldrh r0, [r1]\n\ - cmp r0, r5\n\ - bne _08131F76\n\ -_08131F86:\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldrh r1, [r0, 0x2]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r6\n\ - ldrb r0, [r0, 0x1]\n\ - cmp r0, 0x1\n\ - bhi _08131F9C\n\ - b _08132126\n\ -_08131F9C:\n\ - lsls r0, r3, 1\n\ - ldr r1, =sDiscouragedPowerfulMoveEffects\n\ - adds r0, r1\n\ - ldrh r3, [r0]\n\ - ldr r0, =0x0000ffff\n\ - cmp r3, r0\n\ - beq _08131FAC\n\ - b _08132126\n\ -_08131FAC:\n\ - ldr r0, =gDynamicBasePower\n\ - movs r1, 0\n\ - strh r1, [r0]\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - strb r1, [r0, 0x13]\n\ - ldr r0, =gBattleScripting\n\ - movs r2, 0x1\n\ - strb r2, [r0, 0xE]\n\ - ldr r0, =gBattleMoveFlags\n\ - strb r1, [r0]\n\ - ldr r0, =gCritMultiplier\n\ - strb r2, [r0]\n\ - movs r6, 0\n\ - mov r9, r3\n\ - ldr r2, =sDiscouragedPowerfulMoveEffects\n\ - ldrh r2, [r2]\n\ - str r2, [sp, 0x10]\n\ -_08131FD0:\n\ - movs r3, 0\n\ - ldr r5, =gBattleMons\n\ - lsls r4, r6, 1\n\ - ldr r7, =sBank_AI\n\ - lsls r0, r6, 2\n\ - mov r8, r0\n\ - adds r1, r6, 0x1\n\ - mov r10, r1\n\ - ldr r2, [sp, 0x10]\n\ - cmp r2, r9\n\ - beq _08132014\n\ - ldr r2, =gBattleMoves\n\ - ldrb r1, [r7]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - adds r0, r4, r0\n\ - adds r1, r5, 0\n\ - adds r1, 0xC\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r2\n\ - ldrb r2, [r0]\n\ - ldr r1, =sDiscouragedPowerfulMoveEffects\n\ -_08132004:\n\ - ldrh r0, [r1]\n\ - cmp r2, r0\n\ - beq _08132014\n\ - adds r1, 0x2\n\ - adds r3, 0x1\n\ - ldrh r0, [r1]\n\ - cmp r0, r9\n\ - bne _08132004\n\ -_08132014:\n\ - ldrb r1, [r7]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - adds r0, r4, r0\n\ - adds r1, r5, 0\n\ - adds r1, 0xC\n\ - adds r1, r0, r1\n\ - ldrh r0, [r1]\n\ - cmp r0, 0\n\ - beq _081320C0\n\ - lsls r0, r3, 1\n\ - ldr r2, =sDiscouragedPowerfulMoveEffects\n\ - adds r0, r2\n\ - ldrh r0, [r0]\n\ - cmp r0, r9\n\ - bne _081320C0\n\ - ldr r0, =gBattleMoves\n\ - ldrh r2, [r1]\n\ - lsls r1, r2, 1\n\ - adds r1, r2\n\ - lsls r1, 2\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - cmp r0, 0x1\n\ - bls _081320C0\n\ - ldr r5, =gCurrentMove\n\ - strh r2, [r5]\n\ - ldrb r0, [r7]\n\ - ldr r4, =gBankTarget\n\ - ldrb r1, [r4]\n\ - bl AI_CalcDmg\n\ - ldrh r0, [r5]\n\ - ldrb r1, [r7]\n\ - ldrb r2, [r4]\n\ - bl TypeCalc\n\ - mov r4, sp\n\ - add r4, r8\n\ - ldr r2, =gBattleMoveDamage\n\ - ldr r0, =gBattleResources\n\ - ldr r0, [r0]\n\ - ldr r0, [r0, 0x14]\n\ - adds r0, 0x18\n\ - adds r0, r6\n\ - ldrb r1, [r0]\n\ - ldr r0, [r2]\n\ - muls r0, r1\n\ - movs r1, 0x64\n\ - bl __divsi3\n\ - str r0, [r4]\n\ - cmp r0, 0\n\ - bne _081320C8\n\ - movs r0, 0x1\n\ - str r0, [r4]\n\ - b _081320C8\n\ - .pool\n\ -_081320C0:\n\ - mov r1, sp\n\ - add r1, r8\n\ - movs r0, 0\n\ - str r0, [r1]\n\ -_081320C8:\n\ - mov r6, r10\n\ - cmp r6, 0x3\n\ - bgt _081320D0\n\ - b _08131FD0\n\ -_081320D0:\n\ - movs r6, 0\n\ - ldr r2, =gBattleResources\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldrb r0, [r0, 0x1]\n\ - lsls r0, 2\n\ - add r0, sp\n\ - ldr r1, [sp]\n\ - ldr r0, [r0]\n\ - ldr r5, =gAIScriptPtr\n\ - cmp r1, r0\n\ - bgt _08132106\n\ - adds r4, r2, 0\n\ - mov r3, sp\n\ -_081320EC:\n\ - adds r3, 0x4\n\ - adds r6, 0x1\n\ - cmp r6, 0x3\n\ - bgt _08132106\n\ - ldr r0, [r4]\n\ - ldr r0, [r0, 0x14]\n\ - ldrb r0, [r0, 0x1]\n\ - lsls r0, 2\n\ - add r0, sp\n\ - ldr r1, [r3]\n\ - ldr r0, [r0]\n\ - cmp r1, r0\n\ - ble _081320EC\n\ -_08132106:\n\ - cmp r6, 0x4\n\ - bne _0813211C\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x2\n\ - str r0, [r1, 0x8]\n\ - b _08132130\n\ - .pool\n\ -_0813211C:\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x1\n\ - str r0, [r1, 0x8]\n\ - b _08132130\n\ -_08132126:\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0\n\ - str r0, [r1, 0x8]\n\ - ldr r5, =gAIScriptPtr\n\ -_08132130:\n\ - ldr r0, [r5]\n\ - adds r0, 0x1\n\ - str r0, [r5]\n\ - add sp, 0x14\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\ - .pool\n\ - .syntax divided"); + s32 i, checkedMove; + s32 moveDmgs[4]; + + for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) + { + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == sDiscouragedPowerfulMoveEffects[i]) + break; + } + + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power > 1 + && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF) + { + gDynamicBasePower = 0; + *(&gBattleStruct->dynamicMoveType) = 0; + gBattleScripting.dmgMultiplier = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + + for (checkedMove = 0; checkedMove < 4; checkedMove++) + { + for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) + { + if (gBattleMoves[gBattleMons[sBank_AI].moves[checkedMove]].effect == sDiscouragedPowerfulMoveEffects[i]) + break; + } + + if (gBattleMons[sBank_AI].moves[checkedMove] != MOVE_NONE + && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF + && gBattleMoves[gBattleMons[sBank_AI].moves[checkedMove]].power > 1) + { + gCurrentMove = gBattleMons[sBank_AI].moves[checkedMove]; + AI_CalcDmg(sBank_AI, gBankTarget); + TypeCalc(gCurrentMove, sBank_AI, gBankTarget); + moveDmgs[checkedMove] = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[checkedMove] / 100; + if (moveDmgs[checkedMove] == 0) + moveDmgs[checkedMove] = 1; + } + else + { + moveDmgs[checkedMove] = 0; + } + } + + for (checkedMove = 0; checkedMove < 4; checkedMove++) + { + if (moveDmgs[checkedMove] > moveDmgs[AI_THINKING_STRUCT->movesetIndex]) + break; + } + + if (checkedMove == 4) + AI_THINKING_STRUCT->funcResult = 2; // is the most powerful + else + AI_THINKING_STRUCT->funcResult = 1; // not most powerful + } + else + { + AI_THINKING_STRUCT->funcResult = 0; // highly discouraged in terms of power + } + + gAIScriptPtr++; } static void BattleAICmd_get_last_used_bank_move(void) @@ -1759,7 +1277,7 @@ static void BattleAICmd_if_arg_not_equal(void) static void BattleAICmd_if_would_go_first(void) { - if (b_first_side(sBank_AI, gBankTarget, 1) == gAIScriptPtr[1]) + if (GetWhoStrikesFirst(sBank_AI, gBankTarget, TRUE) == gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; @@ -1767,7 +1285,7 @@ static void BattleAICmd_if_would_go_first(void) static void BattleAICmd_if_would_not_go_first(void) { - if (b_first_side(sBank_AI, gBankTarget, 1) != gAIScriptPtr[1]) + if (GetWhoStrikesFirst(sBank_AI, gBankTarget, TRUE) != gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; @@ -1795,7 +1313,7 @@ static void BattleAICmd_count_alive_pokemon(void) else index = gBankTarget; - if (GetBankSide(index) == 0) + if (GetBankSide(index) == SIDE_PLAYER) party = gPlayerParty; else party = gEnemyParty; @@ -1805,7 +1323,7 @@ static void BattleAICmd_count_alive_pokemon(void) u32 status; bankOnField1 = gBattlePartyID[index]; status = GetBankIdentity(index) ^ 2; - bankOnField2 = gBattlePartyID[GetBankByPlayerAI(status)]; + bankOnField2 = gBattlePartyID[GetBankByIdentity(status)]; } else // in singles there's only one bank by side { @@ -1899,11 +1417,10 @@ static void BattleAICmd_get_ability(void) gAIScriptPtr += 2; } -#ifdef NONMATCHING static void BattleAICmd_check_ability(void) { - u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); - u8 ability = gAIScriptPtr[2]; + u32 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); + u32 ability = gAIScriptPtr[2]; if (gAIScriptPtr[1] == AI_TARGET || gAIScriptPtr[1] == AI_TARGET_PARTNER) { @@ -1923,8 +1440,9 @@ static void BattleAICmd_check_ability(void) { if (gBaseStats[gBattleMons[bank].species].ability2 != ABILITY_NONE) { - if (gBaseStats[gBattleMons[bank].species].ability1 != ability - && gBaseStats[gBattleMons[bank].species].ability2 != ability) + u8 abilityDummyVariable = ability; // needed to match + if (gBaseStats[gBattleMons[bank].species].ability1 != abilityDummyVariable + && gBaseStats[gBattleMons[bank].species].ability2 != abilityDummyVariable) { ability = gBaseStats[gBattleMons[bank].species].ability1; } @@ -1960,137 +1478,6 @@ static void BattleAICmd_check_ability(void) } gAIScriptPtr += 3; } -#else -__attribute__((naked)) -static void BattleAICmd_check_ability(void) -{ - asm(".syntax unified\n\ - push {r4-r6,lr}\n\ - ldr r4, =gAIScriptPtr\n\ - ldr r0, [r4]\n\ - ldrb r0, [r0, 0x1]\n\ - bl BattleAI_GetWantedBank\n\ - lsls r0, 24\n\ - lsrs r5, r0, 24\n\ - ldr r0, [r4]\n\ - ldrb r3, [r0, 0x2]\n\ - ldrb r0, [r0, 0x1]\n\ - cmp r0, 0\n\ - beq _0813253A\n\ - cmp r0, 0x2\n\ - bne _081325BC\n\ -_0813253A:\n\ - ldr r0, =gBattleResources\n\ - ldr r4, [r0]\n\ - ldr r1, [r4, 0x18]\n\ - adds r1, 0x40\n\ - adds r2, r1, r5\n\ - ldrb r1, [r2]\n\ - adds r6, r0, 0\n\ - cmp r1, 0\n\ - beq _0813255C\n\ - adds r3, r1, 0\n\ - ldr r0, [r4, 0x14]\n\ - str r3, [r0, 0x8]\n\ - b _081325CA\n\ - .pool\n\ -_0813255C:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - muls r0, r5\n\ - adds r4, r0, r1\n\ - adds r0, r4, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0x17\n\ - beq _08132576\n\ - cmp r0, 0x2A\n\ - beq _08132576\n\ - cmp r0, 0x47\n\ - bne _08132588\n\ -_08132576:\n\ - movs r0, 0x58\n\ - muls r0, r5\n\ - adds r0, r1\n\ - adds r0, 0x20\n\ - ldrb r3, [r0]\n\ - b _081325CA\n\ - .pool\n\ -_08132588:\n\ - ldr r2, =gBaseStats\n\ - ldrh r1, [r4]\n\ - lsls r0, r1, 3\n\ - subs r0, r1\n\ - lsls r0, 2\n\ - adds r1, r0, r2\n\ - ldrb r4, [r1, 0x16]\n\ - cmp r4, 0\n\ - beq _081325B8\n\ - ldrb r2, [r1, 0x17]\n\ - cmp r2, 0\n\ - beq _081325B4\n\ - adds r0, r3, 0\n\ - cmp r4, r0\n\ - beq _081325CE\n\ - cmp r2, r0\n\ - beq _081325CE\n\ - adds r3, r4, 0\n\ - b _081325CA\n\ - .pool\n\ -_081325B4:\n\ - ldrb r3, [r1, 0x16]\n\ - b _081325CA\n\ -_081325B8:\n\ - ldrb r3, [r1, 0x17]\n\ - b _081325CA\n\ -_081325BC:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - muls r0, r5\n\ - adds r0, r1\n\ - adds r0, 0x20\n\ - ldrb r3, [r0]\n\ - ldr r6, =gBattleResources\n\ -_081325CA:\n\ - cmp r3, 0\n\ - bne _081325E8\n\ -_081325CE:\n\ - ldr r0, [r6]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x2\n\ - str r0, [r1, 0x8]\n\ - ldr r2, =gAIScriptPtr\n\ - b _08132608\n\ - .pool\n\ -_081325E8:\n\ - ldr r0, =gAIScriptPtr\n\ - ldr r1, [r0]\n\ - adds r2, r0, 0\n\ - ldrb r1, [r1, 0x2]\n\ - cmp r3, r1\n\ - bne _08132600\n\ - ldr r0, [r6]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x1\n\ - b _08132606\n\ - .pool\n\ -_08132600:\n\ - ldr r0, [r6]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0\n\ -_08132606:\n\ - str r0, [r1, 0x8]\n\ -_08132608:\n\ - ldr r0, [r2]\n\ - adds r0, 0x3\n\ - str r0, [r2]\n\ - pop {r4-r6}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} -#endif static void BattleAICmd_get_highest_type_effectiveness(void) { @@ -2187,7 +1574,7 @@ static void BattleAICmd_if_status_in_party(void) switch(gAIScriptPtr[1]) { - case 1: + case AI_USER: index = sBank_AI; break; default: @@ -2400,7 +1787,7 @@ static void BattleAICmd_if_cant_faint(void) static void BattleAICmd_if_has_move(void) { int i; - u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); + const u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); switch(gAIScriptPtr[1]) { @@ -2467,7 +1854,7 @@ static void BattleAICmd_if_has_move(void) static void BattleAICmd_if_dont_have_move(void) { int i; - u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); + const u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); switch(gAIScriptPtr[1]) { @@ -2634,7 +2021,7 @@ static void BattleAICmd_if_curr_move_disabled_or_encored(void) static void BattleAICmd_flee(void) { - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK2 being enabled. + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); } static void BattleAICmd_if_random_100(void) @@ -2649,7 +2036,7 @@ static void BattleAICmd_if_random_100(void) static void BattleAICmd_watch(void) { - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK3 being enabled. + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } static void BattleAICmd_get_hold_effect(void) @@ -2678,7 +2065,7 @@ static void BattleAICmd_if_holds_item(void) u16 item; u8 var1, var2; - if ((bank & 1) == (sBank_AI & 1)) + if ((bank & BIT_SIDE) == (sBank_AI & BIT_SIDE)) item = gBattleMons[bank].item; else item = BATTLE_HISTORY->itemEffects[bank]; @@ -2755,7 +2142,7 @@ static void BattleAICmd_get_used_held_item(void) #ifdef NONMATCHING AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[bank]; #else - AI_THINKING_STRUCT->funcResult = *(u8*)((u8*)(gBattleStruct) + 0xB8 + (bank * 2)); + AI_THINKING_STRUCT->funcResult = *(u8*)((u8*)(gBattleStruct) + offsetof(struct BattleStruct, usedHeldItems) + (bank * 2)); #endif // NONMATCHING gAIScriptPtr += 2; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c new file mode 100644 index 000000000..d86be6fad --- /dev/null +++ b/src/battle_ai_switch_items.c @@ -0,0 +1,951 @@ +#include "global.h" +#include "battle.h" +#include "battle_controllers.h" +#include "abilities.h" +#include "moves.h" +#include "pokemon.h" +#include "species.h" +#include "rng.h" +#include "util.h" +#include "items.h" +#include "pokemon_item_effects.h" + +extern u8 gActiveBank; +extern u8 gAbsentBankFlags; +extern u32 gBattleTypeFlags; +extern u32 gStatuses3[BATTLE_BANKS_COUNT]; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u16 gUnknown_02024250[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_02024270[BATTLE_BANKS_COUNT]; +extern u16 gDynamicBasePower; +extern u8 gBattleMoveFlags; +extern u8 gCritMultiplier; +extern s32 gBattleMoveDamage; + +extern const struct BattleMove gBattleMoves[]; +extern const struct BaseStats gBaseStats[]; +extern const u8 gTypeEffectiveness[]; +extern const u8 * const gItemEffectTable[]; // todo: fix once struct is declared + +// this file's functions +static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); +static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent); +static bool8 ShouldUseItem(void); + +static bool8 ShouldSwitchIfPerishSong(void) +{ + if (gStatuses3[gActiveBank] & STATUS3_PERISH_SONG + && gDisableStructs[gActiveBank].perishSong1 == 0) + { + *(gBattleStruct->field_294 + gActiveBank) = 6; + EmitCmd33(1, 2, 0); + return TRUE; + } + + return FALSE; +} + +static bool8 ShouldSwitchIfWonderGuard(void) +{ + u8 opposingIdentity; + u8 opposingBank; + u8 moveFlags; + s32 i, j; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party = NULL; + u16 move; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + return FALSE; + + opposingIdentity = GetBankIdentity(gActiveBank) ^ BIT_SIDE; + + if (gBattleMons[GetBankByIdentity(opposingIdentity)].ability != ABILITY_WONDER_GUARD) + return FALSE; + + // check if pokemon has a super effective move + for (opposingBank = GetBankByIdentity(opposingIdentity), i = 0; i < 4; i++) + { + move = gBattleMons[gActiveBank].moves[i]; + if (move == MOVE_NONE) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[opposingBank].species, gBattleMons[opposingBank].ability); + if (moveFlags & MOVESTATUS_SUPEREFFECTIVE) + return FALSE; + } + + // get party information + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) + { + if ((gActiveBank & BIT_MON) == 0) + firstId = 0, lastId = 3; + else + firstId = 3, lastId = 6; + } + else + { + firstId = 0, lastId = 6; + } + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + // find a pokemon in the party that has a super effective move + for (i = firstId; i < lastId; i++) + { + if (GetMonData(&party[i], MON_DATA_HP) == 0) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + if (i == gBattlePartyID[gActiveBank]) + continue; + + GetMonData(&party[i], MON_DATA_SPECIES); // unused return value + GetMonData(&party[i], MON_DATA_ALT_ABILITY); // unused return value + + for (opposingBank = GetBankByIdentity(opposingIdentity), j = 0; j < 4; j++) + { + move = GetMonData(&party[i], MON_DATA_MOVE1 + j); + if (move == MOVE_NONE) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[opposingBank].species, gBattleMons[opposingBank].ability); + if (moveFlags & MOVESTATUS_SUPEREFFECTIVE && Random() % 3 < 2) + { + // we found a mon + *(gBattleStruct->field_294 + gActiveBank) = i; + EmitCmd33(1, 2, 0); + return TRUE; + } + } + } + + return FALSE; // at this point there is not a single pokemon in the party that has a super effective move against a pokemon with wonder guard +} + +static bool8 FindMonThatAbsorbsOpponentsMove(void) +{ + u8 bankIn1, bankIn2; + u8 absorbingTypeAbility; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; + s32 i; + + if (HasSuperEffectiveMoveAgainstOpponents(TRUE) && Random() % 3 != 0) + return FALSE; + if (gUnknown_02024250[gActiveBank] == 0) + return FALSE; + if (gUnknown_02024250[gActiveBank] == 0xFFFF) + return FALSE; + if (gBattleMoves[gUnknown_02024250[gActiveBank]].power == 0) + return FALSE; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + bankIn1 = gActiveBank; + if (gAbsentBankFlags & gBitTable[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)]) + bankIn2 = gActiveBank; + else + bankIn2 = GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON); + } + else + { + bankIn1 = gActiveBank; + bankIn2 = gActiveBank; + } + + if (gBattleMoves[gUnknown_02024250[gActiveBank]].type == TYPE_FIRE) + absorbingTypeAbility = ABILITY_FLASH_FIRE; + else if (gBattleMoves[gUnknown_02024250[gActiveBank]].type == TYPE_WATER) + absorbingTypeAbility = ABILITY_WATER_ABSORB; + else if (gBattleMoves[gUnknown_02024250[gActiveBank]].type == TYPE_ELECTRIC) + absorbingTypeAbility = ABILITY_VOLT_ABSORB; + else + return FALSE; + + if (gBattleMons[gActiveBank].ability == absorbingTypeAbility) + return FALSE; + + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) + { + if ((gActiveBank & BIT_MON) == 0) + firstId = 0, lastId = 3; + else + firstId = 3, lastId = 6; + } + else + { + firstId = 0, lastId = 6; + } + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = firstId; i < lastId; i++) + { + u16 species; + u8 monAbility; + + if (GetMonData(&party[i], MON_DATA_HP) == 0) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + if (i == gBattlePartyID[bankIn1]) + continue; + if (i == gBattlePartyID[bankIn2]) + continue; + if (i == *(gBattleStruct->field_5C + bankIn1)) + continue; + if (i == *(gBattleStruct->field_5C + bankIn2)) + continue; + + species = GetMonData(&party[i], MON_DATA_SPECIES); + if (GetMonData(&party[i], MON_DATA_ALT_ABILITY) != 0) + monAbility = gBaseStats[species].ability2; + else + monAbility = gBaseStats[species].ability1; + + if (absorbingTypeAbility == monAbility && Random() & 1) + { + // we found a mon + *(gBattleStruct->field_294 + gActiveBank) = i; + EmitCmd33(1, 2, 0); + return TRUE; + } + } + + return FALSE; +} + +static bool8 ShouldSwitchIfNaturalCure(void) +{ + if (!(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + return FALSE; + if (gBattleMons[gActiveBank].ability != ABILITY_NATURAL_CURE) + return FALSE; + if (gBattleMons[gActiveBank].hp < gBattleMons[gActiveBank].maxHP / 2) + return FALSE; + + if ((gUnknown_02024250[gActiveBank] == 0 || gUnknown_02024250[gActiveBank] == 0xFFFF) && Random() & 1) + { + *(gBattleStruct->field_294 + gActiveBank) = 6; + EmitCmd33(1, 2, 0); + return TRUE; + } + else if (gBattleMoves[gUnknown_02024250[gActiveBank]].power == 0 && Random() & 1) + { + *(gBattleStruct->field_294 + gActiveBank) = 6; + EmitCmd33(1, 2, 0); + return TRUE; + } + + if (FindMonWithFlagsAndSuperEffective(MOVESTATUS_NOTAFFECTED, 1)) + return TRUE; + if (FindMonWithFlagsAndSuperEffective(MOVESTATUS_NOTVERYEFFECTIVE, 1)) + return TRUE; + if (Random() & 1) + { + *(gBattleStruct->field_294 + gActiveBank) = 6; + EmitCmd33(1, 2, 0); + return TRUE; + } + + return FALSE; +} + +static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng) +{ + u8 opposingIdentity; + u8 opposingBank; + s32 i; + u8 moveFlags; + u16 move; + + opposingIdentity = GetBankIdentity(gActiveBank) ^ BIT_SIDE; + opposingBank = GetBankByIdentity(opposingIdentity); + + if (!(gAbsentBankFlags & gBitTable[opposingBank])) + { + for (i = 0; i < 4; i++) + { + move = gBattleMons[gActiveBank].moves[i]; + if (move == MOVE_NONE) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[opposingBank].species, gBattleMons[opposingBank].ability); + if (moveFlags & MOVESTATUS_SUPEREFFECTIVE) + { + if (noRng) + return TRUE; + if (Random() % 10 != 0) + return TRUE; + } + } + } + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + return FALSE; + + opposingBank = GetBankByIdentity(opposingIdentity ^ BIT_MON); + + if (!(gAbsentBankFlags & gBitTable[opposingBank])) + { + for (i = 0; i < 4; i++) + { + move = gBattleMons[gActiveBank].moves[i]; + if (move == MOVE_NONE) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[opposingBank].species, gBattleMons[opposingBank].ability); + if (moveFlags & MOVESTATUS_SUPEREFFECTIVE) + { + if (noRng) + return TRUE; + if (Random() % 10 != 0) + return TRUE; + } + } + } + + return FALSE; +} + +static bool8 AreStatsRaised(void) +{ + u8 buffedStatsValue = 0; + s32 i; + + for (i = 0; i < BATTLE_STATS_NO; i++) + { + if (gBattleMons[gActiveBank].statStages[i] > 6) + buffedStatsValue += gBattleMons[gActiveBank].statStages[i] - 6; + } + + return (buffedStatsValue > 3); +} + +static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) +{ + u8 bankIn1, bankIn2; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; + s32 i, j; + u16 move; + u8 moveFlags; + + if (gUnknown_02024250[gActiveBank] == 0) + return FALSE; + if (gUnknown_02024250[gActiveBank] == 0xFFFF) + return FALSE; + if (gUnknown_02024270[gActiveBank] == 0xFF) + return FALSE; + if (gBattleMoves[gUnknown_02024250[gActiveBank]].power == 0) + return FALSE; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + bankIn1 = gActiveBank; + if (gAbsentBankFlags & gBitTable[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)]) + bankIn2 = gActiveBank; + else + bankIn2 = GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON); + } + else + { + bankIn1 = gActiveBank; + bankIn2 = gActiveBank; + } + + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) + { + if ((gActiveBank & BIT_MON) == 0) + firstId = 0, lastId = 3; + else + firstId = 3, lastId = 6; + } + else + { + firstId = 0, lastId = 6; + } + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = firstId; i < lastId; i++) + { + u16 species; + u8 monAbility; + + if (GetMonData(&party[i], MON_DATA_HP) == 0) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + if (i == gBattlePartyID[bankIn1]) + continue; + if (i == gBattlePartyID[bankIn2]) + continue; + if (i == *(gBattleStruct->field_5C + bankIn1)) + continue; + if (i == *(gBattleStruct->field_5C + bankIn2)) + continue; + + species = GetMonData(&party[i], MON_DATA_SPECIES); + if (GetMonData(&party[i], MON_DATA_ALT_ABILITY) != 0) + monAbility = gBaseStats[species].ability2; + else + monAbility = gBaseStats[species].ability1; + + moveFlags = AI_TypeCalc(gUnknown_02024250[gActiveBank], species, monAbility); + if (moveFlags & flags) + { + bankIn1 = gUnknown_02024270[gActiveBank]; + + for (j = 0; j < 4; j++) + { + move = GetMonData(&party[i], MON_DATA_MOVE1 + j); + if (move == 0) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[bankIn1].species, gBattleMons[bankIn1].ability); + if (moveFlags & MOVESTATUS_SUPEREFFECTIVE && Random() % moduloPercent == 0) + { + *(gBattleStruct->field_294 + gActiveBank) = i; + EmitCmd33(1, 2, 0); + return TRUE; + } + } + } + } + + return FALSE; +} + +static bool8 ShouldSwitch(void) +{ + u8 bankIn1, bankIn2; + u8 *activeBankPtr; // needed to match + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; + s32 i; + s32 availableToSwitch; + + if (gBattleMons[*(activeBankPtr = &gActiveBank)].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + return FALSE; + if (gStatuses3[gActiveBank] & STATUS3_ROOTED) + return FALSE; + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBank, ABILITY_SHADOW_TAG, 0, 0)) + return FALSE; + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBank, ABILITY_ARENA_TRAP, 0, 0)) + return FALSE; // misses the flying or levitate check + if (AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_MAGNET_PULL, 0, 0)) + { + if (gBattleMons[gActiveBank].type1 == TYPE_STEEL) + return FALSE; + if (gBattleMons[gActiveBank].type2 == TYPE_STEEL) + return FALSE; + } + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + return FALSE; + + availableToSwitch = 0; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + bankIn1 = *activeBankPtr; + if (gAbsentBankFlags & gBitTable[GetBankByIdentity(GetBankIdentity(*activeBankPtr) ^ BIT_MON)]) + bankIn2 = *activeBankPtr; + else + bankIn2 = GetBankByIdentity(GetBankIdentity(*activeBankPtr) ^ BIT_MON); + } + else + { + bankIn1 = *activeBankPtr; + bankIn2 = *activeBankPtr; + } + + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) + { + if ((gActiveBank & BIT_MON) == 0) + firstId = 0, lastId = 3; + else + firstId = 3, lastId = 6; + } + else + { + firstId = 0, lastId = 6; + } + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = firstId; i < lastId; i++) + { + if (GetMonData(&party[i], MON_DATA_HP) == 0) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + if (i == gBattlePartyID[bankIn1]) + continue; + if (i == gBattlePartyID[bankIn2]) + continue; + if (i == *(gBattleStruct->field_5C + bankIn1)) + continue; + if (i == *(gBattleStruct->field_5C + bankIn2)) + continue; + + availableToSwitch++; + } + + if (availableToSwitch == 0) + return FALSE; + if (ShouldSwitchIfPerishSong()) + return TRUE; + if (ShouldSwitchIfWonderGuard()) + return TRUE; + if (FindMonThatAbsorbsOpponentsMove()) + return TRUE; + if (ShouldSwitchIfNaturalCure()) + return TRUE; + if (HasSuperEffectiveMoveAgainstOpponents(FALSE)) + return FALSE; + if (AreStatsRaised()) + return FALSE; + if (FindMonWithFlagsAndSuperEffective(MOVESTATUS_NOTAFFECTED, 2) + || FindMonWithFlagsAndSuperEffective(MOVESTATUS_NOTVERYEFFECTIVE, 3)) + return TRUE; + + return FALSE; +} + +void AI_TrySwitchOrUseItem(void) +{ + struct Pokemon *party; + u8 bankIn1, bankIn2; + s32 firstId; + s32 lastId; // + 1 + u8 bankIdentity = GetBankIdentity(gActiveBank); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (ShouldSwitch()) + { + if (*(gBattleStruct->field_294 + gActiveBank) == 6) + { + s32 monToSwitchId = GetMostSuitableMonToSwitchInto(); + if (monToSwitchId == 6) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + bankIn1 = GetBankByIdentity(bankIdentity); + bankIn2 = bankIn1; + } + else + { + bankIn1 = GetBankByIdentity(bankIdentity); + bankIn2 = GetBankByIdentity(bankIdentity ^ BIT_MON); + } + + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) + { + if ((gActiveBank & BIT_MON) == 0) + firstId = 0, lastId = 3; + else + firstId = 3, lastId = 6; + } + else + { + firstId = 0, lastId = 6; + } + + for (monToSwitchId = firstId; monToSwitchId < lastId; monToSwitchId++) + { + if (GetMonData(&party[monToSwitchId], MON_DATA_HP) == 0) + continue; + if (monToSwitchId == gBattlePartyID[bankIn1]) + continue; + if (monToSwitchId == gBattlePartyID[bankIn2]) + continue; + if (monToSwitchId == *(gBattleStruct->field_5C + bankIn1)) + continue; + if (monToSwitchId == *(gBattleStruct->field_5C + bankIn2)) + continue; + + break; + } + } + + *(gBattleStruct->field_294 + gActiveBank) = monToSwitchId; + } + + *(gBattleStruct->field_5C + gActiveBank) = *(gBattleStruct->field_294 + gActiveBank); + return; + } + else if (ShouldUseItem()) + { + return; + } + } + + EmitCmd33(1, 0, (gActiveBank ^ BIT_SIDE) << 8); +} + +#define TYPE_FORESIGHT 0xFE +#define TYPE_ENDTABLE 0xFF + +static void ModulateByTypeEffectiveness(u8 atkType, u8 defType1, u8 defType2, u8 *var) +{ + s32 i = 0; + + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + i += 3; + continue; + } + else if (gTypeEffectiveness[i] == atkType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == defType1) + *var = (*var * gTypeEffectiveness[i + 2]) / 10; + // check type2 + if (gTypeEffectiveness[i + 1] == defType2 && defType1 != defType2) + *var = (*var * gTypeEffectiveness[i + 2]) / 10; + } + i += 3; + } +} + +u8 GetMostSuitableMonToSwitchInto(void) +{ + u8 opposingBank; + u8 bestDmg; // note : should be changed to u32 for obvious reasons + u8 bestMonId; + u8 bankIn1, bankIn2; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; + s32 i, j; + u8 invalidMons; + u16 move; + + if (*(gBattleStruct->field_5C + gActiveBank) != 6) + return *(gBattleStruct->field_5C + gActiveBank); + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + return gBattlePartyID[gActiveBank] + 1; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + bankIn1 = gActiveBank; + if (gAbsentBankFlags & gBitTable[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)]) + bankIn2 = gActiveBank; + else + bankIn2 = GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON); + + // UB: It considers the opponent only player's side even though it can battle alongside player; + opposingBank = Random() & BIT_MON; + if (gAbsentBankFlags & gBitTable[opposingBank]) + opposingBank ^= BIT_MON; + } + else + { + opposingBank = GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_SIDE); + bankIn1 = gActiveBank; + bankIn2 = gActiveBank; + } + + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) + { + if ((gActiveBank & BIT_MON) == 0) + firstId = 0, lastId = 3; + else + firstId = 3, lastId = 6; + } + else + { + firstId = 0, lastId = 6; + } + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + invalidMons = 0; + + while (invalidMons != 0x3F) // all mons are invalid + { + bestDmg = 0; + bestMonId = 6; + // find the mon which type is the most suitable offensively + for (i = firstId; i < lastId; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES); + if (species != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_HP) != 0 + && !(gBitTable[i] & invalidMons) + && gBattlePartyID[bankIn1] != i + && gBattlePartyID[bankIn2] != i + && i != *(gBattleStruct->field_5C + bankIn1) + && i != *(gBattleStruct->field_5C + bankIn2)) + { + u8 type1 = gBaseStats[species].type1; + u8 type2 = gBaseStats[species].type2; + u8 typeDmg = 10; + ModulateByTypeEffectiveness(gBattleMons[opposingBank].type1, type1, type2, &typeDmg); + ModulateByTypeEffectiveness(gBattleMons[opposingBank].type2, type1, type2, &typeDmg); + if (bestDmg < typeDmg) + { + bestDmg = typeDmg; + bestMonId = i; + } + } + else + { + invalidMons |= gBitTable[i]; + } + } + + // ok, we know the mon has the right typing but does it have at least one super effective move? + if (bestMonId != 6) + { + for (i = 0; i < 4; i++) + { + move = GetMonData(&party[bestMonId], MON_DATA_MOVE1 + i); + if (move != MOVE_NONE && TypeCalc(move, gActiveBank, opposingBank) & MOVESTATUS_SUPEREFFECTIVE) + break; + } + + if (i != 4) + return bestMonId; // has both the typing and at least one super effective move + + invalidMons |= gBitTable[bestMonId]; // sorry buddy, we want something better + } + else + { + invalidMons = 0x3F; // no viable mon to switch + } + } + + gDynamicBasePower = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleScripting.dmgMultiplier = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + bestDmg = 0; + bestMonId = 6; + + // if we couldn't find the best mon in terms of typing, find the one that deals most damage + for (i = firstId; i < lastId; i++) + { + if ((u16)(GetMonData(&party[i], MON_DATA_SPECIES)) == SPECIES_NONE) + continue; + if (GetMonData(&party[i], MON_DATA_HP) == 0) + continue; + if (gBattlePartyID[bankIn1] == i) + continue; + if (gBattlePartyID[bankIn2] == i) + continue; + if (i == *(gBattleStruct->field_5C + bankIn1)) + continue; + if (i == *(gBattleStruct->field_5C + bankIn2)) + continue; + + for (j = 0; j < 4; j++) + { + move = GetMonData(&party[i], MON_DATA_MOVE1 + j); + gBattleMoveDamage = 0; + if (move != MOVE_NONE && gBattleMoves[move].power != 1) + { + AI_CalcDmg(gActiveBank, opposingBank); + TypeCalc(move, gActiveBank, opposingBank); + } + if (bestDmg < gBattleMoveDamage) + { + bestDmg = gBattleMoveDamage; + bestMonId = i; + } + } + } + + return bestMonId; +} + +// TODO: use PokemonItemEffect struct instead of u8 once it's documented +static u8 GetAI_ItemType(u8 itemId, const u8 *itemEffect) // NOTE: should take u16 as item Id argument +{ + if (itemId == ITEM_FULL_RESTORE) + return AI_ITEM_FULL_RESTORE; + if (itemEffect[4] & 4) + return AI_ITEM_HEAL_HP; + if (itemEffect[3] & 0x3F) + return AI_ITEM_CURE_CONDITION; + if (itemEffect[0] & 0x3F || itemEffect[1] != 0 || itemEffect[2] != 0) + return AI_ITEM_X_STAT; + if (itemEffect[3] & 0x80) + return AI_ITEM_GUARD_SPECS; + + return AI_ITEM_NOT_RECOGNIZABLE; +} + +static bool8 ShouldUseItem(void) +{ + struct Pokemon *party; + s32 i; + u8 validMons = 0; + bool8 shouldUse = FALSE; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON2) + return FALSE; + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < 6; i++) + { + if (GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) + { + validMons++; + } + } + + for (i = 0; i < 4; i++) + { + u16 item; + const u8 *itemEffects; + u8 paramOffset; + u8 bankSide; + + if (i != 0 && validMons > (gBattleResources->battleHistory->itemsNo - i) + 1) + continue; + item = gBattleResources->battleHistory->trainerItems[i]; + if (item == ITEM_NONE) + continue; + if (gItemEffectTable[item - 13] == NULL) + continue; + + if (item == ITEM_ENIGMA_BERRY) + itemEffects = gSaveBlock1Ptr->enigmaBerry.itemEffect; + else + itemEffects = gItemEffectTable[item - 13]; + + *(gBattleStruct->AI_itemType + gActiveBank / 2) = GetAI_ItemType(item, itemEffects); + + switch (*(gBattleStruct->AI_itemType + gActiveBank / 2)) + { + case AI_ITEM_FULL_RESTORE: + if (gBattleMons[gActiveBank].hp >= gBattleMons[gActiveBank].maxHP / 4) + break; + if (gBattleMons[gActiveBank].hp == 0) + break; + shouldUse = TRUE; + break; + case AI_ITEM_HEAL_HP: + paramOffset = GetItemEffectParamOffset(item, 4, 4); + if (paramOffset == 0) + break; + if (gBattleMons[gActiveBank].hp == 0) + break; + if (gBattleMons[gActiveBank].hp < gBattleMons[gActiveBank].maxHP / 4 || gBattleMons[gActiveBank].maxHP - gBattleMons[gActiveBank].hp > itemEffects[paramOffset]) + shouldUse = TRUE; + break; + case AI_ITEM_CURE_CONDITION: + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) = 0; + if (itemEffects[3] & 0x20 && gBattleMons[gActiveBank].status1 & STATUS_SLEEP) + { + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x20; + shouldUse = TRUE; + } + if (itemEffects[3] & 0x10 && (gBattleMons[gActiveBank].status1 & STATUS_POISON || gBattleMons[gActiveBank].status1 & STATUS_TOXIC_POISON)) + { + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x10; + shouldUse = TRUE; + } + if (itemEffects[3] & 0x8 && gBattleMons[gActiveBank].status1 & STATUS_BURN) + { + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x8; + shouldUse = TRUE; + } + if (itemEffects[3] & 0x4 && gBattleMons[gActiveBank].status1 & STATUS_FREEZE) + { + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x4; + shouldUse = TRUE; + } + if (itemEffects[3] & 0x2 && gBattleMons[gActiveBank].status1 & STATUS_PARALYSIS) + { + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x2; + shouldUse = TRUE; + } + if (itemEffects[3] & 0x1 && gBattleMons[gActiveBank].status2 & STATUS2_CONFUSION) + { + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x1; + shouldUse = TRUE; + } + break; + case AI_ITEM_X_STAT: + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) = 0; + if (gDisableStructs[gActiveBank].isFirstTurn == 0) + break; + if (itemEffects[0] & 0xF) + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x1; + if (itemEffects[1] & 0xF0) + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x2; + if (itemEffects[1] & 0xF) + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x4; + if (itemEffects[2] & 0xF) + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x8; + if (itemEffects[2] & 0xF0) + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x20; + if (itemEffects[0] & 0x30) + *(gBattleStruct->AI_itemFlags + gActiveBank / 2) |= 0x80; + shouldUse = TRUE; + break; + case AI_ITEM_GUARD_SPECS: + bankSide = GetBankSide(gActiveBank); + if (gDisableStructs[gActiveBank].isFirstTurn != 0 && gSideTimers[bankSide].mistTimer == 0) + shouldUse = TRUE; + break; + case AI_ITEM_NOT_RECOGNIZABLE: + return FALSE; + } + + if (shouldUse) + { + EmitCmd33(1, 1, 0); + *(gBattleStruct->field_C0 + (gActiveBank / 2) * 2) = item; + gBattleResources->battleHistory->trainerItems[i] = 0; + return shouldUse; + } + } + + return FALSE; +} 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_dome_cards.c b/src/battle_dome_cards.c index c0557ac70..5251ee06a 100644 --- a/src/battle_dome_cards.c +++ b/src/battle_dome_cards.c @@ -17,7 +17,7 @@ extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[]; extern const union AffineAnimCmd *const gUnknown_082FF618[]; extern const union AffineAnimCmd *const gUnknown_082FF694[]; extern const union AnimCmd *const gUnknown_082FF70C[]; -extern const union AnimCmd *const *const gUnknown_08309AAC[NUM_SPECIES]; +extern const union AnimCmd *const *const gMonAnimationsSpriteAnimsPtrTable[NUM_SPECIES]; extern const union AnimCmd *const *const gUnknown_0830536C[]; extern const u8 gUnknown_0831F578[]; @@ -282,7 +282,7 @@ u16 sub_818D3E4(u16 species, u32 otId, u32 personality, u8 flags, s16 x, s16 y, images[j].size = 0x800; } gUnknown_0203CCEC.tileTag = 0xFFFF; - gUnknown_0203CCEC.anims = gUnknown_08309AAC[species]; + gUnknown_0203CCEC.anims = gMonAnimationsSpriteAnimsPtrTable[species]; gUnknown_0203CCEC.images = images; if (flags2 == 0x01) { 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_message.c b/src/battle_message.c new file mode 100644 index 000000000..aeff721d6 --- /dev/null +++ b/src/battle_message.c @@ -0,0 +1,2333 @@ +#include "global.h" +#include "battle.h" +#include "battle_message.h" +#include "battle_string_ids.h" +#include "moves.h" +#include "text.h" +#include "string_util.h" +#include "items.h" +#include "event_data.h" +#include "link.h" +#include "item.h" +#include "window.h" +#include "palette.h" +#include "battle_controllers.h" + +extern u16 gLastUsedItem; +extern u8 gLastUsedAbility; +extern u8 gActiveBank; +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern u8 gStringBank; +extern u8 gEffectBank; +extern u8 gAbilitiesPerBank[BATTLE_BANKS_COUNT]; +extern u32 gBattleTypeFlags; +extern u16 gTrainerBattleOpponent_A; +extern u16 gTrainerBattleOpponent_B; +extern u16 gPartnerTrainerId; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT]; +extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200]; +extern u8 gMoveSelectionCursor[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_0203C7B4; +extern struct StringInfoBattle *gStringInfo; + +extern const u8 gMoveNames[LAST_MOVE_INDEX + 1][13]; +extern const u8 gAbilityNames[][13]; +extern const u8 gTrainerClassNames[][13]; +extern const u8 gTypeNames[][7]; +extern const u16 gUnknown_08D85620[]; + +// strings +extern const u8 gText_PkmnBoxSomeonesPCFull[]; +extern const u8 gText_PkmnBoxLanettesPCFull[]; +extern const u8 gText_PkmnTransferredSomeonesPC[]; +extern const u8 gText_PkmnTransferredLanettesPC[]; + +extern u16 sub_8068BB0(void); // pokemon_1 +extern u8 sub_81A4D00(void); // battle_frontier_2 +extern u8 GetFrontierOpponentClass(u16 trainerId); // battle_tower +extern u8 sub_81D5530(u16 trainerId); // pokenav +extern u8 GetEreaderTrainerClassId(void); // battle_tower +extern void sub_81A4D50(u8 *txtPtr); // battle_frontier_2 +extern void sub_81D5554(u8 *txtPtr, u16 trainerId); // pokenav +extern void GetEreaderTrainerName(u8 *txtPtr); +extern void sub_81A36D0(u8 arg0, u16 trainerId); // battle_frontier_2 +extern void sub_81D572C(u8 arg0, u16 trainerId); // pokenav +extern const u8* GetTrainer1LoseText(void); // battle_setup +extern const u8* GetTrainer2LoseText(void); // battle_setup +extern void GetFrontierTrainerName(u8 *dst, u16 trainerId); +extern s32 GetStringCenterAlignXOffsetWithLetterSpacing(u8 fontId, const u8 *str, s32 totalWidth, s16 letterSpacing); +extern u8 sub_8185FC4(void); +extern u8 sav2_get_text_speed(void); + +// this file's functions +static void sub_814F8F8(u8 *textPtr); +static void sub_814F950(u8 *dst); +static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst); + +// ewram variables +EWRAM_DATA u8 gDisplayedStringBattle[300] = {0}; +EWRAM_DATA u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT] = {0}; +EWRAM_DATA u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT] = {0}; +EWRAM_DATA u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT] = {0}; + +// const rom data +// todo: make some of those names less vague: attacker/target vs pkmn, etc. + +const u8 gText_Trainer1LoseText[] = _("{B_TRAINER1_LOSE_TEXT}"); +const u8 gText_PkmnGainedEXP[] = _("{B_BUFF1} gained{B_BUFF2}\n{B_BUFF3} EXP. Points!\p"); +const u8 gText_EmptyString4[] = _(""); +const u8 gText_ABoosted[] = _(" a boosted"); +const u8 gText_PkmnGrewToLv[] = _("{B_BUFF1} grew to\nLV. {B_BUFF2}!{UNKNOWN_A}\p"); +const u8 gText_PkmnLearnedMove[] = _("{B_BUFF1} learned\n{B_BUFF2}!{UNKNOWN_A}\p"); +const u8 gText_TryToLearnMove1[] = _("{B_BUFF1} is trying to\nlearn {B_BUFF2}.\p"); +const u8 gText_TryToLearnMove2[] = _("But, {B_BUFF1} can’t learn\nmore than four moves.\p"); +const u8 gText_TryToLearnMove3[] = _("Delete a move to make\nroom for {B_BUFF2}?"); +const u8 gText_PkmnForgotMove[] = _("{B_BUFF1} forgot\n{B_BUFF2}.\p"); +const u8 gText_StopLearningMove[] = _("{PAUSE 32}Stop learning\n{B_BUFF2}?"); +const u8 gText_DidNotLearnMove[] = _("{B_BUFF1} did not learn\n{B_BUFF2}.\p"); +const u8 gText_UseNextPkmn[] = _("Use next POKéMON?"); +const u8 gText_AttackMissed[] = _("{B_ATK_NAME_WITH_PREFIX}’s\nattack missed!"); +const u8 gText_PkmnProtectedItself[] = _("{B_DEF_NAME_WITH_PREFIX}\nprotected itself!"); +const u8 gText_AvoidedDamage[] = _("{B_DEF_NAME_WITH_PREFIX} avoided\ndamage with {B_DEF_ABILITY}!"); +const u8 gText_PkmnMakesGroundMiss[] = _("{B_DEF_NAME_WITH_PREFIX} makes GROUND\nmoves miss with {B_DEF_ABILITY}!"); +const u8 gText_PkmnAvoidedAttack[] = _("{B_DEF_NAME_WITH_PREFIX} avoided\nthe attack!"); +const u8 gText_ItDoesntAffect[] = _("It doesn’t affect\n{B_DEF_NAME_WITH_PREFIX}…"); +const u8 gText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\p"); +const u8 gText_TargetFainted[] = _("{B_DEF_NAME_WITH_PREFIX}\nfainted!\p"); +const u8 gText_PlayerGotMoney[] = _("{B_PLAYER_NAME} got ¥{B_BUFF1}\nfor winning!\p"); +const u8 gText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p"); +const u8 gText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}"); +const u8 gText_PreventsEscape[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} prevents\nescape with {B_SCR_ACTIVE_ABILITY}!\p"); +const u8 gText_CantEscape2[] = _("Can’t escape!\p"); +const u8 gText_AttackerCantEscape[] = _("{B_ATK_NAME_WITH_PREFIX} can’t escape!"); +const u8 gText_HitXTimes[] = _("Hit {B_BUFF1} time(s)!"); +const u8 gText_PkmnFellAsleep[] = _("{B_EFF_NAME_WITH_PREFIX}\nfell asleep!"); +const u8 gText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!"); +const u8 gText_PkmnAlreadyAsleep[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready asleep!"); +const u8 gText_PkmnAlreadyAsleep2[] = _("{B_ATK_NAME_WITH_PREFIX} is\nalready asleep!"); +const u8 gText_PkmnWasntAffected[] = _("{B_DEF_NAME_WITH_PREFIX}\nwasn’t affected!"); +const u8 gText_PkmnWasPoisoned[] = _("{B_EFF_NAME_WITH_PREFIX}\nwas poisoned!"); +const u8 gText_PkmnPoisonedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\npoisoned {B_EFF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnHurtByPoison[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby poison!"); +const u8 gText_PkmnAlreadyPoisoned[] = _("{B_DEF_NAME_WITH_PREFIX} is already\npoisoned."); +const u8 gText_PkmnBadlyPoisoned[] = _("{B_EFF_NAME_WITH_PREFIX} is badly\npoisoned!"); +const u8 gText_PkmnEnergyDrained[] = _("{B_DEF_NAME_WITH_PREFIX} had its\nenergy drained!"); +const u8 gText_PkmnWasBurned[] = _("{B_EFF_NAME_WITH_PREFIX} was burned!"); +const u8 gText_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nburned {B_EFF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnHurtByBurn[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its burn!"); +const u8 gText_PkmnAlreadyHasBurn[] = _("{B_DEF_NAME_WITH_PREFIX} already\nhas a burn."); +const u8 gText_PkmnWasFrozen[] = _("{B_EFF_NAME_WITH_PREFIX} was\nfrozen solid!"); +const u8 gText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!"); +const u8 gText_PkmnIsFrozen[] = _("{B_ATK_NAME_WITH_PREFIX} is\nfrozen solid!"); +const u8 gText_PkmnWasDefrosted[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndefrosted!"); +const u8 gText_PkmnWasDefrosted2[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted!"); +const u8 gText_PkmnWasDefrostedBy[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted by {B_CURRENT_MOVE}!"); +const u8 gText_PkmnWasParalyzed[] = _("{B_EFF_NAME_WITH_PREFIX} is paralyzed!\nIt may be unable to move!"); +const u8 gText_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nparalyzed {B_EFF_NAME_WITH_PREFIX}!\lIt may be unable to move!"); +const u8 gText_PkmnIsParalyzed[] = _("{B_ATK_NAME_WITH_PREFIX} is paralyzed!\nIt can’t move!"); +const u8 gText_PkmnIsAlreadyParalyzed[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready paralyzed!"); +const u8 gText_PkmnHealedParalysis[] = _("{B_DEF_NAME_WITH_PREFIX} was\nhealed of paralysis!"); +const u8 gText_PkmnDreamEaten[] = _("{B_DEF_NAME_WITH_PREFIX}’s\ndream was eaten!"); +const u8 gText_StatsWontIncrease[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_BUFF1}\nwon’t go higher!"); +const u8 gText_StatsWontDecrease[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_BUFF1}\nwon’t go lower!"); +const u8 gText_TeamStoppedWorking[] = _("Your team’s {B_BUFF1}\nstopped working!"); +const u8 gText_FoeStoppedWorking[] = _("The foe’s {B_BUFF1}\nstopped working!"); +const u8 gText_PkmnIsConfused[] = _("{B_ATK_NAME_WITH_PREFIX} is\nconfused!"); +const u8 gText_PkmnHealedConfusion[] = _("{B_ATK_NAME_WITH_PREFIX} snapped\nout of confusion!"); +const u8 gText_PkmnWasConfused[] = _("{B_EFF_NAME_WITH_PREFIX} became\nconfused!"); +const u8 gText_PkmnAlreadyConfused[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready confused!"); +const u8 gText_PkmnFellInLove[] = _("{B_DEF_NAME_WITH_PREFIX}\nfell in love!"); +const u8 gText_PkmnInLove[] = _("{B_ATK_NAME_WITH_PREFIX} is in love\nwith {B_SCR_ACTIVE_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnImmobilizedByLove[] = _("{B_ATK_NAME_WITH_PREFIX} is\nimmobilized by love!"); +const u8 gText_PkmnBlownAway[] = _("{B_DEF_NAME_WITH_PREFIX} was\nblown away!"); +const u8 gText_PkmnChangedType[] = _("{B_ATK_NAME_WITH_PREFIX} transformed\ninto the {B_BUFF1} type!"); +const u8 gText_PkmnFlinched[] = _("{B_ATK_NAME_WITH_PREFIX} flinched!"); +const u8 gText_PkmnRegainedHealth[] = _("{B_DEF_NAME_WITH_PREFIX} regained\nhealth!"); +const u8 gText_PkmnHPFull[] = _("{B_DEF_NAME_WITH_PREFIX}’s\nHP is full!"); +const u8 gText_PkmnRaisedSpDef[] = _("{B_ATK_PREFIX2}’s {B_CURRENT_MOVE}\nraised SP. DEF!"); +const u8 gText_PkmnRaisedSpDefALittle[] = _("{B_ATK_PREFIX2}’s {B_CURRENT_MOVE}\nraised SP. DEF a little!"); +const u8 gText_PkmnRaisedDef[] = _("{B_ATK_PREFIX2}’s {B_CURRENT_MOVE}\nraised DEFENSE!"); +const u8 gText_PkmnRaisedDefALittle[] = _("{B_ATK_PREFIX2}’s {B_CURRENT_MOVE}\nraised DEFENSE a little!"); +const u8 gText_PkmnCoveredByVeil[] = _("{B_ATK_PREFIX2}’s party is covered\nby a veil!"); +const u8 gText_PkmnUsedSafeguard[] = _("{B_DEF_NAME_WITH_PREFIX}’s party is protected\nby SAFEGUARD!"); +const u8 gText_PkmnSafeguardExpired[] = _("{B_ATK_PREFIX3}’s party is no longer\nprotected by SAFEGUARD!"); +const u8 gText_PkmnWentToSleep[] = _("{B_ATK_NAME_WITH_PREFIX} went\nto sleep!"); +const u8 gText_PkmnSleptHealthy[] = _("{B_ATK_NAME_WITH_PREFIX} slept and\nbecame healthy!"); +const u8 gText_PkmnWhippedWhirlwind[] = _("{B_ATK_NAME_WITH_PREFIX} whipped\nup a whirlwind!"); +const u8 gText_PkmnTookSunlight[] = _("{B_ATK_NAME_WITH_PREFIX} took\nin sunlight!"); +const u8 gText_PkmnLoweredHead[] = _("{B_ATK_NAME_WITH_PREFIX} lowered\nits head!"); +const u8 gText_PkmnIsGlowing[] = _("{B_ATK_NAME_WITH_PREFIX} is glowing!"); +const u8 gText_PkmnFlewHigh[] = _("{B_ATK_NAME_WITH_PREFIX} flew\nup high!"); +const u8 gText_PkmnDugHole[] = _("{B_ATK_NAME_WITH_PREFIX} dug a hole!"); +const u8 gText_PkmnHidUnderwater[] = _("{B_ATK_NAME_WITH_PREFIX} hid\nunderwater!"); +const u8 gText_PkmnSprangUp[] = _("{B_ATK_NAME_WITH_PREFIX} sprang up!"); +const u8 gText_PkmnSqueezedByBind[] = _("{B_DEF_NAME_WITH_PREFIX} was squeezed by\n{B_ATK_NAME_WITH_PREFIX}’s BIND!"); +const u8 gText_PkmnTrappedInVortex[] = _("{B_DEF_NAME_WITH_PREFIX} was trapped\nin the vortex!"); +const u8 gText_PkmnTrappedBySandTomb[] = _("{B_DEF_NAME_WITH_PREFIX} was trapped\nby SAND TOMB!"); +const u8 gText_PkmnWrappedBy[] = _("{B_DEF_NAME_WITH_PREFIX} was WRAPPED by\n{B_ATK_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnClamped[] = _("{B_ATK_NAME_WITH_PREFIX} CLAMPED\n{B_DEF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnHurtBy[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby {B_BUFF1}!"); +const u8 gText_PkmnFreedFrom[] = _("{B_ATK_NAME_WITH_PREFIX} was freed\nfrom {B_BUFF1}!"); +const u8 gText_PkmnCrashed[] = _("{B_ATK_NAME_WITH_PREFIX} kept going\nand crashed!"); +const u8 gText_PkmnShroudedInMist[] = _("{B_ATK_PREFIX2} became\nshrouded in MIST!"); +const u8 gText_PkmnProtectedByMist[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is protected\nby MIST!"); +const u8 gText_PkmnGettingPumped[] = _("{B_ATK_NAME_WITH_PREFIX} is getting\npumped!"); +const u8 gText_PkmnHitWithRecoil[] = _("{B_ATK_NAME_WITH_PREFIX} is hit\nwith recoil!"); +const u8 gText_PkmnProtectedItself2[] = _("{B_ATK_NAME_WITH_PREFIX} protected\nitself!"); +const u8 gText_PkmnBuffetedBySandstorm[] = _("{B_ATK_NAME_WITH_PREFIX} is buffeted\nby the sandstorm!"); +const u8 gText_PkmnPeltedByHail[] = _("{B_ATK_NAME_WITH_PREFIX} is pelted\nby HAIL!"); +const u8 gText_PkmnsXWoreOff[] = _("{B_ATK_PREFIX1}’s {B_BUFF1}\nwore off!"); +const u8 gText_PkmnSeeded[] = _("{B_DEF_NAME_WITH_PREFIX} was seeded!"); +const u8 gText_PkmnEvadedAttack[] = _("{B_DEF_NAME_WITH_PREFIX} evaded\nthe attack!"); +const u8 gText_PkmnSappedByLeechSeed[] = _("{B_ATK_NAME_WITH_PREFIX}’s health is\nsapped by LEECH SEED!"); +const u8 gText_PkmnFastAsleep[] = _("{B_ATK_NAME_WITH_PREFIX} is fast\nasleep."); +const u8 gText_PkmnWokeUp[] = _("{B_ATK_NAME_WITH_PREFIX} woke up!"); +const u8 gText_PkmnUproarKeptAwake[] = _("But {B_SCR_ACTIVE_NAME_WITH_PREFIX}’s UPROAR\nkept it awake!"); +const u8 gText_PkmnWokeUpInUproar[] = _("{B_ATK_NAME_WITH_PREFIX} woke up\nin the UPROAR!"); +const u8 gText_PkmnCausedUproar[] = _("{B_ATK_NAME_WITH_PREFIX} caused\nan UPROAR!"); +const u8 gText_PkmnMakingUproar[] = _("{B_ATK_NAME_WITH_PREFIX} is making\nan UPROAR!"); +const u8 gText_PkmnCalmedDown[] = _("{B_ATK_NAME_WITH_PREFIX} calmed down."); +const u8 gText_PkmnCantSleepInUproar[] = _("But {B_DEF_NAME_WITH_PREFIX} can’t\nsleep in an UPROAR!"); +const u8 gText_PkmnStockpiled[] = _("{B_ATK_NAME_WITH_PREFIX} STOCKPILED\n{B_BUFF1}!"); +const u8 gText_PkmnCantStockpile[] = _("{B_ATK_NAME_WITH_PREFIX} can’t\nSTOCKPILE any more!"); +const u8 gText_PkmnCantSleepInUproar2[] = _("But {B_DEF_NAME_WITH_PREFIX} can’t\nsleep in an UPROAR!"); +const u8 gText_UproarKeptPkmnAwake[] = _("But the UPROAR kept\n{B_DEF_NAME_WITH_PREFIX} awake!"); +const u8 gText_PkmnStayedAwakeUsing[] = _("{B_DEF_NAME_WITH_PREFIX} stayed awake\nusing its {B_DEF_ABILITY}!"); +const u8 gText_PkmnStoringEnergy[] = _("{B_ATK_NAME_WITH_PREFIX} is storing\nenergy!"); +const u8 gText_PkmnUnleashedEnergy[] = _("{B_ATK_NAME_WITH_PREFIX} unleashed\nenergy!"); +const u8 gText_PkmnFatigueConfusion[] = _("{B_ATK_NAME_WITH_PREFIX} became\nconfused due to fatigue!"); +const u8 gText_PkmnPickedUpItem[] = _("{B_PLAYER_NAME} picked up\n¥{B_BUFF1}!\p"); +const u8 gText_PkmnUnaffected[] = _("{B_DEF_NAME_WITH_PREFIX} is\nunaffected!"); +const u8 gText_PkmnTransformedInto[] = _("{B_ATK_NAME_WITH_PREFIX} transformed\ninto {B_BUFF1}!"); +const u8 gText_PkmnMadeSubstitute[] = _("{B_ATK_NAME_WITH_PREFIX} made\na SUBSTITUTE!"); +const u8 gText_PkmnHasSubstitute[] = _("{B_ATK_NAME_WITH_PREFIX} already\nhas a SUBSTITUTE!"); +const u8 gText_SubstituteDamaged[] = _("The SUBSTITUTE took damage\nfor {B_DEF_NAME_WITH_PREFIX}!\p"); +const u8 gText_PkmnSubstituteFaded[] = _("{B_DEF_NAME_WITH_PREFIX}’s\nSUBSTITUTE faded!\p"); +const u8 gText_PkmnMustRecharge[] = _("{B_ATK_NAME_WITH_PREFIX} must\nrecharge!"); +const u8 gText_PkmnRageBuilding[] = _("{B_DEF_NAME_WITH_PREFIX}’s RAGE\nis building!"); +const u8 gText_PkmnMoveWasDisabled[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_BUFF1}\nwas disabled!"); +const u8 gText_PkmnMoveDisabledNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is disabled\nno more!"); +const u8 gText_PkmnGotEncore[] = _("{B_DEF_NAME_WITH_PREFIX} got\nan ENCORE!"); +const u8 gText_PkmnEncoreEnded[] = _("{B_ATK_NAME_WITH_PREFIX}’s ENCORE\nended!"); +const u8 gText_PkmnTookAim[] = _("{B_ATK_NAME_WITH_PREFIX} took aim\nat {B_DEF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnSketchedMove[] = _("{B_ATK_NAME_WITH_PREFIX} SKETCHED\n{B_BUFF1}!"); +const u8 gText_PkmnTryingToTakeFoe[] = _("{B_ATK_NAME_WITH_PREFIX} is trying\nto take its foe with it!"); +const u8 gText_PkmnTookFoe[] = _("{B_DEF_NAME_WITH_PREFIX} took\n{B_ATK_NAME_WITH_PREFIX} with it!"); +const u8 gText_PkmnReducedPP[] = _("Reduced {B_DEF_NAME_WITH_PREFIX}’s\n{B_BUFF1} by {B_BUFF2}!"); +const u8 gText_PkmnStoleItem[] = _("{B_ATK_NAME_WITH_PREFIX} stole\n{B_DEF_NAME_WITH_PREFIX}’s {B_LAST_ITEM}!"); +const u8 gText_TargetCantEscapeNow[] = _("{B_DEF_NAME_WITH_PREFIX} can’t\nescape now!"); +const u8 gText_PkmnFellIntoNightmare[] = _("{B_DEF_NAME_WITH_PREFIX} fell into\na NIGHTMARE!"); +const u8 gText_PkmnLockedInNightmare[] = _("{B_ATK_NAME_WITH_PREFIX} is locked\nin a NIGHTMARE!"); +const u8 gText_PkmnLaidCurse[] = _("{B_ATK_NAME_WITH_PREFIX} cut its own HP and\nlaid a CURSE on {B_DEF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnAfflictedByCurse[] = _("{B_ATK_NAME_WITH_PREFIX} is afflicted\nby the CURSE!"); +const u8 gText_SpikesScattered[] = _("SPIKES were scattered all around\nthe opponent’s side!"); +const u8 gText_PkmnHurtBySpikes[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is hurt\nby SPIKES!"); +const u8 gText_PkmnIdentified[] = _("{B_ATK_NAME_WITH_PREFIX} identified\n{B_DEF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnPerishCountFell[] = _("{B_ATK_NAME_WITH_PREFIX}’s PERISH count\nfell to {B_BUFF1}!"); +const u8 gText_PkmnBracedItself[] = _("{B_ATK_NAME_WITH_PREFIX} braced\nitself!"); +const u8 gText_PkmnEnduredHit[] = _("{B_DEF_NAME_WITH_PREFIX} ENDURED\nthe hit!"); +const u8 gText_MagnitudeStrength[] = _("MAGNITUDE {B_BUFF1}!"); +const u8 gText_PkmnCutHPMaxedAttack[] = _("{B_ATK_NAME_WITH_PREFIX} cut its own HP\nand maximized ATTACK!"); +const u8 gText_PkmnCopiedStatChanges[] = _("{B_ATK_NAME_WITH_PREFIX} copied\n{B_DEF_NAME_WITH_PREFIX}’s stat changes!"); +const u8 gText_PkmnGotFree[] = _("{B_ATK_NAME_WITH_PREFIX} got free of\n{B_DEF_NAME_WITH_PREFIX}’s {B_BUFF1}!"); +const u8 gText_PkmnShedLeechSeed[] = _("{B_ATK_NAME_WITH_PREFIX} shed\nLEECH SEED!"); +const u8 gText_PkmnBlewAwaySpikes[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nSPIKES!"); +const u8 gText_PkmnFledFromBattle[] = _("{B_ATK_NAME_WITH_PREFIX} fled from\nbattle!"); +const u8 gText_PkmnForesawAttack[] = _("{B_ATK_NAME_WITH_PREFIX} foresaw\nan attack!"); +const u8 gText_PkmnTookAttack[] = _("{B_DEF_NAME_WITH_PREFIX} took the\n{B_BUFF1} attack!"); +const u8 gText_PkmnChoseXAsDestiny[] = _("{B_ATK_NAME_WITH_PREFIX} chose\n{B_CURRENT_MOVE} as its destiny!"); +const u8 gText_PkmnAttack[] = _("{B_BUFF1}’s attack!"); +const u8 gText_PkmnCenterAttention[] = _("{B_ATK_NAME_WITH_PREFIX} became the\ncenter of attention!"); +const u8 gText_PkmnChargingPower[] = _("{B_ATK_NAME_WITH_PREFIX} began\ncharging power!"); +const u8 gText_NaturePowerTurnedInto[] = _("NATURE POWER turned into\n{B_CURRENT_MOVE}!"); +const u8 gText_PkmnStatusNormal[] = _("{B_ATK_NAME_WITH_PREFIX}’s status\nreturned to normal!"); +const u8 gText_PkmnSubjectedToTorment[] = _("{B_DEF_NAME_WITH_PREFIX} was subjected\nto TORMENT!"); +const u8 gText_PkmnTighteningFocus[] = _("{B_ATK_NAME_WITH_PREFIX} is tightening\nits focus!"); +const u8 gText_PkmnFellForTaunt[] = _("{B_DEF_NAME_WITH_PREFIX} fell for\nthe TAUNT!"); +const u8 gText_PkmnReadyToHelp[] = _("{B_ATK_NAME_WITH_PREFIX} is ready to\nhelp {B_DEF_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnSwitchedItems[] = _("{B_ATK_NAME_WITH_PREFIX} switched\nitems with its opponent!"); +const u8 gText_PkmnObtainedX[] = _("{B_ATK_NAME_WITH_PREFIX} obtained\n{B_BUFF1}."); +const u8 gText_PkmnObtainedX2[] = _("{B_DEF_NAME_WITH_PREFIX} obtained\n{B_BUFF2}."); +const u8 gText_PkmnObtainedXYObtainedZ[] = _("{B_ATK_NAME_WITH_PREFIX} obtained\n{B_BUFF1}.\p{B_DEF_NAME_WITH_PREFIX} obtained\n{B_BUFF2}."); +const u8 gText_PkmnCopiedFoe[] = _("{B_ATK_NAME_WITH_PREFIX} copied\n{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}!"); +const u8 gText_PkmnMadeWish[] = _("{B_ATK_NAME_WITH_PREFIX} made a WISH!"); +const u8 gText_PkmnWishCameTrue[] = _("{B_BUFF1}’s WISH\ncame true!"); +const u8 gText_PkmnPlantedRoots[] = _("{B_ATK_NAME_WITH_PREFIX} planted its roots!"); +const u8 gText_PkmnAbsorbedNutrients[] = _("{B_ATK_NAME_WITH_PREFIX} absorbed\nnutrients with its roots!"); +const u8 gText_PkmnAnchoredItself[] = _("{B_DEF_NAME_WITH_PREFIX} anchored\nitself with its roots!"); +const u8 gText_PkmnWasMadeDrowsy[] = _("{B_ATK_NAME_WITH_PREFIX} made\n{B_DEF_NAME_WITH_PREFIX} drowsy!"); +const u8 gText_PkmnKnockedOff[] = _("{B_ATK_NAME_WITH_PREFIX} knocked off\n{B_DEF_NAME_WITH_PREFIX}’s {B_LAST_ITEM}!"); +const u8 gText_PkmnSwappedAbilities[] = _("{B_ATK_NAME_WITH_PREFIX} swapped abilities\nwith its opponent!"); +const u8 gText_PkmnSealedOpponentMove[] = _("{B_ATK_NAME_WITH_PREFIX} sealed the\nopponent’s move(s)!"); +const u8 gText_PkmnWantsGrudge[] = _("{B_ATK_NAME_WITH_PREFIX} wants the\nopponent to bear a GRUDGE!"); +const u8 gText_PkmnLostPPGrudge[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_BUFF1} lost\nall its PP due to the GRUDGE!"); +const u8 gText_PkmnShroudedItself[] = _("{B_ATK_NAME_WITH_PREFIX} shrouded\nitself in {B_CURRENT_MOVE}!"); +const u8 gText_PkmnMoveBounced[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_CURRENT_MOVE}\nwas bounced back by MAGIC COAT!"); +const u8 gText_PkmnWaitsForTarget[] = _("{B_ATK_NAME_WITH_PREFIX} waits for a target\nto make a move!"); +const u8 gText_PkmnSnatchedMove[] = _("{B_DEF_NAME_WITH_PREFIX} SNATCHED\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s move!"); +const u8 gText_ElectricityWeakened[] = _("Electricity’s power was\nweakened!"); +const u8 gText_FireWeakened[] = _("Fire’s power was\nweakened!"); +const u8 gText_XFoundOneY[] = _("{B_ATK_NAME_WITH_PREFIX} found\none {B_LAST_ITEM}!"); +const u8 gText_SoothingAroma[] = _("A soothing aroma wafted\nthrough the area!"); +const u8 gText_ItemsCantBeUsedNow[] = _("Items can’t be used now.{PAUSE 64}"); +const u8 gText_ForXCommaYZ[] = _("For {B_SCR_ACTIVE_NAME_WITH_PREFIX},\n{B_LAST_ITEM} {B_BUFF1}"); +const u8 gText_PkmnUsedXToGetPumped[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used\n{B_LAST_ITEM} to get pumped!"); +const u8 gText_PkmnLostFocus[] = _("{B_ATK_NAME_WITH_PREFIX} lost its\nfocus and couldn’t move!"); +const u8 gText_PkmnWasDraggedOut[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndragged out!\p"); +const u8 gText_TheWallShattered[] = _("The wall shattered!"); +const u8 gText_ButNoEffect[] = _("But it had no effect!"); +const u8 gText_PkmnHasNoMovesLeft[] = _("{B_ACTIVE_NAME_WITH_PREFIX} has no\nmoves left!\p"); +const u8 gText_PkmnMoveIsDisabled[] = _("{B_ACTIVE_NAME_WITH_PREFIX}’s {B_CURRENT_MOVE}\nis disabled!\p"); +const u8 gText_PkmnCantUseMoveTorment[] = _("{B_ACTIVE_NAME_WITH_PREFIX} can’t use the same\nmove in a row due to the TORMENT!\p"); +const u8 gText_PkmnCantUseMoveTaunt[] = _("{B_ACTIVE_NAME_WITH_PREFIX} can’t use\n{B_CURRENT_MOVE} after the TAUNT!\p"); +const u8 gText_PkmnCantUseMoveSealed[] = _("{B_ACTIVE_NAME_WITH_PREFIX} can’t use the\nsealed {B_CURRENT_MOVE}!\p"); +const u8 gText_PkmnMadeItRain[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nmade it rain!"); +const u8 gText_PkmnRaisedSpeed[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nraised its SPEED!"); +const u8 gText_PkmnProtectedBy[] = _("{B_DEF_NAME_WITH_PREFIX} was protected\nby {B_DEF_ABILITY}!"); +const u8 gText_PkmnPreventsUsage[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nprevents {B_ATK_NAME_WITH_PREFIX}\lfrom using {B_CURRENT_MOVE}!"); +const u8 gText_PkmnRestoredHPUsing[] = _("{B_DEF_NAME_WITH_PREFIX} restored HP\nusing its {B_DEF_ABILITY}!"); +const u8 gText_PkmnsXMadeYUseless[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nmade {B_CURRENT_MOVE} useless!"); +const u8 gText_PkmnChangedTypeWith[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nmade it the {B_BUFF1} type!"); +const u8 gText_PkmnPreventsParalysisWith[] = _("{B_EFF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nprevents paralysis!"); +const u8 gText_PkmnPreventsRomanceWith[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nprevents romance!"); +const u8 gText_PkmnPreventsPoisoningWith[] = _("{B_EFF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nprevents poisoning!"); +const u8 gText_PkmnPreventsConfusionWith[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nprevents confusion!"); +const u8 gText_PkmnRaisedFirePowerWith[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nraised its FIRE power!"); +const u8 gText_PkmnAnchorsItselfWith[] = _("{B_DEF_NAME_WITH_PREFIX} anchors\nitself with {B_DEF_ABILITY}!"); +const u8 gText_PkmnCutsAttackWith[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\ncuts {B_DEF_NAME_WITH_PREFIX}’s ATTACK!"); +const u8 gText_PkmnPreventsStatLossWith[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nprevents stat loss!"); +const u8 gText_PkmnHurtsWith[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nhurt {B_ATK_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnTraced[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} TRACED\n{B_BUFF1}’s {B_BUFF2}!"); +const u8 gText_PkmnsXPreventsBurns[] = _("{B_EFF_NAME_WITH_PREFIX}’s {B_EFF_ABILITY}\nprevents burns!"); +const u8 gText_PkmnsXBlocksY[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nblocks {B_CURRENT_MOVE}!"); +const u8 gText_PkmnsXBlocksY2[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nblocks {B_CURRENT_MOVE}!"); +const u8 gText_PkmnsXRestoredHPALittle2[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_ATK_ABILITY}\nrestored its HP a little!"); +const u8 gText_PkmnsXWhippedUpSandstorm[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nwhipped up a sandstorm!"); +const u8 gText_PkmnsXIntensifiedSun[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nintensified the sun’s rays!"); +const u8 gText_PkmnsXPreventsYLoss[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nprevents {B_BUFF1} loss!"); +const u8 gText_PkmnsXInfatuatedY[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\ninfatuated {B_ATK_NAME_WITH_PREFIX}!"); +const u8 gText_PkmnsXMadeYIneffective[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nmade {B_CURRENT_MOVE} ineffective!"); +const u8 gText_PkmnsXCuredYProblem[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\ncured its {B_BUFF1} problem!"); +const u8 gText_ItSuckedLiquidOoze[] = _("It sucked up the\nLIQUID OOZE!"); +const u8 gText_PkmnTransformed[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} transformed!"); +const u8 gText_PkmnsXTookAttack[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\ntook the attack!"); +const u8 gText_PkmnsXPreventsSwitching[] = _("{B_BUFF1}’s {B_LAST_ABILITY}\nprevents switching!\p"); +const u8 gText_PreventedFromWorking[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_DEF_ABILITY}\nprevented {B_SCR_ACTIVE_NAME_WITH_PREFIX}’s\l{B_BUFF1} from working!"); +const u8 gText_PkmnsXMadeItIneffective[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nmade it ineffective!"); +const u8 gText_PkmnsXPreventsFlinching[] = _("{B_EFF_NAME_WITH_PREFIX}’s {B_EFF_ABILITY}\nprevents flinching!"); +const u8 gText_PkmnsXPreventsYsZ[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_ATK_ABILITY}\nprevents {B_DEF_NAME_WITH_PREFIX}’s\l{B_DEF_ABILITY} from working!"); +const u8 gText_PkmnsXCuredItsYProblem[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\ncured its {B_BUFF1} problem!"); +const u8 gText_PkmnsXHadNoEffectOnY[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_SCR_ACTIVE_ABILITY}\nhad no effect on {B_EFF_NAME_WITH_PREFIX}!"); +const u8 gText_StatSharply[] = _("sharply "); +const u8 gText_StatRose[] = _("rose!"); +const u8 gText_StatHarshly[] = _("harshly "); +const u8 gText_StatFell[] = _("fell!"); +const u8 gText_PkmnsStatChanged[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_BUFF1}\n{B_BUFF2}"); +const u8 gText_PkmnsStatChanged2[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_BUFF1}\n{B_BUFF2}"); +const u8 gText_UsingXTheYOfZN[] = _("Using {B_LAST_ITEM}, the {B_BUFF1}\nof {B_SCR_ACTIVE_NAME_WITH_PREFIX} {B_BUFF2}"); +const u8 gText_PkmnsStatChanged3[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_BUFF1}\n{B_BUFF2}"); +const u8 gText_PkmnsStatChanged4[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_BUFF1}\n{B_BUFF2}"); +const u8 gText_StatsWontIncrease2[] = _("{B_ATK_NAME_WITH_PREFIX}’s stats won’t\ngo any higher!"); +const u8 gText_StatsWontDecrease2[] = _("{B_DEF_NAME_WITH_PREFIX}’s stats won’t\ngo any lower!"); +const u8 gText_CriticalHit[] = _("A critical hit!"); +const u8 gText_OneHitKO[] = _("It’s a one-hit KO!"); +const u8 gText_123Poof[] = _("{PAUSE 32}1, {PAUSE 15}2, and{PAUSE 15}… {PAUSE 15}… {PAUSE 15}… {PAUSE 15}{PLAY_SE 0x0038}Poof!\p"); +const u8 gText_AndEllipsis[] = _("And…\p"); +const u8 gText_HMMovesCantBeForgotten[] = _("HM moves can’t be\nforgotten now.\p"); +const u8 gText_NotVeryEffective[] = _("It’s not very effective…"); +const u8 gText_SuperEffective[] = _("It’s super effective!"); +const u8 gText_GotAwaySafely[] = _("{PLAY_SE 0x0011}Got away safely!\p"); +const u8 gText_PkmnFledUsingIts[] = _("{PLAY_SE 0x0011}{B_ATK_NAME_WITH_PREFIX} fled\nusing its {B_LAST_ITEM}!\p"); +const u8 gText_PkmnFledUsing[] = _("{PLAY_SE 0x0011}{B_ATK_NAME_WITH_PREFIX} fled\nusing {B_ATK_ABILITY}!\p"); +const u8 gText_WildPkmnFled[] = _("{PLAY_SE 0x0011}Wild {B_BUFF1} fled!"); +const u8 gText_PlayerDefeatedLinkTrainer[] = _("Player defeated\n{B_20}!"); +const u8 gText_TwoLinkTrainersDefeated[] = _("Player beat {B_20}\nand {B_21}!"); +const u8 gText_PlayerLostAgainstLinkTrainer[] = _("Player lost against\n{B_20}!"); +const u8 gText_PlayerLostToTwo[] = _("Player lost to {B_20}\nand {B_21}!"); +const u8 gText_PlayerBattledToDrawLinkTrainer[] = _("Player battled to a draw against\n{B_20}!"); +const u8 gText_PlayerBattledToDrawVsTwo[] = _("Player battled to a draw against\n{B_20} and {B_21}!"); +const u8 gText_WildFled[] = _("{PLAY_SE 0x0011}{B_20} fled!"); +const u8 gText_TwoWildFled[] = _("{PLAY_SE 0x0011}{B_20} and\n{B_21} fled!"); +const u8 gText_NoRunningFromTrainers[] = _("No! There’s no running\nfrom a TRAINER battle!\p"); +const u8 gText_CantEscape[] = _("Can’t escape!\p"); +const u8 gText_DontLeaveBirch[] = _("PROF. BIRCH: Don’t leave me like this!\p"); +const u8 gText_ButNothingHappened[] = _("But nothing happened!"); +const u8 gText_ButItFailed[] = _("But it failed!"); +const u8 gText_ItHurtConfusion[] = _("It hurt itself in its\nconfusion!"); +const u8 gText_MirrorMoveFailed[] = _("The MIRROR MOVE failed!"); +const u8 gText_StartedToRain[] = _("It started to rain!"); +const u8 gText_DownpourStarted[] = _("A downpour started!"); +const u8 gText_RainContinues[] = _("Rain continues to fall."); +const u8 gText_DownpourContinues[] = _("The downpour continues."); +const u8 gText_RainStopped[] = _("The rain stopped."); +const u8 gText_SandstormBrewed[] = _("A sandstorm brewed!"); +const u8 gText_SandstormRages[] = _("The sandstorm rages."); +const u8 gText_SandstormSubsided[] = _("The sandstorm subsided."); +const u8 gText_SunlightGotBright[] = _("The sunlight got bright!"); +const u8 gText_SunlightStrong[] = _("The sunlight is strong."); +const u8 gText_SunlightFaded[] = _("The sunlight faded."); +const u8 gText_StartedHail[] = _("It started to hail!"); +const u8 gText_HailContinues[] = _("Hail continues to fall."); +const u8 gText_HailStopped[] = _("The hail stopped."); +const u8 gText_FailedToSpitUp[] = _("But it failed to SPIT UP\na thing!"); +const u8 gText_FailedToSwallow[] = _("But it failed to SWALLOW\na thing!"); +const u8 gText_WindBecameHeatWave[] = _("The wind turned into a\nHEAT WAVE!"); +const u8 gText_StatChangesGone[] = _("All stat changes were\neliminated!"); +const u8 gText_CoinsScattered[] = _("Coins scattered everywhere!"); +const u8 gText_TooWeakForSubstitute[] = _("It was too weak to make\na SUBSTITUTE!"); +const u8 gText_SharedPain[] = _("The battlers shared\ntheir pain!"); +const u8 gText_BellChimed[] = _("A bell chimed!"); +const u8 gText_FaintInThree[] = _("All affected POKéMON will\nfaint in three turns!"); +const u8 gText_NoPPLeft[] = _("There’s no PP left for\nthis move!\p"); +const u8 gText_ButNoPPLeft[] = _("But there was no PP left\nfor the move!"); +const u8 gText_PkmnIgnoresAsleep[] = _("{B_ATK_NAME_WITH_PREFIX} ignored\norders while asleep!"); +const u8 gText_PkmnIgnoredOrders[] = _("{B_ATK_NAME_WITH_PREFIX} ignored\norders!"); +const u8 gText_PkmnBeganToNap[] = _("{B_ATK_NAME_WITH_PREFIX} began to nap!"); +const u8 gText_PkmnLoafing[] = _("{B_ATK_NAME_WITH_PREFIX} is\nloafing around!"); +const u8 gText_PkmnWontObey[] = _("{B_ATK_NAME_WITH_PREFIX} won’t\nobey!"); +const u8 gText_PkmnTurnedAway[] = _("{B_ATK_NAME_WITH_PREFIX} turned away!"); +const u8 gText_PkmnPretendNotNotice[] = _("{B_ATK_NAME_WITH_PREFIX} pretended\nnot to notice!"); +const u8 gText_EnemyAboutToSwitchPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} is\nabout to use {B_BUFF2}.\pWill {B_PLAYER_NAME} change\nPOKéMON?"); +const u8 gText_PkmnLearnedMove2[] = _("{B_ATK_NAME_WITH_PREFIX} learned\n{B_BUFF1}!"); +const u8 gText_PlayerDefeatedLinkTrainerTrainer1[] = _("Player defeated\n{B_TRAINER1_CLASS} {B_TRAINER1_NAME}!\p"); +const u8 gText_CreptCloser[] = _("{B_PLAYER_NAME} crept closer to\n{B_OPPONENT_MON1_NAME}!"); +const u8 gText_CantGetCloser[] = _("{B_PLAYER_NAME} can’t get any closer!"); +const u8 gText_PkmnWatchingCarefully[] = _("{B_OPPONENT_MON1_NAME} is watching\ncarefully!"); +const u8 gText_PkmnCuriousAboutX[] = _("{B_OPPONENT_MON1_NAME} is curious about\nthe {B_BUFF1}!"); +const u8 gText_PkmnEnthralledByX[] = _("{B_OPPONENT_MON1_NAME} is enthralled by\nthe {B_BUFF1}!"); +const u8 gText_PkmnIgnoredX[] = _("{B_OPPONENT_MON1_NAME} completely ignored\nthe {B_BUFF1}!"); +const u8 gText_ThrewPokeblockAtPkmn[] = _("{B_PLAYER_NAME} threw a {POKEBLOCK}\nat the {B_OPPONENT_MON1_NAME}!"); +const u8 gText_OutOfSafariBalls[] = _("{PLAY_SE 0x0049}ANNOUNCER: You’re out of\nSAFARI BALLS! Game over!\p"); +const u8 gText_OpponentMon1Appeared[] = _("{B_OPPONENT_MON1_NAME} appeared!\p"); +const u8 gText_WildPkmnAppeared[] = _("Wild {B_OPPONENT_MON1_NAME} appeared!\p"); +const u8 gText_WildPkmnAppeared2[] = _("Wild {B_OPPONENT_MON1_NAME} appeared!\p"); +const u8 gText_WildPkmnAppearedPause[] = _("Wild {B_OPPONENT_MON1_NAME} appeared!{PAUSE 127}"); +const u8 gText_TwoWildPkmnAppeared[] = _("Wild {B_OPPONENT_MON1_NAME} and\n{B_OPPONENT_MON2_NAME} appeared!\p"); +const u8 gText_Trainer1WantsToBattle[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME}\nwould like to battle!\p"); +const u8 gText_LinkTrainerWantsToBattle[] = _("{B_20}\nwants to battle!"); +const u8 gText_TwoLinkTrainersWantToBattle[] = _("{B_20} and {B_21}\nwant to battle!"); +const u8 gText_Trainer1SentOutPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent\nout {B_OPPONENT_MON1_NAME}!"); +const u8 gText_Trainer1SentOutTwoPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent\nout {B_OPPONENT_MON1_NAME} and {B_OPPONENT_MON2_NAME}!"); +const u8 gText_Trainer1SentOutPkmn2[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent\nout {B_BUFF1}!"); +const u8 gText_LinkTrainerSentOutPkmn[] = _("{B_20} sent out\n{B_OPPONENT_MON1_NAME}!"); +const u8 gText_LinkTrainerSentOutTwoPkmn[] = _("{B_20} sent out\n{B_OPPONENT_MON1_NAME} and {B_OPPONENT_MON2_NAME}!"); +const u8 gText_TwoLinkTrainersSentOutPkmn[] = _("{B_20} sent out {B_LINK_OPPONENT_MON1_NAME}!\n{B_21} sent out {B_LINK_OPPONENT_MON2_NAME}!"); +const u8 gText_LinkTrainerSentOutPkmn2[] = _("{B_20} sent out\n{B_BUFF1}!"); +const u8 gText_LinkTrainerMultiSentOutPkmn[] = _("{B_22} sent out\n{B_BUFF1}!"); +const u8 gText_GoPkmn[] = _("Go! {B_PLAYER_MON1_NAME}!"); +const u8 gText_GoTwoPkmn[] = _("Go! {B_PLAYER_MON1_NAME} and\n{B_PLAYER_MON2_NAME}!"); +const u8 gText_GoPkmn2[] = _("Go! {B_BUFF1}!"); +const u8 gText_DoItPkmn[] = _("Do it! {B_BUFF1}!"); +const u8 gText_GoForItPkmn[] = _("Go for it, {B_BUFF1}!"); +const u8 gText_YourFoesWeakGetEmPkmn[] = _("Your foe’s weak!\nGet ’em, {B_BUFF1}!"); +const u8 gText_LinkPartnerSentOutPkmnGoPkmn[] = _("{B_1F} sent out {B_LINK_PLAYER_MON2_NAME}!\nGo! {B_LINK_PLAYER_MON1_NAME}!"); +const u8 gText_PkmnThatsEnough[] = _("{B_BUFF1}, that’s enough!\nCome back!"); +const u8 gText_PkmnComeBack[] = _("{B_BUFF1}, come back!"); +const u8 gText_PkmnOkComeBack[] = _("{B_BUFF1}, OK!\nCome back!"); +const u8 gText_PkmnGoodComeBack[] = _("{B_BUFF1}, good!\nCome back!"); +const u8 gText_Trainer1WithdrewPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME}\nwithdrew {B_BUFF1}!"); +const u8 gText_LinkTrainer1WithdrewPkmn[] = _("{B_20} withdrew\n{B_BUFF1}!"); +const u8 gText_LinkTrainer2WithdrewPkmn[] = _("{B_22} withdrew\n{B_BUFF1}!"); +const u8 gText_WildPkmnPrefix[] = _("Wild "); +const u8 gText_FoePkmnPrefix[] = _("Foe "); +const u8 gText_EmptyString8[] = _( ""); +const u8 gText_FoePkmnPrefix2[] = _("Foe"); +const u8 gText_AllyPkmnPrefix[] = _("Ally"); +const u8 gText_FoePkmnPrefix3[] = _("Foe"); +const u8 gText_AllyPkmnPrefix2[] = _("Ally"); +const u8 gText_FoePkmnPrefix4[] = _("Foe"); +const u8 gText_AllyPkmnPrefix3[] = _("Ally"); +const u8 gText_AttackerUsedX[] = _("{B_ATK_NAME_WITH_PREFIX} used\n{B_BUFF2}"); +const u8 gText_ExclamationMark[] = _("!"); +const u8 gText_ExclamationMark2[] = _("!"); +const u8 gText_ExclamationMark3[] = _("!"); +const u8 gText_ExclamationMark4[] = _("!"); +const u8 gText_ExclamationMark5[] = _("!"); +const u8 gText_HP2[] = _("HP"); +const u8 gText_Attack2[] = _("ATTACK"); +const u8 gText_Defense2[] = _("DEFENSE"); +const u8 gText_Speed[] = _("SPEED"); +const u8 gText_SpAtk2[] = _("SP. ATK"); +const u8 gText_SpDef2[] = _("SP. DEF"); +const u8 gText_Accuracy[] = _("accuracy"); +const u8 gText_Evasiveness[] = _("evasiveness"); + +const u8 * const gStatNamesTable[] = +{ + gText_HP2, gText_Attack2, gText_Defense2, + gText_Speed, gText_SpAtk2, gText_SpDef2, + gText_Accuracy, gText_Evasiveness +}; + +const u8 gText_PokeblockWasTooSpicy[] = _("was too spicy!"); +const u8 gText_PokeblockWasTooDry[] = _("was too dry!"); +const u8 gText_PokeblockWasTooSweet[] = _("was too sweet!"); +const u8 gText_PokeblockWasTooBitter[] = _("was too bitter!"); +const u8 gText_PokeblockWasTooSour[] = _("was too sour!"); + +const u8 * const gPokeblockWasTooXStringTable[] = +{ + gText_PokeblockWasTooSpicy, gText_PokeblockWasTooDry, + gText_PokeblockWasTooSweet, gText_PokeblockWasTooBitter, + gText_PokeblockWasTooSour +}; + +const u8 gText_PlayerUsedItem[] = _("{B_PLAYER_NAME} used\n{B_LAST_ITEM}!"); +const u8 gText_WallyUsedItem[] = _("WALLY used\n{B_LAST_ITEM}!"); +const u8 gText_Trainer1UsedItem[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME}\nused {B_LAST_ITEM}!"); +const u8 gText_TrainerBlockedBall[] = _("The TRAINER blocked the BALL!"); +const u8 gText_DontBeAThief[] = _("Don’t be a thief!"); +const u8 gText_ItDodgedBall[] = _("It dodged the thrown BALL!\nThis POKéMON can’t be caught!"); +const u8 gText_YouMissedPkmn[] = _("You missed the POKéMON!"); +const u8 gText_PkmnBrokeFree[] = _("Oh, no!\nThe POKéMON broke free!"); +const u8 gText_ItAppearedCaught[] = _("Aww!\nIt appeared to be caught!"); +const u8 gText_AarghAlmostHadIt[] = _("Aargh!\nAlmost had it!"); +const u8 gText_ShootSoClose[] = _("Shoot!\nIt was so close, too!"); +const u8 gText_GotchaPkmnCaught[] = _("Gotcha!\n{B_OPPONENT_MON1_NAME} was caught!{UNKNOWN_A}{PLAY_BGM BGM_KACHI22}\p"); +const u8 gText_GotchaPkmnCaught2[] = _("Gotcha!\n{B_OPPONENT_MON1_NAME} was caught!{UNKNOWN_A}{PLAY_BGM BGM_KACHI22}{PAUSE 127}"); +const u8 gText_GiveNicknameCaptured[] = _("Give a nickname to the\ncaptured {B_OPPONENT_MON1_NAME}?"); +const u8 gText_PkmnSentToPC[] = _("{B_OPPONENT_MON1_NAME} was sent to\n{B_PC_CREATOR_NAME} PC."); +const u8 gText_Someones[] = _("someone’s"); +const u8 gText_Lanettes[] = _("LANETTE’s"); +const u8 gText_PkmnDataAddedToDex[] = _("{B_OPPONENT_MON1_NAME}’s data was\nadded to the POKéDEX.\p"); +const u8 gText_ItIsRaining[] = _("It is raining."); +const u8 gText_SandstormIsRaging[] = _("A sandstorm is raging."); +const u8 gText_BoxIsFull[] = _("The BOX is full!\nYou can’t catch any more!\p"); +const u8 gText_EnigmaBerry[] = _("ENIGMA BERRY"); +const u8 gText_BerrySuffix[] = _(" BERRY"); +const u8 gText_PkmnsItemCuredParalysis[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\ncured paralysis!"); +const u8 gText_PkmnsItemCuredPoison[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\ncured poison!"); +const u8 gText_PkmnsItemHealedBurn[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nhealed its burn!"); +const u8 gText_PkmnsItemDefrostedIt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\ndefrosted it!"); +const u8 gText_PkmnsItemWokeIt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nwoke it from its sleep!"); +const u8 gText_PkmnsItemSnappedOut[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nsnapped it out of confusion!"); +const u8 gText_PkmnsItemCuredProblem[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\ncured its {B_BUFF1} problem!"); +const u8 gText_PkmnsItemNormalizedStatus[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nnormalized its status!"); +const u8 gText_PkmnsItemRestoredHealth[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nrestored health!"); +const u8 gText_PkmnsItemRestoredPP[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nrestored {B_BUFF1}’s PP!"); +const u8 gText_PkmnsItemRestoredStatus[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nrestored its status!"); +const u8 gText_PkmnsItemRestoredHPALittle[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s {B_LAST_ITEM}\nrestored its HP a little!"); +const u8 gText_ItemAllowsOnlyYMove[] = _("{B_LAST_ITEM} allows the\nuse of only {B_CURRENT_MOVE}!\p"); +const u8 gText_PkmnHungOnWithX[] = _("{B_DEF_NAME_WITH_PREFIX} hung on\nusing its {B_LAST_ITEM}!"); +const u8 gText_EmptyString3[] = _(""); +const u8 gText_YouThrowABallNowRight[] = _("You throw a BALL now, right?\nI… I’ll do my best!"); + +// early declaration of strings +const u8 gText_PkmnIncapableOfPower[]; +const u8 gText_GlintAppearsInEye[]; +const u8 gText_PkmnGettingIntoPosition[]; +const u8 gText_PkmnBeganGrowlingDeeply[]; +const u8 gText_PkmnEagerForMore[]; +const u8 gText_DefeatedOpponentByReferee[]; +const u8 gText_LostToOpponentByReferee[]; +const u8 gText_TiedOpponentByReferee[]; +const u8 gText_QuestionForfeitMatch[]; +const u8 gText_ForfeitedMatch[]; +const u8 gText_Trainer1WinText[]; +const u8 gText_Trainer2WinText[]; +const u8 gText_TwoInGameTrainersDefeated[]; +const u8 gText_Trainer2LoseText[]; + +const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT] = +{ + gText_Trainer1LoseText, + gText_PkmnGainedEXP, + gText_PkmnGrewToLv, + gText_PkmnLearnedMove, + gText_TryToLearnMove1, + gText_TryToLearnMove2, + gText_TryToLearnMove3, + gText_PkmnForgotMove, + gText_StopLearningMove, + gText_DidNotLearnMove, + gText_PkmnLearnedMove2, + gText_AttackMissed, + gText_PkmnProtectedItself, + gText_StatsWontIncrease2, + gText_AvoidedDamage, + gText_ItDoesntAffect, + gText_AttackerFainted, + gText_TargetFainted, + gText_PlayerGotMoney, + gText_PlayerWhiteout, + gText_PlayerWhiteout2, + gText_PreventsEscape, + gText_HitXTimes, + gText_PkmnFellAsleep, + gText_PkmnMadeSleep, + gText_PkmnAlreadyAsleep, + gText_PkmnAlreadyAsleep2, + gText_PkmnWasntAffected, + gText_PkmnWasPoisoned, + gText_PkmnPoisonedBy, + gText_PkmnHurtByPoison, + gText_PkmnAlreadyPoisoned, + gText_PkmnBadlyPoisoned, + gText_PkmnEnergyDrained, + gText_PkmnWasBurned, + gText_PkmnBurnedBy, + gText_PkmnHurtByBurn, + gText_PkmnWasFrozen, + gText_PkmnFrozenBy, + gText_PkmnIsFrozen, + gText_PkmnWasDefrosted, + gText_PkmnWasDefrosted2, + gText_PkmnWasDefrostedBy, + gText_PkmnWasParalyzed, + gText_PkmnWasParalyzedBy, + gText_PkmnIsParalyzed, + gText_PkmnIsAlreadyParalyzed, + gText_PkmnHealedParalysis, + gText_PkmnDreamEaten, + gText_StatsWontIncrease, + gText_StatsWontDecrease, + gText_TeamStoppedWorking, + gText_FoeStoppedWorking, + gText_PkmnIsConfused, + gText_PkmnHealedConfusion, + gText_PkmnWasConfused, + gText_PkmnAlreadyConfused, + gText_PkmnFellInLove, + gText_PkmnInLove, + gText_PkmnImmobilizedByLove, + gText_PkmnBlownAway, + gText_PkmnChangedType, + gText_PkmnFlinched, + gText_PkmnRegainedHealth, + gText_PkmnHPFull, + gText_PkmnRaisedSpDef, + gText_PkmnRaisedDef, + gText_PkmnCoveredByVeil, + gText_PkmnUsedSafeguard, + gText_PkmnSafeguardExpired, + gText_PkmnWentToSleep, + gText_PkmnSleptHealthy, + gText_PkmnWhippedWhirlwind, + gText_PkmnTookSunlight, + gText_PkmnLoweredHead, + gText_PkmnIsGlowing, + gText_PkmnFlewHigh, + gText_PkmnDugHole, + gText_PkmnSqueezedByBind, + gText_PkmnTrappedInVortex, + gText_PkmnWrappedBy, + gText_PkmnClamped, + gText_PkmnHurtBy, + gText_PkmnFreedFrom, + gText_PkmnCrashed, + gText_PkmnShroudedInMist, + gText_PkmnProtectedByMist, + gText_PkmnGettingPumped, + gText_PkmnHitWithRecoil, + gText_PkmnProtectedItself2, + gText_PkmnBuffetedBySandstorm, + gText_PkmnPeltedByHail, + gText_PkmnSeeded, + gText_PkmnEvadedAttack, + gText_PkmnSappedByLeechSeed, + gText_PkmnFastAsleep, + gText_PkmnWokeUp, + gText_PkmnUproarKeptAwake, + gText_PkmnWokeUpInUproar, + gText_PkmnCausedUproar, + gText_PkmnMakingUproar, + gText_PkmnCalmedDown, + gText_PkmnCantSleepInUproar, + gText_PkmnStockpiled, + gText_PkmnCantStockpile, + gText_PkmnCantSleepInUproar2, + gText_UproarKeptPkmnAwake, + gText_PkmnStayedAwakeUsing, + gText_PkmnStoringEnergy, + gText_PkmnUnleashedEnergy, + gText_PkmnFatigueConfusion, + gText_PkmnPickedUpItem, + gText_PkmnUnaffected, + gText_PkmnTransformedInto, + gText_PkmnMadeSubstitute, + gText_PkmnHasSubstitute, + gText_SubstituteDamaged, + gText_PkmnSubstituteFaded, + gText_PkmnMustRecharge, + gText_PkmnRageBuilding, + gText_PkmnMoveWasDisabled, + gText_PkmnMoveIsDisabled, + gText_PkmnMoveDisabledNoMore, + gText_PkmnGotEncore, + gText_PkmnEncoreEnded, + gText_PkmnTookAim, + gText_PkmnSketchedMove, + gText_PkmnTryingToTakeFoe, + gText_PkmnTookFoe, + gText_PkmnReducedPP, + gText_PkmnStoleItem, + gText_TargetCantEscapeNow, + gText_PkmnFellIntoNightmare, + gText_PkmnLockedInNightmare, + gText_PkmnLaidCurse, + gText_PkmnAfflictedByCurse, + gText_SpikesScattered, + gText_PkmnHurtBySpikes, + gText_PkmnIdentified, + gText_PkmnPerishCountFell, + gText_PkmnBracedItself, + gText_PkmnEnduredHit, + gText_MagnitudeStrength, + gText_PkmnCutHPMaxedAttack, + gText_PkmnCopiedStatChanges, + gText_PkmnGotFree, + gText_PkmnShedLeechSeed, + gText_PkmnBlewAwaySpikes, + gText_PkmnFledFromBattle, + gText_PkmnForesawAttack, + gText_PkmnTookAttack, + gText_PkmnAttack, + gText_PkmnCenterAttention, + gText_PkmnChargingPower, + gText_NaturePowerTurnedInto, + gText_PkmnStatusNormal, + gText_PkmnHasNoMovesLeft, + gText_PkmnSubjectedToTorment, + gText_PkmnCantUseMoveTorment, + gText_PkmnTighteningFocus, + gText_PkmnFellForTaunt, + gText_PkmnCantUseMoveTaunt, + gText_PkmnReadyToHelp, + gText_PkmnSwitchedItems, + gText_PkmnCopiedFoe, + gText_PkmnMadeWish, + gText_PkmnWishCameTrue, + gText_PkmnPlantedRoots, + gText_PkmnAbsorbedNutrients, + gText_PkmnAnchoredItself, + gText_PkmnWasMadeDrowsy, + gText_PkmnKnockedOff, + gText_PkmnSwappedAbilities, + gText_PkmnSealedOpponentMove, + gText_PkmnCantUseMoveSealed, + gText_PkmnWantsGrudge, + gText_PkmnLostPPGrudge, + gText_PkmnShroudedItself, + gText_PkmnMoveBounced, + gText_PkmnWaitsForTarget, + gText_PkmnSnatchedMove, + gText_PkmnMadeItRain, + gText_PkmnRaisedSpeed, + gText_PkmnProtectedBy, + gText_PkmnPreventsUsage, + gText_PkmnRestoredHPUsing, + gText_PkmnChangedTypeWith, + gText_PkmnPreventsParalysisWith, + gText_PkmnPreventsRomanceWith, + gText_PkmnPreventsPoisoningWith, + gText_PkmnPreventsConfusionWith, + gText_PkmnRaisedFirePowerWith, + gText_PkmnAnchorsItselfWith, + gText_PkmnCutsAttackWith, + gText_PkmnPreventsStatLossWith, + gText_PkmnHurtsWith, + gText_PkmnTraced, + gText_StatSharply, + gText_StatRose, + gText_StatHarshly, + gText_StatFell, + gText_PkmnsStatChanged, + gText_PkmnsStatChanged2, + gText_PkmnsStatChanged3, + gText_PkmnsStatChanged4, + gText_CriticalHit, + gText_OneHitKO, + gText_123Poof, + gText_AndEllipsis, + gText_NotVeryEffective, + gText_SuperEffective, + gText_GotAwaySafely, + gText_WildPkmnFled, + gText_NoRunningFromTrainers, + gText_CantEscape, + gText_DontLeaveBirch, + gText_ButNothingHappened, + gText_ButItFailed, + gText_ItHurtConfusion, + gText_MirrorMoveFailed, + gText_StartedToRain, + gText_DownpourStarted, + gText_RainContinues, + gText_DownpourContinues, + gText_RainStopped, + gText_SandstormBrewed, + gText_SandstormRages, + gText_SandstormSubsided, + gText_SunlightGotBright, + gText_SunlightStrong, + gText_SunlightFaded, + gText_StartedHail, + gText_HailContinues, + gText_HailStopped, + gText_FailedToSpitUp, + gText_FailedToSwallow, + gText_WindBecameHeatWave, + gText_StatChangesGone, + gText_CoinsScattered, + gText_TooWeakForSubstitute, + gText_SharedPain, + gText_BellChimed, + gText_FaintInThree, + gText_NoPPLeft, + gText_ButNoPPLeft, + gText_PlayerUsedItem, + gText_WallyUsedItem, + gText_TrainerBlockedBall, + gText_DontBeAThief, + gText_ItDodgedBall, + gText_YouMissedPkmn, + gText_PkmnBrokeFree, + gText_ItAppearedCaught, + gText_AarghAlmostHadIt, + gText_ShootSoClose, + gText_GotchaPkmnCaught, + gText_GotchaPkmnCaught2, + gText_GiveNicknameCaptured, + gText_PkmnSentToPC, + gText_PkmnDataAddedToDex, + gText_ItIsRaining, + gText_SandstormIsRaging, + gText_CantEscape2, + gText_PkmnIgnoresAsleep, + gText_PkmnIgnoredOrders, + gText_PkmnBeganToNap, + gText_PkmnLoafing, + gText_PkmnWontObey, + gText_PkmnTurnedAway, + gText_PkmnPretendNotNotice, + gText_EnemyAboutToSwitchPkmn, + gText_CreptCloser, + gText_CantGetCloser, + gText_PkmnWatchingCarefully, + gText_PkmnCuriousAboutX, + gText_PkmnEnthralledByX, + gText_PkmnIgnoredX, + gText_ThrewPokeblockAtPkmn, + gText_OutOfSafariBalls, + gText_PkmnsItemCuredParalysis, + gText_PkmnsItemCuredPoison, + gText_PkmnsItemHealedBurn, + gText_PkmnsItemDefrostedIt, + gText_PkmnsItemWokeIt, + gText_PkmnsItemSnappedOut, + gText_PkmnsItemCuredProblem, + gText_PkmnsItemRestoredHealth, + gText_PkmnsItemRestoredPP, + gText_PkmnsItemRestoredStatus, + gText_PkmnsItemRestoredHPALittle, + gText_ItemAllowsOnlyYMove, + gText_PkmnHungOnWithX, + gText_EmptyString3, + gText_PkmnsXPreventsBurns, + gText_PkmnsXBlocksY, + gText_PkmnsXRestoredHPALittle2, + gText_PkmnsXWhippedUpSandstorm, + gText_PkmnsXPreventsYLoss, + gText_PkmnsXInfatuatedY, + gText_PkmnsXMadeYIneffective, + gText_PkmnsXCuredYProblem, + gText_ItSuckedLiquidOoze, + gText_PkmnTransformed, + gText_ElectricityWeakened, + gText_FireWeakened, + gText_PkmnHidUnderwater, + gText_PkmnSprangUp, + gText_HMMovesCantBeForgotten, + gText_XFoundOneY, + gText_PlayerDefeatedLinkTrainerTrainer1, + gText_SoothingAroma, + gText_ItemsCantBeUsedNow, + gText_ForXCommaYZ, + gText_UsingXTheYOfZN, + gText_PkmnUsedXToGetPumped, + gText_PkmnsXMadeYUseless, + gText_PkmnTrappedBySandTomb, + gText_EmptyString4, + gText_ABoosted, + gText_PkmnsXIntensifiedSun, + gText_PkmnMakesGroundMiss, + gText_YouThrowABallNowRight, + gText_PkmnsXTookAttack, + gText_PkmnChoseXAsDestiny, + gText_PkmnLostFocus, + gText_UseNextPkmn, + gText_PkmnFledUsingIts, + gText_PkmnFledUsing, + gText_PkmnWasDraggedOut, + gText_PreventedFromWorking, + gText_PkmnsItemNormalizedStatus, + gText_Trainer1UsedItem, + gText_BoxIsFull, + gText_PkmnAvoidedAttack, + gText_PkmnsXMadeItIneffective, + gText_PkmnsXPreventsFlinching, + gText_PkmnAlreadyHasBurn, + gText_StatsWontDecrease2, + gText_PkmnsXBlocksY2, + gText_PkmnsXWoreOff, + gText_PkmnRaisedDefALittle, + gText_PkmnRaisedSpDefALittle, + gText_TheWallShattered, + gText_PkmnsXPreventsYsZ, + gText_PkmnsXCuredItsYProblem, + gText_AttackerCantEscape, + gText_PkmnObtainedX, + gText_PkmnObtainedX2, + gText_PkmnObtainedXYObtainedZ, + gText_ButNoEffect, + gText_PkmnsXHadNoEffectOnY, + gText_TwoInGameTrainersDefeated, + gText_Trainer2LoseText, + gText_PkmnIncapableOfPower, + gText_GlintAppearsInEye, + gText_PkmnGettingIntoPosition, + gText_PkmnBeganGrowlingDeeply, + gText_PkmnEagerForMore, + gText_DefeatedOpponentByReferee, + gText_LostToOpponentByReferee, + gText_TiedOpponentByReferee, + gText_QuestionForfeitMatch, + gText_ForfeitedMatch, + gText_PkmnTransferredSomeonesPC, + gText_PkmnTransferredLanettesPC, + gText_PkmnBoxSomeonesPCFull, + gText_PkmnBoxLanettesPCFull, + gText_Trainer1WinText, + gText_Trainer2WinText, +}; + +const u16 gMissStringIds[] = +{ + STRINGID_ATTACKMISSED, STRINGID_PKMNPROTECTEDITSELF, + STRINGID_PKMNAVOIDEDATTACK, STRINGID_AVOIDEDDAMAGE, + STRINGID_PKMNMAKESGROUNDMISS +}; + +const u16 gNoEscapeStringIds[] = +{ + STRINGID_CANTESCAPE, STRINGID_DONTLEAVEBIRCH, STRINGID_PREVENTSESCAPE, + STRINGID_CANTESCAPE2, STRINGID_ATTACKERCANTESCAPE +}; + +const u16 gMoveWeatherChangeStringIds[] = +{ + STRINGID_STARTEDTORAIN, STRINGID_DOWNPOURSTARTED, STRINGID_BUTITFAILED, + STRINGID_SANDSTORMBREWED, STRINGID_SUNLIGHTGOTBRIGHT, STRINGID_STARTEDHAIL +}; + +const u16 gSandStormHailContinuesStringIds[] = +{ + STRINGID_SANDSTORMRAGES, STRINGID_HAILCONTINUES +}; + +const u16 gSandStormHailDmgStringIds[] = +{ + STRINGID_PKMNBUFFETEDBYSANDSTORM, STRINGID_PKMNPELTEDBYHAIL +}; + +// todo once battlescripts are dumped +const u16 gTooLazyToSplitThemStringIds[] = +{ + STRINGID_SANDSTORMSUBSIDED, STRINGID_HAILSTOPPED, STRINGID_RAINCONTINUES, STRINGID_DOWNPOURCONTINUES, + STRINGID_RAINSTOPPED, STRINGID_PKMNPROTECTEDITSELF2, STRINGID_PKMNBRACEDITSELF, + STRINGID_BUTITFAILED, STRINGID_BUTITFAILED, STRINGID_PKMNRAISEDDEF, + STRINGID_PKMNRAISEDDEFALITTLE, STRINGID_PKMNRAISEDSPDEF, STRINGID_PKMNRAISEDSPDEFALITTLE, + STRINGID_PKMNCOVEREDBYVEIL, STRINGID_PKMNSEEDED, STRINGID_PKMNEVADEDATTACK, + STRINGID_ITDOESNTAFFECT, STRINGID_PKMNSAPPEDBYLEECHSEED, STRINGID_ITSUCKEDLIQUIDOOZE, + STRINGID_PKMNWENTTOSLEEP, STRINGID_PKMNSLEPTHEALTHY, STRINGID_PKMNMAKINGUPROAR, + STRINGID_PKMNCALMEDDOWN, STRINGID_PKMNSTOCKPILED, STRINGID_PKMNCANTSTOCKPILE, + STRINGID_PKMNWOKEUP, STRINGID_PKMNWOKEUPINUPROAR, STRINGID_FAILEDTOSWALLOW, + STRINGID_PKMNHPFULL, STRINGID_PKMNCANTSLEEPINUPROAR2, STRINGID_UPROARKEPTPKMNAWAKE, + STRINGID_PKMNSTAYEDAWAKEUSING, STRINGID_PKMNSSTATCHANGED, STRINGID_PKMNSSTATCHANGED2, + STRINGID_STATSWONTINCREASE, STRINGID_EMPTYSTRING3, STRINGID_USINGXTHEYOFZN, + STRINGID_PKMNUSEDXTOGETPUMPED, STRINGID_PKMNSSTATCHANGED3, STRINGID_PKMNSSTATCHANGED4, + STRINGID_STATSWONTDECREASE, STRINGID_EMPTYSTRING3, STRINGID_PKMNWHIPPEDWHIRLWIND, + STRINGID_PKMNTOOKSUNLIGHT, STRINGID_PKMNLOWEREDHEAD, STRINGID_PKMNISGLOWING, + STRINGID_PKMNFLEWHIGH, STRINGID_PKMNDUGHOLE, STRINGID_PKMNHIDUNDERWATER, + STRINGID_PKMNSPRANGUP, STRINGID_PKMNSQUEEZEDBYBIND, STRINGID_PKMNWRAPPEDBY, + STRINGID_PKMNTRAPPEDINVORTEX, STRINGID_PKMNCLAMPED, STRINGID_PKMNTRAPPEDINVORTEX, + STRINGID_PKMNTRAPPEDBYSANDTOMB, STRINGID_PKMNSHROUDEDINMIST, STRINGID_BUTITFAILED, + STRINGID_PKMNGETTINGPUMPED, STRINGID_BUTITFAILED, STRINGID_PKMNTRANSFORMEDINTO, + STRINGID_BUTITFAILED, STRINGID_PKMNMADESUBSTITUTE, STRINGID_TOOWEAKFORSUBSTITUTE, + STRINGID_PKMNWASPOISONED, STRINGID_PKMNPOISONEDBY, STRINGID_PKMNWASPARALYZED, + STRINGID_PKMNWASPARALYZEDBY, STRINGID_PKMNFELLASLEEP, STRINGID_PKMNMADESLEEP, + STRINGID_PKMNWASBURNED, STRINGID_PKMNBURNEDBY, STRINGID_PKMNWASFROZEN, + STRINGID_PKMNFROZENBY, STRINGID_PKMNWASDEFROSTED2, STRINGID_PKMNWASDEFROSTEDBY, + STRINGID_ATTACKMISSED, STRINGID_PKMNUNAFFECTED, STRINGID_PKMNFELLINLOVE, + STRINGID_PKMNSXINFATUATEDY, STRINGID_PKMNENERGYDRAINED, STRINGID_ITSUCKEDLIQUIDOOZE, + STRINGID_ELECTRICITYWEAKENED, STRINGID_FIREWEAKENED, STRINGID_BELLCHIMED, + STRINGID_BELLCHIMED, STRINGID_BELLCHIMED, STRINGID_BELLCHIMED, + STRINGID_SOOTHINGAROMA, STRINGID_PKMNFORESAWATTACK, STRINGID_PKMNCHOSEXASDESTINY, + STRINGID_PKMNBROKEFREE, STRINGID_ITAPPEAREDCAUGHT, STRINGID_AARGHALMOSTHADIT, + STRINGID_SHOOTSOCLOSE, STRINGID_ITISRAINING, STRINGID_ITISRAINING, + STRINGID_ITISRAINING, STRINGID_ITISRAINING, STRINGID_ITISRAINING, + STRINGID_ITISRAINING, STRINGID_ITISRAINING, STRINGID_ITISRAINING, + STRINGID_SANDSTORMISRAGING, STRINGID_ITISRAINING, STRINGID_ITISRAINING, + STRINGID_ITISRAINING, STRINGID_SUNLIGHTSTRONG, STRINGID_ITISRAINING, + STRINGID_ITISRAINING, STRINGID_ITISRAINING, STRINGID_PKMNLOAFING, + STRINGID_PKMNWONTOBEY, STRINGID_PKMNTURNEDAWAY, STRINGID_PKMNPRETENDNOTNOTICE, + STRINGID_PKMNINCAPABLEOFPOWER, STRINGID_CREPTCLOSER, STRINGID_CANTGETCLOSER, + STRINGID_PKMNCURIOUSABOUTX, STRINGID_PKMNENTHRALLEDBYX, STRINGID_PKMNIGNOREDX, + STRINGID_PKMNSITEMSNAPPEDOUT, STRINGID_PKMNSITEMCUREDPARALYSIS, STRINGID_PKMNSITEMDEFROSTEDIT, + STRINGID_PKMNSITEMHEALEDBURN, STRINGID_PKMNSITEMCUREDPOISON, STRINGID_PKMNSITEMWOKEIT, + STRINGID_PKMNSITEMCUREDPROBLEM, STRINGID_PKMNSITEMNORMALIZEDSTATUS, STRINGID_PKMNSXPREVENTSBURNS, + STRINGID_PKMNSXPREVENTSYSZ, STRINGID_PKMNSXHADNOEFFECTONY, STRINGID_PKMNPREVENTSPARALYSISWITH, + STRINGID_PKMNSXPREVENTSYSZ, STRINGID_PKMNSXHADNOEFFECTONY, STRINGID_PKMNPREVENTSPOISONINGWITH, + STRINGID_PKMNSXPREVENTSYSZ, STRINGID_PKMNSXHADNOEFFECTONY, STRINGID_PKMNOBTAINEDX, + STRINGID_PKMNOBTAINEDX2, STRINGID_PKMNOBTAINEDXYOBTAINEDZ, STRINGID_PKMNRAISEDFIREPOWERWITH, + STRINGID_PKMNSXMADEYINEFFECTIVE, STRINGID_PKMNTRANSFERREDSOMEONESPC, STRINGID_PKMNTRANSFERREDLANETTESPC, + STRINGID_PKMNBOXSOMEONESPCFULL, STRINGID_PKMNBOXLANETTESPCFULL, +}; + +const u16 gTrappingMoves[] = +{ + MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, 0xFFFF +}; + +const u8 gText_PkmnIsEvolving[] = _("What?\n{STR_VAR_1} is evolving!"); +const u8 gText_CongratsPkmnEvolved[] = _("Congratulations! Your {STR_VAR_1}\nevolved into {STR_VAR_2}!{UNKNOWN_A}\p"); +const u8 gText_PkmnStoppedEvolving[] = _("Huh? {STR_VAR_1}\nstopped evolving!\p"); +const u8 gText_EllipsisQuestionMark[] = _("……?\p"); +const u8 gText_WhatWillPkmnDo[] = _("What will\n{B_ACTIVE_NAME_WITH_PREFIX} do?"); +const u8 gText_WhatWillPkmnDo2[] = _("What will\n{B_PLAYER_NAME} do?"); +const u8 gText_WhatWillWallyDo[] = _("What will\nWALLY do?"); +const u8 gText_LinkStandby[] = _("{PAUSE 16}Link standby…"); +const u8 gText_BattleMenu[] = _("FIGHT{CLEAR_TO 56}BAG\nPOKéMON{CLEAR_TO 56}RUN"); +const u8 gText_SafariZoneMenu[] = _("BALL{CLEAR_TO 56}{POKEBLOCK}\nGO NEAR{CLEAR_TO 56}RUN"); +const u8 gText_MoveInterfacePP[] = _("PP "); +const u8 gText_MoveInterfaceType[] = _("TYPE/"); +const u8 gText_MoveInterfacePpType[] = _("{PALETTE 5}{COLOR_HIGHLIGHT_SHADOW DYNAMIC_COLOR4 DYNAMIC_COLOR5 DYNAMIC_COLOR6}PP\nTYPE/"); +const u8 gText_MoveInterfaceDynamicColors[] = _("{PALETTE 5}{COLOR_HIGHLIGHT_SHADOW DYNAMIC_COLOR4 DYNAMIC_COLOR5 DYNAMIC_COLOR6}"); +const u8 gText_WhichMoveToForget4[] = _("{PALETTE 5}{COLOR_HIGHLIGHT_SHADOW DYNAMIC_COLOR4 DYNAMIC_COLOR5 DYNAMIC_COLOR6}Which move should\nbe forgotten?"); +const u8 gText_BattleYesNoChoice[] = _("{PALETTE 5}{COLOR_HIGHLIGHT_SHADOW DYNAMIC_COLOR4 DYNAMIC_COLOR5 DYNAMIC_COLOR6}Yes\nNo"); +const u8 gText_BattleSwitchWhich[] = _("{PALETTE 5}{COLOR_HIGHLIGHT_SHADOW DYNAMIC_COLOR4 DYNAMIC_COLOR5 DYNAMIC_COLOR6}Switch\nwhich?"); +const u8 gText_BattleSwitchWhich2[] = _("{PALETTE 5}{COLOR_HIGHLIGHT_SHADOW DYNAMIC_COLOR4 DYNAMIC_COLOR5 DYNAMIC_COLOR6}"); +const u8 gText_BattleSwitchWhich3[] = _("{UP_ARROW}"); +const u8 gText_BattleSwitchWhich4[] = _("{ESCAPE 4}"); +const u8 gText_BattleSwitchWhich5[] = _("-"); + +const u8 gText_HP[] = _("HP"); +const u8 gText_Attack[] = _("ATTACK"); +const u8 gText_Defense[] = _("DEFENSE"); +const u8 gText_SpAtk[] = _("SP. ATK"); +const u8 gText_SpDef[] = _("SP. DEF"); + +const u8 * const gStatNamesTable2[] = +{ + gText_HP, gText_SpAtk, gText_Attack, + gText_SpDef, gText_Defense, gText_Speed +}; + +const u8 gText_SafariBalls[] = _("{HIGHLIGHT DARK_GREY}SAFARI BALLS"); +const u8 gText_SafariBallLeft[] = _("{HIGHLIGHT DARK_GREY}Left: $" "{HIGHLIGHT DARK_GREY}");const u8 gText_Sleep[] = _( "sleep");const u8 gText_Poison[] = _( "poison");const u8 gText_Burn[] = _( "burn");const u8 gText_Paralysis[] = _( "paralysis");const u8 gText_Ice[] = _( "ice");const u8 gText_Confusion[] = _( "confusion");const u8 gText_Love[] = _( "love"); +const u8 gText_SpaceAndSpace[] = _(" and "); +const u8 gText_CommaSpace[] = _(", "); +const u8 gText_Space2[] = _(" "); +const u8 gText_ScrollTextUp[] = _("\l"); +const u8 gText_NewLine[] = _("\n"); +const u8 gText_Are[] = _("are"); +const u8 gText_Are2[] = _("are"); +const u8 gText_BadEgg[] = _("Bad EGG"); +const u8 gText_BattleWallyName[] = _("WALLY"); +const u8 gText_Win[] = _("{HIGHLIGHT TRANSPARENT}Win"); +const u8 gText_Loss[] = _("{HIGHLIGHT TRANSPARENT}Loss"); +const u8 gText_Draw[] = _("{HIGHLIGHT TRANSPARENT}Draw"); +const u8 gText_SpaceIs[] = _(" is"); +const u8 gText_ApostropheS[] = _("’s"); + +const u8 gText_UnknownMoveTypes[][17] = +{ + _("a NORMAL move"), + _("a FIGHTING move"), + _("a FLYING move"), + _("a POISON move"), + _("a GROUND move"), + _("a ROCK move"), + _("a BUG move"), + _("a GHOST move"), + _("a STEEL move"), + _("a ??? move"), + _("a FIRE move"), + _("a WATER move"), + _("a GRASS move"), + _("an ELECTRIC move"), + _("a PSYCHIC move"), + _("an ICE move"), + _("a DRAGON move"), + _("a DARK move") +}; + +const u8 gText_BattleTourney[] = _("BATTLE TOURNEY"); +const u8 gText_Round1[] = _("Round 1"); +const u8 gText_Round2[] = _("Round 2"); +const u8 gText_Semifinal[] = _("Semifinal"); +const u8 gText_Final[] = _("Final"); + +const u8 * const gRoundsStringTable[] = +{ + gText_Round1, + gText_Round2, + gText_Semifinal, + gText_Final +}; + +const u8 gText_TheGreatNewHope[] = _("The great new hope!\p"); +const u8 gText_WillChampinshipDreamComeTrue[] = _("Will the championship dream come true?!\p"); +const u8 gText_AFormerChampion[] = _("A former CHAMPION!\p"); +const u8 gText_ThePreviousChampion[] = _("The previous CHAMPION!\p"); +const u8 gText_TheUnbeatenChampion[] = _("The unbeaten CHAMPION!\p"); +const u8 gText_PlayerMon1Name[] = _("{B_PLAYER_MON1_NAME}"); +const u8 gText_Vs[] = _("VS"); +const u8 gText_OpponentMon1Name[] = _("{B_OPPONENT_MON1_NAME}"); +const u8 gText_Mind[] = _("Mind"); +const u8 gText_Skill[] = _("Skill"); +const u8 gText_Body[] = _("Body"); +const u8 gText_Judgement[] = _("{B_BUFF1}{CLEAR 13}Judgment{CLEAR 13}{B_BUFF2}"); +const u8 gText_TwoTrainersSentPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent\nout {B_OPPONENT_MON1_NAME}!\p{B_TRAINER2_CLASS} {B_TRAINER2_NAME} sent\nout {B_OPPONENT_MON2_NAME}!"); +const u8 gText_Trainer2SentOutPkmn[] = _("{B_TRAINER2_CLASS} {B_TRAINER2_NAME} sent\nout {B_BUFF1}!"); +const u8 gText_TwoTrainersWantToBattle[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} and\n{B_TRAINER2_CLASS} {B_TRAINER2_NAME}\lwant to battle!\p"); +const u8 gText_InGamePartnerSentOutZGoN[] = _("{B_PARTNER_CLASS} {B_PARTNER_NAME} sent\nout {B_PLAYER_MON2_NAME}!\lGo, {B_PLAYER_MON1_NAME}!"); +const u8 gText_TwoInGameTrainersDefeated[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} and\n{B_TRAINER2_CLASS} {B_TRAINER2_NAME}\lwere defeated!\p"); +const u8 gText_Trainer2LoseText[] = _("{B_TRAINER2_LOSE_TEXT}"); +const u8 gText_PkmnIncapableOfPower[] = _("{B_ATK_NAME_WITH_PREFIX} appears incapable\nof using its power!"); +const u8 gText_GlintAppearsInEye[] = _("A glint appears in\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}’s eyes!"); +const u8 gText_PkmnGettingIntoPosition[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is getting into\nposition!"); +const u8 gText_PkmnBeganGrowlingDeeply[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} began growling deeply!"); +const u8 gText_PkmnEagerForMore[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is eager for more!"); + +const u16 gUnknown_085CCF0A[] = +{ + 0x016E, 0x016F, 0x0170, 0x0171 +}; + +const u8 gText_RefIfNothingIsDecided[] = _("REFEREE: If nothing is decided in\n3 turns, we will go to judging!"); +const u8 gText_RefThatsIt[] = _("REFEREE: That’s it! We will now go to\njudging to determine the winner!"); +const u8 gText_RefJudgeMind[] = _("REFEREE: Judging category 1, Mind!\nThe POKéMON showing the most guts!\p"); +const u8 gText_RefJudgeSkill[] = _("REFEREE: Judging category 2, Skill!\nThe POKéMON using moves the best!\p"); +const u8 gText_RefJudgeBody[] = _("REFEREE: Judging category 3, Body!\nThe POKéMON with the most vitality!\p"); +const u8 gText_RefJudgement1[] = _("REFEREE: Judgment: {B_BUFF1} to {B_BUFF2}!\nThe winner is {B_PLAYER_NAME}’s {B_PLAYER_MON1_NAME}!\p"); +const u8 gText_RefJudgement2[] = _("REFEREE: Judgment: {B_BUFF1} to {B_BUFF2}!\nThe winner is {B_TRAINER1_NAME}’s {B_OPPONENT_MON1_NAME}!\p"); +const u8 gText_RefJudgement3[] = _("REFEREE: Judgment: 3 to 3!\nWe have a draw!\p"); +const u8 gText_DefeatedOpponentByReferee[] = _("{B_PLAYER_MON1_NAME} defeated the opponent\n{B_OPPONENT_MON1_NAME} in a REFEREE’s decision!"); +const u8 gText_LostToOpponentByReferee[] = _("{B_PLAYER_MON1_NAME} lost to the opponent\n{B_OPPONENT_MON1_NAME} in a REFEREE’s decision!"); +const u8 gText_TiedOpponentByReferee[] = _("{B_PLAYER_MON1_NAME} tied the opponent\n{B_OPPONENT_MON1_NAME} in a REFEREE’s decision!"); +const u8 gText_RefCommenceBattle[] = _("REFEREE: {B_PLAYER_MON1_NAME} VS {B_OPPONENT_MON1_NAME}!\nCommence battling!"); + +const u8 * const gRefereeStringsTable[] = +{ + gText_RefIfNothingIsDecided, + gText_RefThatsIt, + gText_RefJudgeMind, + gText_RefJudgeSkill, + gText_RefJudgeBody, + gText_RefJudgement1, + gText_RefJudgement2, + gText_RefJudgement3, + gText_RefCommenceBattle, +}; + +const u8 gText_QuestionForfeitMatch[] = _("Would you like to forfeit the match\nand quit now?"); +const u8 gText_ForfeitedMatch[] = _("{B_PLAYER_NAME} forfeited the match!"); +const u8 gText_Trainer1WinText[] = _("{B_TRAINER1_WIN_TEXT}"); +const u8 gText_Trainer2WinText[] = _("{B_TRAINER2_WIN_TEXT}"); +const u8 gText_Trainer1Fled[] = _( "{PLAY_SE 0x0011}{B_TRAINER1_CLASS} {B_TRAINER1_NAME} fled!"); +const u8 gText_PlayerLostAgainstTrainer1[] = _("Player lost against\n{B_TRAINER1_CLASS} {B_TRAINER1_NAME}!"); +const u8 gText_PlayerBattledToDrawTrainer1[] = _("Player battled to a draw against\n{B_TRAINER1_CLASS} {B_TRAINER1_NAME}!"); +const u8 gText_RecordBattleToPass[] = _("Would you like to record your battle\non your FRONTIER PASS?"); +const u8 gText_BattleRecordedOnPass[] = _("{B_PLAYER_NAME}’s battle result was recorded\non the FRONTIER PASS."); +const u8 gText_LinkTrainerWantsToBattlePause[] = _("{B_20}\nwants to battle!{PAUSE 49}"); +const u8 gText_TwoLinkTrainersWantToBattlePause[] = _("{B_20} and {B_21}\nwant to battle!{PAUSE 49}"); + +static const u16 sUnknownMoveTable[] = +{ + MOVE_SWORDS_DANCE, MOVE_STRENGTH, MOVE_GROWTH, + MOVE_HARDEN, MOVE_MINIMIZE, MOVE_SMOKESCREEN, + MOVE_WITHDRAW, MOVE_DEFENSE_CURL, MOVE_EGG_BOMB, + MOVE_SMOG, MOVE_BONE_CLUB, MOVE_FLASH, MOVE_SPLASH, + MOVE_ACID_ARMOR, MOVE_BONEMERANG, MOVE_REST, MOVE_SHARPEN, + MOVE_SUBSTITUTE, MOVE_MIND_READER, MOVE_SNORE, + MOVE_PROTECT, MOVE_SPIKES, MOVE_ENDURE, MOVE_ROLLOUT, + MOVE_SWAGGER, MOVE_SLEEP_TALK, MOVE_HIDDEN_POWER, + MOVE_PSYCH_UP, MOVE_EXTREME_SPEED, MOVE_FOLLOW_ME, + MOVE_TRICK, MOVE_ASSIST, MOVE_INGRAIN, MOVE_KNOCK_OFF, + MOVE_CAMOUFLAGE, MOVE_ASTONISH, MOVE_ODOR_SLEUTH, + MOVE_GRASS_WHISTLE, MOVE_SHEER_COLD, MOVE_MUDDY_WATER, + MOVE_IRON_DEFENSE, MOVE_BOUNCE, MOVE_NONE, + + MOVE_TELEPORT, MOVE_RECOVER, MOVE_BIDE, MOVE_AMNESIA, + MOVE_FLAIL, MOVE_TAUNT, MOVE_BULK_UP, MOVE_NONE, + + MOVE_MEDITATE, MOVE_AGILITY, MOVE_MIMIC, MOVE_DOUBLE_TEAM, + MOVE_BARRAGE, MOVE_TRANSFORM, MOVE_STRUGGLE, MOVE_SCARY_FACE, + MOVE_CHARGE, MOVE_WISH, MOVE_BRICK_BREAK, MOVE_YAWN, + MOVE_FEATHER_DANCE, MOVE_TEETER_DANCE, MOVE_MUD_SPORT, + MOVE_FAKE_TEARS, MOVE_WATER_SPORT, MOVE_CALM_MIND, MOVE_NONE, + + MOVE_POUND, MOVE_SCRATCH, MOVE_VICE_GRIP, + MOVE_WING_ATTACK, MOVE_FLY, MOVE_BIND, MOVE_SLAM, + MOVE_HORN_ATTACK, MOVE_WRAP, MOVE_THRASH, MOVE_TAIL_WHIP, + MOVE_LEER, MOVE_BITE, MOVE_GROWL, MOVE_ROAR, + MOVE_SING, MOVE_PECK, MOVE_ABSORB, MOVE_STRING_SHOT, + MOVE_EARTHQUAKE, MOVE_FISSURE, MOVE_DIG, MOVE_TOXIC, + MOVE_SCREECH, MOVE_METRONOME, MOVE_LICK, MOVE_CLAMP, + MOVE_CONSTRICT, MOVE_POISON_GAS, MOVE_BUBBLE, + MOVE_SLASH, MOVE_SPIDER_WEB, MOVE_NIGHTMARE, MOVE_CURSE, + MOVE_FORESIGHT, MOVE_CHARM, MOVE_ATTRACT, MOVE_ROCK_SMASH, + MOVE_UPROAR, MOVE_SPIT_UP, MOVE_SWALLOW, MOVE_TORMENT, + MOVE_FLATTER, MOVE_ROLE_PLAY, MOVE_ENDEAVOR, MOVE_TICKLE, + MOVE_COVET, MOVE_NONE +}; + +static const u8 sDummyWeirdStatusString[] = {EOS, EOS, EOS, EOS, EOS, EOS, EOS, EOS, 0, 0}; + +static const u8 gUnknown_085CD42C[] = +{ + 0xFF, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x1, 0xF, 0x6, 0x0, 0x0, 0xFF, 0x1, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0xF, 0x6, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, + 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, + 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, + 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, + 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, + 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xC, 0xE, 0xB, 0x0, 0x0, + 0xEE, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, + 0x1, 0x2, 0x1, 0x0, 0x0, 0x0, 0xC, 0xE, 0xB, 0x0, 0x0, 0xEE, 0x7, 0x0, + 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, + 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, + 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, + 0xE, 0xF, 0x0, 0x0, 0x0, 0x1, 0x20, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, + 0x0, 0x0, 0xEE, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, + 0x0, 0xEE, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, + 0xEE, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, + 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, + 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0xFF, + 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0x0, 0x1, 0xFF, 0x1, 0x0, + 0x0, 0x0, 0x1, 0x0, 0x6, 0x0, 0x0, 0x0, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, + 0x6, 0x0, 0x0, 0x0, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x6, 0x0, 0x0 +}; + +static const u8 gUnknown_085CD54C[] = +{ + 0xFF, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x1, 0xF, 0x6, 0x0, 0x0, 0xFF, 0x1, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0xF, 0x6, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, + 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, + 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, + 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, + 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, + 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0, 0xC, 0xE, 0xB, 0x0, 0x0, + 0xEE, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, + 0x1, 0x2, 0x1, 0x0, 0x0, 0x0, 0xC, 0xE, 0xB, 0x0, 0x0, 0xEE, 0x7, 0x0, + 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x7, 0x0, 0x1, 0x0, + 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, + 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0xD, + 0xE, 0xF, 0x0, 0x0, 0x0, 0x1, 0x20, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, + 0x0, 0x0, 0xEE, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0x1, 0xE, 0xF, 0x0, + 0x0, 0xEE, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, + 0xEE, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, + 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, + 0xFF, 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0xFF, + 0x1, 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0xEE, 0x1, 0xFF, 0x1, + 0x0, 0x0, 0x0, 0xD, 0xE, 0xF, 0x0, 0x0, 0x11, 0x1, 0x0, 0x1, 0x0, 0x0, + 0x1, 0x2, 0x1, 0x3, 0x0, 0x0 +}; + +static const u8 * const gUnknown_085CD660[] = +{ + gUnknown_085CD42C, gUnknown_085CD54C +}; + +static const u8 sRecordedBattleTextSpeeds[] = {8, 4, 1, 0}; + +void BufferStringBattle(u16 stringID) +{ + s32 i; + const u8* stringPtr = NULL; + + gStringInfo = (struct StringInfoBattle*)(&gBattleBufferA[gActiveBank][4]); + gLastUsedItem = gStringInfo->lastItem; + gLastUsedAbility = gStringInfo->lastAbility; + gBattleScripting.bank = gStringInfo->scrActive; + *(&gBattleStruct->field_52) = gStringInfo->unk1605E; + *(&gBattleStruct->hpScale) = gStringInfo->hpScale; + gStringBank = gStringInfo->StringBank; + *(&gBattleStruct->stringMoveType) = gStringInfo->moveType; + + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + gAbilitiesPerBank[i] = gStringInfo->abilities[i]; + } + for (i = 0; i < TEXT_BUFF_ARRAY_COUNT; i++) + { + gBattleTextBuff1[i] = gStringInfo->textBuffs[0][i]; + gBattleTextBuff2[i] = gStringInfo->textBuffs[1][i]; + gBattleTextBuff3[i] = gStringInfo->textBuffs[2][i]; + } + + switch (stringID) + { + case STRINGID_INTROMSG: // first battle msg + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + if (gBattleTypeFlags & BATTLE_TYPE_x800000) + { + stringPtr = gText_TwoTrainersWantToBattle; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + stringPtr = gText_TwoLinkTrainersWantToBattlePause; + else + stringPtr = gText_TwoLinkTrainersWantToBattle; + } + else + { + if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + stringPtr = gText_Trainer1WantsToBattle; + else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + stringPtr = gText_LinkTrainerWantsToBattlePause; + else + stringPtr = gText_LinkTrainerWantsToBattle; + } + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + stringPtr = gText_TwoTrainersWantToBattle; + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = gText_TwoTrainersWantToBattle; + else + stringPtr = gText_Trainer1WantsToBattle; + } + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY) + stringPtr = gText_WildPkmnAppeared2; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) // interesting, looks like they had something planned for wild double battles + stringPtr = gText_TwoWildPkmnAppeared; + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) + stringPtr = gText_WildPkmnAppearedPause; + else + stringPtr = gText_WildPkmnAppeared; + } + break; + case STRINGID_INTROSENDOUT: // poke first send-out + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + stringPtr = gText_InGamePartnerSentOutZGoN; + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = gText_GoTwoPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + stringPtr = gText_LinkPartnerSentOutPkmnGoPkmn; + else + stringPtr = gText_GoTwoPkmn; + } + else + { + stringPtr = gText_GoPkmn; + } + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = gText_TwoTrainersSentPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_x800000) + stringPtr = gText_TwoTrainersSentPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + stringPtr = gText_TwoLinkTrainersSentOutPkmn; + else if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + stringPtr = gText_LinkTrainerSentOutTwoPkmn; + else + stringPtr = gText_Trainer1SentOutTwoPkmn; + } + else + { + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) + stringPtr = gText_Trainer1SentOutPkmn; + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + stringPtr = gText_Trainer1SentOutPkmn; + else + stringPtr = gText_LinkTrainerSentOutPkmn; + } + } + break; + case STRINGID_RETURNMON: // sending poke to ball msg + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + if (*(&gBattleStruct->hpScale) == 0) + stringPtr = gText_PkmnThatsEnough; + else if (*(&gBattleStruct->hpScale) == 1 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + stringPtr = gText_PkmnComeBack; + else if (*(&gBattleStruct->hpScale) == 2) + stringPtr = gText_PkmnOkComeBack; + else + stringPtr = gText_PkmnGoodComeBack; + } + else + { + if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_800 || gBattleTypeFlags & BATTLE_TYPE_x2000000) + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + stringPtr = gText_LinkTrainer2WithdrewPkmn; + else + stringPtr = gText_LinkTrainer1WithdrewPkmn; + } + else + { + stringPtr = gText_Trainer1WithdrewPkmn; + } + } + break; + case STRINGID_SWITCHINMON: // switch-in msg + if (GetBankSide(gBattleScripting.bank) == SIDE_PLAYER) + { + if (*(&gBattleStruct->hpScale) == 0 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + stringPtr = gText_GoPkmn2; + else if (*(&gBattleStruct->hpScale) == 1) + stringPtr = gText_DoItPkmn; + else if (*(&gBattleStruct->hpScale) == 2) + stringPtr = gText_GoForItPkmn; + else + stringPtr = gText_YourFoesWeakGetEmPkmn; + } + else + { + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + if (gBattleTypeFlags & BATTLE_TYPE_x800000) + { + if (gBattleScripting.bank == 1) + stringPtr = gText_Trainer1SentOutPkmn2; + else + stringPtr = gText_Trainer2SentOutPkmn; + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + stringPtr = gText_LinkTrainerMultiSentOutPkmn; + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + stringPtr = gText_Trainer1SentOutPkmn2; + else + stringPtr = gText_LinkTrainerSentOutPkmn2; + } + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (gBattleScripting.bank == 1) + stringPtr = gText_Trainer1SentOutPkmn2; + else + stringPtr = gText_Trainer2SentOutPkmn; + } + else + { + stringPtr = gText_Trainer1SentOutPkmn2; + } + } + } + break; + case STRINGID_USEDMOVE: // pokemon used a move msg + sub_814F8F8(gBattleTextBuff1); // buff1 doesn't appear in the string, leftover from japanese move names? + + if (gStringInfo->currentMove > LAST_MOVE_INDEX) + StringCopy(gBattleTextBuff2, gText_UnknownMoveTypes[*(&gBattleStruct->stringMoveType)]); + else + StringCopy(gBattleTextBuff2, gMoveNames[gStringInfo->currentMove]); + + sub_814F950(gBattleTextBuff2); + stringPtr = gText_AttackerUsedX; + break; + case STRINGID_BATTLEEND: // battle end + if (gBattleTextBuff1[0] & BATTLE_OUTCOME_BIT_x80) + { + gBattleTextBuff1[0] &= ~(BATTLE_OUTCOME_BIT_x80); + if (GetBankSide(gActiveBank) == SIDE_OPPONENT && gBattleTextBuff1[0] != BATTLE_DREW) + gBattleTextBuff1[0] ^= (BATTLE_LOST | BATTLE_WON); + + if (gBattleTextBuff1[0] == BATTLE_LOST || gBattleTextBuff1[0] == BATTLE_DREW) + stringPtr = gText_GotAwaySafely; + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + stringPtr = gText_TwoWildFled; + else + stringPtr = gText_WildFled; + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT && gBattleTextBuff1[0] != BATTLE_DREW) + gBattleTextBuff1[0] ^= (BATTLE_LOST | BATTLE_WON); + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + switch (gBattleTextBuff1[0]) + { + case BATTLE_WON: + if (gBattleTypeFlags & BATTLE_TYPE_x800000) + stringPtr = gText_TwoInGameTrainersDefeated; + else + stringPtr = gText_TwoLinkTrainersDefeated; + break; + case BATTLE_LOST: + stringPtr = gText_PlayerLostToTwo; + break; + case BATTLE_DREW: + stringPtr = gText_PlayerBattledToDrawVsTwo; + break; + } + } + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + { + switch (gBattleTextBuff1[0]) + { + case BATTLE_WON: + stringPtr = gText_PlayerDefeatedLinkTrainerTrainer1; + break; + case BATTLE_LOST: + stringPtr = gText_PlayerLostAgainstTrainer1; + break; + case BATTLE_DREW: + stringPtr = gText_PlayerBattledToDrawTrainer1; + break; + } + } + else + { + switch (gBattleTextBuff1[0]) + { + case BATTLE_WON: + stringPtr = gText_PlayerDefeatedLinkTrainer; + break; + case BATTLE_LOST: + stringPtr = gText_PlayerLostAgainstLinkTrainer; + break; + case BATTLE_DREW: + stringPtr = gText_PlayerBattledToDrawLinkTrainer; + break; + } + } + } + break; + default: // load a string from the table + if (stringID >= BATTLESTRINGS_COUNT + BATTLESTRINGS_ID_ADDER) + { + gDisplayedStringBattle[0] = EOS; + return; + } + else + { + stringPtr = gBattleStringsTable[stringID - BATTLESTRINGS_ID_ADDER]; + } + break; + } + + BattleStringExpandPlaceholdersToDisplayedString(stringPtr); +} + +u32 BattleStringExpandPlaceholdersToDisplayedString(const u8* src) +{ + BattleStringExpandPlaceholders(src, gDisplayedStringBattle); +} + +static const u8* TryGetStatusString(u8* src) +{ + u32 i; + u8 status[8]; + u32 chars1, chars2; + u8* statusPtr; + + memcpy(status, sDummyWeirdStatusString, 8); + + statusPtr = status; + for (i = 0; i < 8; i++) + { + if (*src == EOS) + break; + *statusPtr = *src; + src++; + statusPtr++; + } + + chars1 = *(u32*)(&status[0]); + chars2 = *(u32*)(&status[4]); + + for (i = 0; i < ARRAY_COUNT(gStatusConditionStringsTable); i++) + { + if (chars1 == *(u32*)(&gStatusConditionStringsTable[i][0][0]) + && chars2 == *(u32*)(&gStatusConditionStringsTable[i][0][4])) + return gStatusConditionStringsTable[i][1]; + } + return NULL; +} + +#define HANDLE_NICKNAME_STRING_CASE(bank, monIndex) \ + if (GetBankSide(bank) != SIDE_PLAYER) \ + { \ + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) \ + toCpy = gText_FoePkmnPrefix; \ + else \ + toCpy = gText_WildPkmnPrefix; \ + while (*toCpy != EOS) \ + { \ + dst[dstID] = *toCpy; \ + dstID++; \ + toCpy++; \ + } \ + GetMonData(&gEnemyParty[monIndex], MON_DATA_NICKNAME, text); \ + } \ + else \ + { \ + GetMonData(&gPlayerParty[monIndex], MON_DATA_NICKNAME, text); \ + } \ + StringGetEnd10(text); \ + toCpy = text; + +u32 BattleStringExpandPlaceholders(const u8* src, u8* dst) +{ + u32 dstID = 0; // if they used dstID, why not use srcID as well? + const u8* toCpy = NULL; + u8 text[30]; + u8 multiplayerID; + s32 i; + + if (gBattleTypeFlags & BATTLE_TYPE_x2000000) + multiplayerID = gUnknown_0203C7B4; + else + multiplayerID = GetMultiplayerId(); + + while (*src != EOS) + { + if (*src == PLACEHOLDER_BEGIN) + { + src++; + switch (*src) + { + case B_TXT_BUFF1: + if (gBattleTextBuff1[0] == B_BUFF_PLACEHOLDER_BEGIN) + { + ExpandBattleTextBuffPlaceholders(gBattleTextBuff1, gStringVar1); + toCpy = gStringVar1; + } + else + { + toCpy = TryGetStatusString(gBattleTextBuff1); + if (toCpy == NULL) + toCpy = gBattleTextBuff1; + } + break; + case B_TXT_BUFF2: + if (gBattleTextBuff2[0] == B_BUFF_PLACEHOLDER_BEGIN) + { + ExpandBattleTextBuffPlaceholders(gBattleTextBuff2, gStringVar2); + toCpy = gStringVar2; + } + else + toCpy = gBattleTextBuff2; + break; + case B_TXT_BUFF3: + if (gBattleTextBuff3[0] == B_BUFF_PLACEHOLDER_BEGIN) + { + ExpandBattleTextBuffPlaceholders(gBattleTextBuff3, gStringVar3); + toCpy = gStringVar3; + } + else + toCpy = gBattleTextBuff3; + break; + case B_TXT_COPY_VAR_1: + toCpy = gStringVar1; + break; + case B_TXT_COPY_VAR_2: + toCpy = gStringVar2; + break; + case B_TXT_COPY_VAR_3: + toCpy = gStringVar3; + break; + case B_TXT_PLAYER_MON1_NAME: // first player poke name + GetMonData(&gPlayerParty[gBattlePartyID[GetBankByIdentity(IDENTITY_PLAYER_MON1)]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_OPPONENT_MON1_NAME: // first enemy poke name + GetMonData(&gEnemyParty[gBattlePartyID[GetBankByIdentity(IDENTITY_OPPONENT_MON1)]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_PLAYER_MON2_NAME: // second player poke name + GetMonData(&gPlayerParty[gBattlePartyID[GetBankByIdentity(IDENTITY_PLAYER_MON2)]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_OPPONENT_MON2_NAME: // second enemy poke name + GetMonData(&gEnemyParty[gBattlePartyID[GetBankByIdentity(IDENTITY_OPPONENT_MON2)]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_LINK_PLAYER_MON1_NAME: // link first player poke name + GetMonData(&gPlayerParty[gBattlePartyID[gLinkPlayers[multiplayerID].lp_field_18]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_LINK_OPPONENT_MON1_NAME: // link first opponent poke name + GetMonData(&gEnemyParty[gBattlePartyID[gLinkPlayers[multiplayerID].lp_field_18 ^ 1]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_LINK_PLAYER_MON2_NAME: // link second player poke name + GetMonData(&gPlayerParty[gBattlePartyID[gLinkPlayers[multiplayerID].lp_field_18 ^ 2]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_LINK_OPPONENT_MON2_NAME: // link second opponent poke name + GetMonData(&gEnemyParty[gBattlePartyID[gLinkPlayers[multiplayerID].lp_field_18 ^ 3]], + MON_DATA_NICKNAME, text); + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_ATK_NAME_WITH_PREFIX_MON1: // attacker name with prefix, only bank 0/1 + HANDLE_NICKNAME_STRING_CASE(gBankAttacker, + gBattlePartyID[GetBankByIdentity(GET_BANK_SIDE(gBankAttacker))]) + break; + case B_TXT_ATK_PARTNER_NAME: // attacker partner name + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + GetMonData(&gPlayerParty[gBattlePartyID[GetBankByIdentity(GET_BANK_SIDE(gBankAttacker)) + 2]], MON_DATA_NICKNAME, text); + else + GetMonData(&gEnemyParty[gBattlePartyID[GetBankByIdentity(GET_BANK_SIDE(gBankAttacker)) + 2]], MON_DATA_NICKNAME, text); + + StringGetEnd10(text); + toCpy = text; + break; + case B_TXT_ATK_NAME_WITH_PREFIX: // attacker name with prefix + HANDLE_NICKNAME_STRING_CASE(gBankAttacker, gBattlePartyID[gBankAttacker]) + break; + case B_TXT_DEF_NAME_WITH_PREFIX: // target name with prefix + HANDLE_NICKNAME_STRING_CASE(gBankTarget, gBattlePartyID[gBankTarget]) + break; + case B_TXT_EFF_NAME_WITH_PREFIX: // effect bank name with prefix + HANDLE_NICKNAME_STRING_CASE(gEffectBank, gBattlePartyID[gEffectBank]) + break; + case B_TXT_ACTIVE_NAME_WITH_PREFIX: // active bank name with prefix + HANDLE_NICKNAME_STRING_CASE(gActiveBank, gBattlePartyID[gActiveBank]) + break; + case B_TXT_SCR_ACTIVE_NAME_WITH_PREFIX: // scripting active bank name with prefix + HANDLE_NICKNAME_STRING_CASE(gBattleScripting.bank, gBattlePartyID[gBattleScripting.bank]) + break; + case B_TXT_CURRENT_MOVE: // current move name + if (gStringInfo->currentMove > LAST_MOVE_INDEX) + toCpy = gText_UnknownMoveTypes[gBattleStruct->stringMoveType]; + else + toCpy = gMoveNames[gStringInfo->currentMove]; + break; + case B_TXT_LAST_MOVE: // last used move name + if (gStringInfo->lastMove > LAST_MOVE_INDEX) + toCpy = gText_UnknownMoveTypes[gBattleStruct->stringMoveType]; + else + toCpy = gMoveNames[gStringInfo->lastMove]; + break; + case B_TXT_LAST_ITEM: // last used item + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + if (gLastUsedItem == ITEM_ENIGMA_BERRY) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + if ((gBattleScripting.multiplayerId != 0 && (gStringBank & BIT_SIDE)) + || (gBattleScripting.multiplayerId == 0 && !(gStringBank & BIT_SIDE))) + { + StringCopy(text, gEnigmaBerries[gStringBank].name); + StringAppend(text, gText_BerrySuffix); + toCpy = text; + } + else + { + toCpy = gText_EnigmaBerry; + } + } + else + { + if (gLinkPlayers[gBattleScripting.multiplayerId].lp_field_18 == gStringBank) + { + StringCopy(text, gEnigmaBerries[gStringBank].name); + StringAppend(text, gText_BerrySuffix); + toCpy = text; + } + else + toCpy = gText_EnigmaBerry; + } + } + else + { + CopyItemName(gLastUsedItem, text); + toCpy = text; + } + } + else + { + CopyItemName(gLastUsedItem, text); + toCpy = text; + } + break; + case B_TXT_LAST_ABILITY: // last used ability + toCpy = gAbilityNames[gLastUsedAbility]; + break; + case B_TXT_ATK_ABILITY: // attacker ability + toCpy = gAbilityNames[gAbilitiesPerBank[gBankAttacker]]; + break; + case B_TXT_DEF_ABILITY: // target ability + toCpy = gAbilityNames[gAbilitiesPerBank[gBankTarget]]; + break; + case B_TXT_SCR_ACTIVE_ABILITY: // scripting active ability + toCpy = gAbilityNames[gAbilitiesPerBank[gBattleScripting.bank]]; + break; + case B_TXT_EFF_ABILITY: // effect bank ability + toCpy = gAbilityNames[gAbilitiesPerBank[gEffectBank]]; + break; + case B_TXT_TRAINER1_CLASS: // trainer class name + if (gBattleTypeFlags & BATTLE_TYPE_SECRET_BASE) + toCpy = gTrainerClassNames[GetSecretBaseTrainerNameIndex()]; + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + toCpy = gTrainerClassNames[sub_8068BB0()]; + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_3FE) + toCpy = gTrainerClassNames[sub_81A4D00()]; + else if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + toCpy = gTrainerClassNames[GetFrontierOpponentClass(gTrainerBattleOpponent_A)]; + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + toCpy = gTrainerClassNames[sub_81D5530(gTrainerBattleOpponent_A)]; + else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER) + toCpy = gTrainerClassNames[GetEreaderTrainerClassId()]; + else + toCpy = gTrainerClassNames[gTrainers[gTrainerBattleOpponent_A].trainerClass]; + break; + case B_TXT_TRAINER1_NAME: // trainer1 name + if (gBattleTypeFlags & BATTLE_TYPE_SECRET_BASE) + { + for (i = 0; i < (s32) ARRAY_COUNT(gBattleResources->secretBase->trainerName); i++) + text[i] = gBattleResources->secretBase->trainerName[i]; + text[i] = EOS; + ConvertInternationalString(text, gBattleResources->secretBase->language); + toCpy = text; + } + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00) + { + toCpy = gLinkPlayers[multiplayerID ^ BIT_SIDE].name; + } + else if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_3FE) + { + sub_81A4D50(text); + toCpy = text; + } + else if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + GetFrontierTrainerName(text, gTrainerBattleOpponent_A); + toCpy = text; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + sub_81D5554(text, gTrainerBattleOpponent_A); + toCpy = text; + } + else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER) + { + GetEreaderTrainerName(text); + toCpy = text; + } + else + { + toCpy = gTrainers[gTrainerBattleOpponent_A].trainerName; + } + break; + case B_TXT_1E: // link player name? + toCpy = gLinkPlayers[multiplayerID].name; + break; + case B_TXT_1F: // link partner name? + toCpy = gLinkPlayers[sub_806D864(2 ^ gLinkPlayers[multiplayerID].lp_field_18)].name; + break; + case B_TXT_20: // link opponent 1 name? + toCpy = gLinkPlayers[sub_806D864(1 ^ gLinkPlayers[multiplayerID].lp_field_18)].name; + break; + case B_TXT_21: // link opponent 2 name? + toCpy = gLinkPlayers[sub_806D864(3 ^ gLinkPlayers[multiplayerID].lp_field_18)].name; + break; + case B_TXT_22: // link scripting active name + toCpy = gLinkPlayers[sub_806D864(gBattleScripting.bank)].name; + break; + case B_TXT_PLAYER_NAME: // player name + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + toCpy = gLinkPlayers[0].name; + else + toCpy = gSaveBlock2Ptr->playerName; + break; + case B_TXT_TRAINER1_LOSE_TEXT: // trainerA lose text + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + sub_81A36D0(2, gTrainerBattleOpponent_A); + toCpy = gStringVar4; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + sub_81D572C(4, gTrainerBattleOpponent_A); + toCpy = gStringVar4; + } + else + { + toCpy = GetTrainer1LoseText(); + } + break; + case B_TXT_TRAINER1_WIN_TEXT: // trainerA win text + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + sub_81A36D0(1, gTrainerBattleOpponent_A); + toCpy = gStringVar4; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + sub_81D572C(3, gTrainerBattleOpponent_A); + toCpy = gStringVar4; + } + break; + case B_TXT_26: // ? + HANDLE_NICKNAME_STRING_CASE(gBattleScripting.bank, *(&gBattleStruct->field_52)) + break; + case B_TXT_PC_CREATOR_NAME: // lanette pc + if (FlagGet(SYS_PC_LANETTE)) + toCpy = gText_Lanettes; + else + toCpy = gText_Someones; + break; + case B_TXT_ATK_PREFIX2: + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + toCpy = gText_AllyPkmnPrefix2; + else + toCpy = gText_FoePkmnPrefix3; + break; + case B_TXT_DEF_PREFIX2: + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + toCpy = gText_AllyPkmnPrefix2; + else + toCpy = gText_FoePkmnPrefix3; + break; + case B_TXT_ATK_PREFIX1: + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + toCpy = gText_AllyPkmnPrefix; + else + toCpy = gText_FoePkmnPrefix2; + break; + case B_TXT_DEF_PREFIX1: + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + toCpy = gText_AllyPkmnPrefix; + else + toCpy = gText_FoePkmnPrefix2; + break; + case B_TXT_ATK_PREFIX3: + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + toCpy = gText_AllyPkmnPrefix3; + else + toCpy = gText_FoePkmnPrefix4; + break; + case B_TXT_DEF_PREFIX3: + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + toCpy = gText_AllyPkmnPrefix3; + else + toCpy = gText_FoePkmnPrefix4; + break; + case B_TXT_TRAINER2_CLASS: + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + toCpy = gTrainerClassNames[GetFrontierOpponentClass(gTrainerBattleOpponent_B)]; + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + toCpy = gTrainerClassNames[sub_81D5530(gTrainerBattleOpponent_B)]; + else + toCpy = gTrainerClassNames[gTrainers[gTrainerBattleOpponent_B].trainerClass]; + break; + case B_TXT_TRAINER2_NAME: + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + GetFrontierTrainerName(text, gTrainerBattleOpponent_B); + toCpy = text; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + sub_81D5554(text, gTrainerBattleOpponent_B); + toCpy = text; + } + else + { + toCpy = gTrainers[gTrainerBattleOpponent_B].trainerName; + } + break; + case B_TXT_TRAINER2_LOSE_TEXT: + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + sub_81A36D0(2, gTrainerBattleOpponent_B); + toCpy = gStringVar4; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + sub_81D572C(4, gTrainerBattleOpponent_B); + toCpy = gStringVar4; + } + else + { + toCpy = GetTrainer2LoseText(); + } + break; + case B_TXT_TRAINER2_WIN_TEXT: + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + { + sub_81A36D0(1, gTrainerBattleOpponent_B); + toCpy = gStringVar4; + } + else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + sub_81D572C(3, gTrainerBattleOpponent_B); + toCpy = gStringVar4; + } + break; + case B_TXT_PARTNER_CLASS: + toCpy = gTrainerClassNames[GetFrontierOpponentClass(gPartnerTrainerId)]; + break; + case B_TXT_PARTNER_NAME: + GetFrontierTrainerName(text, gPartnerTrainerId); + toCpy = text; + break; + } + + // missing if (toCpy != NULL) check + while (*toCpy != EOS) + { + dst[dstID] = *toCpy; + dstID++; + toCpy++; + } + if (*src == B_TXT_TRAINER1_LOSE_TEXT || *src == B_TXT_TRAINER2_LOSE_TEXT + || *src == B_TXT_TRAINER1_WIN_TEXT || *src == B_TXT_TRAINER2_WIN_TEXT) + { + dst[dstID] = EXT_CTRL_CODE_BEGIN; + dstID++; + dst[dstID] = 9; + dstID++; + } + } + else + { + dst[dstID] = *src; + dstID++; + } + src++; + } + + dst[dstID] = *src; + dstID++; + + return dstID; +} + +// TODO: move these to a general header like util.h +#define ByteRead16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) +#define ByteRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) + +static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst) +{ + u32 srcID = 1; + u32 value = 0; + u8 text[12]; + u16 hword; + + *dst = EOS; + while (src[srcID] != B_BUFF_EOS) + { + switch (src[srcID]) + { + case B_BUFF_STRING: // battle string + hword = ByteRead16(&src[srcID + 1]); + StringAppend(dst, gBattleStringsTable[hword - BATTLESTRINGS_ID_ADDER]); + srcID += 3; + break; + case B_BUFF_NUMBER: // int to string + switch (src[srcID + 1]) + { + case 1: + value = src[srcID + 3]; + break; + case 2: + value = ByteRead16(&src[srcID + 3]); + break; + case 4: + value = ByteRead32(&src[srcID + 3]); + break; + } + ConvertIntToDecimalStringN(dst, value, 0, src[srcID + 2]); + srcID += src[srcID + 1] + 3; + break; + case B_BUFF_MOVE: // move name + StringAppend(dst, gMoveNames[ByteRead16(&src[srcID + 1])]); + srcID += 3; + break; + case B_BUFF_TYPE: // type name + StringAppend(dst, gTypeNames[src[srcID + 1]]); + srcID += 2; + break; + case B_BUFF_MON_NICK_WITH_PREFIX: // poke nick with prefix + if (GetBankSide(src[srcID + 1]) == SIDE_PLAYER) + { + GetMonData(&gPlayerParty[src[srcID + 2]], MON_DATA_NICKNAME, text); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + StringAppend(dst, gText_FoePkmnPrefix); + else + StringAppend(dst, gText_WildPkmnPrefix); + + GetMonData(&gEnemyParty[src[srcID + 2]], MON_DATA_NICKNAME, text); + } + StringGetEnd10(text); + StringAppend(dst, text); + srcID += 3; + break; + case B_BUFF_STAT: // stats + StringAppend(dst, gStatNamesTable[src[srcID + 1]]); + srcID += 2; + break; + case B_BUFF_SPECIES: // species name + GetSpeciesName(dst, ByteRead16(&src[srcID + 1])); + srcID += 3; + break; + case B_BUFF_MON_NICK: // poke nick without prefix + if (GetBankSide(src[srcID + 1]) == SIDE_PLAYER) + GetMonData(&gPlayerParty[src[srcID + 2]], MON_DATA_NICKNAME, dst); + else + GetMonData(&gEnemyParty[src[srcID + 2]], MON_DATA_NICKNAME, dst); + StringGetEnd10(dst); + srcID += 3; + break; + case B_BUFF_NEGATIVE_FLAVOUR: // flavour table + StringAppend(dst, gPokeblockWasTooXStringTable[src[srcID + 1]]); + srcID += 2; + break; + case B_BUFF_ABILITY: // ability names + StringAppend(dst, gAbilityNames[src[srcID + 1]]); + srcID += 2; + break; + case B_BUFF_ITEM: // item name + hword = ByteRead16(&src[srcID + 1]); + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + if (hword == ITEM_ENIGMA_BERRY) + { + if (gLinkPlayers[gBattleScripting.multiplayerId].lp_field_18 == gStringBank) + { + StringCopy(dst, gEnigmaBerries[gStringBank].name); + StringAppend(dst, gText_BerrySuffix); + } + else + StringAppend(dst, gText_EnigmaBerry); + } + else + CopyItemName(hword, dst); + } + else + CopyItemName(hword, dst); + srcID += 3; + break; + } + } +} + +static void sub_814F8F8(u8* textBuff) +{ + s32 counter = 0; + u32 i = 0; + + while (counter != 4) + { + if (sUnknownMoveTable[i] == MOVE_NONE) + counter++; + if (sUnknownMoveTable[i++] == gStringInfo->currentMove) + break; + } + + if (counter >= 0) + { + if (counter <= 2) + StringCopy(textBuff, gText_SpaceIs); // is + else if (counter <= 4) + StringCopy(textBuff, gText_ApostropheS); // 's + } +} + +static void sub_814F950(u8* dst) +{ + s32 counter = 0; + s32 i = 0; + + while (*dst != EOS) + dst++; + + while (counter != 4) + { + if (sUnknownMoveTable[i] == MOVE_NONE) + counter++; + if (sUnknownMoveTable[i++] == gStringInfo->currentMove) + break; + } + + switch (counter) + { + case 0: + StringCopy(dst, gText_ExclamationMark); + break; + case 1: + StringCopy(dst, gText_ExclamationMark2); + break; + case 2: + StringCopy(dst, gText_ExclamationMark3); + break; + case 3: + StringCopy(dst, gText_ExclamationMark4); + break; + case 4: + StringCopy(dst, gText_ExclamationMark5); + break; + } +} + +void sub_814F9EC(const u8 *text, u8 arg1) +{ + const u8 *r8 = gUnknown_085CD660[gBattleScripting.field_24]; + bool32 r9; + struct TextSubPrinter textSubPrinter; + u8 speed; + + if (arg1 & 0x80) + { + arg1 &= ~(0x80); + r9 = FALSE; + } + else + { + FillWindowPixelBuffer(arg1, r8[12 * arg1]); + r9 = TRUE; + } + + textSubPrinter.current_text_offset = text; + textSubPrinter.windowId = arg1; + textSubPrinter.fontId = r8[(12 * arg1) + 1]; + textSubPrinter.x = r8[(12 * arg1) + 2]; + textSubPrinter.y = r8[(12 * arg1) + 3]; + textSubPrinter.currentX = textSubPrinter.x; + textSubPrinter.currentY = textSubPrinter.y; + textSubPrinter.letterSpacing = r8[(12 * arg1) + 4]; + textSubPrinter.lineSpacing = r8[(12 * arg1) + 5]; + textSubPrinter.fontColor_l = 0; + textSubPrinter.fontColor_h = r8[(12 * arg1) + 7]; + textSubPrinter.bgColor = r8[(12 * arg1) + 8]; + textSubPrinter.shadowColor = r8[(12 * arg1) + 9]; + + if (textSubPrinter.x == 0xFF) + { + s32 var2; + u32 var = sub_80397C4(gBattleScripting.field_24, arg1); + var2 = GetStringCenterAlignXOffsetWithLetterSpacing(textSubPrinter.fontId, textSubPrinter.current_text_offset, var, textSubPrinter.letterSpacing); + textSubPrinter.x = textSubPrinter.currentX = var2; + } + + if (arg1 == 0x16) + gTextFlags.flag_1 = 0; + else + gTextFlags.flag_1 = 1; + + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED)) + gTextFlags.flag_2 = 1; + else + gTextFlags.flag_2 = 0; + + if (arg1 == 0 || arg1 == 0x16) + { + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + speed = 1; + else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + speed = sRecordedBattleTextSpeeds[sub_8185FC4()]; + else + speed = sav2_get_text_speed(); + + gTextFlags.flag_0 = 1; + } + else + { + speed = r8[(12 * arg1) + 6]; + gTextFlags.flag_0 = 0; + } + + AddTextPrinter(&textSubPrinter, speed, NULL); + + if (r9) + { + PutWindowTilemap(arg1); + CopyWindowToVram(arg1, 3); + } +} + +void SetPpNumbersPaletteInMoveSelection(void) +{ + struct ChooseMoveStruct *chooseMoveStruct = (struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBank][4]); + const u16 *palPtr = gUnknown_08D85620; + u8 var = GetCurrentPpToMaxPpState(chooseMoveStruct->currentPp[gMoveSelectionCursor[gActiveBank]], + chooseMoveStruct->maxPp[gMoveSelectionCursor[gActiveBank]]); + + gPlttBufferUnfaded[92] = palPtr[(var * 2) + 0]; + gPlttBufferUnfaded[91] = palPtr[(var * 2) + 1]; + + CpuCopy16(&gPlttBufferUnfaded[92], &gPlttBufferFaded[92], sizeof(u16)); + CpuCopy16(&gPlttBufferUnfaded[91], &gPlttBufferFaded[91], sizeof(u16)); +} + +u8 GetCurrentPpToMaxPpState(u8 currentPp, u8 maxPp) +{ + if (maxPp == currentPp) + { + return 3; + } + else if (maxPp <= 2) + { + if (currentPp > 1) + return 3; + else + return 2 - currentPp; + } + else if (maxPp <= 7) + { + if (currentPp > 2) + return 3; + else + return 2 - currentPp; + } + else + { + if (currentPp == 0) + return 2; + if (currentPp <= maxPp / 4) + return 1; + if (currentPp > maxPp / 2) + return 3; + } + + return 0; +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c new file mode 100644 index 000000000..28357d984 --- /dev/null +++ b/src/battle_script_commands.c @@ -0,0 +1,11415 @@ +#include "global.h" +#include "battle.h" +#include "battle_move_effects.h" +#include "battle_message.h" +#include "battle_ai_script_commands.h" +#include "moves.h" +#include "abilities.h" +#include "item.h" +#include "items.h" +#include "hold_effects.h" +#include "util.h" +#include "pokemon.h" +#include "calculate_base_damage.h" +#include "rng.h" +#include "battle_controllers.h" +#include "species.h" +#include "songs.h" +#include "text.h" +#include "sound.h" +#include "pokedex.h" +#include "recorded_battle.h" +#include "window.h" +#include "reshow_battle_screen.h" +#include "main.h" +#include "palette.h" +#include "money.h" +#include "bg.h" +#include "string_util.h" +#include "pokemon_icon.h" +#include "pokemon_item_effects.h" +#include "m4a.h" +#include "mail.h" +#include "event_data.h" +#include "pokemon_storage_system.h" +#include "task.h" +#include "naming_screen.h" +#include "battle_string_ids.h" + +// variables + +extern u8 gCritMultiplier; +extern s32 gBattleMoveDamage; +extern u32 gStatuses3[BATTLE_BANKS_COUNT]; +extern u32 gBattleTypeFlags; +extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT]; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; +extern u8 gActiveBank; +extern u32 gBattleExecBuffer; +extern u8 gNoOfAllBanks; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gBanksByTurnOrder[BATTLE_BANKS_COUNT]; +extern u8 gActionsByTurnOrder[BATTLE_BANKS_COUNT]; +extern u16 gCurrentMove; +extern u8 gLastUsedAbility; +extern u16 gBattleWeather; +extern u8 gStringBank; +extern u8 gEffectBank; +extern u8 gAbsentBankFlags; +extern u8 gMultiHitCounter; +extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gSideAffecting[2]; +extern u16 gPauseCounterBattle; +extern u16 gPaydayMoney; +extern u16 gRandomTurnNumber; +extern u8 gBattleOutcome; +extern u8 gBattleTerrain; +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern const u8* gBattlescriptCurrInstr; +extern u8 gCurrMovePos; +extern u8 gCurrentActionFuncId; +extern u32 gHitMarker; +extern u8 gBattleMoveFlags; +extern u8 gBattleCommunication[]; +extern u16 gUnknown_02024250[4]; +extern u16 gUnknown_02024258[4]; +extern u16 gUnknown_02024260[4]; +extern u8 gUnknown_02024270[4]; +extern u8 gStringBank; +extern u16 gDynamicBasePower; +extern u16 gLastUsedItem; +extern u16 gBattleMovePower; +extern s32 gHpDealt; +extern s32 gTakenDmg[BATTLE_BANKS_COUNT]; +extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT]; +extern u8 gSentPokesToOpponent[2]; +extern u8 gBank1; +extern u16 gExpShareExp; +extern u8 gLeveledUpInBattle; +extern void (*gBattleMainFunc)(void); +extern u8 gPlayerPartyCount; +extern u16 gMoveToLearn; +extern u16 gRandomMove; +extern u8 gBankInMenu; +extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; +extern u8 gCurrentTurnActionNumber; +extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; +extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; +extern u16 gPartnerTrainerId; +extern u16 gLastUsedMove; +extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; +extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gTrainerBattleOpponent_A; +extern u16 gTrainerBattleOpponent_B; +extern u8 gUnknown_020241E9; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattle_BG3_X; +extern struct MusicPlayerInfo gMPlay_BGM; + +struct TrainerMoney +{ + u8 classId; + u8 value; +}; + +extern const struct BattleMove gBattleMoves[]; +extern const struct BaseStats gBaseStats[]; +extern const u8 gTypeEffectiveness[]; +extern const u16 gMissStringIds[]; +extern const u16 gTrappingMoves[]; +extern const struct TrainerMoney gTrainerMoneyTable[]; +extern const u8* const gBattleScriptsForMoveEffects[]; + +// functions +extern void sub_81A5718(u8 bank); // battle frontier 2 +extern void sub_81A56B4(void); // battle frontier 2 +extern void sub_81BFA38(struct Pokemon* party, u8 monPartyId, u8 monCount, void (*callback)(void), u16 move); // pokemon summary screen +extern u8 sub_81C1B94(void); // pokemon summary screen +extern void IncrementGameStat(u8 statId); // rom_4 +extern void sub_81D388C(struct Pokemon* mon, void* statStoreLocation); // pokenav.s +extern void sub_81D3640(u8 arg0, void* statStoreLocation1, void* statStoreLocation2, u8 arg3, u8 arg4, u8 arg5); // pokenav.s +extern void sub_81D3784(u8 arg0, void* statStoreLocation1, u8 arg2, u8 arg3, u8 arg4); // pokenav.s +extern u8* GetMonNickname(struct Pokemon* mon, u8* dst); // party_menu +extern u8 sub_81A5258(u8* arg0); // battle frontier 2 +extern void sub_81A5BF8(void); // battle frontier 2 +extern void sub_81A5D44(void); // battle frontier 2 +extern void sub_81B8E80(u8 bank, u8, u8); // party menu +extern bool8 sub_81B1250(void); // ? +extern u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale); // battle interface +extern bool8 InBattlePike(void); +extern bool8 InBattlePyramid(void); +extern u16 GetBattlePyramidPickupItemId(void); +extern u8 sav1_map_get_light_level(void); +extern u8 sub_813B21C(void); +extern u16 get_unknown_box_id(void); +extern void sub_80356D0(void); + +// BattleScripts +extern const u8 BattleScript_MoveEnd[]; +extern const u8 BattleScript_NoPPForMove[]; +extern const u8 BattleScript_MagicCoatBounce[]; +extern const u8 BattleScript_TookAttack[]; +extern const u8 BattleScript_SnatchedMove[]; +extern const u8 BattleScript_Pausex20[]; +extern const u8 BattleScript_SubstituteFade[]; +extern const u8 BattleScript_HangedOnMsg[]; +extern const u8 BattleScript_OneHitKOMsg[]; +extern const u8 BattleScript_EnduredMsg[]; +extern const u8 BattleScript_PSNPrevention[]; +extern const u8 BattleScript_BRNPrevention[]; +extern const u8 BattleScript_PRLZPrevention[]; +extern const u8 BattleScript_FlinchPrevention[]; +extern const u8 BattleScript_StatUp[]; +extern const u8 BattleScript_StatDown[]; +extern const u8 BattleScript_NoItemSteal[]; +extern const u8 BattleScript_ItemSteal[]; +extern const u8 BattleScript_RapidSpinAway[]; +extern const u8 BattleScript_TargetPRLZHeal[]; +extern const u8 BattleScript_KnockedOff[]; +extern const u8 BattleScript_StickyHoldActivates[]; +extern const u8 BattleScript_AllStatsUp[]; +extern const u8 BattleScript_AtkDefDown[]; +extern const u8 BattleScript_SAtkDown2[]; +extern const u8 BattleScript_LevelUp[]; +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; +extern const u8 BattleScript_ButItFailed[]; +extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_MistProtected[]; +extern const u8 BattleScript_AbilityNoStatLoss[]; +extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; +extern const u8 BattleScript_TrainerBallBlock[]; +extern const u8 BattleScript_WallyBallThrow[]; +extern const u8 BattleScript_SuccessBallThrow[]; +extern const u8 BattleScript_ShakeBallThrow[]; +extern const u8 BattleScript_FaintAttacker[]; +extern const u8 BattleScript_FaintTarget[]; +extern const u8 BattleScript_DestinyBondTakesLife[]; +extern const u8 BattleScript_GrudgeTakesPp[]; +extern const u8 BattleScript_RageIsBuilding[]; +extern const u8 BattleScript_DefrostedViaFireMove[]; +extern const u8 gUnknown_082DB87D[]; +extern const u8 gUnknown_082DAE90[]; +extern const u8 gUnknown_082DAE59[]; +extern const u8 gUnknown_082DAEC7[]; +extern const u8 BattleScript_MoveEffectSleep[]; +extern const u8 BattleScript_MoveEffectPoison[]; +extern const u8 BattleScript_MoveEffectBurn[]; +extern const u8 BattleScript_MoveEffectFreeze[]; +extern const u8 BattleScript_MoveEffectParalysis[]; +extern const u8 BattleScript_MoveEffectToxic[]; +extern const u8 BattleScript_MoveEffectConfusion[]; +extern const u8 BattleScript_MoveEffectUproar[]; +extern const u8 BattleScript_MoveEffectPayDay[]; +extern const u8 BattleScript_MoveEffectWrap[]; +extern const u8 BattleScript_MoveEffectRecoil33[]; +extern const u8 BattleScript_DampStopsExplosion[]; +extern const u8 BattleScript_MistProtected[]; +extern const u8 BattleScript_AbilityNoStatLoss[]; +extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; +extern const u8 BattleScript_ButItFailed[]; +extern const u8 gUnknown_082DADD8[]; +extern const u8 BattleScript_PrintPayDayMoneyString[]; +extern const u8 BattleScript_SturdyPreventsOHKO[]; +extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_PauseEffectivenessSoundResultMsgEndMove[]; +extern const u8 BattleScript_CastformChange[]; +extern const u8 BattleScript_TrainerBallBlock[]; +extern const u8 BattleScript_WallyBallThrow[]; +extern const u8 BattleScript_SuccessBallThrow[]; +extern const u8 BattleScript_ShakeBallThrow[]; +extern const u8 BattleScript_PresentDamageTarget[]; +extern const u8 BattleScript_AlreadyAtFullHp[]; +extern const u8 BattleScript_PresentHealTarget[]; +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; + +// strings +extern const u8 gText_BattleYesNoChoice[]; + +// read via orr +#define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) +#define BSScriptRead16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) +#define BSScriptReadPtr(ptr) ((void *)BSScriptRead32(ptr)) + +// read via add +#define BS2ScriptRead32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) +#define BS2ScriptRead16(ptr) ((ptr)[0] + ((ptr)[1] << 8)) +#define BS2ScriptReadPtr(ptr) ((void *)BS2ScriptRead32(ptr)) + +#define TARGET_PROTECT_AFFECTED ((gProtectStructs[gBankTarget].protected && gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) + +#define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))) + +// this file's functions +static bool8 IsTwoTurnsMove(u16 move); +static void DestinyBondFlagUpdate(void); +static u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. +static void CheckWonderGuardAndLevitate(void); +static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); +static bool32 IsMonGettingExpSentOut(void); +static void sub_804F17C(void); +static bool8 sub_804F1CC(void); +static void sub_804F100(void); +static void sub_804F144(void); +static bool8 sub_804F344(void); +static void PutMonIconOnLvlUpBox(void); +static void PutLevelAndGenderOnLvlUpBox(void); + +static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite); + +static void atk00_attackcanceler(void); +static void atk01_accuracycheck(void); +static void atk02_attackstring(void); +static void atk03_ppreduce(void); +static void atk04_critcalc(void); +static void atk05_damagecalc1(void); +static void atk06_typecalc(void); +static void atk07_dmg_adjustment(void); +static void atk08_dmg_adjustment2(void); +static void atk09_attackanimation(void); +static void atk0A_waitanimation(void); +static void atk0B_healthbarupdate(void); +static void atk0C_datahpupdate(void); +static void atk0D_critmessage(void); +static void atk0E_effectiveness_sound(void); +static void atk0F_resultmessage(void); +static void atk10_printstring(void); +static void atk11_printstring_playeronly(void); +static void atk12_waitmessage(void); +static void atk13_printfromtable(void); +static void atk14_printfromtable_playeronly(void); +static void atk15_seteffectwithchance(void); +static void atk16_seteffectprimary(void); +static void atk17_seteffectsecondary(void); +static void atk18_status_effect_clear(void); +static void atk19_faint_pokemon(void); +static void atk1A_faint_animation(void); +static void atk1B_faint_effects_clear(void); +static void atk1C_jumpifstatus(void); +static void atk1D_jumpifstatus2(void); +static void atk1E_jumpifability(void); +static void atk1F_jumpifsideaffecting(void); +static void atk20_jumpifstat(void); +static void atk21_jumpifstatus3(void); +static void atk22_jumpiftype(void); +static void atk23_getexp(void); +static void atk24(void); +static void atk25_move_values_cleanup(void); +static void atk26_set_multihit(void); +static void atk27_decrement_multihit(void); +static void atk28_goto(void); +static void atk29_jumpifbyte(void); +static void atk2A_jumpifhalfword(void); +static void atk2B_jumpifword(void); +static void atk2C_jumpifarrayequal(void); +static void atk2D_jumpifarraynotequal(void); +static void atk2E_setbyte(void); +static void atk2F_addbyte(void); +static void atk30_subbyte(void); +static void atk31_copyarray(void); +static void atk32_copyarray_withindex(void); +static void atk33_orbyte(void); +static void atk34_orhalfword(void); +static void atk35_orword(void); +static void atk36_bicbyte(void); +static void atk37_bichalfword(void); +static void atk38_bicword(void); +static void atk39_pause(void); +static void atk3A_waitstate(void); +static void atk3B_healthbar_update(void); +static void atk3C_return(void); +static void atk3D_end(void); +static void atk3E_end2(void); +static void atk3F_end3(void); +static void atk40_jump_if_move_affected_by_protect(void); +static void atk41_call(void); +static void atk42_jumpiftype2(void); +static void atk43_jumpifabilitypresent(void); +static void atk44_end_selection_script(void); +static void atk45_playanimation(void); +static void atk46_playanimation2(void); +static void atk47_setgraphicalstatchangevalues(void); +static void atk48_playstatchangeanimation(void); +static void atk49_moveend(void); +static void atk4A_typecalc2(void); +static void atk4B_return_atk_to_ball(void); +static void atk4C_copy_poke_data(void); +static void atk4D_switch_data_update(void); +static void atk4E_switchin_anim(void); +static void atk4F_jump_if_cannot_switch(void); +static void atk50_openpartyscreen(void); +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_fanfare(void); +static void atk56_fainting_cry(void); +static void atk57(void); +static void atk58_return_to_ball(void); +static void atk59_learnmove_inbattle(void); +static void atk5A_yesnoboxlearnmove(void); +static void atk5B_yesnoboxstoplearningmove(void); +static void atk5C_hitanimation(void); +static void atk5D_getmoneyreward(void); +static void atk5E_8025A70(void); +static void atk5F_8025B24(void); +static void atk60_increment_gamestat(void); +static void atk61_draw_party_status_summary(void); +static void atk62_08025C6C(void); +static void atk63_jumptorandomattack(void); +static void atk64_statusanimation(void); +static void atk65_status2animation(void); +static void atk66_chosenstatusanimation(void); +static void atk67_yesnobox(void); +static void atk68_80246A0(void); +static void atk69_dmg_adjustment3(void); +static void atk6A_removeitem(void); +static void atk6B_atknameinbuff1(void); +static void atk6C_draw_lvlupbox(void); +static void atk6D_reset_sentpokes_value(void); +static void atk6E_set_atk_to_player0(void); +static void atk6F_set_visible(void); +static void atk70_record_last_used_ability(void); +static void atk71_buffer_move_to_learn(void); +static void atk72_jump_if_run_attempt_success(void); +static void atk73_hp_thresholds(void); +static void atk74_hp_thresholds2(void); +static void atk75_item_effect_on_opponent(void); +static void atk76_various(void); +static void atk77_set_protect_like(void); +static void atk78_faintifabilitynotdamp(void); +static void atk79_setatkhptozero(void); +static void atk7A_jumpwhiletargetvalid(void); +static void atk7B_healhalfHP_if_possible(void); +static void atk7C_trymirrormove(void); +static void atk7D_set_rain(void); +static void atk7E_setreflect(void); +static void atk7F_setseeded(void); +static void atk80_manipulatedamage(void); +static void atk81_setrest(void); +static void atk82_jumpifnotfirstturn(void); +static void atk83_nop(void); +static void atk84_jump_if_cant_sleep(void); +static void atk85_stockpile(void); +static void atk86_stockpiletobasedamage(void); +static void atk87_stockpiletohpheal(void); +static void atk88_negativedamage(void); +static void atk89_statbuffchange(void); +static void atk8A_normalisebuffs(void); +static void atk8B_setbide(void); +static void atk8C_confuseifrepeatingattackends(void); +static void atk8D_setmultihit_counter(void); +static void atk8E_init_multihit_string(void); +static void atk8F_forcerandomswitch(void); +static void atk90_conversion_type_change(void); +static void atk91_givepaydaymoney(void); +static void atk92_setlightscreen(void); +static void atk93_ko_move(void); +static void atk94_damagetohalftargethp(void); +static void atk95_setsandstorm(void); +static void atk96_weatherdamage(void); +static void atk97_try_infatuation(void); +static void atk98_status_icon_update(void); +static void atk99_setmist(void); +static void atk9A_set_focusenergy(void); +static void atk9B_transformdataexecution(void); +static void atk9C_set_substitute(void); +static void atk9D_mimicattackcopy(void); +static void atk9E_metronome(void); +static void atk9F_dmgtolevel(void); +static void atkA0_psywavedamageeffect(void); +static void atkA1_counterdamagecalculator(void); +static void atkA2_mirrorcoatdamagecalculator(void); +static void atkA3_disablelastusedattack(void); +static void atkA4_setencore(void); +static void atkA5_painsplitdmgcalc(void); +static void atkA6_settypetorandomresistance(void); +static void atkA7_setalwayshitflag(void); +static void atkA8_copymovepermanently(void); +static void atkA9_sleeptalk_choose_move(void); +static void atkAA_set_destinybond(void); +static void atkAB_DestinyBondFlagUpdate(void); +static void atkAC_remaininghptopower(void); +static void atkAD_spite_ppreduce(void); +static void atkAE_heal_party_status(void); +static void atkAF_cursetarget(void); +static void atkB0_set_spikes(void); +static void atkB1_set_foresight(void); +static void atkB2_setperishsong(void); +static void atkB3_rolloutdamagecalculation(void); +static void atkB4_jumpifconfusedandstatmaxed(void); +static void atkB5_furycuttercalc(void); +static void atkB6_happinesstodamagecalculation(void); +static void atkB7_presentdamagecalculation(void); +static void atkB8_set_safeguard(void); +static void atkB9_magnitudedamagecalculation(void); +static void atkBA_jumpifnopursuitswitchdmg(void); +static void atkBB_setsunny(void); +static void atkBC_maxattackhalvehp(void); +static void atkBD_copyfoestats(void); +static void atkBE_rapidspinfree(void); +static void atkBF_set_defense_curl(void); +static void atkC0_recoverbasedonsunlight(void); +static void atkC1_hidden_power(void); +static void atkC2_selectnexttarget(void); +static void atkC3_setfutureattack(void); +static void atkC4_beat_up(void); +static void atkC5_setsemiinvulnerablebit(void); +static void atkC6_clearsemiinvulnerablebit(void); +static void atkC7_setminimize(void); +static void atkC8_sethail(void); +static void atkC9_jumpifattackandspecialattackcannotfall(void); +static void atkCA_setforcedtarget(void); +static void atkCB_setcharge(void); +static void atkCC_callterrainattack(void); +static void atkCD_cureifburnedparalysedorpoisoned(void); +static void atkCE_settorment(void); +static void atkCF_jumpifnodamage(void); +static void atkD0_settaunt(void); +static void atkD1_set_helpinghand(void); +static void atkD2_swap_items(void); +static void atkD3_copy_ability(void); +static void atkD4_wish_effect(void); +static void atkD5_setroots(void); +static void atkD6_doubledamagedealtifdamaged(void); +static void atkD7_setyawn(void); +static void atkD8_setdamagetohealthdifference(void); +static void atkD9_scaledamagebyhealthratio(void); +static void atkDA_abilityswap(void); +static void atkDB_imprisoneffect(void); +static void atkDC_setgrudge(void); +static void atkDD_weightdamagecalculation(void); +static void atkDE_asistattackselect(void); +static void atkDF_setmagiccoat(void); +static void atkE0_setstealstatchange(void); +static void atkE1_intimidate_string_loader(void); +static void atkE2_switchout_abilities(void); +static void atkE3_jumpifhasnohp(void); +static void atkE4_getsecretpowereffect(void); +static void atkE5_pickup(void); +static void atkE6_castform_change_animation(void); +static void atkE7_castform_data_change(void); +static void atkE8_settypebasedhalvers(void); +static void atkE9_setweatherballtype(void); +static void atkEA_recycleitem(void); +static void atkEB_settypetoterrain(void); +static void atkEC_pursuit_sth(void); +static void atkED_802B4B4(void); +static void atkEE_removelightscreenreflect(void); +static void atkEF_pokeball_catch_calculation(void); +static void atkF0_give_caught_mon(void); +static void atkF1_set_caught_mon_dex_flags(void); +static void atkF2_display_dex_info(void); +static void atkF3_nickname_caught_poke(void); +static void atkF4_subattackerhpbydmg(void); +static void atkF5_removeattackerstatus1(void); +static void atkF6_action_finished(void); +static void atkF7_turn_finished(void); +static void atkF8_trainer_slide_back(void); + +void (* const gBattleScriptingCommandsTable[])(void) = +{ + atk00_attackcanceler, + atk01_accuracycheck, + atk02_attackstring, + atk03_ppreduce, + atk04_critcalc, + atk05_damagecalc1, + atk06_typecalc, + atk07_dmg_adjustment, + atk08_dmg_adjustment2, + atk09_attackanimation, + atk0A_waitanimation, + atk0B_healthbarupdate, + atk0C_datahpupdate, + atk0D_critmessage, + atk0E_effectiveness_sound, + atk0F_resultmessage, + atk10_printstring, + atk11_printstring_playeronly, + atk12_waitmessage, + atk13_printfromtable, + atk14_printfromtable_playeronly, + atk15_seteffectwithchance, + atk16_seteffectprimary, + atk17_seteffectsecondary, + atk18_status_effect_clear, + atk19_faint_pokemon, + atk1A_faint_animation, + atk1B_faint_effects_clear, + atk1C_jumpifstatus, + atk1D_jumpifstatus2, + atk1E_jumpifability, + atk1F_jumpifsideaffecting, + atk20_jumpifstat, + atk21_jumpifstatus3, + atk22_jumpiftype, + atk23_getexp, + atk24, + atk25_move_values_cleanup, + atk26_set_multihit, + atk27_decrement_multihit, + atk28_goto, + atk29_jumpifbyte, + atk2A_jumpifhalfword, + atk2B_jumpifword, + atk2C_jumpifarrayequal, + atk2D_jumpifarraynotequal, + atk2E_setbyte, + atk2F_addbyte, + atk30_subbyte, + atk31_copyarray, + atk32_copyarray_withindex, + atk33_orbyte, + atk34_orhalfword, + atk35_orword, + atk36_bicbyte, + atk37_bichalfword, + atk38_bicword, + atk39_pause, + atk3A_waitstate, + atk3B_healthbar_update, + atk3C_return, + atk3D_end, + atk3E_end2, + atk3F_end3, + atk40_jump_if_move_affected_by_protect, + atk41_call, + atk42_jumpiftype2, + atk43_jumpifabilitypresent, + atk44_end_selection_script, + atk45_playanimation, + atk46_playanimation2, + atk47_setgraphicalstatchangevalues, + atk48_playstatchangeanimation, + atk49_moveend, + atk4A_typecalc2, + atk4B_return_atk_to_ball, + atk4C_copy_poke_data, + atk4D_switch_data_update, + atk4E_switchin_anim, + atk4F_jump_if_cannot_switch, + atk50_openpartyscreen, + atk51_switch_handle_order, + atk52_switch_in_effects, + atk53_trainer_slide, + atk54_effectiveness_sound, + atk55_play_fanfare, + atk56_fainting_cry, + atk57, + atk58_return_to_ball, + atk59_learnmove_inbattle, + atk5A_yesnoboxlearnmove, + atk5B_yesnoboxstoplearningmove, + atk5C_hitanimation, + atk5D_getmoneyreward, + atk5E_8025A70, + atk5F_8025B24, + atk60_increment_gamestat, + atk61_draw_party_status_summary, + atk62_08025C6C, + atk63_jumptorandomattack, + atk64_statusanimation, + atk65_status2animation, + atk66_chosenstatusanimation, + atk67_yesnobox, + atk68_80246A0, + atk69_dmg_adjustment3, + atk6A_removeitem, + atk6B_atknameinbuff1, + atk6C_draw_lvlupbox, + atk6D_reset_sentpokes_value, + atk6E_set_atk_to_player0, + atk6F_set_visible, + atk70_record_last_used_ability, + atk71_buffer_move_to_learn, + atk72_jump_if_run_attempt_success, + atk73_hp_thresholds, + atk74_hp_thresholds2, + atk75_item_effect_on_opponent, + atk76_various, + atk77_set_protect_like, + atk78_faintifabilitynotdamp, + atk79_setatkhptozero, + atk7A_jumpwhiletargetvalid, + atk7B_healhalfHP_if_possible, + atk7C_trymirrormove, + atk7D_set_rain, + atk7E_setreflect, + atk7F_setseeded, + atk80_manipulatedamage, + atk81_setrest, + atk82_jumpifnotfirstturn, + atk83_nop, + atk84_jump_if_cant_sleep, + atk85_stockpile, + atk86_stockpiletobasedamage, + atk87_stockpiletohpheal, + atk88_negativedamage, + atk89_statbuffchange, + atk8A_normalisebuffs, + atk8B_setbide, + atk8C_confuseifrepeatingattackends, + atk8D_setmultihit_counter, + atk8E_init_multihit_string, + atk8F_forcerandomswitch, + atk90_conversion_type_change, + atk91_givepaydaymoney, + atk92_setlightscreen, + atk93_ko_move, + atk94_damagetohalftargethp, + atk95_setsandstorm, + atk96_weatherdamage, + atk97_try_infatuation, + atk98_status_icon_update, + atk99_setmist, + atk9A_set_focusenergy, + atk9B_transformdataexecution, + atk9C_set_substitute, + atk9D_mimicattackcopy, + atk9E_metronome, + atk9F_dmgtolevel, + atkA0_psywavedamageeffect, + atkA1_counterdamagecalculator, + atkA2_mirrorcoatdamagecalculator, + atkA3_disablelastusedattack, + atkA4_setencore, + atkA5_painsplitdmgcalc, + atkA6_settypetorandomresistance, + atkA7_setalwayshitflag, + atkA8_copymovepermanently, + atkA9_sleeptalk_choose_move, + atkAA_set_destinybond, + atkAB_DestinyBondFlagUpdate, + atkAC_remaininghptopower, + atkAD_spite_ppreduce, + atkAE_heal_party_status, + atkAF_cursetarget, + atkB0_set_spikes, + atkB1_set_foresight, + atkB2_setperishsong, + atkB3_rolloutdamagecalculation, + atkB4_jumpifconfusedandstatmaxed, + atkB5_furycuttercalc, + atkB6_happinesstodamagecalculation, + atkB7_presentdamagecalculation, + atkB8_set_safeguard, + atkB9_magnitudedamagecalculation, + atkBA_jumpifnopursuitswitchdmg, + atkBB_setsunny, + atkBC_maxattackhalvehp, + atkBD_copyfoestats, + atkBE_rapidspinfree, + atkBF_set_defense_curl, + atkC0_recoverbasedonsunlight, + atkC1_hidden_power, + atkC2_selectnexttarget, + atkC3_setfutureattack, + atkC4_beat_up, + atkC5_setsemiinvulnerablebit, + atkC6_clearsemiinvulnerablebit, + atkC7_setminimize, + atkC8_sethail, + atkC9_jumpifattackandspecialattackcannotfall, + atkCA_setforcedtarget, + atkCB_setcharge, + atkCC_callterrainattack, + atkCD_cureifburnedparalysedorpoisoned, + atkCE_settorment, + atkCF_jumpifnodamage, + atkD0_settaunt, + atkD1_set_helpinghand, + atkD2_swap_items, + atkD3_copy_ability, + atkD4_wish_effect, + atkD5_setroots, + atkD6_doubledamagedealtifdamaged, + atkD7_setyawn, + atkD8_setdamagetohealthdifference, + atkD9_scaledamagebyhealthratio, + atkDA_abilityswap, + atkDB_imprisoneffect, + atkDC_setgrudge, + atkDD_weightdamagecalculation, + atkDE_asistattackselect, + atkDF_setmagiccoat, + atkE0_setstealstatchange, + atkE1_intimidate_string_loader, + atkE2_switchout_abilities, + atkE3_jumpifhasnohp, + atkE4_getsecretpowereffect, + atkE5_pickup, + atkE6_castform_change_animation, + atkE7_castform_data_change, + atkE8_settypebasedhalvers, + atkE9_setweatherballtype, + atkEA_recycleitem, + atkEB_settypetoterrain, + atkEC_pursuit_sth, + atkED_802B4B4, + atkEE_removelightscreenreflect, + atkEF_pokeball_catch_calculation, + atkF0_give_caught_mon, + atkF1_set_caught_mon_dex_flags, + atkF2_display_dex_info, + atkF3_nickname_caught_poke, + atkF4_subattackerhpbydmg, + atkF5_removeattackerstatus1, + atkF6_action_finished, + atkF7_turn_finished, + atkF8_trainer_slide_back +}; + +struct StatFractions +{ + u8 dividend; + u8 divisor; +}; + +static const struct StatFractions sAccuracyStageRatios[] = +{ + { 33, 100}, // -6 + { 36, 100}, // -5 + { 43, 100}, // -4 + { 50, 100}, // -3 + { 60, 100}, // -2 + { 75, 100}, // -1 + { 1, 1}, // 0 + {133, 100}, // +1 + {166, 100}, // +2 + { 2, 1}, // +3 + {233, 100}, // +4 + {133, 50}, // +5 + { 3, 1}, // +6 +}; + +// The chance is 1/N for each stage. +static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2}; + +static const u32 sStatusFlagsForMoveEffects[] = +{ + 0x00000000, + STATUS_SLEEP, + STATUS_POISON, + STATUS_BURN, + STATUS_FREEZE, + STATUS_PARALYSIS, + STATUS_TOXIC_POISON, + STATUS2_CONFUSION, + STATUS2_FLINCHED, + 0x00000000, + STATUS2_UPROAR, + 0x00000000, + STATUS2_MULTIPLETURNS, + STATUS2_WRAPPED, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + STATUS2_RECHARGE, + 0x00000000, + 0x00000000, + STATUS2_ESCAPE_PREVENTION, + 0x08000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + STATUS2_LOCK_CONFUSE, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u8* const sMoveEffectBS_Ptrs[] = +{ + BattleScript_MoveEffectSleep, // 0 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SLEEP + BattleScript_MoveEffectPoison, // MOVE_EFFECT_POISON + BattleScript_MoveEffectBurn, // MOVE_EFFECT_BURN + BattleScript_MoveEffectFreeze, // MOVE_EFFECT_FREEZE + BattleScript_MoveEffectParalysis, // MOVE_EFFECT_PARALYSIS + BattleScript_MoveEffectToxic, // MOVE_EFFECT_TOXIC + BattleScript_MoveEffectConfusion, // MOVE_EFFECT_CONFUSION + BattleScript_MoveEffectSleep, // MOVE_EFFECT_FLINCH + BattleScript_MoveEffectSleep, // MOVE_EFFECT_TRI_ATTACK + BattleScript_MoveEffectUproar, // MOVE_EFFECT_UPROAR + BattleScript_MoveEffectPayDay, // MOVE_EFFECT_PAYDAY + BattleScript_MoveEffectSleep, // MOVE_EFFECT_CHARGING + BattleScript_MoveEffectWrap, // MOVE_EFFECT_WRAP + BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_25 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RECHARGE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAGE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_STEAL_ITEM + BattleScript_MoveEffectSleep, // MOVE_EFFECT_PREVENT_ESCAPE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_NIGHTMARE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ALL_STATS_UP + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAPIDSPIN + BattleScript_MoveEffectSleep, // MOVE_EFFECT_REMOVE_PARALYSIS + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_DEF_DOWN + BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_33_PARALYSIS +}; + +static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, 0x3F}; + +static const u16 sUnknown_0831C2C8[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal"); +static const u8 sUnknown_0831C2E8[] = INCBIN_U8("graphics/battle_interface/unk_battlebox.4bpp.lz"); + +// unused +static const u8 sRubyLevelUpStatBoxStats[] = +{ + MON_DATA_MAX_HP, MON_DATA_SPATK, MON_DATA_ATK, + MON_DATA_SPDEF, MON_DATA_DEF, MON_DATA_SPEED +}; + +#define MON_ICON_LVLUP_BOX_TAG 0xD75A + +static const struct OamData sOamData_MonIconOnLvlUpBox = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = 2, + .tileNum = 0, + .priority = 0, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBox = +{ + .tileTag = MON_ICON_LVLUP_BOX_TAG, + .paletteTag = MON_ICON_LVLUP_BOX_TAG, + .oam = &sOamData_MonIconOnLvlUpBox, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_MonIconOnLvlUpBox +}; + +static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8}; + +#define MIMIC_FORBIDDEN_END 0xFFFE +#define METRONOME_FORBIDDEN_END 0xFFFF +#define ASSIST_FORBIDDEN_END 0xFFFF + +static const u16 sMovesForbiddenToCopy[] = +{ + MOVE_METRONOME, + MOVE_STRUGGLE, + MOVE_SKETCH, + MOVE_MIMIC, + MIMIC_FORBIDDEN_END, + MOVE_COUNTER, + MOVE_MIRROR_COAT, + MOVE_PROTECT, + MOVE_DETECT, + MOVE_ENDURE, + MOVE_DESTINY_BOND, + MOVE_SLEEP_TALK, + MOVE_THIEF, + MOVE_FOLLOW_ME, + MOVE_SNATCH, + MOVE_HELPING_HAND, + MOVE_COVET, + MOVE_TRICK, + MOVE_FOCUS_PUNCH, + METRONOME_FORBIDDEN_END +}; + +static const u8 sFlailHpScaleToPowerTable[] = +{ + 1, 200, + 4, 150, + 9, 100, + 16, 80, + 32, 40, + 48, 20 +}; + +static const u16 sNaturePowerMoves[] = +{ + MOVE_STUN_SPORE, + MOVE_RAZOR_LEAF, + MOVE_EARTHQUAKE, + MOVE_HYDRO_PUMP, + MOVE_SURF, + MOVE_BUBBLE_BEAM, + MOVE_ROCK_SLIDE, + MOVE_SHADOW_BALL, + MOVE_SWIFT, + MOVE_SWIFT +}; + +// format: min. weight (hectograms), base power +static const u16 sWeightToDamageTable[] = +{ + 100, 20, + 250, 40, + 500, 60, + 1000, 80, + 2000, 100, + 0xFFFF, 0xFFFF +}; + +static const u16 sPickupItems[] = +{ + ITEM_POTION, + ITEM_ANTIDOTE, + ITEM_SUPER_POTION, + ITEM_GREAT_BALL, + ITEM_REPEL, + ITEM_ESCAPE_ROPE, + ITEM_X_ATTACK, + ITEM_FULL_HEAL, + ITEM_ULTRA_BALL, + ITEM_HYPER_POTION, + ITEM_RARE_CANDY, + ITEM_PROTEIN, + ITEM_REVIVE, + ITEM_HP_UP, + ITEM_FULL_RESTORE, + ITEM_MAX_REVIVE, + ITEM_PP_UP, + ITEM_MAX_ELIXIR, +}; + +static const u16 sRarePickupItems[] = +{ + ITEM_HYPER_POTION, + ITEM_NUGGET, + ITEM_KINGS_ROCK, + ITEM_FULL_RESTORE, + ITEM_ETHER, + ITEM_WHITE_HERB, + ITEM_TM44, + ITEM_ELIXIR, + ITEM_TM01, + ITEM_LEFTOVERS, + ITEM_TM26, +}; + +static const u8 sPickupProbabilities[] = +{ + 30, 40, 50, 60, 70, 80, 90, 94, 98 +}; + +static const u8 sTerrainToType[] = +{ + TYPE_GRASS, // tall grass + TYPE_GRASS, // long grass + TYPE_GROUND, // sand + TYPE_WATER, // underwater + TYPE_WATER, // water + TYPE_WATER, // pond water + TYPE_ROCK, // rock + TYPE_ROCK, // cave + TYPE_NORMAL, // building + TYPE_NORMAL, // plain +}; + +static const u8 sBallCatchBonuses[] = +{ + 20, 15, 10, 15 // Ultra, Great, Poke, Safari +}; + +// could be a 2d array or a struct +const ALIGNED(4) u8 gUnknown_0831C494[] = +{ + 0x3d, 0x44, 0x3d, 0x44, 0x14, 0x2d, 0x54, 0x5c, + 0x46, 0x55, 0x20, 0x5c, 0x26, 0x45, 0x46, 0x55, + 0x14, 0x5a, 0x46, 0x5c, 0x1e, 0x32, 0x20, 0x5a, + 0x38, 0x4e, 0x38, 0x4e, 0x19, 0x28, 0x4b, 0x5a, + 0x45, 0x4b, 0x1c, 0x53, 0x23, 0x2d, 0x1d, 0x23, + 0x3e, 0x48, 0x1e, 0x32, 0x3a, 0x5f, 0x58, 0x5e, + 0x22, 0x2d, 0x1d, 0x28, 0x23, 0x28, 0x23, 0x5f, + 0x38, 0x4e, 0x38, 0x4e, 0x23, 0x50, 0x22, 0x5e, + 0x2c, 0x5e, 0x22, 0x28, 0x38, 0x4e, 0x38, 0x4e, + 0x1e, 0x58, 0x1e, 0x58, 0x1e, 0x2b, 0x1b, 0x21, + 0x28, 0x5a, 0x19, 0x57, 0x12, 0x58, 0x5a, 0x5f, + 0x58, 0x5e, 0x16, 0x2a, 0x2a, 0x5c, 0x2a, 0x2f, + 0x38, 0x4e, 0x38, 0x4e +}; + +static const u8 sUnknown_0831C4F8[] = +{ + 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, + 0x01, 0x02, 0x02, 0x00, 0x03, 0x01, 0x03, 0x01, + 0x02, 0x03, 0x03, 0x02, 0x01, 0x00, 0x02, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; + +static void atk00_attackcanceler(void) +{ + s32 i; + + if (gBattleOutcome != 0) + { + gCurrentActionFuncId = ACTION_FINISHED; + return; + } + if (gBattleMons[gBankAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + { + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + return; + } + if (AtkCanceller_UnableToUseMove()) + return; + if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBankTarget, 0, 0, 0)) + return; + if (!gBattleMons[gBankAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE && !(gHitMarker & 0x800200) + && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + gBattlescriptCurrInstr = BattleScript_NoPPForMove; + gBattleMoveFlags |= MOVESTATUS_MISSED; + return; + } + + gHitMarker &= ~(HITMARKER_x800000); + + if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + i = IsPokeDisobedient(); // why use the 'i' variable...? + switch (i) + { + case 0: + break; + case 2: + gHitMarker |= HITMARKER_OBEYS; + return; + default: + gBattleMoveFlags |= MOVESTATUS_MISSED; + return; + } + } + + gHitMarker |= HITMARKER_OBEYS; + + if (gProtectStructs[gBankTarget].bounceMove && gBattleMoves[gCurrentMove].flags & FLAG_MAGICCOAT_AFFECTED) + { + PressurePPLose(gBankAttacker, gBankTarget, MOVE_MAGIC_COAT); + gProtectStructs[gBankTarget].bounceMove = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; + return; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + if ((gProtectStructs[gBanksByTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) + { + PressurePPLose(gBankAttacker, gBanksByTurnOrder[i], MOVE_SNATCH); + gProtectStructs[gBanksByTurnOrder[i]].stealMove = 0; + gBattleScripting.bank = gBanksByTurnOrder[i]; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SnatchedMove; + return; + } + } + + if (gSpecialStatuses[gBankTarget].lightningRodRedirected) + { + gSpecialStatuses[gBankTarget].lightningRodRedirected = 0; + gLastUsedAbility = ABILITY_LIGHTNING_ROD; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_TookAttack; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else if (TARGET_PROTECT_AFFECTED + && (gCurrentMove != MOVE_CURSE || (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST)) + && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)))) + { + CancelMultiTurnMoves(gBankAttacker); + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = 1; + gBattlescriptCurrInstr++; + } + else + { + gBattlescriptCurrInstr++; + } +} + +static void JumpIfMoveFailed(u8 adder, u16 move) +{ + const void* BS_ptr = gBattlescriptCurrInstr + adder; + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + DestinyBondFlagUpdate(); + if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBankTarget, 0, 0, move)) + return; + } + gBattlescriptCurrInstr = BS_ptr; +} + +static void atk40_jump_if_move_affected_by_protect(void) +{ + if (TARGET_PROTECT_AFFECTED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(5, 0); + gBattleCommunication[6] = 1; + } + else + { + gBattlescriptCurrInstr += 5; + } +} + +bool8 JumpIfMoveAffectedByProtect(u16 move) +{ + bool8 affected = FALSE; + if (TARGET_PROTECT_AFFECTED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + gBattleCommunication[6] = 1; + affected = TRUE; + } + return affected; +} + +bool8 AccuracyCalcHelper(u16 move) +{ + if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) + { + JumpIfMoveFailed(7, move); + return TRUE; + } + + if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBankTarget] & STATUS3_ON_AIR) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_ON_AIR; + + if (!(gHitMarker & HITMARKER_IGNORE_UNDERGROUND) && gStatuses3[gBankTarget] & STATUS3_UNDERGROUND) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_UNDERGROUND; + + if (!(gHitMarker & HITMARKER_IGNORE_UNDERWATER) && gStatuses3[gBankTarget] & STATUS3_UNDERWATER) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_UNDERWATER; + + if ((WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) && gBattleMoves[move].effect == EFFECT_THUNDER) + || (gBattleMoves[move].effect == EFFECT_ALWAYS_HIT || gBattleMoves[move].effect == EFFECT_VITAL_THROW)) + { + JumpIfMoveFailed(7, move); + return TRUE; + } + + return FALSE; +} + +static void atk01_accuracycheck(void) +{ + u16 move = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + if (move == 0xFFFE || move == 0xFFFF) + { + if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && move == 0xFFFF && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) + gBattlescriptCurrInstr += 7; + else if (gStatuses3[gBankTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else if (!JumpIfMoveAffectedByProtect(0)) + gBattlescriptCurrInstr += 7; + } + else + { + u8 type, moveAcc, holdEffect, quality; + s8 buff; + u16 calc; + + if (move == 0) + move = gCurrentMove; + + GET_MOVE_TYPE(move, type); + + if (JumpIfMoveAffectedByProtect(move)) + return; + if (AccuracyCalcHelper(move)) + return; + + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + { + u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; + buff = acc; + } + else + { + u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; + buff = acc + 6 - gBattleMons[gBankTarget].statStages[STAT_STAGE_EVASION]; + } + + if (buff < 0) + buff = 0; + if (buff > 0xC) + buff = 0xC; + + moveAcc = gBattleMoves[move].accuracy; + // check Thunder on sunny weather + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER) + moveAcc = 50; + + calc = sAccuracyStageRatios[buff].dividend * moveAcc; + calc /= sAccuracyStageRatios[buff].divisor; + + if (gBattleMons[gBankAttacker].ability == ABILITY_COMPOUND_EYES) + calc = (calc * 130) / 100; // 1.3 compound eyes boost + if (WEATHER_HAS_EFFECT && gBattleMons[gBankTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & WEATHER_SANDSTORM_ANY) + calc = (calc * 80) / 100; // 1.2 sand veil loss + if (gBattleMons[gBankAttacker].ability == ABILITY_HUSTLE && type < 9) + calc = (calc * 80) / 100; // 1.2 hustle loss + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect; + quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_EVASION_UP) + calc = (calc * (100 - quality)) / 100; + + // final calculation + if ((Random() % 100 + 1) > calc) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && + (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) + gBattleCommunication[6] = 2; + else + gBattleCommunication[6] = 0; + + CheckWonderGuardAndLevitate(); + } + JumpIfMoveFailed(7, move); + } +} + +static void atk02_attackstring(void) +{ + if (gBattleExecBuffer) + return; + if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED))) + { + PrepareStringBattle(STRINGID_USEDMOVE, gBankAttacker); + gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; + } + gBattlescriptCurrInstr++; + gBattleCommunication[MSG_DISPLAY] = 0; +} + +static void atk03_ppreduce(void) +{ + s32 ppToDeduct = 1; + + if (gBattleExecBuffer) + return; + + if (!gSpecialStatuses[gBankAttacker].flag20) + { + switch (gBattleMoves[gCurrentMove].target) + { + case MOVE_TARGET_FOES_AND_ALLY: + ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBankAttacker, ABILITY_PRESSURE, 0, 0); + break; + case MOVE_TARGET_BOTH: + case MOVE_TARGET_OPPONENTS_FIELD: + ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_PRESSURE, 0, 0); + break; + default: + if (gBankAttacker != gBankTarget && gBattleMons[gBankTarget].ability == ABILITY_PRESSURE) + ppToDeduct++; + break; + } + } + + if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBankAttacker].pp[gCurrMovePos]) + { + gProtectStructs[gBankAttacker].notFirstStrike = 1; + + if (gBattleMons[gBankAttacker].pp[gCurrMovePos] > ppToDeduct) + gBattleMons[gBankAttacker].pp[gCurrMovePos] -= ppToDeduct; + else + gBattleMons[gBankAttacker].pp[gCurrMovePos] = 0; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) + && !((gDisableStructs[gBankAttacker].unk18_b) & gBitTable[gCurrMovePos])) + { + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBankAttacker].pp[gCurrMovePos]); + MarkBufferBankForExecution(gBankAttacker); + } + } + + gHitMarker &= ~(HITMARKER_NO_PPDEDUCT); + gBattlescriptCurrInstr++; +} + +static void atk04_critcalc(void) +{ + u8 holdEffect; + u16 item, critChance; + + item = gBattleMons[gBankAttacker].item; + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[gBankAttacker].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + gStringBank = gBankAttacker; + + critChance = 2 * ((gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + + (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL) + + (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK) + + (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK) + + (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL) + + (holdEffect == HOLD_EFFECT_SCOPE_LENS) + + 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBankAttacker].species == SPECIES_CHANSEY) + + 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBankAttacker].species == SPECIES_FARFETCHD); + + if (critChance > 4) + critChance = 4; + + if ((gBattleMons[gBankTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBankTarget].ability != ABILITY_SHELL_ARMOR) + && !(gStatuses3[gBankAttacker] & STATUS3_CANT_SCORE_A_CRIT) + && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) + && !(Random() % sCriticalHitChance[critChance])) + gCritMultiplier = 2; + else + gCritMultiplier = 1; + + gBattlescriptCurrInstr++; +} + +static void atk05_damagecalc1(void) +{ + u16 sideStatus = gSideAffecting[GET_BANK_SIDE(gBankTarget)]; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + sideStatus, gDynamicBasePower, + gBattleStruct->dynamicMoveType, gBankAttacker, gBankTarget); + gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; + + if (gStatuses3[gBankAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + gBattleMoveDamage *= 2; + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + + gBattlescriptCurrInstr++; +} + +void AI_CalcDmg(u8 bankAtk, u8 bankDef) +{ + u16 sideStatus = gSideAffecting[GET_BANK_SIDE(bankDef)]; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[bankAtk], &gBattleMons[bankDef], gCurrentMove, + sideStatus, gDynamicBasePower, + gBattleStruct->dynamicMoveType, bankAtk, bankDef); + gDynamicBasePower = 0; + gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; + + if (gStatuses3[bankAtk] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + gBattleMoveDamage *= 2; + if (gProtectStructs[bankAtk].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; +} + +static void ModulateDmgByType(u8 multiplier) +{ + gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; + if (gBattleMoveDamage == 0 && multiplier != 0) + gBattleMoveDamage = 1; + + switch (multiplier) + { + case TYPE_MUL_NO_EFFECT: + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; + break; + case TYPE_MUL_NOT_EFFECTIVE: + if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) + gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; + else + gBattleMoveFlags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + break; + case TYPE_MUL_SUPER_EFFECTIVE: + if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) + gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + else + gBattleMoveFlags |= MOVESTATUS_SUPEREFFECTIVE; + } + break; + } +} + +#define TYPE_FORESIGHT 0xFE +#define TYPE_ENDTABLE 0xFF + +static void atk06_typecalc(void) +{ + s32 i = 0; + u8 moveType; + + if (gCurrentMove == MOVE_STRUGGLE) + { + gBattlescriptCurrInstr++; + return; + } + + GET_MOVE_TYPE(gCurrentMove, moveType); + + // check stab + if (gBattleMons[gBankAttacker].type1 == moveType || gBattleMons[gBankAttacker].type2 == moveType) + { + gBattleMoveDamage = gBattleMoveDamage * 15; + gBattleMoveDamage = gBattleMoveDamage / 10; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + else if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) + ModulateDmgByType(gTypeEffectiveness[i + 2]); + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && + gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2) + ModulateDmgByType(gTypeEffectiveness[i + 2]); + } + i += 3; + } + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 + && (!(gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) || ((gBattleMoveFlags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gProtectStructs[gBankAttacker].targetNotAffected = 1; + + gBattlescriptCurrInstr++; +} + +static void CheckWonderGuardAndLevitate(void) +{ + u8 flags = 0; + s32 i = 0; + u8 moveType; + + if (gCurrentMove == MOVE_STRUGGLE || !gBattleMoves[gCurrentMove].power) + return; + + GET_MOVE_TYPE(gCurrentMove, moveType); + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = ABILITY_LEVITATE; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, ABILITY_LEVITATE); + return; + } + + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + if (gTypeEffectiveness[i] == moveType) + { + // check no effect + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gProtectStructs[gBankAttacker].targetNotAffected = 1; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && + gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 && + gTypeEffectiveness[i + 2] == TYPE_MUL_NO_EFFECT) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gProtectStructs[gBankAttacker].targetNotAffected = 1; + } + + // check super effective + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 20) + flags |= 1; + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == TYPE_MUL_SUPER_EFFECTIVE) + flags |= 1; + + // check not very effective + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 5) + flags |= 2; + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == TYPE_MUL_NOT_EFFECTIVE) + flags |= 2; + } + i += 3; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2) + { + if (((flags & 2) || !(flags & 1)) && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, ABILITY_WONDER_GUARD); + } + } +} + +static void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments +{ + gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; + if (gBattleMoveDamage == 0 && multiplier != 0) + gBattleMoveDamage = 1; + + switch (multiplier) + { + case TYPE_MUL_NO_EFFECT: + *flags |= MOVESTATUS_NOTAFFECTED; + *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + *flags &= ~MOVESTATUS_SUPEREFFECTIVE; + break; + case TYPE_MUL_NOT_EFFECTIVE: + if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) + { + if (*flags & MOVESTATUS_SUPEREFFECTIVE) + *flags &= ~MOVESTATUS_SUPEREFFECTIVE; + else + *flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + break; + case TYPE_MUL_SUPER_EFFECTIVE: + if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) + { + if (*flags & MOVESTATUS_NOTVERYEFFECTIVE) + *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + else + *flags |= MOVESTATUS_SUPEREFFECTIVE; + } + break; + } +} + +u8 TypeCalc(u16 move, u8 bankAtk, u8 bankDef) +{ + s32 i = 0; + u8 flags = 0; + u8 moveType; + + if (move == MOVE_STRUGGLE) + return 0; + + moveType = gBattleMoves[move].type; + + // check stab + if (gBattleMons[bankAtk].type1 == moveType || gBattleMons[bankAtk].type2 == moveType) + { + gBattleMoveDamage = gBattleMoveDamage * 15; + gBattleMoveDamage = gBattleMoveDamage / 10; + } + + if (gBattleMons[bankDef].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + flags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + } + else + { + while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[bankDef].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + + else if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type1) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type2 && + gBattleMons[bankDef].type1 != gBattleMons[bankDef].type2) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + } + i += 3; + } + } + + if (gBattleMons[bankDef].ability == ABILITY_WONDER_GUARD && !(flags & MOVESTATUS_MISSED) + && AttacksThisTurn(bankAtk, move) == 2 + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[move].power) + { + flags |= MOVESTATUS_MISSED; + } + return flags; +} + +u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility) +{ + s32 i = 0; + u8 flags = 0; + u8 type1 = gBaseStats[targetSpecies].type1, type2 = gBaseStats[targetSpecies].type2; + u8 moveType; + + if (move == MOVE_STRUGGLE) + return 0; + + moveType = gBattleMoves[move].type; + + if (targetAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + flags = MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED; + } + else + { + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + i += 3; + continue; + } + if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == type1) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + // check type2 + if (gTypeEffectiveness[i + 1] == type2 && type1 != type2) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + } + i += 3; + } + } + if (targetAbility == ABILITY_WONDER_GUARD + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[move].power) + flags |= MOVESTATUS_NOTAFFECTED; + return flags; +} + +// Multiplies the damage by a random factor between 85% to 100% inclusive +static inline void ApplyRandomDmgMultiplier(void) +{ + u16 rand = Random(); + u16 randPercent = 100 - (rand % 16); + + if (gBattleMoveDamage != 0) + { + gBattleMoveDamage *= randPercent; + gBattleMoveDamage /= 100; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } +} + +static void Unused_ApplyRandomDmgMultiplier(void) +{ + ApplyRandomDmgMultiplier(); +} + +static void atk07_dmg_adjustment(void) +{ + u8 holdEffect, quality; + + ApplyRandomDmgMultiplier(); + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured + && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +static void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for false swipe move effect. +{ + u8 holdEffect, quality; + + ApplyRandomDmgMultiplier(); + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (!gProtectStructs[gBankTarget].endured && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +static void atk09_attackanimation(void) +{ + if (gBattleExecBuffer) + return; + + if ((gHitMarker & HITMARKER_NO_ANIMATIONS) && (gCurrentMove != MOVE_TRANSFORM && gCurrentMove != MOVE_SUBSTITUTE)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_Pausex20; + gBattleScripting.animTurn++; + gBattleScripting.animTargetsHit++; + } + else + { + if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH + || gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY + || gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS) + && gBattleScripting.animTargetsHit) + { + gBattlescriptCurrInstr++; + return; + } + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + u8 multihit; + + gActiveBank = gBankAttacker; + + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + multihit = gMultiHitCounter; + else if (gMultiHitCounter != 0 && gMultiHitCounter != 1) + { + if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) + multihit = 1; + else + multihit = gMultiHitCounter; + } + else + multihit = gMultiHitCounter; + + EmitMoveAnimation(0, gCurrentMove, gBattleScripting.animTurn, gBattleMovePower, gBattleMoveDamage, gBattleMons[gBankAttacker].friendship, &gDisableStructs[gBankAttacker], multihit); + gBattleScripting.animTurn += 1; + gBattleScripting.animTargetsHit += 1; + MarkBufferBankForExecution(gBankAttacker); + gBattlescriptCurrInstr++; + } + else + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_Pausex20; + } + } +} + +static void atk0A_waitanimation(void) +{ + if (gBattleExecBuffer == 0) + gBattlescriptCurrInstr++; +} + +static void atk0B_healthbarupdate(void) +{ + if (gBattleExecBuffer) + return; + + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, gActiveBank); + } + else + { + s16 healthValue; + + s32 currDmg = gBattleMoveDamage; + s32 maxPossibleDmgValue = 10000; // not present in R/S, ensures that huge damage values don't change sign + + if (currDmg <= maxPossibleDmgValue) + healthValue = currDmg; + else + healthValue = maxPossibleDmgValue; + + EmitHealthBarUpdate(0, healthValue); + MarkBufferBankForExecution(gActiveBank); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER && gBattleMoveDamage > 0) + gBattleResults.unk5_0 = 1; + } + } + + gBattlescriptCurrInstr += 2; +} + +static void atk0C_datahpupdate(void) +{ + u32 moveType; + + if (gBattleExecBuffer) + return; + + if (gBattleStruct->dynamicMoveType == 0) + moveType = gBattleMoves[gCurrentMove].type; + else if (!(gBattleStruct->dynamicMoveType & 0x40)) + moveType = gBattleStruct->dynamicMoveType & 0x3F; + else + moveType = gBattleMoves[gCurrentMove].type; + + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + if (gDisableStructs[gActiveBank].substituteHP >= gBattleMoveDamage) + { + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = gBattleMoveDamage; + gDisableStructs[gActiveBank].substituteHP -= gBattleMoveDamage; + gHpDealt = gBattleMoveDamage; + } + else + { + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = gDisableStructs[gActiveBank].substituteHP; + gHpDealt = gDisableStructs[gActiveBank].substituteHP; + gDisableStructs[gActiveBank].substituteHP = 0; + } + // check substitute fading + if (gDisableStructs[gActiveBank].substituteHP == 0) + { + gBattlescriptCurrInstr += 2; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SubstituteFade; + return; + } + } + else + { + gHitMarker &= ~(HITMARKER_IGNORE_SUBSTITUTE); + if (gBattleMoveDamage < 0) // hp goes up + { + gBattleMons[gActiveBank].hp -= gBattleMoveDamage; + if (gBattleMons[gActiveBank].hp > gBattleMons[gActiveBank].maxHP) + gBattleMons[gActiveBank].hp = gBattleMons[gActiveBank].maxHP; + + } + else // hp goes down + { + if (gHitMarker & HITMARKER_x20) + { + gHitMarker &= ~(HITMARKER_x20); + } + else + { + gTakenDmg[gActiveBank] += gBattleMoveDamage; + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + gTakenDmgBanks[gActiveBank] = gBankAttacker; + else + gTakenDmgBanks[gActiveBank] = gBankTarget; + } + + if (gBattleMons[gActiveBank].hp > gBattleMoveDamage) + { + gBattleMons[gActiveBank].hp -= gBattleMoveDamage; + gHpDealt = gBattleMoveDamage; + } + else + { + gHpDealt = gBattleMons[gActiveBank].hp; + gBattleMons[gActiveBank].hp = 0; + } + + if (!gSpecialStatuses[gActiveBank].moveturnLostHP && !(gHitMarker & HITMARKER_x100000)) + gSpecialStatuses[gActiveBank].moveturnLostHP = gHpDealt; + + if (moveType <= 8 && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT) + { + gProtectStructs[gActiveBank].physicalDmg = gHpDealt; + gSpecialStatuses[gActiveBank].moveturnLostHP_physical = gHpDealt; + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + { + gProtectStructs[gActiveBank].physicalBank = gBankAttacker; + gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankAttacker; + } + else + { + gProtectStructs[gActiveBank].physicalBank = gBankTarget; + gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankTarget; + } + } + else if (moveType > 8 && !(gHitMarker & HITMARKER_x100000)) + { + gProtectStructs[gActiveBank].specialDmg = gHpDealt; + gSpecialStatuses[gActiveBank].moveturnLostHP_special = gHpDealt; + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + { + gProtectStructs[gActiveBank].specialBank = gBankAttacker; + gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankAttacker; + } + else + { + gProtectStructs[gActiveBank].specialBank = gBankTarget; + gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankTarget; + } + } + } + gHitMarker &= ~(HITMARKER_x100000); + EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + MarkBufferBankForExecution(gActiveBank); + } + } + else + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = 0xFFFF; + } + gBattlescriptCurrInstr += 2; +} + +static void atk0D_critmessage(void) +{ + if (gBattleExecBuffer == 0) + { + if (gCritMultiplier == 2 && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + PrepareStringBattle(STRINGID_CRITICALHIT, gBankAttacker); + gBattleCommunication[MSG_DISPLAY] = 1; + } + gBattlescriptCurrInstr++; + } +} + +static void atk0E_effectiveness_sound(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = gBankTarget; + if (!(gBattleMoveFlags & MOVESTATUS_MISSED)) + { + switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) + { + case MOVESTATUS_SUPEREFFECTIVE: + EmitEffectivenessSound(0, SE_KOUKA_H); + MarkBufferBankForExecution(gActiveBank); + break; + case MOVESTATUS_NOTVERYEFFECTIVE: + EmitEffectivenessSound(0, SE_KOUKA_L); + MarkBufferBankForExecution(gActiveBank); + break; + case MOVESTATUS_NOTAFFECTED: + case MOVESTATUS_FAILED: + // no sound + break; + case MOVESTATUS_ENDURED: + case MOVESTATUS_ONEHITKO: + case MOVESTATUS_HUNGON: + default: + if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) + { + EmitEffectivenessSound(0, SE_KOUKA_H); + MarkBufferBankForExecution(gActiveBank); + } + else if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) + { + EmitEffectivenessSound(0, SE_KOUKA_L); + MarkBufferBankForExecution(gActiveBank); + } + else if (!(gBattleMoveFlags & (MOVESTATUS_NOTAFFECTED | MOVESTATUS_FAILED))) + { + EmitEffectivenessSound(0, SE_KOUKA_M); + MarkBufferBankForExecution(gActiveBank); + } + break; + } + } + gBattlescriptCurrInstr++; +} + +static void atk0F_resultmessage(void) +{ + u32 stringId = 0; + + if (gBattleExecBuffer) + return; + + if (gBattleMoveFlags & MOVESTATUS_MISSED && (!(gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) || gBattleCommunication[6] > 2)) + { + stringId = gMissStringIds[gBattleCommunication[6]]; + gBattleCommunication[MSG_DISPLAY] = 1; + } + else + { + gBattleCommunication[MSG_DISPLAY] = 1; + switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) + { + case MOVESTATUS_SUPEREFFECTIVE: + stringId = STRINGID_SUPEREFFECTIVE; + break; + case MOVESTATUS_NOTVERYEFFECTIVE: + stringId = STRINGID_NOTVERYEFFECTIVE; + break; + case MOVESTATUS_ONEHITKO: + stringId = STRINGID_ONEHITKO; + break; + case MOVESTATUS_ENDURED: + stringId = STRINGID_PKMNENDUREDHIT; + break; + case MOVESTATUS_FAILED: + stringId = STRINGID_BUTITFAILED; + break; + case MOVESTATUS_NOTAFFECTED: + stringId = STRINGID_ITDOESNTAFFECT; + break; + case MOVESTATUS_HUNGON: + gLastUsedItem = gBattleMons[gBankTarget].item; + gStringBank = gBankTarget; + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_HangedOnMsg; + return; + default: + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + { + stringId = STRINGID_ITDOESNTAFFECT; + } + else if (gBattleMoveFlags & MOVESTATUS_ONEHITKO) + { + gBattleMoveFlags &= ~(MOVESTATUS_ONEHITKO); + gBattleMoveFlags &= ~(MOVESTATUS_SUPEREFFECTIVE); + gBattleMoveFlags &= ~(MOVESTATUS_NOTVERYEFFECTIVE); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_OneHitKOMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_ENDURED) + { + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_EnduredMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_HUNGON) + { + gLastUsedItem = gBattleMons[gBankTarget].item; + gStringBank = gBankTarget; + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_HangedOnMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_FAILED) + { + stringId = STRINGID_BUTITFAILED; + } + else + { + gBattleCommunication[MSG_DISPLAY] = 0; + } + } + } + + if (stringId) + PrepareStringBattle(stringId, gBankAttacker); + + gBattlescriptCurrInstr++; +} + +static void atk10_printstring(void) +{ + if (gBattleExecBuffer == 0) + { + u16 var = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + PrepareStringBattle(var, gBankAttacker); + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +static void atk11_printstring_playeronly(void) +{ + gActiveBank = gBankAttacker; + + EmitPrintStringPlayerOnly(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 1; +} + +static void atk12_waitmessage(void) +{ + if (gBattleExecBuffer == 0) + { + if (!gBattleCommunication[MSG_DISPLAY]) + { + gBattlescriptCurrInstr += 3; + } + else + { + u16 toWait = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + if (++gPauseCounterBattle >= toWait) + { + gPauseCounterBattle = 0; + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 0; + } + } + } +} + +static void atk13_printfromtable(void) +{ + if (gBattleExecBuffer == 0) + { + const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + ptr += gBattleCommunication[MULTISTRING_CHOOSER]; + + PrepareStringBattle(*ptr, gBankAttacker); + + gBattlescriptCurrInstr += 5; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +static void atk14_printfromtable_playeronly(void) +{ + if (gBattleExecBuffer == 0) + { + const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + ptr += gBattleCommunication[MULTISTRING_CHOOSER]; + + gActiveBank = gBankAttacker; + EmitPrintStringPlayerOnly(0, *ptr); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 5; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +u8 BankGetTurnOrder(u8 bank) +{ + s32 i; + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBanksByTurnOrder[i] == bank) + break; + } + return i; +} + +#define INCREMENT_RESET_RETURN \ +{ \ + gBattlescriptCurrInstr++; \ + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ + return; \ +} + +#define RESET_RETURN \ +{ \ + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ + return; \ +} + +void SetMoveEffect(bool8 primary, u8 certain) +{ + bool32 statusChanged = FALSE; + u8 affectsUser = 0; // 0x40 otherwise + bool32 noSunCanFreeze = TRUE; + + if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_AFFECTS_USER) + { + gEffectBank = gBankAttacker; // bank that effects get applied on + gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_AFFECTS_USER); + affectsUser = MOVE_EFFECT_AFFECTS_USER; + gBattleScripting.bank = gBankTarget; // theoretically the attacker + } + else + { + gEffectBank = gBankTarget; + gBattleScripting.bank = gBankAttacker; + } + + if (gBattleMons[gEffectBank].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9) + INCREMENT_RESET_RETURN + + if (gSideAffecting[GET_BANK_SIDE(gEffectBank)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7) + INCREMENT_RESET_RETURN + + if (gBattleMons[gEffectBank].hp == 0 + && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY + && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM) + INCREMENT_RESET_RETURN + + if (gBattleMons[gEffectBank].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER) + INCREMENT_RESET_RETURN + + if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change + { + switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + case STATUS_SLEEP: + // check active uproar + if (gBattleMons[gEffectBank].ability != ABILITY_SOUNDPROOF) + { + for (gActiveBank = 0; + gActiveBank < gNoOfAllBanks && !(gBattleMons[gActiveBank].status2 & STATUS2_UPROAR); + gActiveBank++) + {} + } + else + gActiveBank = gNoOfAllBanks; + + if (gBattleMons[gEffectBank].status1) + break; + if (gActiveBank != gNoOfAllBanks) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_VITAL_SPIRIT) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_INSOMNIA) + break; + + CancelMultiTurnMoves(gEffectBank); + statusChanged = TRUE; + break; + case STATUS_POISON: + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + gLastUsedAbility = ABILITY_IMMUNITY; + RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON + || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].type1 == TYPE_POISON) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_POISON) + break; + if (gBattleMons[gEffectBank].type1 == TYPE_STEEL) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_STEEL) + break; + if (gBattleMons[gEffectBank].status1) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) + break; + + statusChanged = TRUE; + break; + case STATUS_BURN: + if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + gLastUsedAbility = ABILITY_WATER_VEIL; + RecordAbilityBattle(gEffectBank, ABILITY_WATER_VEIL); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BRNPrevention; + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_FIRE + || gBattleMons[gEffectBank].type2 == TYPE_FIRE) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BRNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].type1 == TYPE_FIRE) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_FIRE) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL) + break; + if (gBattleMons[gEffectBank].status1) + break; + + statusChanged = TRUE; + break; + case STATUS_FREEZE: + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) + noSunCanFreeze = FALSE; + if (gBattleMons[gEffectBank].type1 == TYPE_ICE) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_ICE) + break; + if (gBattleMons[gEffectBank].status1) + break; + if (noSunCanFreeze == 0) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_MAGMA_ARMOR) + break; + + CancelMultiTurnMoves(gEffectBank); + statusChanged = TRUE; + break; + case STATUS_PARALYSIS: + if (gBattleMons[gEffectBank].ability == ABILITY_LIMBER) + { + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) + { + gLastUsedAbility = ABILITY_LIMBER; + RecordAbilityBattle(gEffectBank, ABILITY_LIMBER); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PRLZPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + else + break; + } + if (gBattleMons[gEffectBank].status1) + break; + + statusChanged = TRUE; + break; + case STATUS_TOXIC_POISON: + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + gLastUsedAbility = ABILITY_IMMUNITY; + RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON + || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].status1) + break; + if (gBattleMons[gEffectBank].type1 != TYPE_POISON + && gBattleMons[gEffectBank].type2 != TYPE_POISON + && gBattleMons[gEffectBank].type1 != TYPE_STEEL + && gBattleMons[gEffectBank].type2 != TYPE_STEEL) + { + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) + break; + + // It's redundant, because at this point we know the status1 value is 0. + gBattleMons[gEffectBank].status1 &= ~(STATUS_TOXIC_POISON); + gBattleMons[gEffectBank].status1 &= ~(STATUS_POISON); + statusChanged = TRUE; + break; + } + else + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + } + break; + } + if (statusChanged == TRUE) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + + if (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) + gBattleMons[gEffectBank].status1 |= ((Random() & 3) + 2); + else + gBattleMons[gEffectBank].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + gActiveBank = gEffectBank; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); + MarkBufferBankForExecution(gActiveBank); + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + // for synchronize + + if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_POISON + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_TOXIC + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_PARALYSIS + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) + { + u8* synchronizeEffect = &gBattleStruct->synchronizeMoveEffect; + *synchronizeEffect = gBattleCommunication[MOVE_EFFECT_BYTE]; + gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; + } + return; + } + else if (statusChanged == FALSE) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattlescriptCurrInstr++; + return; + } + return; + } + else + { + if (gBattleMons[gEffectBank].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + gBattlescriptCurrInstr++; + } + else + { + u8 side; + switch (gBattleCommunication[MOVE_EFFECT_BYTE]) + { + case MOVE_EFFECT_CONFUSION: + if (gBattleMons[gEffectBank].ability == ABILITY_OWN_TEMPO + || gBattleMons[gEffectBank].status2 & STATUS2_CONFUSION) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + } + break; + case MOVE_EFFECT_FLINCH: + if (gBattleMons[gEffectBank].ability == ABILITY_INNER_FOCUS) + { + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) + { + gLastUsedAbility = ABILITY_INNER_FOCUS; + RecordAbilityBattle(gEffectBank, ABILITY_INNER_FOCUS); + gBattlescriptCurrInstr = BattleScript_FlinchPrevention; + } + else + { + gBattlescriptCurrInstr++; + } + } + else + { + if (BankGetTurnOrder(gEffectBank) > gCurrentTurnActionNumber) + gBattleMons[gEffectBank].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr++; + } + break; + case MOVE_EFFECT_UPROAR: + if (!(gBattleMons[gEffectBank].status2 & STATUS2_UPROAR)) + { + + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 4; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + } + else + { + gBattlescriptCurrInstr++; + } + break; + case MOVE_EFFECT_PAYDAY: + if (GET_BANK_SIDE(gBankAttacker) == SIDE_PLAYER) + { + u16 PayDay = gPaydayMoney; + gPaydayMoney += (gBattleMons[gBankAttacker].level * 5); + if (PayDay > gPaydayMoney) + gPaydayMoney = 0xFFFF; + } + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_TRI_ATTACK: + if (gBattleMons[gEffectBank].status1) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3; + SetMoveEffect(FALSE, 0); + } + break; + case MOVE_EFFECT_CHARGING: + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gProtectStructs[gEffectBank].chargingTurn = 1; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_WRAP: + if (gBattleMons[gEffectBank].status2 & STATUS2_WRAPPED) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 3) << 0xD; + + *(gBattleStruct->wrappedMove + gEffectBank * 2 + 0) = gCurrentMove; + *(gBattleStruct->wrappedMove + gEffectBank * 2 + 1) = gCurrentMove >> 8; + *(gBattleStruct->wrappedBy + gEffectBank) = gBankAttacker; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) + { + if (gBattleCommunication[MULTISTRING_CHOOSER] > 4) + break; + if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) + break; + } + } + break; + case MOVE_EFFECT_RECOIL_25: // 25% recoil + gBattleMoveDamage = (gHpDealt) / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_ATK_PLUS_1: + case MOVE_EFFECT_DEF_PLUS_1: + case MOVE_EFFECT_SPD_PLUS_1: + case MOVE_EFFECT_SP_ATK_PLUS_1: + case MOVE_EFFECT_SP_DEF_PLUS_1: + case MOVE_EFFECT_ACC_PLUS_1: + case MOVE_EFFECT_EVS_PLUS_1: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_1 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + break; + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_EVS_MINUS_1: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_1 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatDown; + } + break; + case MOVE_EFFECT_ATK_PLUS_2: + case MOVE_EFFECT_DEF_PLUS_2: + case MOVE_EFFECT_SPD_PLUS_2: + case MOVE_EFFECT_SP_ATK_PLUS_2: + case MOVE_EFFECT_SP_DEF_PLUS_2: + case MOVE_EFFECT_ACC_PLUS_2: + case MOVE_EFFECT_EVS_PLUS_2: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_2 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + break; + case MOVE_EFFECT_ATK_MINUS_2: + case MOVE_EFFECT_DEF_MINUS_2: + case MOVE_EFFECT_SPD_MINUS_2: + case MOVE_EFFECT_SP_ATK_MINUS_2: + case MOVE_EFFECT_SP_DEF_MINUS_2: + case MOVE_EFFECT_ACC_MINUS_2: + case MOVE_EFFECT_EVS_MINUS_2: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_2 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatDown; + } + break; + case MOVE_EFFECT_RECHARGE: + gBattleMons[gEffectBank].status2 |= STATUS2_RECHARGE; + gDisableStructs[gEffectBank].rechargeCounter = 2; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_RAGE: + gBattleMons[gBankAttacker].status2 |= STATUS2_RAGE; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_STEAL_ITEM: + { + if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + gBattlescriptCurrInstr++; + break; + } + + side = GetBankSide(gBankAttacker); + if (GetBankSide(gBankAttacker) == SIDE_OPPONENT + && !(gBattleTypeFlags & + (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE))) + { + gBattlescriptCurrInstr++; + } + else if (!(gBattleTypeFlags & + (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE)) + && (gWishFutureKnock.knockedOffPokes[side] & gBitTable[gBattlePartyID[gBankAttacker]])) + { + gBattlescriptCurrInstr++; + } + else if (gBattleMons[gBankTarget].item + && gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_NoItemSteal; + + gLastUsedAbility = gBattleMons[gBankTarget].ability; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else if (gBattleMons[gBankAttacker].item != 0 + || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY + || IS_ITEM_MAIL(gBattleMons[gBankTarget].item) + || gBattleMons[gBankTarget].item == 0) + { + gBattlescriptCurrInstr++; + } + else + { + u16* changedItem = &gBattleStruct->changedItems[gBankAttacker]; + gLastUsedItem = *changedItem = gBattleMons[gBankTarget].item; + gBattleMons[gBankTarget].item = 0; + + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); + MarkBufferBankForExecution(gBankAttacker); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_ItemSteal; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + } + + } + break; + case MOVE_EFFECT_PREVENT_ESCAPE: + gBattleMons[gBankTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gDisableStructs[gBankTarget].bankPreventingEscape = gBankAttacker; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_NIGHTMARE: + gBattleMons[gBankTarget].status2 |= STATUS2_NIGHTMARE; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_ALL_STATS_UP: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AllStatsUp; + break; + case MOVE_EFFECT_RAPIDSPIN: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_RapidSpinAway; + break; + case MOVE_EFFECT_REMOVE_PARALYSIS: // Smelling salts + if (!(gBattleMons[gBankTarget].status1 & STATUS_PARALYSIS)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gBankTarget].status1 &= ~(STATUS_PARALYSIS); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; + } + break; + case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AtkDefDown; + break; + case MOVE_EFFECT_RECOIL_33_PARALYSIS: // Volt Tackle + gBattleMoveDamage = gHpDealt / 3; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_THRASH: + if (gBattleMons[gEffectBank].status2 & STATUS2_LOCK_CONFUSE) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattleMons[gEffectBank].status2 |= (((Random() & 1) + 2) << 0xA); + } + break; + case MOVE_EFFECT_KNOCK_OFF: + if (gBattleMons[gEffectBank].ability == ABILITY_STICKY_HOLD) + { + if (gBattleMons[gEffectBank].item == 0) + { + gBattlescriptCurrInstr++; + } + else + { + gLastUsedAbility = ABILITY_STICKY_HOLD; + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; + RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD); + } + break; + } + if (gBattleMons[gEffectBank].item) + { + side = GetBankSide(gEffectBank); + + gLastUsedItem = gBattleMons[gEffectBank].item; + gBattleMons[gEffectBank].item = 0; + gWishFutureKnock.knockedOffPokes[side] |= gBitTable[gBattlePartyID[gEffectBank]]; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_KnockedOff; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 1) = 0; + } + else + { + gBattlescriptCurrInstr++; + } + break; + case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_SAtkDown2; + break; + } + } + } + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; +} + +static void atk15_seteffectwithchance(void) +{ + u32 percentChance; + + if (gBattleMons[gBankAttacker].ability == ABILITY_SERENE_GRACE) + percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance * 2; + else + percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance; + + if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_CERTAIN + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_CERTAIN); + SetMoveEffect(0, MOVE_EFFECT_CERTAIN); + } + else if (Random() % 100 < percentChance + && gBattleCommunication[MOVE_EFFECT_BYTE] + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (percentChance >= 100) + SetMoveEffect(0, MOVE_EFFECT_CERTAIN); + else + SetMoveEffect(0, 0); + } + else + { + gBattlescriptCurrInstr++; + } + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleScripting.field_16 = 0; +} + +static void atk16_seteffectprimary(void) +{ + SetMoveEffect(TRUE, 0); +} + +static void atk17_seteffectsecondary(void) +{ + SetMoveEffect(FALSE, 0); +} + +static void atk18_status_effect_clear(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) + gBattleMons[gActiveBank].status1 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + else + gBattleMons[gActiveBank].status2 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattlescriptCurrInstr += 2; + gBattleScripting.field_16 = 0; +} + +static void atk19_faint_pokemon(void) +{ + const u8 *BS_ptr; + + if (gBattlescriptCurrInstr[2] != 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + { + BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); + + BattleScriptPop(); + gBattlescriptCurrInstr = BS_ptr; + gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); + } + else + { + gBattlescriptCurrInstr += 7; + } + } + else + { + u8 bank; + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) + { + gActiveBank = gBankAttacker; + bank = gBankTarget; + BS_ptr = BattleScript_FaintAttacker; + } + else + { + gActiveBank = gBankTarget; + bank = gBankAttacker; + BS_ptr = BattleScript_FaintTarget; + } + if (!(gAbsentBankFlags & gBitTable[gActiveBank]) + && gBattleMons[gActiveBank].hp == 0) + { + gHitMarker |= HITMARKER_FAINTED(gActiveBank); + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BS_ptr; + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + gHitMarker |= HITMARKER_x400000; + if (gBattleResults.playerFaintCounter < 0xFF) + gBattleResults.playerFaintCounter++; + AdjustFriendshipOnBattleFaint(gActiveBank); + } + else + { + if (gBattleResults.opponentFaintCounter < 0xFF) + gBattleResults.opponentFaintCounter++; + gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); + } + if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBankAttacker].hp != 0) + { + gHitMarker &= ~(HITMARKER_DESTINYBOND); + BattleScriptPush(gBattlescriptCurrInstr); + gBattleMoveDamage = gBattleMons[bank].hp; + gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; + } + if ((gStatuses3[gBankTarget] & STATUS3_GRUDGE) + && !(gHitMarker & HITMARKER_GRUDGE) + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) + && gBattleMons[gBankAttacker].hp != 0 + && gCurrentMove != MOVE_STRUGGLE) + { + u8 moveIndex = *(gBattleStruct->chosenMovePositions + gBankAttacker); + + gBattleMons[gBankAttacker].pp[moveIndex] = 0; + BattleScriptPush(gBattlescriptCurrInstr); + gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; + gActiveBank = gBankAttacker; + EmitSetMonData(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); + MarkBufferBankForExecution(gActiveBank); + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].moves[moveIndex]) + } + } + else + { + gBattlescriptCurrInstr += 7; + } + } +} + +static void atk1A_faint_animation(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitFaintAnimation(0); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } +} + +static void atk1B_faint_effects_clear(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBank].hp == 0) + { + gBattleMons[gActiveBank].status1 = 0; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + + FaintClearSetData(); // Effects like attractions, trapping, etc. + gBattlescriptCurrInstr += 2; + } +} + +static void atk1C_jumpifstatus(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (gBattleMons[bank].status1 & flags && gBattleMons[bank].hp) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 10; +} + +static void atk1D_jumpifstatus2(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (gBattleMons[bank].status2 & flags && gBattleMons[bank].hp) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 10; +} + +static void atk1E_jumpifability(void) +{ + u8 bank; + u8 ability = gBattlescriptCurrInstr[2]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER_SIDE) + { + bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_BANK_SIDE, gBankAttacker, ability, 0, 0); + if (bank) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank - 1, gLastUsedAbility); + gBattleScripting.field_15 = bank - 1; + } + else + gBattlescriptCurrInstr += 7; + } + else if (gBattlescriptCurrInstr[1] == BS_GET_NOT_ATTACKER_SIDE) + { + bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBankAttacker, ability, 0, 0); + if (bank) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank - 1, gLastUsedAbility); + gBattleScripting.field_15 = bank - 1; + } + else + gBattlescriptCurrInstr += 7; + } + else + { + bank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gBattleMons[bank].ability == ability) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank, gLastUsedAbility); + gBattleScripting.field_15 = bank; + } + else + gBattlescriptCurrInstr += 7; + } +} + +static void atk1F_jumpifsideaffecting(void) +{ + u8 side; + u16 flags; + const u8* jumpPtr; + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) + side = GET_BANK_SIDE(gBankAttacker); + else + side = GET_BANK_SIDE(gBankTarget); + + flags = BS2ScriptRead16(gBattlescriptCurrInstr + 2); + jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 4); + + if (gSideAffecting[side] & flags) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 8; +} + +static void atk20_jumpifstat(void) +{ + u8 ret = 0; + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u8 value = gBattleMons[bank].statStages[gBattlescriptCurrInstr[3]]; + + switch (gBattlescriptCurrInstr[2]) + { + case CMP_EQUAL: + if (value == gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_NOT_EQUAL: + if (value != gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_GREATER_THAN: + if (value > gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_LESS_THAN: + if (value < gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_COMMON_BITS: + if (value & gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_NO_COMMON_BITS: + if (!(value & gBattlescriptCurrInstr[4])) + ret++; + break; + } + + if (ret) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + else + gBattlescriptCurrInstr += 9; +} + +static void atk21_jumpifstatus3(void) +{ + u32 flags; + const u8* jumpPtr; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); + + if (gBattlescriptCurrInstr[6]) + { + if ((gStatuses3[gActiveBank] & flags) != 0) + gBattlescriptCurrInstr += 11; + else + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if ((gStatuses3[gActiveBank] & flags) != 0) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 11; + } +} + +static void atk22_jumpiftype(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u8 type = gBattlescriptCurrInstr[2]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattleMons[bank].type1 == type || gBattleMons[bank].type2 == type) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 7; +} + +static void atk23_getexp(void) +{ + u16 item; + s32 i; // also used as stringId + u8 holdEffect; + s32 sentIn; + + s32 viaExpShare = 0; + u16* exp = &gBattleStruct->expValue; + + gBank1 = GetBattleBank(gBattlescriptCurrInstr[1]); + sentIn = gSentPokesToOpponent[(gBank1 & 2) >> 1]; + + switch (gBattleScripting.atk23_state) + { + case 0: // check if should receive exp at all + if (GetBankSide(gBank1) != SIDE_OPPONENT || (gBattleTypeFlags & + (BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000 + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER))) + { + gBattleScripting.atk23_state = 6; // goto last case + } + else + { + gBattleScripting.atk23_state++; + gBattleStruct->field_DF |= gBitTable[gBattlePartyID[gBank1]]; + } + break; + case 1: // calculate experience points to redistribute + { + u16 calculatedExp; + s32 viaSentIn; + + for (viaSentIn = 0, i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) + continue; + if (gBitTable[i] & sentIn) + viaSentIn++; + + item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + if (holdEffect == HOLD_EFFECT_EXP_SHARE) + viaExpShare++; + } + + calculatedExp = gBaseStats[gBattleMons[gBank1].species].expYield * gBattleMons[gBank1].level / 7; + + if (viaExpShare) // at least one mon is getting exp via exp share + { + *exp = calculatedExp / 2 / viaSentIn; + if (*exp == 0) + *exp = 1; + + gExpShareExp = calculatedExp / 2 / viaExpShare; + if (gExpShareExp == 0) + gExpShareExp = 1; + } + else + { + *exp = calculatedExp / viaSentIn; + if (*exp == 0) + *exp = 1; + gExpShareExp = 0; + } + + gBattleScripting.atk23_state++; + gBattleStruct->expGetterId = 0; + gBattleStruct->sentInPokes = sentIn; + } + // fall through + case 2: // set exp value to the poke in expgetter_id and print message + if (gBattleExecBuffer == 0) + { + item = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HELD_ITEM); + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1)) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.atk23_state = 5; + gBattleMoveDamage = 0; // used for exp + } + else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) == MAX_MON_LEVEL) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.atk23_state = 5; + gBattleMoveDamage = 0; // used for exp + } + else + { + // music change in wild battle after fainting a poke + if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) + { + BattleMusicStop(); + PlayBGM(0x161); + gBattleStruct->wildVictorySong++; + } + + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP)) + { + if (gBattleStruct->sentInPokes & 1) + gBattleMoveDamage = *exp; + else + gBattleMoveDamage = 0; + + if (holdEffect == HOLD_EFFECT_EXP_SHARE) + gBattleMoveDamage += gExpShareExp; + if (holdEffect == HOLD_EFFECT_LUCKY_EGG) + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + + if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterId])) + { + // check if the pokemon doesn't belong to the player + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterId >= 3) + { + i = 0x149; + } + else + { + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + i = 0x14A; + } + } + else + { + i = 0x149; + } + + // get exp getter bank + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (!(gBattlePartyID[2] != gBattleStruct->expGetterId) && !(gAbsentBankFlags & gBitTable[2])) + gBattleStruct->expGetterBank = 2; + else + { + if (!(gAbsentBankFlags & gBitTable[0])) + gBattleStruct->expGetterBank = 0; + else + gBattleStruct->expGetterBank = 2; + } + } + else + gBattleStruct->expGetterBank = 0; + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBank, gBattleStruct->expGetterId) + + // buffer 'gained' or 'gained a boosted' + PREPARE_STRING_BUFFER(gBattleTextBuff2, i) + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage) + + PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBank); + MonGainEVs(&gPlayerParty[gBattleStruct->expGetterId], gBattleMons[gBank1].species); + } + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.atk23_state++; + } + } + break; + case 3: // Set stats and give exp + if (gBattleExecBuffer == 0) + { + gBattleBufferB[gBattleStruct->expGetterBank][0] = 0; + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) != MAX_MON_LEVEL) + { + BATTLE_LVLUP_STATS->hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + BATTLE_LVLUP_STATS->atk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + BATTLE_LVLUP_STATS->def = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + BATTLE_LVLUP_STATS->spd = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED); + BATTLE_LVLUP_STATS->spAtk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + BATTLE_LVLUP_STATS->spDef = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); + + gActiveBank = gBattleStruct->expGetterBank; + EmitExpUpdate(0, gBattleStruct->expGetterId, gBattleMoveDamage); + MarkBufferBankForExecution(gActiveBank); + } + gBattleScripting.atk23_state++; + } + break; + case 4: // lvl up if necessary + if (gBattleExecBuffer == 0) + { + gActiveBank = gBattleStruct->expGetterBank; + if (gBattleBufferB[gActiveBank][0] == 0x21 && gBattleBufferB[gActiveBank][1] == 0xB) + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId) + sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank); + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBank, gBattleStruct->expGetterId) + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL)) + + BattleScriptPushCursor(); + gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterId]; + gBattlescriptCurrInstr = BattleScript_LevelUp; + gBattleMoveDamage = (gBattleBufferB[gActiveBank][2] | (gBattleBufferB[gActiveBank][3] << 8)); + AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterId], 0); + + // update battle mon structure after level up + if (gBattlePartyID[0] == gBattleStruct->expGetterId && gBattleMons[0].hp) + { + gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); + gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + // Why is this duplicated? + gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED); + gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED); + + gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); + } + // What is else if? + if (gBattlePartyID[2] == gBattleStruct->expGetterId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); + gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + // Duplicated again, but this time there's no Sp Defense + gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED); + gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED); + + gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + } + gBattleScripting.atk23_state = 5; + } + else + { + gBattleMoveDamage = 0; + gBattleScripting.atk23_state = 5; + } + } + break; + case 5: // looper increment + if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp + gBattleScripting.atk23_state = 3; + else + { + gBattleStruct->expGetterId++; + if (gBattleStruct->expGetterId <= 5) + gBattleScripting.atk23_state = 2; // loop again + else + gBattleScripting.atk23_state = 6; // we're done + } + break; + case 6: // increment instruction + if (gBattleExecBuffer == 0) + { + // not sure why gf clears the item and ability here + gBattleMons[gBank1].item = 0; + gBattleMons[gBank1].ability = 0; + gBattlescriptCurrInstr += 2; + } + break; + } +} + +#ifdef NONMATCHING +static void atk24(void) +{ + u16 HP_count = 0; + s32 i; + + if (gBattleExecBuffer) + return; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId == STEVEN_PARTNER_ID) + { + for (i = 0; i < 3; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); + } + } + else + { + for (i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) + && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A0 & gBitTable[i]))) + { + HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); + } + } + } + + if (HP_count == 0) + gBattleOutcome |= BATTLE_LOST; + + for (HP_count = 0, i = 0; i < 6; i++) + { + if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES) && !GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG) + && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A1 & gBitTable[i]))) + { + HP_count += GetMonData(&gEnemyParty[i], MON_DATA_HP); + } + } + + if (HP_count == 0) + gBattleOutcome |= BATTLE_WON; + + if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) + { + s32 foundPlayer; + s32 foundOpponent; + + // Impossible to decompile loops. + for (foundPlayer = 0, i = 0; i < gNoOfAllBanks; i += 2) + { + if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) + foundPlayer++; + } + + for (foundOpponent = 0, i = 1; i < gNoOfAllBanks; i += 2) + { + if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) + foundOpponent++; + } + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (foundOpponent + foundPlayer > 1) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + } + else + { + if (foundOpponent != 0 && foundPlayer != 0) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + } + } + else + { + gBattlescriptCurrInstr += 5; + } +} +#else +__attribute__((naked)) +static void atk24(void) +{ + asm("\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + movs r6, 0\n\ + ldr r0, =gBattleExecBuffer\n\ + ldr r0, [r0]\n\ + cmp r0, 0\n\ + beq _0804ACE2\n\ + b _0804AF22\n\ + _0804ACE2:\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 15\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AD48\n\ + ldr r0, =gPartnerTrainerId\n\ + ldrh r1, [r0]\n\ + ldr r0, =0x00000c03\n\ + cmp r1, r0\n\ + bne _0804AD48\n\ + movs r5, 0\n\ + _0804ACFC:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gPlayerParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804AD2C\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804AD2C\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804AD2C:\n\ + adds r5, 0x1\n\ + cmp r5, 0x2\n\ + ble _0804ACFC\n\ + b _0804ADA8\n\ + .pool\n\ + _0804AD48:\n\ + movs r5, 0\n\ + _0804AD4A:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gPlayerParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804ADA2\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804ADA2\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 11\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AD94\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + movs r1, 0xA8\n\ + lsls r1, 2\n\ + adds r0, r1\n\ + ldrb r1, [r0]\n\ + ldr r2, =gBitTable\n\ + lsls r0, r5, 2\n\ + adds r0, r2\n\ + ldr r0, [r0]\n\ + ands r1, r0\n\ + cmp r1, 0\n\ + bne _0804ADA2\n\ + _0804AD94:\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804ADA2:\n\ + adds r5, 0x1\n\ + cmp r5, 0x5\n\ + ble _0804AD4A\n\ + _0804ADA8:\n\ + cmp r6, 0\n\ + bne _0804ADB6\n\ + ldr r0, =gBattleOutcome\n\ + ldrb r1, [r0]\n\ + movs r2, 0x2\n\ + orrs r1, r2\n\ + strb r1, [r0]\n\ + _0804ADB6:\n\ + movs r6, 0\n\ + movs r5, 0\n\ + _0804ADBA:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gEnemyParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804AE10\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804AE10\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 11\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AE02\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + ldr r1, =0x000002a1\n\ + adds r0, r1\n\ + ldrb r1, [r0]\n\ + ldr r2, =gBitTable\n\ + lsls r0, r5, 2\n\ + adds r0, r2\n\ + ldr r0, [r0]\n\ + ands r1, r0\n\ + cmp r1, 0\n\ + bne _0804AE10\n\ + _0804AE02:\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804AE10:\n\ + adds r5, 0x1\n\ + cmp r5, 0x5\n\ + ble _0804ADBA\n\ + ldr r2, =gBattleOutcome\n\ + cmp r6, 0\n\ + bne _0804AE24\n\ + ldrb r0, [r2]\n\ + movs r1, 0x1\n\ + orrs r0, r1\n\ + strb r0, [r2]\n\ + _0804AE24:\n\ + ldrb r0, [r2]\n\ + cmp r0, 0\n\ + bne _0804AF1A\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r1, [r0]\n\ + ldr r2, =0x02000002\n\ + ands r1, r2\n\ + mov r8, r0\n\ + cmp r1, 0\n\ + beq _0804AF1A\n\ + movs r3, 0\n\ + movs r5, 0\n\ + ldr r0, =gNoOfAllBanks\n\ + ldrb r1, [r0]\n\ + mov r12, r0\n\ + ldr r7, =gBattlescriptCurrInstr\n\ + cmp r3, r1\n\ + bge _0804AE70\n\ + ldr r0, =gHitMarker\n\ + movs r6, 0x80\n\ + lsls r6, 21\n\ + ldr r4, [r0]\n\ + adds r2, r1, 0\n\ + ldr r1, =gSpecialStatuses\n\ + _0804AE54:\n\ + adds r0, r6, 0\n\ + lsls r0, r5\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _0804AE68\n\ + ldrb r0, [r1]\n\ + lsls r0, 25\n\ + cmp r0, 0\n\ + blt _0804AE68\n\ + adds r3, 0x1\n\ + _0804AE68:\n\ + adds r1, 0x28\n\ + adds r5, 0x2\n\ + cmp r5, r2\n\ + blt _0804AE54\n\ + _0804AE70:\n\ + movs r2, 0\n\ + movs r5, 0x1\n\ + mov r4, r12\n\ + ldrb r1, [r4]\n\ + cmp r5, r1\n\ + bge _0804AEAA\n\ + ldr r0, =gHitMarker\n\ + movs r4, 0x80\n\ + lsls r4, 21\n\ + mov r12, r4\n\ + ldr r6, [r0]\n\ + ldr r0, =gSpecialStatuses\n\ + adds r4, r1, 0\n\ + adds r1, r0, 0\n\ + adds r1, 0x14\n\ + _0804AE8E:\n\ + mov r0, r12\n\ + lsls r0, r5\n\ + ands r0, r6\n\ + cmp r0, 0\n\ + beq _0804AEA2\n\ + ldrb r0, [r1]\n\ + lsls r0, 25\n\ + cmp r0, 0\n\ + blt _0804AEA2\n\ + adds r2, 0x1\n\ + _0804AEA2:\n\ + adds r1, 0x28\n\ + adds r5, 0x2\n\ + cmp r5, r4\n\ + blt _0804AE8E\n\ + _0804AEAA:\n\ + mov r1, r8\n\ + ldr r0, [r1]\n\ + movs r1, 0x40\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AEF0\n\ + adds r0, r2, r3\n\ + cmp r0, 0x1\n\ + bgt _0804AEF8\n\ + b _0804AF12\n\ + .pool\n\ + _0804AEF0:\n\ + cmp r2, 0\n\ + beq _0804AF12\n\ + cmp r3, 0\n\ + beq _0804AF12\n\ + _0804AEF8:\n\ + ldr r2, [r7]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + adds r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + adds r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + adds r1, r0\n\ + str r1, [r7]\n\ + b _0804AF22\n\ + _0804AF12:\n\ + ldr r0, [r7]\n\ + adds r0, 0x5\n\ + str r0, [r7]\n\ + b _0804AF22\n\ + _0804AF1A:\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + ldr r0, [r1]\n\ + adds r0, 0x5\n\ + str r0, [r1]\n\ + _0804AF22:\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +static void MoveValuesCleanUp(void) +{ + gBattleMoveFlags = 0; + gBattleScripting.dmgMultiplier = 1; + gCritMultiplier = 1; + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleCommunication[6] = 0; + gHitMarker &= ~(HITMARKER_DESTINYBOND); + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); +} + +static void atk25_move_values_cleanup(void) +{ + MoveValuesCleanUp(); + gBattlescriptCurrInstr += 1; +} + +static void atk26_set_multihit(void) +{ + gMultiHitCounter = gBattlescriptCurrInstr[1]; + gBattlescriptCurrInstr += 2; +} + +static void atk27_decrement_multihit(void) +{ + if (--gMultiHitCounter == 0) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atk28_goto(void) +{ + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atk29_jumpifbyte(void) +{ + u8 caseID = gBattlescriptCurrInstr[1]; + const u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u8 value = gBattlescriptCurrInstr[6]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); + + gBattlescriptCurrInstr += 11; + + switch (caseID) + { + case CMP_EQUAL: + if (*memByte == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memByte != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memByte > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memByte < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memByte & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memByte & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +static void atk2A_jumpifhalfword(void) +{ + u8 caseID = gBattlescriptCurrInstr[1]; + const u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 8); + + gBattlescriptCurrInstr += 12; + + switch (caseID) + { + case CMP_EQUAL: + if (*memHword == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memHword != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memHword > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memHword < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memHword & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memHword & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +static void atk2B_jumpifword(void) +{ + u8 caseID = gBattlescriptCurrInstr[1]; + const u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u32 value = BSScriptRead32(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + gBattlescriptCurrInstr += 14; + + switch (caseID) + { + case CMP_EQUAL: + if (*memWord == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memWord != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memWord > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memWord < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memWord & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memWord & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +static void atk2C_jumpifarrayequal(void) +{ + const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + u32 size = gBattlescriptCurrInstr[9]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + u8 i; + for (i = 0; i < size; i++) + { + if (*mem1 != *mem2) + { + gBattlescriptCurrInstr += 14; + break; + } + mem1++, mem2++; + } + + if (i == size) + gBattlescriptCurrInstr = jumpPtr; +} + +static void atk2D_jumpifarraynotequal(void) +{ + u8 equalBytes = 0; + const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + u32 size = gBattlescriptCurrInstr[9]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + u8 i; + for (i = 0; i < size; i++) + { + if (*mem1 == *mem2) + { + equalBytes++; + } + mem1++, mem2++; + } + + if (equalBytes != size) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 14; +} + +static void atk2E_setbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte = gBattlescriptCurrInstr[5]; + + gBattlescriptCurrInstr += 6; +} + +static void atk2F_addbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte += gBattlescriptCurrInstr[5]; + gBattlescriptCurrInstr += 6; +} + +static void atk30_subbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte -= gBattlescriptCurrInstr[5]; + gBattlescriptCurrInstr += 6; +} + +static void atk31_copyarray(void) +{ + u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + s32 size = gBattlescriptCurrInstr[9]; + + s32 i; + for (i = 0; i < size; i++) + { + dest[i] = src[i]; + } + + gBattlescriptCurrInstr += 10; +} + +static void atk32_copyarray_withindex(void) +{ + u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + const u8* index = BS2ScriptReadPtr(gBattlescriptCurrInstr + 9); + s32 size = gBattlescriptCurrInstr[13]; + + s32 i; + for (i = 0; i < size; i++) + { + dest[i] = src[i + *index]; + } + + gBattlescriptCurrInstr += 14; +} + +static void atk33_orbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte |= gBattlescriptCurrInstr[5]; + gBattlescriptCurrInstr += 6; +} + +static void atk34_orhalfword(void) +{ + u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + *memHword |= val; + gBattlescriptCurrInstr += 7; +} + +static void atk35_orword(void) +{ + u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); + + *memWord |= val; + gBattlescriptCurrInstr += 9; +} + +static void atk36_bicbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte &= ~(gBattlescriptCurrInstr[5]); + gBattlescriptCurrInstr += 6; +} + +static void atk37_bichalfword(void) +{ + u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + *memHword &= ~val; + gBattlescriptCurrInstr += 7; +} + +static void atk38_bicword(void) +{ + u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); + + *memWord &= ~val; + gBattlescriptCurrInstr += 9; +} + +static void atk39_pause(void) +{ + if (gBattleExecBuffer == 0) + { + u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + if (++gPauseCounterBattle >= value) + { + gPauseCounterBattle = 0; + gBattlescriptCurrInstr += 3; + } + } +} + +static void atk3A_waitstate(void) +{ + if (gBattleExecBuffer == 0) + gBattlescriptCurrInstr++; +} + +static void atk3B_healthbar_update(void) +{ + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + gActiveBank = gBankTarget; + else + gActiveBank = gBankAttacker; + + EmitHealthBarUpdate(0, gBattleMoveDamage); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; +} + +static void atk3C_return(void) +{ + BattleScriptPop(); +} + +static void atk3D_end(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A5718(gBankAttacker); + + gBattleMoveFlags = 0; + gActiveBank = 0; + gCurrentActionFuncId = 0xB; +} + +static void atk3E_end2(void) +{ + gActiveBank = 0; + gCurrentActionFuncId = 0xB; +} + +static void atk3F_end3(void) // pops the main function stack +{ + BattleScriptPop(); + if (BATTLE_CALLBACKS_STACK->size) + BATTLE_CALLBACKS_STACK->size--; + gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size]; +} + +static void atk41_call(void) +{ + BattleScriptPush(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atk42_jumpiftype2(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattlescriptCurrInstr[2] == gBattleMons[bank].type1 || gBattlescriptCurrInstr[2] == gBattleMons[bank].type2) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; +} + +static void atk43_jumpifabilitypresent(void) +{ + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +static void atk44_end_selection_script(void) +{ + *(gBankAttacker + gBattleStruct->selectionScriptFinished) = TRUE; +} + +static void atk45_playanimation(void) +{ + const u16* argumentPtr; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE + || gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE + || gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE) + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } + else if (gHitMarker & HITMARKER_NO_ANIMATIONS) + { + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BattleScript_Pausex20; + } + else if (gBattlescriptCurrInstr[2] == B_ANIM_RAIN_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_SUN_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_SANDSTORM_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_HAIL_CONTINUES) + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } + else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + { + gBattlescriptCurrInstr += 7; + } + else + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } +} + +static void atk46_playanimation2(void) // animation Id is stored in the first pointer +{ + const u16* argumentPtr; + const u8* animationIdPtr; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + animationIdPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (*animationIdPtr == B_ANIM_STATS_CHANGE + || *animationIdPtr == B_ANIM_SNATCH_MOVE + || *animationIdPtr == B_ANIM_SUBSTITUTE_FADE) + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } + else if (gHitMarker & HITMARKER_NO_ANIMATIONS) + { + gBattlescriptCurrInstr += 10; + } + else if (*animationIdPtr == B_ANIM_RAIN_CONTINUES + || *animationIdPtr == B_ANIM_SUN_CONTINUES + || *animationIdPtr == B_ANIM_SANDSTORM_CONTINUES + || *animationIdPtr == B_ANIM_HAIL_CONTINUES) + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } + else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + { + gBattlescriptCurrInstr += 10; + } + else + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } +} + +static void atk47_setgraphicalstatchangevalues(void) +{ + u8 value = 0; + switch (gBattleScripting.statChanger & 0xF0) + { + case 0x10: // +1 + value = 0xF; + break; + case 0x20: // +2 + value = 0x27; + break; + case 0x90: // -1 + value = 0x16; + break; + case 0xA0: // -2 + value = 0x2E; + break; + } + gBattleScripting.animArg1 = (gBattleScripting.statChanger & 0xF) + value - 1; + gBattleScripting.animArg2 = 0; + gBattlescriptCurrInstr++; +} + +#ifdef NONMATCHING +static void atk48_playstatchangeanimation(void) +{ + u32 currStat = 0; + s16 statAnimId = 0; + s16 checkingStatAnimId = 0; + s32 changeableStats = 0; + u32 statsToCheck = 0; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + statsToCheck = gBattlescriptCurrInstr[2]; + + if (gBattlescriptCurrInstr[3] & ATK48_STAT_NEGATIVE) // goes down + { + checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x2D : 0x15; + while (statsToCheck != 0) + { + if (statsToCheck & 1) + { + if (!(gBattlescriptCurrInstr[3] & ATK48_LOWER_FAIL_CHECK)) + { + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + else if (!gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && gBattleMons[gActiveBank].ability != ABILITY_CLEAR_BODY + && gBattleMons[gActiveBank].ability != ABILITY_WHITE_SMOKE + && !(gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC) + && !(gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK)) + { + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + } + statsToCheck >>= 1, checkingStatAnimId++, currStat++; + } + + if (changeableStats > 1) // more than one stat, so the color is gray + { + if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) + statAnimId = 0x3A; + else + statAnimId = 0x39; + } + } + else // goes up + { + checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x26 : 0xE; + while (statsToCheck != 0) + { + if (statsToCheck & 1 && gBattleMons[gActiveBank].statStages[currStat] < 0xC) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + statsToCheck >>= 1, checkingStatAnimId += 1, currStat++; + } + + if (changeableStats > 1) // more than one stat, so the color is gray + { + if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) + statAnimId = 0x38; + else + statAnimId = 0x37; + } + } + + if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats < 2) + { + gBattlescriptCurrInstr += 4; + } + else if (changeableStats != 0 && gBattleScripting.field_1B == 0) + { + EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId); + MarkBufferBankForExecution(gActiveBank); + if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats > 1) + gBattleScripting.field_1B = 1; + gBattlescriptCurrInstr += 4; + } + else + { + gBattlescriptCurrInstr += 4; + } +} +#else +__attribute__((naked)) +static void atk48_playstatchangeanimation(void) +{ + asm("\n\ + .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\ + movs r7, 0\n\ + movs r0, 0\n\ + mov r8, r0\n\ + movs r3, 0\n\ + ldr r5, =gBattlescriptCurrInstr\n\ + ldr r0, [r5]\n\ + ldrb r0, [r0, 0x1]\n\ + str r3, [sp]\n\ + bl GetBattleBank\n\ + ldr r2, =gActiveBank\n\ + strb r0, [r2]\n\ + ldr r0, [r5]\n\ + ldrb r4, [r0, 0x2]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x1\n\ + ands r0, r1\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + beq _0804BAEC\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x15\n\ + cmp r0, 0\n\ + beq _0804BA18\n\ + movs r1, 0x2D\n\ +_0804BA18:\n\ + cmp r4, 0\n\ + beq _0804BAC0\n\ + movs r0, 0x1\n\ + mov r10, r0\n\ + ldr r0, =gBattleMons + 0x18\n\ + mov r9, r0\n\ + lsls r5, r1, 16\n\ +_0804BA26:\n\ + adds r0, r4, 0\n\ + mov r1, r10\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BAB2\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x8\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BA58\n\ + ldr r0, =gActiveBank\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r7, r0\n\ + b _0804BAA0\n\ + .pool\n\ +_0804BA58:\n\ + ldr r6, =gActiveBank\n\ + ldrb r0, [r6]\n\ + str r3, [sp]\n\ + bl GetBankIdentity\n\ + mov r1, r10\n\ + ands r1, r0\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + ldr r1, =gSideTimers\n\ + adds r0, r1\n\ + ldrb r0, [r0, 0x4]\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + bne _0804BAB2\n\ + ldr r0, =gBattleMons\n\ + ldrb r2, [r6]\n\ + movs r1, 0x58\n\ + muls r2, r1\n\ + adds r0, r2, r0\n\ + adds r0, 0x20\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x1D\n\ + beq _0804BAB2\n\ + cmp r0, 0x49\n\ + beq _0804BAB2\n\ + cmp r0, 0x33\n\ + bne _0804BA96\n\ + cmp r7, 0x6\n\ + beq _0804BAB2\n\ +_0804BA96:\n\ + cmp r0, 0x34\n\ + bne _0804BA9E\n\ + cmp r7, 0x1\n\ + beq _0804BAB2\n\ +_0804BA9E:\n\ + adds r0, r7, r2\n\ +_0804BAA0:\n\ + add r0, r9\n\ + ldrb r0, [r0]\n\ + lsls r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0\n\ + ble _0804BAB2\n\ + lsrs r0, r5, 16\n\ + mov r8, r0\n\ + adds r3, 0x1\n\ +_0804BAB2:\n\ + lsrs r4, 1\n\ + movs r1, 0x80\n\ + lsls r1, 9\n\ + adds r5, r1\n\ + adds r7, 0x1\n\ + cmp r4, 0\n\ + bne _0804BA26\n\ +_0804BAC0:\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + mov r9, r0\n\ + cmp r3, 0x1\n\ + ble _0804BB4E\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x39\n\ + mov r8, r1\n\ + cmp r0, 0\n\ + beq _0804BB4E\n\ + movs r0, 0x3A\n\ + b _0804BB4C\n\ + .pool\n\ +_0804BAEC:\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0xE\n\ + cmp r0, 0\n\ + beq _0804BAF8\n\ + movs r1, 0x26\n\ +_0804BAF8:\n\ + mov r9, r5\n\ + cmp r4, 0\n\ + beq _0804BB34\n\ + ldr r6, =gBattleMons + 0x18\n\ + adds r5, r2, 0\n\ + lsls r2, r1, 16\n\ +_0804BB04:\n\ + movs r0, 0x1\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _0804BB26\n\ + ldrb r1, [r5]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r7, r0\n\ + adds r0, r6\n\ + ldrb r0, [r0]\n\ + lsls r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0xB\n\ + bgt _0804BB26\n\ + lsrs r1, r2, 16\n\ + mov r8, r1\n\ + adds r3, 0x1\n\ +_0804BB26:\n\ + lsrs r4, 1\n\ + movs r0, 0x80\n\ + lsls r0, 9\n\ + adds r2, r0\n\ + adds r7, 0x1\n\ + cmp r4, 0\n\ + bne _0804BB04\n\ +_0804BB34:\n\ + cmp r3, 0x1\n\ + ble _0804BB4E\n\ + mov r1, r9\n\ + ldr r0, [r1]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x37\n\ + mov r8, r1\n\ + cmp r0, 0\n\ + beq _0804BB4E\n\ + movs r0, 0x38\n\ +_0804BB4C:\n\ + mov r8, r0\n\ +_0804BB4E:\n\ + mov r1, r9\n\ + ldr r2, [r1]\n\ + ldrb r1, [r2, 0x3]\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BB6C\n\ + cmp r3, 0x1\n\ + bgt _0804BB6C\n\ + adds r0, r2, 0x4\n\ + mov r1, r9\n\ + b _0804BBBA\n\ + .pool\n\ +_0804BB6C:\n\ + cmp r3, 0\n\ + beq _0804BBB4\n\ + ldr r4, =gBattleScripting\n\ + ldrb r0, [r4, 0x1B]\n\ + cmp r0, 0\n\ + bne _0804BBB4\n\ + movs r0, 0\n\ + movs r1, 0x1\n\ + mov r2, r8\n\ + str r3, [sp]\n\ + bl EmitBattleAnimation\n\ + ldr r0, =gActiveBank\n\ + ldrb r0, [r0]\n\ + bl MarkBufferBankForExecution\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + beq _0804BBA4\n\ + cmp r3, 0x1\n\ + ble _0804BBA4\n\ + movs r0, 0x1\n\ + strb r0, [r4, 0x1B]\n\ +_0804BBA4:\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + b _0804BBB6\n\ + .pool\n\ +_0804BBB4:\n\ + mov r1, r9\n\ +_0804BBB6:\n\ + ldr r0, [r1]\n\ + adds r0, 0x4\n\ +_0804BBBA:\n\ + str r0, [r1]\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 + +#define ATK49_LAST_CASE 17 + +static void atk49_moveend(void) +{ + s32 i; + bool32 effect; + u8 moveType; + u8 holdEffectAtk; + u16 *choicedMoveAtk; + u8 arg1, arg2; + u16 lastMove; + + effect = FALSE; + + if (gLastUsedMove == 0xFFFF) + lastMove = 0; + else + lastMove = gLastUsedMove; + + arg1 = gBattlescriptCurrInstr[1]; + arg2 = gBattlescriptCurrInstr[2]; + + if (gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY) + holdEffectAtk = gEnigmaBerries[gBankAttacker].holdEffect; + else + holdEffectAtk = ItemId_GetHoldEffect(gBattleMons[gBankAttacker].item); + + choicedMoveAtk = &gBattleStruct->choicedMove[gBankAttacker]; + + GET_MOVE_TYPE(gCurrentMove, moveType); + + do + { + switch (gBattleScripting.atk49_state) + { + case 0: // rage check + if (gBattleMons[gBankTarget].status2 & STATUS2_RAGE + && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && TARGET_TURN_DAMAGED + && gBattleMoves[gCurrentMove].power && gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] <= 0xB) + { + gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK]++; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RageIsBuilding; + effect = TRUE; + } + gBattleScripting.atk49_state++; + break; + case 1: // defrosting check + if (gBattleMons[gBankTarget].status1 & STATUS_FREEZE + && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget + && gSpecialStatuses[gBankTarget].moveturnLostHP_special + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && moveType == TYPE_FIRE) + { + gBattleMons[gBankTarget].status1 &= ~(STATUS_FREEZE); + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); + MarkBufferBankForExecution(gActiveBank); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove; + effect = TRUE; + } + gBattleScripting.atk49_state++; + break; + case 2: // target synchronize + if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBankTarget, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 3: // contact abilities + if (AbilityBattleEffects(ABILITYEFFECT_CONTACT, gBankTarget, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 4: // status immunities + if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0)) + effect = TRUE; // it loops through all banks, so we increment after its done with all banks + else + gBattleScripting.atk49_state++; + break; + case 5: // attacker synchronize + if (AbilityBattleEffects(ABILITYEFFECT_ATK_SYNCHRONIZE, gBankAttacker, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 6: // update choice band move + if (!(gHitMarker & HITMARKER_OBEYS) || holdEffectAtk != HOLD_EFFECT_CHOICE_BAND + || gLastUsedMove == MOVE_STRUGGLE || (*choicedMoveAtk != 0 && *choicedMoveAtk != 0xFFFF)) + goto LOOP; + if (gLastUsedMove == MOVE_BATON_PASS && !(gBattleMoveFlags & MOVESTATUS_FAILED)) + { + gBattleScripting.atk49_state++; + break; + } + *choicedMoveAtk = gLastUsedMove; + LOOP: + { + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == *choicedMoveAtk) + break; + } + if (i == 4) + *choicedMoveAtk = 0; + + gBattleScripting.atk49_state++; + } + break; + case 7: // changed held items + for (i = 0; i < gNoOfAllBanks; i++) + { + u16* changedItem = &gBattleStruct->changedItems[i]; + if (*changedItem != 0) + { + gBattleMons[i].item = *changedItem; + *changedItem = 0; + } + } + gBattleScripting.atk49_state++; + break; + case 11: // item effects for all banks + if (ItemBattleEffects(3, 0, FALSE)) + effect = TRUE; + else + gBattleScripting.atk49_state++; + break; + case 12: // king's rock and shell bell + if (ItemBattleEffects(4, 0, FALSE)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 8: // make attacker sprite invisible + if (gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE) + && gHitMarker & HITMARKER_NO_ANIMATIONS) + { + gActiveBank = gBankAttacker; + EmitSpriteInvisibility(0, TRUE); + MarkBufferBankForExecution(gActiveBank); + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 9: // make attacker sprite visible + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT + || !(gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE)) + || WasUnableToUseMove(gBankAttacker)) + { + gActiveBank = gBankAttacker; + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + gStatuses3[gBankAttacker] &= ~(STATUS3_SEMI_INVULNERABLE); + gSpecialStatuses[gBankAttacker].restoredBankSprite = 1; + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 10: // make target sprite visible + if (!gSpecialStatuses[gBankTarget].restoredBankSprite && gBankTarget < gNoOfAllBanks + && !(gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE)) + { + gActiveBank = gBankTarget; + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + gStatuses3[gBankTarget] &= ~(STATUS3_SEMI_INVULNERABLE); + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 13: // update substitute + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gDisableStructs[i].substituteHP == 0) + gBattleMons[i].status2 &= ~(STATUS2_SUBSTITUTE); + } + gBattleScripting.atk49_state++; + break; + case 14: // This case looks interesting, although I am not certain what it does. Probably fine tunes edge cases. + if (gHitMarker & HITMARKER_PURSUIT_TRAP) + { + gActiveBank = gBankAttacker; + gBankAttacker = gBankTarget; + gBankTarget = gActiveBank; + gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); + } + if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) + { + gUnknownMovesUsedByBanks[gBankAttacker] = gLastUsedMove; + } + if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) + && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) + && gBattleMoves[lastMove].effect != EFFECT_BATON_PASS) + { + if (gHitMarker & HITMARKER_OBEYS) + { + gLastUsedMovesByBanks[gBankAttacker] = gLastUsedMove; + gUnknown_02024260[gBankAttacker] = gCurrentMove; + } + else + { + gLastUsedMovesByBanks[gBankAttacker] = 0xFFFF; + gUnknown_02024260[gBankAttacker] = 0xFFFF; + } + + if (!(gHitMarker & HITMARKER_FAINTED(gBankTarget))) + gUnknown_02024270[gBankTarget] = gBankAttacker; + + if (gHitMarker & HITMARKER_OBEYS && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gLastUsedMove == 0xFFFF) + { + gUnknown_02024250[gBankTarget] = gLastUsedMove; + } + else + { + gUnknown_02024250[gBankTarget] = gCurrentMove; + GET_MOVE_TYPE(gCurrentMove, gUnknown_02024258[gBankTarget]); + } + } + else + { + gUnknown_02024250[gBankTarget] = 0xFFFF; + } + } + gBattleScripting.atk49_state++; + break; + case 15: // mirror move + if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) + && gBattleMoves[lastMove].flags & FLAG_MIRROR_MOVE_AFFECTED && gHitMarker & HITMARKER_OBEYS + && gBankAttacker != gBankTarget && !(gHitMarker & HITMARKER_FAINTED(gBankTarget)) + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + u8 target, attacker; + + *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 0) = gLastUsedMove; + *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 1) = gLastUsedMove >> 8; + + target = gBankTarget; + attacker = gBankAttacker; + *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = gLastUsedMove; + + target = gBankTarget; + attacker = gBankAttacker; + *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = gLastUsedMove >> 8; + } + gBattleScripting.atk49_state++; + break; + case 16: // + if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !gProtectStructs[gBankAttacker].chargingTurn && gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH + && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + { + u8 bank = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + if (gBattleMons[bank].hp != 0) + { + gBankTarget = bank; + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + gBattleScripting.atk49_state = 0; + MoveValuesCleanUp(); + BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattlescriptCurrInstr = gUnknown_082DB87D; + return; + } + else + { + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + } + } + gBattleScripting.atk49_state++; + break; + case ATK49_LAST_CASE: + break; + } + + if (arg1 == 1 && effect == FALSE) + gBattleScripting.atk49_state = ATK49_LAST_CASE; + if (arg1 == 2 && arg2 == gBattleScripting.atk49_state) + gBattleScripting.atk49_state = ATK49_LAST_CASE; + + } while (gBattleScripting.atk49_state != ATK49_LAST_CASE && effect == FALSE); + + if (gBattleScripting.atk49_state == ATK49_LAST_CASE && effect == FALSE) + gBattlescriptCurrInstr += 3; +} + +static void atk4A_typecalc2(void) +{ + u8 flags = 0; + s32 i = 0; + u8 moveType = gBattleMoves[gCurrentMove].type; + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + gUnknown_02024250[gBankTarget] = 0; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + { + break; + } + else + { + i += 3; + continue; + } + } + + if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) + { + if (gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + break; + } + if (gTypeEffectiveness[i + 2] == 5) + { + flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + if (gTypeEffectiveness[i + 2] == 20) + { + flags |= MOVESTATUS_SUPEREFFECTIVE; + } + } + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2) + { + if (gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + break; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 5) + { + flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 20) + { + flags |= MOVESTATUS_SUPEREFFECTIVE; + } + } + } + i += 3; + } + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD + && !(flags & MOVESTATUS_NOEFFECT) + && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gProtectStructs[gBankAttacker].targetNotAffected = 1; + + gBattlescriptCurrInstr++; +} + +static void atk4B_return_atk_to_ball(void) +{ + gActiveBank = gBankAttacker; + if (!(gHitMarker & HITMARKER_FAINTED(gActiveBank))) + { + EmitReturnMonToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr++; +} + +static void atk4C_copy_poke_data(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + gBattlePartyID[gActiveBank] = *(gBattleStruct->field_5C + gActiveBank); + + EmitGetMonData(0, 0, gBitTable[gBattlePartyID[gActiveBank]]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk4D_switch_data_update(void) +{ + struct BattlePokemon oldData; + s32 i; + u8 *monData; + + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + oldData = gBattleMons[gActiveBank]; + monData = (u8*)(&gBattleMons[gActiveBank]); + + for (i = 0; i < sizeof(struct BattlePokemon); i++) + { + monData[i] = gBattleBufferB[gActiveBank][4 + i]; + } + + gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1; + gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2; + gBattleMons[gActiveBank].ability = GetAbilityBySpecies(gBattleMons[gActiveBank].species, gBattleMons[gActiveBank].altAbility); + + // check knocked off item + i = GetBankSide(gActiveBank); + if (gWishFutureKnock.knockedOffPokes[i] & gBitTable[gBattlePartyID[gActiveBank]]) + { + gBattleMons[gActiveBank].item = 0; + } + + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + for (i = 0; i < 8; i++) + { + gBattleMons[gActiveBank].statStages[i] = oldData.statStages[i]; + } + gBattleMons[gActiveBank].status2 = oldData.status2; + } + + SwitchInClearSetData(); + + if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp + && gBattleMons[gActiveBank].hp != 0 && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + { + gBattleStruct->field_92 |= gBitTable[gActiveBank]; + } + + gBattleScripting.bank = gActiveBank; + gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = 7; + gBattleTextBuff1[2] = gActiveBank; + gBattleTextBuff1[3] = gBattlePartyID[gActiveBank]; + gBattleTextBuff1[4] = EOS; + + gBattlescriptCurrInstr += 2; +} + +static void atk4E_switchin_anim(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (GetBankSide(gActiveBank) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000 + | BATTLE_TYPE_FRONTIER))) + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); + + gAbsentBankFlags &= ~(gBitTable[gActiveBank]); + + EmitSwitchInAnim(0, gBattlePartyID[gActiveBank], gBattlescriptCurrInstr[2]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A56B4(); +} + +static void atk4F_jump_if_cannot_switch(void) +{ + s32 val = 0; + s32 compareVar = 0; + struct Pokemon *party = NULL; + s32 r7 = 0; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(ATK4F_DONT_CHECK_STATUSES)); + + if (!(gBattlescriptCurrInstr[1] & ATK4F_DONT_CHECK_STATUSES) + && ((gBattleMons[gActiveBank].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + || (gStatuses3[gActiveBank] & STATUS3_ROOTED))) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + #ifndef NONMATCHING + asm("":::"r5"); + #endif // NONMATCHING + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + party = gEnemyParty; + else + party = gPlayerParty; + + val = 0; + if (2 & gActiveBank) + val = 3; + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleTypeFlags & BATTLE_TYPE_x800000) + { + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + party = gPlayerParty; + + val = 0; + if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) + val = 3; + } + else + { + party = gEnemyParty; + + if (gActiveBank == 1) + val = 0; + else + val = 3; + } + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + party = gEnemyParty; + else + party = gPlayerParty; + + + val = 0; + if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) + val = 3; + } + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + party = gEnemyParty; + + val = 0; + if (gActiveBank == 3) + val = 3; + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + r7 = GetBankByIdentity(1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + compareVar = GetBankByIdentity(3); + else + compareVar = r7; + + party = gEnemyParty; + } + else + { + r7 = GetBankByIdentity(0); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + compareVar = GetBankByIdentity(2); + else + compareVar = r7; + + party = gPlayerParty; + } + for (val = 0; val < 6; val++) + { + if (GetMonData(&party[val], MON_DATA_HP) != 0 + && GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && val != gBattlePartyID[r7] && val != gBattlePartyID[compareVar]) + break; + } + + if (val == 6) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } +} + +static void sub_804CF10(u8 arg0) +{ + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + *(gBattleStruct->field_5C + gActiveBank) = 6; + gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); + + EmitChoosePokemon(0, 1, arg0, 0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); +} + +static void atk50_openpartyscreen(void) +{ + u32 flags; + u8 hitmarkerFaintBits; + u8 bank; + const u8 *jumpPtr; + + bank = 0; + flags = 0; + jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + + if (gBattlescriptCurrInstr[1] == 5) + { + if ((gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI)) != BATTLE_TYPE_DOUBLE) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + { + if (sub_80423F4(gActiveBank, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(6); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + u8 flag40_0, flag40_1, flag40_2, flag40_3; + + hitmarkerFaintBits = gHitMarker >> 0x1C; + + if (gBitTable[0] & hitmarkerFaintBits) + { + gActiveBank = 0; + if (sub_80423F4(0, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitCmd42(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[2]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + flags |= 1; + } + } + if (gBitTable[2] & hitmarkerFaintBits && !(gBitTable[0] & hitmarkerFaintBits)) + { + gActiveBank = 2; + if (sub_80423F4(2, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitCmd42(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[0]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else if (!(flags & 1)) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + if (gBitTable[1] & hitmarkerFaintBits) + { + gActiveBank = 1; + if (sub_80423F4(1, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitCmd42(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[3]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + flags |= 2; + } + } + if (gBitTable[3] & hitmarkerFaintBits && !(gBitTable[1] & hitmarkerFaintBits)) + { + gActiveBank = 3; + if (sub_80423F4(3, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitCmd42(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[1]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else if (!(flags & 2)) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + + flag40_0 = gSpecialStatuses[0].flag40; + if (!flag40_0) + { + flag40_2 = gSpecialStatuses[2].flag40; + if (!flag40_2 && hitmarkerFaintBits != 0) + { + if (gAbsentBankFlags & gBitTable[0]) + gActiveBank = 2; + else + gActiveBank = 0; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + + } + flag40_1 = gSpecialStatuses[1].flag40; + if (!flag40_1) + { + flag40_3 = gSpecialStatuses[3].flag40; + if (!flag40_3 && hitmarkerFaintBits != 0) + { + if (gAbsentBankFlags & gBitTable[1]) + gActiveBank = 3; + else + gActiveBank = 1; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + gBattlescriptCurrInstr += 6; + } + else if (gBattlescriptCurrInstr[1] == 6) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + hitmarkerFaintBits = gHitMarker >> 0x1C; + if (gBitTable[2] & hitmarkerFaintBits && gBitTable[0] & hitmarkerFaintBits) + { + gActiveBank = 2; + if (sub_80423F4(2, gBattleBufferB[0][1], 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitCmd42(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[0]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + if (gBitTable[3] & hitmarkerFaintBits && hitmarkerFaintBits & gBitTable[1]) + { + gActiveBank = 3; + if (sub_80423F4(3, gBattleBufferB[1][1], 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitCmd42(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[1]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + gBattlescriptCurrInstr += 6; + } + else + { + gBattlescriptCurrInstr += 6; + } + } + else + { + gBattlescriptCurrInstr += 6; + } + + hitmarkerFaintBits = gHitMarker >> 0x1C; + + gBank1 = 0; + while (1) + { + if (gBitTable[gBank1] & hitmarkerFaintBits) + break; + if (gBank1 >= gNoOfAllBanks) + break; + gBank1++; + } + + if (gBank1 == gNoOfAllBanks) + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if (gBattlescriptCurrInstr[1] & 0x80) + hitmarkerFaintBits = 0; // used here as the caseId for the EmitChoose function + else + hitmarkerFaintBits = 1; + + bank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(0x80)); + if (gSpecialStatuses[bank].flag40) + { + gBattlescriptCurrInstr += 6; + } + else if (sub_80423F4(bank, 6, 6)) + { + gActiveBank = bank; + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + gBattlescriptCurrInstr = jumpPtr; + } + else + { + gActiveBank = bank; + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + *(gBattleStruct->field_5C + gActiveBank) = 6; + gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); + + EmitChoosePokemon(0, hitmarkerFaintBits, *(gBattleStruct->field_5C + (gActiveBank ^ 2)), 0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 6; + + if (GetBankIdentity(gActiveBank) == 0 && gBattleResults.playerSwitchesCounter < 0xFF) + gBattleResults.playerSwitchesCounter++; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gActiveBank != bank) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + else + { + gActiveBank = GetBankByIdentity(GetBankIdentity(bank) ^ BIT_SIDE); + if (gAbsentBankFlags & gBitTable[gActiveBank]) + gActiveBank ^= BIT_MON; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } +} + +static void atk51_switch_handle_order(void) +{ + s32 i; + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattlescriptCurrInstr[2]) + { + case 0: + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBattleBufferB[i][0] == 0x22) + { + *(gBattleStruct->field_5C + i) = gBattleBufferB[i][1]; + if (!(gBattleStruct->field_93 & gBitTable[i])) + { + RecordedBattle_SetBankAction(i, gBattleBufferB[i][1]); + gBattleStruct->field_93 |= gBitTable[i]; + } + } + } + break; + case 1: + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + sub_803BDA0(gActiveBank); + break; + case 2: + if (!(gBattleStruct->field_93 & gBitTable[gActiveBank])) + { + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]); + gBattleStruct->field_93 |= gBitTable[gActiveBank]; + } + // fall through + case 3: + gBattleCommunication[0] = gBattleBufferB[gActiveBank][1]; + *(gBattleStruct->field_5C + gActiveBank) = gBattleBufferB[gActiveBank][1]; + + if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) &= 0xF; + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0); + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBank][3]; + + *((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0); + *((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4; + *((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBank][3]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + sub_80571DC(gActiveBank, *(gBattleStruct->field_5C + gActiveBank)); + } + else + { + sub_803BDA0(gActiveBank); + } + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].species) + PREPARE_MON_NICK_BUFFER(gBattleTextBuff2, gActiveBank, gBattleBufferB[gActiveBank][1]) + + break; + } + + gBattlescriptCurrInstr += 3; +} + +static void atk52_switch_in_effects(void) +{ + s32 i; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + sub_803FA70(gActiveBank); + + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + gSpecialStatuses[gActiveBank].flag40 = 0; + + if (!(gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES_DAMAGED) + && (gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES) + && gBattleMons[gActiveBank].type1 != TYPE_FLYING + && gBattleMons[gActiveBank].type2 != TYPE_FLYING + && gBattleMons[gActiveBank].ability != ABILITY_LEVITATE) + { + u8 spikesDmg; + + gSideAffecting[GetBankSide(gActiveBank)] |= SIDE_STATUS_SPIKES_DAMAGED; + + gBattleMons[gActiveBank].status2 &= ~(STATUS2_DESTINY_BOND); + gHitMarker &= ~(HITMARKER_DESTINYBOND); + + spikesDmg = (5 - gSideTimers[GetBankSide(gActiveBank)].spikesAmount) * 2; + gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / (spikesDmg); + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattleScripting.bank = gActiveBank; + BattleScriptPushCursor(); + + if (gBattlescriptCurrInstr[1] == 0) + gBattlescriptCurrInstr = gUnknown_082DAE90; + else if (gBattlescriptCurrInstr[1] == 1) + gBattlescriptCurrInstr = gUnknown_082DAE59; + else + gBattlescriptCurrInstr = gUnknown_082DAEC7; + } + else + { + if (gBattleMons[gActiveBank].ability == ABILITY_TRUANT && !gDisableStructs[gActiveBank].truantUnknownBit) + gDisableStructs[gActiveBank].truantCounter = 1; + + gDisableStructs[gActiveBank].truantUnknownBit = 0; + + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBank, 0, 0, 0) == 0 && + ItemBattleEffects(0, gActiveBank, 0) == 0) + { + gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBanksByTurnOrder[i] == gActiveBank) + gActionsByTurnOrder[i] = ACTION_CANCEL_PARTNER; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + u16* hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(i)]; + *hpOnSwitchout = gBattleMons[i].hp; + } + + if (gBattlescriptCurrInstr[1] == 5) + { + u32 hitmarkerFaintBits = gHitMarker >> 0x1C; + + gBank1++; + while (1) + { + if (hitmarkerFaintBits & gBitTable[gBank1] && !(gAbsentBankFlags & gBitTable[gBank1])) + break; + if (gBank1 >= gNoOfAllBanks) + break; + gBank1++; + } + } + gBattlescriptCurrInstr += 2; + } + } +} + +static void atk53_trainer_slide(void) +{ + gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); + EmitTrainerSlide(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk54_effectiveness_sound(void) +{ + gActiveBank = gBankAttacker; + EmitEffectivenessSound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; +} + +static void atk55_play_fanfare(void) +{ + gActiveBank = gBankAttacker; + EmitPlayFanfareOrBGM(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), FALSE); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; +} + +static void atk56_fainting_cry(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitFaintingCry(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk57(void) +{ + gActiveBank = GetBankByIdentity(0); + EmitCmd55(0, gBattleOutcome); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 1; +} + +static void atk58_return_to_ball(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitReturnMonToBall(0, 1); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk59_learnmove_inbattle(void) +{ + const u8* jumpPtr1 = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* jumpPtr2 = BSScriptReadPtr(gBattlescriptCurrInstr + 5); + + u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], gBattlescriptCurrInstr[9]); + while (ret == 0xFFFE) + ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], 0); + + if (ret == 0) + { + gBattlescriptCurrInstr = jumpPtr2; + } + else if (ret == 0xFFFF) + { + gBattlescriptCurrInstr += 10; + } + else + { + gActiveBank = GetBankByIdentity(0); + + if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); + } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + gActiveBank = GetBankByIdentity(2); + if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); + } + } + + gBattlescriptCurrInstr = jumpPtr1; + } +} + +static void atk5A_yesnoboxlearnmove(void) +{ + gActiveBank = 0; + + switch (gBattleScripting.learnMoveState) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleScripting.learnMoveState++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[1] == 0) + { + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleScripting.learnMoveState++; + } + else + { + gBattleScripting.learnMoveState = 5; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleScripting.learnMoveState = 5; + } + break; + case 2: + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + sub_81BFA38(gPlayerParty, gBattleStruct->expGetterId, gPlayerPartyCount - 1, ReshowBattleScreenAfterMenu, gMoveToLearn); + gBattleScripting.learnMoveState++; + } + break; + case 3: + if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) + { + gBattleScripting.learnMoveState++; + } + break; + case 4: + if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) + { + u8 movePosition = sub_81C1B94(); + if (movePosition == 4) + { + gBattleScripting.learnMoveState = 5; + } + else + { + u16 moveId = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MOVE1 + movePosition); + if (IsHMMove2(moveId)) + { + PrepareStringBattle(STRINGID_HMMOVESCANTBEFORGOTTEN, gActiveBank); + gBattleScripting.learnMoveState = 6; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + PREPARE_MOVE_BUFFER(gBattleTextBuff2, moveId) + + RemoveMonPPBonus(&gPlayerParty[gBattleStruct->expGetterId], movePosition); + SetMonMoveSlot(&gPlayerParty[gBattleStruct->expGetterId], gMoveToLearn, movePosition); + + if (gBattlePartyID[0] == gBattleStruct->expGetterId + && !(gBattleMons[0].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[0].unk18_b & gBitTable[movePosition])) + { + RemoveBattleMonPPBonus(&gBattleMons[0], movePosition); + SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition); + } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattlePartyID[2] == gBattleStruct->expGetterId + && !(gBattleMons[2].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[2].unk18_b & gBitTable[movePosition])) + { + RemoveBattleMonPPBonus(&gBattleMons[2], movePosition); + SetBattleMonMoveSlot(&gBattleMons[2], gMoveToLearn, movePosition); + } + } + } + } + break; + case 5: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr += 5; + break; + case 6: + if (gBattleExecBuffer == 0) + { + gBattleScripting.learnMoveState = 2; + } + break; + } +} + +static void atk5B_yesnoboxstoplearningmove(void) +{ + switch (gBattleScripting.learnMoveState) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleScripting.learnMoveState++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + + if (gBattleCommunication[1] != 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + } + break; + } +} + +static void atk5C_hitanimation(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gBattlescriptCurrInstr += 2; + } + else if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) || !(gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) || gDisableStructs[gActiveBank].substituteHP == 0) + { + EmitHitAnimation(0); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } + else + { + gBattlescriptCurrInstr += 2; + } +} + +static u32 GetTrainerMoneyToGive(u16 trainerId) +{ + u32 i = 0; + u32 lastMonLevel = 0; + u32 moneyReward = 0; + + if (trainerId == SECRET_BASE_OPPONENT) + { + moneyReward = 20 * gBattleResources->secretBase->partyLevels[0] * gBattleStruct->moneyMultiplier; + } + else + { + switch (gTrainers[trainerId].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *party = gTrainers[trainerId].party.NoItemDefaultMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_CUSTOM_MOVES: + { + const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + } + + for (; gTrainerMoneyTable[i].classId != 0xFF; i++) + { + if (gTrainerMoneyTable[i].classId == gTrainers[trainerId].trainerClass) + break; + } + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * 2 * gTrainerMoneyTable[i].value; + else + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; + } + + return moneyReward; +} + +static void atk5D_getmoneyreward(void) +{ + u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B); + + AddMoney(&gSaveBlock1Ptr->money, moneyReward); + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward) + + gBattlescriptCurrInstr++; +} + +static void atk5E_8025A70(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattleCommunication[0]) + { + case 0: + EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[0]++; + break; + case 1: + if (gBattleExecBuffer == 0) + { + s32 i; + struct BattlePokemon* bufferPoke = (struct BattlePokemon*) &gBattleBufferB[gActiveBank][4]; + for (i = 0; i < 4; i++) + { + gBattleMons[gActiveBank].moves[i] = bufferPoke->moves[i]; + gBattleMons[gActiveBank].pp[i] = bufferPoke->pp[i]; + } + gBattlescriptCurrInstr += 2; + } + break; + } +} + +static void atk5F_8025B24(void) +{ + gActiveBank = gBankAttacker; + gBankAttacker = gBankTarget; + gBankTarget = gActiveBank; + + if (gHitMarker & HITMARKER_PURSUIT_TRAP) + gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); + else + gHitMarker |= HITMARKER_PURSUIT_TRAP; + + gBattlescriptCurrInstr++; +} + +static void atk60_increment_gamestat(void) +{ + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + IncrementGameStat(gBattlescriptCurrInstr[1]); + + gBattlescriptCurrInstr += 2; +} + +static void atk61_draw_party_status_summary(void) +{ + s32 i; + struct Pokemon* party; + struct HpAndStatus hpStatuses[6]; + + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < 6; i++) + { + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatuses[i].hp = 0xFFFF; + hpStatuses[i].status = 0; + } + else + { + hpStatuses[i].hp = GetMonData(&party[i], MON_DATA_HP); + hpStatuses[i].status = GetMonData(&party[i], MON_DATA_STATUS); + } + } + + EmitDrawPartyStatusSummary(0, hpStatuses, 1); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk62_08025C6C(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitCmd49(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk63_jumptorandomattack(void) +{ + if (gBattlescriptCurrInstr[1] != 0) + gCurrentMove = gRandomMove; + else + gLastUsedMove = gCurrentMove = gRandomMove; + + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; +} + +static void atk64_statusanimation(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, FALSE, gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 2; + } +} + +static void atk65_status2animation(void) +{ + u32 wantedToAnimate; + + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + wantedToAnimate = BSScriptRead32(gBattlescriptCurrInstr + 2); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, TRUE, gBattleMons[gActiveBank].status2 & wantedToAnimate); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 6; + } +} + +static void atk66_chosenstatusanimation(void) +{ + u32 wantedStatus; + + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + wantedStatus = BSScriptRead32(gBattlescriptCurrInstr + 3); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, gBattlescriptCurrInstr[2], wantedStatus); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 7; + } +} + +static void atk67_yesnobox(void) +{ + switch (gBattleCommunication[0]) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[0]++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & B_BUTTON) + { + gBattleCommunication[CURSOR_POSITION] = 1; + PlaySE(SE_SELECT); + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr++; + } + else if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr++; + } + break; + } +} + +static void atk68_80246A0(void) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + gActionsByTurnOrder[i] = ACTION_CANCEL_PARTNER; + + gBattlescriptCurrInstr++; +} + +static void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random damage multiplier. +{ + u8 holdEffect, quality; + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured + && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +static void atk6A_removeitem(void) +{ + u16* usedHeldItem; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; + *usedHeldItem = gBattleMons[gActiveBank].item; + gBattleMons[gActiveBank].item = 0; + + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk6B_atknameinbuff1(void) +{ + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]) + + gBattlescriptCurrInstr++; +} + +static void atk6C_draw_lvlupbox(void) +{ + if (gBattleScripting.atk6C_state == 0) + { + if (IsMonGettingExpSentOut()) + gBattleScripting.atk6C_state = 3; + else + gBattleScripting.atk6C_state = 1; + } + + switch (gBattleScripting.atk6C_state) + { + case 1: + gBattle_BG2_Y = 0x60; + SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 0); + ShowBg(2); + sub_804F17C(); + gBattleScripting.atk6C_state = 2; + break; + case 2: + if (!sub_804F1CC()) + gBattleScripting.atk6C_state = 3; + break; + case 3: + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0x100; + SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 1); + SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 0); + ShowBg(0); + ShowBg(1); + sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x80); + gBattleScripting.atk6C_state = 4; + break; + case 4: + sub_804F100(); + PutWindowTilemap(13); + CopyWindowToVram(13, 3); + gBattleScripting.atk6C_state++; + break; + case 5: + case 7: + if (!IsDma3ManagerBusyWithBgCopy()) + { + gBattle_BG1_Y = 0; + gBattleScripting.atk6C_state++; + } + break; + case 6: + if (gMain.newKeys != 0) + { + PlaySE(SE_SELECT); + sub_804F144(); + CopyWindowToVram(13, 2); + gBattleScripting.atk6C_state++; + } + break; + case 8: + if (gMain.newKeys != 0) + { + PlaySE(SE_SELECT); + sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x81); + gBattleScripting.atk6C_state++; + } + break; + case 9: + if (!sub_804F344()) + { + ClearWindowTilemap(14); + CopyWindowToVram(14, 1); + + ClearWindowTilemap(13); + CopyWindowToVram(13, 1); + + SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 2); + ShowBg(2); + + gBattleScripting.atk6C_state = 10; + } + break; + case 10: + if (!IsDma3ManagerBusyWithBgCopy()) + { + SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 0); + SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 1); + ShowBg(0); + ShowBg(1); + gBattlescriptCurrInstr++; + } + break; + } +} + +static void sub_804F100(void) +{ + struct StatsArray currentStats; + + sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); + sub_81D3640(0xD, gBattleResources->statsBeforeLvlUp, ¤tStats, 0xE, 0xD, 0xF); +} + +static void sub_804F144(void) +{ + struct StatsArray currentStats; + + sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); + sub_81D3784(0xD, ¤tStats, 0xE, 0xD, 0xF); +} + +static void sub_804F17C(void) +{ + gBattle_BG2_Y = 0; + gBattle_BG2_X = 0x1A0; + + LoadPalette(sUnknown_0831C2C8, 0x60, 0x20); + CopyToWindowPixelBuffer(14, sUnknown_0831C2E8, 0, 0); + PutWindowTilemap(14); + CopyWindowToVram(14, 3); + + PutMonIconOnLvlUpBox(); +} + +static bool8 sub_804F1CC(void) +{ + if (IsDma3ManagerBusyWithBgCopy()) + return TRUE; + + if (gBattle_BG2_X == 0x200) + return FALSE; + + if (gBattle_BG2_X == 0x1A0) + PutLevelAndGenderOnLvlUpBox(); + + gBattle_BG2_X += 8; + if (gBattle_BG2_X >= 0x200) + gBattle_BG2_X = 0x200; + + return (gBattle_BG2_X != 0x200); +} + +static void PutLevelAndGenderOnLvlUpBox(void) +{ + u16 monLevel; + u8 monGender; + struct TextSubPrinter subPrinter; + u8 *txtPtr; + u32 var; + + monLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + monGender = GetMonGender(&gPlayerParty[gBattleStruct->expGetterId]); + GetMonNickname(&gPlayerParty[gBattleStruct->expGetterId], gStringVar4); + + subPrinter.current_text_offset = gStringVar4; + subPrinter.windowId = 14; + subPrinter.fontId = 0; + subPrinter.x = 32; + subPrinter.y = 0; + subPrinter.currentX = 32; + subPrinter.currentY = 0; + subPrinter.letterSpacing = 0; + subPrinter.lineSpacing = 0; + subPrinter.fontColor_l = TEXT_COLOR_TRANSPARENT; + subPrinter.fontColor_h = TEXT_COLOR_WHITE; + subPrinter.bgColor = TEXT_COLOR_TRANSPARENT; + subPrinter.shadowColor = TEXT_COLOR_DARK_GREY; + + AddTextPrinter(&subPrinter, 0xFF, NULL); + + txtPtr = gStringVar4; + gStringVar4[0] = CHAR_SPECIAL_F9; + txtPtr++; + txtPtr[0] = 5; + txtPtr++; + + var = (u32)(txtPtr); + txtPtr = ConvertIntToDecimalStringN(txtPtr, monLevel, STR_CONV_MODE_LEFT_ALIGN, 3); + var = (u32)(txtPtr) - var; + txtPtr = StringFill(txtPtr, 0x77, 4 - var); + + if (monGender != MON_GENDERLESS) + { + if (monGender == MON_MALE) + { + txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xC); + txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xD); + *(txtPtr++) = CHAR_MALE; + } + else + { + txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xE); + txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xF); + *(txtPtr++) = CHAR_FEMALE; + } + *(txtPtr++) = EOS; + } + + subPrinter.y = 10; + subPrinter.currentY = 10; + AddTextPrinter(&subPrinter, 0xFF, NULL); + + CopyWindowToVram(14, 2); +} + +static bool8 sub_804F344(void) +{ + if (gBattle_BG2_X == 0x1A0) + return FALSE; + + if (gBattle_BG2_X - 16 < 0x1A0) + gBattle_BG2_X = 0x1A0; + else + gBattle_BG2_X -= 16; + + return (gBattle_BG2_X != 0x1A0); +} + +#define sDestroy data0 +#define sSavedLvlUpBoxXPosition data1 + +static void PutMonIconOnLvlUpBox(void) +{ + u8 spriteId; + const u16* iconPal; + struct SpriteSheet iconSheet; + struct SpritePalette iconPalSheet; + + u16 species = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPECIES); + u32 personality = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_PERSONALITY); + + const u8* iconPtr = GetMonIconPtr(species, personality, 1); + iconSheet.data = iconPtr; + iconSheet.size = 0x200; + iconSheet.tag = MON_ICON_LVLUP_BOX_TAG; + + iconPal = GetValidMonIconPalettePtr(species); + iconPalSheet.data = iconPal; + iconPalSheet.tag = MON_ICON_LVLUP_BOX_TAG; + + LoadSpriteSheet(&iconSheet); + LoadSpritePalette(&iconPalSheet); + + spriteId = CreateSprite(&sSpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0); + gSprites[spriteId].sDestroy = FALSE; + gSprites[spriteId].sSavedLvlUpBoxXPosition = gBattle_BG2_X; +} + +static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite) +{ + sprite->pos2.x = sprite->sSavedLvlUpBoxXPosition - gBattle_BG2_X; + + if (sprite->pos2.x != 0) + { + sprite->sDestroy = TRUE; + } + else if (sprite->sDestroy) + { + DestroySprite(sprite); + FreeSpriteTilesByTag(MON_ICON_LVLUP_BOX_TAG); + FreeSpritePaletteByTag(MON_ICON_LVLUP_BOX_TAG); + } +} + +#undef sDestroy +#undef sSavedLvlUpBoxXPosition + +static bool32 IsMonGettingExpSentOut(void) +{ + if (gBattlePartyID[0] == gBattleStruct->expGetterId) + return TRUE; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlePartyID[2] == gBattleStruct->expGetterId) + return TRUE; + + return FALSE; +} + +static void atk6D_reset_sentpokes_value(void) +{ + ResetSentPokesToOpponentValue(); + gBattlescriptCurrInstr++; +} + +static void atk6E_set_atk_to_player0(void) +{ + gBankAttacker = GetBankByIdentity(0); + gBattlescriptCurrInstr++; +} + +static void atk6F_set_visible(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk70_record_last_used_ability(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for bank argument. +} + +void BufferMoveToLearnIntoBattleTextBuff2(void) +{ + PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn); +} + +static void atk71_buffer_move_to_learn(void) +{ + BufferMoveToLearnIntoBattleTextBuff2(); + gBattlescriptCurrInstr++; +} + +static void atk72_jump_if_run_attempt_success(void) +{ + if (TryRunFromBattle(gBank1)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +static void atk73_hp_thresholds(void) +{ + u8 opposingBank; + s32 result; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + opposingBank = gActiveBank ^ BIT_SIDE; + + result = gBattleMons[opposingBank].hp * 100 / gBattleMons[opposingBank].maxHP; + if (result == 0) + result = 1; + + if (result > 69 || !gBattleMons[opposingBank].hp) + gBattleStruct->hpScale = 0; + else if (result > 39) + gBattleStruct->hpScale = 1; + else if (result > 9) + gBattleStruct->hpScale = 2; + else + gBattleStruct->hpScale = 3; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk74_hp_thresholds2(void) +{ + u8 opposingBank; + s32 result; + u8 hpSwitchout; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + opposingBank = gActiveBank ^ BIT_SIDE; + hpSwitchout = *(gBattleStruct->hpOnSwitchout + GetBankSide(opposingBank)); + result = (hpSwitchout - gBattleMons[opposingBank].hp) * 100 / hpSwitchout; + + if (gBattleMons[opposingBank].hp >= hpSwitchout) + gBattleStruct->hpScale = 0; + else if (result <= 29) + gBattleStruct->hpScale = 1; + else if (result <= 69) + gBattleStruct->hpScale = 2; + else + gBattleStruct->hpScale = 3; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk75_item_effect_on_opponent(void) +{ + gBankInMenu = gBankAttacker; + ExecuteTableBasedItemEffect(&gEnemyParty[gBattlePartyID[gBankAttacker]], gLastUsedItem, gBattlePartyID[gBankAttacker], 0, 1); + + gBattlescriptCurrInstr += 1; +} + +static void atk76_various(void) +{ + u8 side; + s32 i; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattlescriptCurrInstr[2]) + { + case VARIOUS_CANCEL_MULTI_TURN_MOVES: + CancelMultiTurnMoves(gActiveBank); + break; + case VARIOUS_SET_MAGIC_COAT_TARGET: + gBankAttacker = gBankTarget; + side = GetBankSide(gBankAttacker) ^ 1; + if (gSideTimers[side].followmeTimer != 0 && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + gBankTarget = gSideTimers[side].followmeTarget; + else + gBankTarget = gActiveBank; + break; + case VARIOUS_CAN_RUN_FROM_BATTLE: + gBattleCommunication[0] = IsRunningFromBattleImpossible(); + break; + case VARIOUS_GET_MOVE_TARGET: + gBankTarget = GetMoveTarget(gCurrentMove, 0); + break; + case 4: + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + gBattleCommunication[0] = 1; + else + gBattleCommunication[0] = 0; + break; + case VARIOUS_RESET_INTIMIDATE_TRACE_BITS: + gSpecialStatuses[gActiveBank].intimidatedPoke = 0; + gSpecialStatuses[gActiveBank].traced = 0; + break; + case VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP: + if (gBattlePartyID[0] == gBattleStruct->expGetterId || gBattlePartyID[2] == gBattleStruct->expGetterId) + { + u16 *choicedMove; + + if (gBattlePartyID[0] == gBattleStruct->expGetterId) + gActiveBank = 0; + else + gActiveBank = 2; + + choicedMove = &gBattleStruct->choicedMove[gActiveBank]; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gActiveBank].moves[i] == *choicedMove) + break; + } + if (i == 4) + *choicedMove = 0; + } + break; + case 7: + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE)) + && gBattleTypeFlags & BATTLE_TYPE_TRAINER + && gBattleMons[0].hp != 0 + && gBattleMons[1].hp != 0) + { + gHitMarker &= ~(HITMARKER_x400000); + } + break; + case 8: + gBattleCommunication[0] = 0; + gBattleScripting.bank = gActiveBank = gBattleCommunication[1]; + if (!(gBattleStruct->field_92 & gBitTable[gActiveBank]) + && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp + && gBattleMons[gActiveBank].hp != 0 + && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + { + gBattleStruct->field_92 |= gBitTable[gActiveBank]; + gBattleCommunication[0] = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = sUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)]; + } + break; + case 9: + i = sub_81A5258(gBattleCommunication); + if (i == 0) + return; + + gBattleCommunication[1] = i; + break; + case 10: + gBattleMons[1].hp = 0; + gHitMarker |= HITMARKER_FAINTED(1); + gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; + gDisableStructs[1].truantUnknownBit = 1; + break; + case 11: + gBattleMons[0].hp = 0; + gHitMarker |= HITMARKER_FAINTED(0); + gHitMarker |= HITMARKER_x400000; + gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; + gDisableStructs[0].truantUnknownBit = 1; + break; + case 12: + gBattleMons[0].hp = 0; + gBattleMons[1].hp = 0; + gHitMarker |= HITMARKER_FAINTED(0); + gHitMarker |= HITMARKER_FAINTED(1); + gHitMarker |= HITMARKER_x400000; + gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; + gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; + gDisableStructs[0].truantUnknownBit = 1; + gDisableStructs[1].truantUnknownBit = 1; + break; + case 13: + EmitCmd19(0); + MarkBufferBankForExecution(gActiveBank); + break; + case 14: + sub_81A5BF8(); + break; + case 15: + sub_81A5D44(); + break; + case 16: + BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]); + sub_814F9EC(gDisplayedStringBattle, 0x16); + break; + case 17: + if (IsTextPrinterActive(0x16)) + return; + break; + case VARIOUS_WAIT_CRY: + if (!IsCryFinished()) + return; + break; + case VARIOUS_RETURN_OPPONENT_MON1: + gActiveBank = 1; + if (gBattleMons[gActiveBank].hp != 0) + { + EmitReturnMonToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + break; + case VARIOUS_RETURN_OPPONENT_MON2: + if (gNoOfAllBanks > 3) + { + gActiveBank = 3; + if (gBattleMons[gActiveBank].hp != 0) + { + EmitReturnMonToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + break; + case 21: + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x55); + break; + case 22: + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100); + break; + case 23: + gBattleStruct->field_2A2 |= gBitTable[gActiveBank]; + break; + case 24: + if (sub_805725C(gActiveBank)) + return; + break; + case VARIOUS_SET_TELEPORT_OUTCOME: + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + gBattleOutcome = BATTLE_PLAYER_TELEPORTED; + else + gBattleOutcome = BATTLE_OPPONENT_TELEPORTED; + break; + case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC: + EmitPlayFanfareOrBGM(0, BGM_KACHI1, TRUE); + MarkBufferBankForExecution(gActiveBank); + break; + } + + gBattlescriptCurrInstr += 3; +} + +static void atk77_set_protect_like(void) // protect and endure +{ + bool8 notLastTurn = TRUE; + u16 lastMove = gUnknown_02024260[gBankAttacker]; + + if (lastMove != MOVE_PROTECT && lastMove != MOVE_DETECT && lastMove != MOVE_ENDURE) + gDisableStructs[gBankAttacker].protectUses = 0; + + if (gCurrentTurnActionNumber == (gNoOfAllBanks - 1)) + notLastTurn = FALSE; + + if (sProtectSuccessRates[gDisableStructs[gBankAttacker].protectUses] >= Random() && notLastTurn) + { + if (gBattleMoves[gCurrentMove].effect == EFFECT_PROTECT) + { + gProtectStructs[gBankAttacker].protected = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE) + { + gProtectStructs[gBankAttacker].endured = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gDisableStructs[gBankAttacker].protectUses++; + } + else + { + gDisableStructs[gBankAttacker].protectUses = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattleMoveFlags |= MOVESTATUS_MISSED; + } + + gBattlescriptCurrInstr++; +} + +static void atk78_faintifabilitynotdamp(void) +{ + if (gBattleExecBuffer) + return; + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBattleMons[gBankTarget].ability == ABILITY_DAMP) + break; + } + + if (gBankTarget == gNoOfAllBanks) + { + gActiveBank = gBankAttacker; + gBattleMoveDamage = gBattleMons[gActiveBank].hp; + EmitHealthBarUpdate(0, 0x7FFF); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr++; + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + } + else + { + gLastUsedAbility = ABILITY_DAMP; + RecordAbilityBattle(gBankTarget, gBattleMons[gBankTarget].ability); + gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; + } +} + +static void atk79_setatkhptozero(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = gBankAttacker; + gBattleMons[gActiveBank].hp = 0; + EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr++; +} + +static void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all targets. +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + for (gBankTarget++; ; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + + if (gBankTarget >= gNoOfAllBanks) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = jumpPtr; + } + else + gBattlescriptCurrInstr += 5; +} + +static void atk7B_healhalfHP_if_possible(void) +{ + const u8* failPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gBattlescriptCurrInstr[5] == BS_GET_ATTACKER) + gBankTarget = gBankAttacker; + + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + gBattlescriptCurrInstr = failPtr; + else + gBattlescriptCurrInstr += 6; +} + +static void atk7C_trymirrormove(void) +{ + s32 validMovesCount; + s32 i; + u16 move; + u16 movesArray[4]; + + for (i = 0; i < 3; i++) + movesArray[i] = 0; + + for (validMovesCount = 0, i = 0; i < gNoOfAllBanks; i++) + { + if (i != gBankAttacker) + { + move = *(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) + | (*(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) << 8); + + if (move != 0 && move != 0xFFFF) + { + movesArray[validMovesCount] = move; + validMovesCount++; + } + } + } + + move = *(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 0) + | (*(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 1) << 8); + + if (move != 0 && move != 0xFFFF) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gCurrentMove = move; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + else if (validMovesCount) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + i = Random() % validMovesCount; + gCurrentMove = movesArray[i]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr++; + } +} + +static void atk7D_set_rain(void) +{ + if (gBattleWeather & WEATHER_RAIN_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_RAIN_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gWishFutureKnock.weatherDuration = 5; + } + gBattlescriptCurrInstr++; +} + +static void atk7E_setreflect(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_REFLECT) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_REFLECT; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectBank = gBankAttacker; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gBattlescriptCurrInstr++; +} + +static void atk7F_setseeded(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT || gStatuses3[gBankTarget] & STATUS3_LEECHSEED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else if (gBattleMons[gBankTarget].type1 == TYPE_GRASS || gBattleMons[gBankTarget].type2 == TYPE_GRASS) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gStatuses3[gBankTarget] |= gBankAttacker; + gStatuses3[gBankTarget] |= STATUS3_LEECHSEED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + gBattlescriptCurrInstr++; +} + +static void atk80_manipulatedamage(void) +{ + switch (gBattlescriptCurrInstr[1]) + { + case ATK80_DMG_CHANGE_SIGN: + gBattleMoveDamage *= -1; + break; + case ATK80_DMG_HALF_BY_TWO_NOT_MORE_THAN_HALF_MAX_HP: + gBattleMoveDamage /= 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage) + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + break; + case ATK80_DMG_DOUBLED: + gBattleMoveDamage *= 2; + break; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk81_setrest(void) +{ + const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + gActiveBank = gBankTarget = gBankAttacker; + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP * (-1); + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + { + gBattlescriptCurrInstr = failJump; + } + else + { + if (gBattleMons[gBankTarget].status1 & ((u8)(~STATUS_SLEEP))) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + gBattleMons[gBankTarget].status1 = 3; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 5; + } +} + +static void atk82_jumpifnotfirstturn(void) +{ + const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gDisableStructs[gBankAttacker].isFirstTurn) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = failJump; +} + +static void atk83_nop(void) +{ + gBattlescriptCurrInstr++; +} + +bool8 UproarWakeUpCheck(u8 bank) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[bank].ability == ABILITY_SOUNDPROOF) + continue; + + gBattleScripting.bank = i; + + if (gBankTarget == 0xFF) + gBankTarget = i; + else if (gBankTarget == i) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + + break; + } + + if (i == gNoOfAllBanks) + return FALSE; + else + return TRUE; +} + +static void atk84_jump_if_cant_sleep(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (UproarWakeUpCheck(gBankTarget)) + { + gBattlescriptCurrInstr = jumpPtr; + } + else if (gBattleMons[gBankTarget].ability == ABILITY_INSOMNIA + || gBattleMons[gBankTarget].ability == ABILITY_VITAL_SPIRIT) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + gBattlescriptCurrInstr += 5; + } +} + +static void atk85_stockpile(void) +{ + if (gDisableStructs[gBankAttacker].stockpileCounter == 3) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gDisableStructs[gBankAttacker].stockpileCounter++; + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBankAttacker].stockpileCounter) + + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +static void atk86_stockpiletobasedamage(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + if (gDisableStructs[gBankAttacker].stockpileCounter == 0) + { + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if (gBattleCommunication[6] != 1) + { + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, + 0, gBankAttacker, gBankTarget) + * gDisableStructs[gBankAttacker].stockpileCounter; + gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; + + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + } + + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr += 5; + } +} + +static void atk87_stockpiletohpheal(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gDisableStructs[gBankAttacker].stockpileCounter == 0) + { + gBattlescriptCurrInstr = jumpPtr; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else if (gBattleMons[gBankAttacker].maxHP == gBattleMons[gBankAttacker].hp) + { + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr = jumpPtr; + gBankTarget = gBankAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / (1 << (3 - gDisableStructs[gBankAttacker].stockpileCounter)); + + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr += 5; + gBankTarget = gBankAttacker; + } +} + +static void atk88_negativedamage(void) +{ + gBattleMoveDamage = -(gHpDealt / 2); + if (gBattleMoveDamage == 0) + gBattleMoveDamage = -1; + + gBattlescriptCurrInstr++; +} + +static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) +{ + bool8 certain = 0; + bool8 notProtectAffected = FALSE; + u32 index; + + if (flags & MOVE_EFFECT_AFFECTS_USER) + gActiveBank = gBankAttacker; + else + gActiveBank = gBankTarget; + + flags &= ~(MOVE_EFFECT_AFFECTS_USER); + + if (flags & MOVE_EFFECT_CERTAIN) + certain++; + flags &= ~(MOVE_EFFECT_CERTAIN); + + if (flags & STAT_CHANGE_NOT_PROTECT_AFFECTED) + notProtectAffected++; + flags &= ~(STAT_CHANGE_NOT_PROTECT_AFFECTED); + + PREPARE_STAT_BUFFER(gBattleTextBuff1, statId) + + if ((statValue << 0x18) < 0) // stat decrease + { + if (gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && !certain && gCurrentMove != MOVE_CURSE) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBank].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_MistProtected; + gSpecialStatuses[gActiveBank].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gCurrentMove != MOVE_CURSE + && notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0)) + { + gBattlescriptCurrInstr = BattleScript_ButItFailed; + return STAT_CHANGE_DIDNT_WORK; + } + else if ((gBattleMons[gActiveBank].ability == ABILITY_CLEAR_BODY + || gBattleMons[gActiveBank].ability == ABILITY_WHITE_SMOKE) + && !certain && gCurrentMove != MOVE_CURSE) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBank].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + gSpecialStatuses[gActiveBank].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE + && !certain && statId == STAT_STAGE_ACC) + { + if (flags == STAT_CHANGE_BS_PTR) + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER + && !certain && statId == STAT_STAGE_ATK) + { + if (flags == STAT_CHANGE_BS_PTR) + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_SHIELD_DUST && flags == 0) + { + return STAT_CHANGE_DIDNT_WORK; + } + else // try to decrease + { + statValue = -GET_STAT_BUFF_VALUE(statValue); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + index = 1; + if (statValue == -2) + { + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = 0xD3; // harshly + gBattleTextBuff2[3] = 0xD3 >> 8; + index = 4; + } + gBattleTextBuff2[index] = B_BUFF_STRING; + index++; + gBattleTextBuff2[index] = 0xD4; // fell + index++; + gBattleTextBuff2[index] = 0xD4 >> 8; + index++; + gBattleTextBuff2[index] = B_BUFF_EOS; + + if (gBattleMons[gActiveBank].statStages[statId] == 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); + + } + } + else // stat increase + { + statValue = GET_STAT_BUFF_VALUE(statValue); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + index = 1; + if (statValue == 2) + { + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = 0xD1; // sharply + gBattleTextBuff2[3] = 0xD1 >> 8; + index = 4; + } + gBattleTextBuff2[index] = B_BUFF_STRING; + index++; + gBattleTextBuff2[index] = 0xD2; // rose + index++; + gBattleTextBuff2[index] = 0xD2 >> 8; + index++; + gBattleTextBuff2[index] = B_BUFF_EOS; + + if (gBattleMons[gActiveBank].statStages[statId] == 0xC) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); + } + + gBattleMons[gActiveBank].statStages[statId] += statValue; + if (gBattleMons[gActiveBank].statStages[statId] < 0) + gBattleMons[gActiveBank].statStages[statId] = 0; + if (gBattleMons[gActiveBank].statStages[statId] > 0xC) + gBattleMons[gActiveBank].statStages[statId] = 0xC; + + if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && flags & STAT_CHANGE_BS_PTR) + gBattleMoveFlags |= MOVESTATUS_MISSED; + + if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && !(flags & STAT_CHANGE_BS_PTR)) + return STAT_CHANGE_DIDNT_WORK; + + return STAT_CHANGE_WORKED; +} + +static void atk89_statbuffchange(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), gBattlescriptCurrInstr[1], jumpPtr) == STAT_CHANGE_WORKED) + gBattlescriptCurrInstr += 6; +} + +static void atk8A_normalisebuffs(void) // haze +{ + s32 i, j; + + for (i = 0; i < gNoOfAllBanks; i++) + { + for (j = 0; j < BATTLE_STATS_NO; j++) + gBattleMons[i].statStages[j] = 6; + } + + gBattlescriptCurrInstr++; +} + +static void atk8B_setbide(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gBankAttacker] = gCurrentMove; + gTakenDmg[gBankAttacker] = 0; + gBattleMons[gBankAttacker].status2 |= (STATUS2_BIDE - 0x100); // 2 turns + + gBattlescriptCurrInstr++; +} + +static void atk8C_confuseifrepeatingattackends(void) +{ + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_LOCK_CONFUSE)) + gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER); + + gBattlescriptCurrInstr++; +} + +static void atk8D_setmultihit_counter(void) +{ + if (gBattlescriptCurrInstr[1]) + { + gMultiHitCounter = gBattlescriptCurrInstr[1]; + } + else + { + gMultiHitCounter = Random() & 3; + if (gMultiHitCounter > 1) + gMultiHitCounter = (Random() & 3) + 2; + else + gMultiHitCounter += 2; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk8E_init_multihit_string(void) +{ + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) + + gBattlescriptCurrInstr++; +} + +static bool8 sub_8051064(void) +{ + if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + { + *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; + } + else + { + u16 random = Random() & 0xFF; + if ((u32)((random * (gBattleMons[gBankAttacker].level + gBattleMons[gBankTarget].level) >> 8) + 1) <= (gBattleMons[gBankTarget].level / 4)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + return FALSE; + } + *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; + } + + gBattlescriptCurrInstr = gUnknown_082DADD8; + return TRUE; +} + +static void atk8F_forcerandomswitch(void) +{ + s32 i; + s32 bank1PartyId = 0; + s32 bank2PartyId = 0; + + #ifdef NONMATCHING + s32 lastMonId = 0; // + 1 + #else + register s32 lastMonId asm("r8") = 0; // + 1 + #endif // NONMATCHING + + s32 firstMonId = 0; + s32 monsCount = 0; + struct Pokemon* party = NULL; + s32 validMons = 0; + s32 minNeeded = 0; + + if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER)) + { + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK) + || (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_x2000000) + || (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) + { + if ((gBankTarget & BIT_MON) != 0) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000)) + { + if (sub_806D82C(sub_806D864(gBankTarget)) == 1) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; // since there are two opponents, it has to be a double battle + } + else + { + if ((gBankTarget & BIT_MON) != 0) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + } + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; // there is only one pokemon out in single battles + bank1PartyId = gBattlePartyID[gBankTarget]; + } + + for (i = firstMonId; i < lastMonId; i++) + { + if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[i], MON_DATA_IS_EGG) + && GetMonData(&party[i], MON_DATA_HP) != 0) + { + validMons++; + } + } + + if (validMons <= minNeeded) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + if (sub_8051064()) + { + do + { + i = Random() % monsCount; + i += firstMonId; + } + while (i == bank2PartyId + || i == bank1PartyId + || GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE + || GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE + || GetMonData(&party[i], MON_DATA_HP) == 0); + } + *(gBattleStruct->field_5C + gBankTarget) = i; + + if (!sub_81B1250()) + sub_803BDA0(gBankTarget); + + if ((gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + sub_81B8E80(gBankTarget, i, 0); + sub_81B8E80(gBankTarget ^ BIT_MON, i, 1); + } + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + sub_80571DC(gBankTarget, i); + } + } + else + { + sub_8051064(); + } +} + +static void atk90_conversion_type_change(void) // randomly changes user's type to one of its moves' type +{ + u8 validMoves = 0; + u8 moveChecked; + u8 moveType; + + while (validMoves < 4) + { + if (gBattleMons[gBankAttacker].moves[validMoves] == 0) + break; + + validMoves++; + } + + for (moveChecked = 0; moveChecked < validMoves; moveChecked++) + { + moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; + + if (moveType == TYPE_MYSTERY) + { + if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) + moveType = TYPE_GHOST; + else + moveType = TYPE_NORMAL; + } + if (moveType != gBattleMons[gBankAttacker].type1 + && moveType != gBattleMons[gBankAttacker].type2) + { + break; + } + } + + if (moveChecked == validMoves) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + do + { + + while ((moveChecked = Random() & 3) >= validMoves); + + moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; + + if (moveType == TYPE_MYSTERY) + { + if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) + moveType = TYPE_GHOST; + else + moveType = TYPE_NORMAL; + } + } + while (moveType == gBattleMons[gBankAttacker].type1 || moveType == gBattleMons[gBankAttacker].type2); + + gBattleMons[gBankAttacker].type1 = moveType; + gBattleMons[gBankAttacker].type2 = moveType; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType) + + gBattlescriptCurrInstr += 5; + } +} + +static void atk91_givepaydaymoney(void) +{ + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && gPaydayMoney != 0) + { + u32 bonusMoney = gPaydayMoney * gBattleStruct->moneyMultiplier; + AddMoney(&gSaveBlock1Ptr->money, bonusMoney); + + PREPARE_HWORD_NUMBER_BUFFER(gBattleTextBuff1, 5, bonusMoney) + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PrintPayDayMoneyString; + } + else + { + gBattlescriptCurrInstr++; + } +} + +static void atk92_setlightscreen(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_LIGHTSCREEN) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_LIGHTSCREEN; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenBank = gBankAttacker; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + } + + gBattlescriptCurrInstr++; +} + +static void atk93_ko_move(void) +{ + u8 holdEffect, param; + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect; + param = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + param = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) + { + RecordItemEffectBattle(gBankTarget, HOLD_EFFECT_FOCUS_BAND); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_STURDY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gLastUsedAbility = ABILITY_STURDY; + gBattlescriptCurrInstr = BattleScript_SturdyPreventsOHKO; + RecordAbilityBattle(gBankTarget, ABILITY_STURDY); + } + else + { + u16 chance; + if (!(gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS)) + { + chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); + if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + chance = TRUE; + else + chance = FALSE; + } + else if (gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker + && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + { + chance = TRUE; + } + else + { + chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); + if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + chance = TRUE; + else + chance = FALSE; + } + if (chance) + { + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp; + gBattleMoveFlags |= MOVESTATUS_ONEHITKO; + } + gBattlescriptCurrInstr += 5; + } + else + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } +} + +static void atk94_damagetohalftargethp(void) // super fang +{ + gBattleMoveDamage = gBattleMons[gBankTarget].hp / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr++; +} + +static void atk95_setsandstorm(void) +{ + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_SANDSTORM_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gWishFutureKnock.weatherDuration = 5; + } + gBattlescriptCurrInstr++; +} + +static void atk96_weatherdamage(void) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + if (gBattleMons[gBankAttacker].type1 != TYPE_ROCK + && gBattleMons[gBankAttacker].type1 != TYPE_STEEL + && gBattleMons[gBankAttacker].type1 != TYPE_GROUND + && gBattleMons[gBankAttacker].type2 != TYPE_ROCK + && gBattleMons[gBankAttacker].type2 != TYPE_STEEL + && gBattleMons[gBankAttacker].type2 != TYPE_GROUND + && gBattleMons[gBankAttacker].ability != ABILITY_SAND_VEIL + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + else + { + gBattleMoveDamage = 0; + } + } + if (gBattleWeather & WEATHER_HAIL) + { + if (gBattleMons[gBankAttacker].type1 != TYPE_ICE + && gBattleMons[gBankAttacker].type2 != TYPE_ICE + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + else + { + gBattleMoveDamage = 0; + } + } + } + else + { + gBattleMoveDamage = 0; + } + + if (gAbsentBankFlags & gBitTable[gBankAttacker]) + gBattleMoveDamage = 0; + + gBattlescriptCurrInstr++; +} + +static void atk97_try_infatuation(void) +{ + struct Pokemon *monAttacker, *monTarget; + u16 speciesAttacker, speciesTarget; + u32 personalityAttacker, personalityTarget; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + monAttacker = &gPlayerParty[gBattlePartyID[gBankAttacker]]; + else + monAttacker = &gEnemyParty[gBattlePartyID[gBankAttacker]]; + + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + monTarget = &gPlayerParty[gBattlePartyID[gBankTarget]]; + else + monTarget = &gEnemyParty[gBattlePartyID[gBankTarget]]; + + speciesAttacker = GetMonData(monAttacker, MON_DATA_SPECIES); + personalityAttacker = GetMonData(monAttacker, MON_DATA_PERSONALITY); + + speciesTarget = GetMonData(monTarget, MON_DATA_SPECIES); + personalityTarget = GetMonData(monTarget, MON_DATA_PERSONALITY); + + if (gBattleMons[gBankTarget].ability == ABILITY_OBLIVIOUS) + { + gBattlescriptCurrInstr = BattleScript_ObliviousPreventsAttraction; + gLastUsedAbility = ABILITY_OBLIVIOUS; + RecordAbilityBattle(gBankTarget, ABILITY_OBLIVIOUS); + } + else + { + if (GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) + || gBattleMons[gBankTarget].status2 & STATUS2_INFATUATION + || GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == MON_GENDERLESS + || GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) == MON_GENDERLESS) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_INFATUATED_WITH(gBankAttacker); + gBattlescriptCurrInstr += 5; + } + } +} + +static void atk98_status_icon_update(void) +{ + if (gBattleExecBuffer) + return; + + if (gBattlescriptCurrInstr[1] != BS_ATTACKER_WITH_PARTNER) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } + else + { + gActiveBank = gBankAttacker; + if (!(gAbsentBankFlags & gBitTable[gActiveBank])) + { + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + } + if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + if (!(gAbsentBankFlags & gBitTable[gActiveBank])) + { + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + } + } + gBattlescriptCurrInstr += 2; + } +} + +static void atk99_setmist(void) +{ + if (gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistBank = gBankAttacker; + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_MIST; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +static void atk9A_set_focusenergy(void) +{ + if (gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMons[gBankAttacker].status2 |= STATUS2_FOCUS_ENERGY; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +static void atk9B_transformdataexecution(void) +{ + gLastUsedMove = 0xFFFF; + gBattlescriptCurrInstr++; + if (gBattleMons[gBankTarget].status2 & STATUS2_TRANSFORMED + || gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + s32 i; + u8 *battleMonAttacker, *battleMonTarget; + + gBattleMons[gBankAttacker].status2 |= STATUS2_TRANSFORMED; + gDisableStructs[gBankAttacker].disabledMove = 0; + gDisableStructs[gBankAttacker].disableTimer1 = 0; + gDisableStructs[gBankAttacker].unk0 = gBattleMons[gBankTarget].personality; + gDisableStructs[gBankAttacker].unk18_b = 0; + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].species) + + battleMonAttacker = (u8*)(&gBattleMons[gBankAttacker]); + battleMonTarget = (u8*)(&gBattleMons[gBankTarget]); + + for (i = 0; i < offsetof(struct BattlePokemon, pp); i++) + battleMonAttacker[i] = battleMonTarget[i]; + + for (i = 0; i < 4; i++) + { + if (gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp < 5) + gBattleMons[gBankAttacker].pp[i] = gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp; + else + gBattleMons[gBankAttacker].pp[i] = 5; + } + + gActiveBank = gBankAttacker; + EmitResetActionMoveSelection(0, RESET_MOVE_SELECTION); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } +} + +static void atk9C_set_substitute(void) +{ + u32 hp = gBattleMons[gBankAttacker].maxHP / 4; + if (gBattleMons[gBankAttacker].maxHP / 4 == 0) + hp = 1; + + if (gBattleMons[gBankAttacker].hp <= hp) + { + gBattleMoveDamage = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games) + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattleMons[gBankAttacker].status2 |= STATUS2_SUBSTITUTE; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); + gDisableStructs[gBankAttacker].substituteHP = gBattleMoveDamage; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; + } + + gBattlescriptCurrInstr++; +} + +static bool8 IsMoveUncopyableByMimic(u16 move) +{ + s32 i; + for (i = 0; sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END + && sMovesForbiddenToCopy[i] != move; i++); + + return (sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); +} + +static void atk9D_mimicattackcopy(void) +{ + gLastUsedMove = 0xFFFF; + + if (IsMoveUncopyableByMimic(gLastUsedMovesByBanks[gBankTarget]) + || gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED + || gLastUsedMovesByBanks[gBankTarget] == 0 + || gLastUsedMovesByBanks[gBankTarget] == 0xFFFF) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + + if (i == 4) + { + gBattleMons[gBankAttacker].moves[gCurrMovePos] = gLastUsedMovesByBanks[gBankTarget]; + if (gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp < 5) + gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp; + else + gBattleMons[gBankAttacker].pp[gCurrMovePos] = 5; + + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) + + gDisableStructs[gBankAttacker].unk18_b |= gBitTable[gCurrMovePos]; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } +} + +#ifdef NONMATCHING +static void atk9E_metronome(void) +{ + while (1) + { + const u16 *move; + s32 i, j; + + gCurrentMove = (Random() & 0x1FF) + 1; + if (gCurrentMove > LAST_MOVE_INDEX) + continue; + + for (i = 0; i < 4; i++); // ? + + for (move = sMovesForbiddenToCopy; ; move++) + { + if (*move == gCurrentMove) + break; + if (*move == METRONOME_FORBIDDEN_END) + break; + } + + if (*move == METRONOME_FORBIDDEN_END) + break; + } + + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); +} + +#else +__attribute__((naked)) +static void atk9E_metronome(void) +{ + asm( + "\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + ldr r7, =gCurrentMove\n\ + movs r6, 0xB1\n\ + lsls r6, 1\n\ + ldr r5, =sMovesForbiddenToCopy\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + mov r8, r0\n\ +_080524EE:\n\ + bl Random\n\ + ldr r2, =0x000001ff\n\ + adds r1, r2, 0\n\ + ands r0, r1\n\ + adds r0, 0x1\n\ + strh r0, [r7]\n\ + cmp r0, r6\n\ + bhi _080524EE\n\ + movs r0, 0x3\n\ +_08052502:\n\ + subs r0, 0x1\n\ + cmp r0, 0\n\ + bge _08052502\n\ + ldr r4, =gCurrentMove\n\ + ldrh r2, [r4]\n\ + ldr r3, =0x0000ffff\n\ + subs r0, r5, 0x2\n\ +_08052510:\n\ + adds r0, 0x2\n\ + ldrh r1, [r0]\n\ + cmp r1, r2\n\ + beq _0805251C\n\ + cmp r1, r3\n\ + bne _08052510\n\ +_0805251C:\n\ + ldr r0, =0x0000ffff\n\ + cmp r1, r0\n\ + bne _080524EE\n\ + ldr r2, =gHitMarker\n\ + ldr r0, [r2]\n\ + ldr r1, =0xfffffbff\n\ + ands r0, r1\n\ + str r0, [r2]\n\ + ldr r3, =gBattleScriptsForMoveEffects\n\ + ldr r2, =gBattleMoves\n\ + ldrh r1, [r4]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r2\n\ + ldrb r0, [r0]\n\ + lsls r0, 2\n\ + adds r0, r3\n\ + ldr r0, [r0]\n\ + mov r1, r8\n\ + str r0, [r1]\n\ + ldrh r0, [r4]\n\ + movs r1, 0\n\ + bl GetMoveTarget\n\ + ldr r1, =gBankTarget\n\ + strb r0, [r1]\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +static void atk9F_dmgtolevel(void) +{ + gBattleMoveDamage = gBattleMons[gBankAttacker].level; + gBattlescriptCurrInstr++; +} + +static void atkA0_psywavedamageeffect(void) +{ + s32 randDamage; + + while ((randDamage = (Random() & 0xF)) > 10); + + randDamage *= 10; + gBattleMoveDamage = gBattleMons[gBankAttacker].level * (randDamage + 50) / 100; + gBattlescriptCurrInstr++; +} + +static void atkA1_counterdamagecalculator(void) +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].physicalBank); + + if (gProtectStructs[gBankAttacker].physicalDmg + && sideAttacker != sideTarget + && gBattleMons[gProtectStructs[gBankAttacker].physicalBank].hp) + { + gBattleMoveDamage = gProtectStructs[gBankAttacker].physicalDmg * 2; + + if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + gBankTarget = gSideTimers[sideTarget].followmeTarget; + else + gBankTarget = gProtectStructs[gBankAttacker].physicalBank; + + gBattlescriptCurrInstr += 5; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].specialBank); + + if (gProtectStructs[gBankAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBankAttacker].specialBank].hp) + { + gBattleMoveDamage = gProtectStructs[gBankAttacker].specialDmg * 2; + + if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + gBankTarget = gSideTimers[sideTarget].followmeTarget; + else + gBankTarget = gProtectStructs[gBankAttacker].specialBank; + + gBattlescriptCurrInstr += 5; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA3_disablelastusedattack(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + if (gDisableStructs[gBankTarget].disabledMove == 0 + && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) + { + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].moves[i]) + + gDisableStructs[gBankTarget].disabledMove = gBattleMons[gBankTarget].moves[i]; + gDisableStructs[gBankTarget].disableTimer1 = (Random() & 3) + 2; + gDisableStructs[gBankTarget].disableTimer2 = gDisableStructs[gBankTarget].disableTimer1; // used to save the random amount of turns? + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA4_setencore(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + + if (gLastUsedMovesByBanks[gBankTarget] == MOVE_STRUGGLE + || gLastUsedMovesByBanks[gBankTarget] == MOVE_ENCORE + || gLastUsedMovesByBanks[gBankTarget] == MOVE_MIRROR_MOVE) + { + i = 4; + } + + if (gDisableStructs[gBankTarget].encoredMove == 0 + && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) + { + gDisableStructs[gBankTarget].encoredMove = gBattleMons[gBankTarget].moves[i]; + gDisableStructs[gBankTarget].encoredMovePos = i; + gDisableStructs[gBankTarget].encoreTimer1 = (Random() & 3) + 3; + gDisableStructs[gBankTarget].encoreTimer2 = gDisableStructs[gBankTarget].encoreTimer1; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA5_painsplitdmgcalc(void) +{ + if (!(gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE)) + { + s32 hpDiff = (gBattleMons[gBankAttacker].hp + gBattleMons[gBankTarget].hp) / 2; + s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBankTarget].hp - hpDiff; + u8* storeLoc = (void*)(&gBattleScripting.painSplitHp); + + storeLoc[0] = (painSplitHp); + storeLoc[1] = (painSplitHp & 0x0000FF00) >> 8; + storeLoc[2] = (painSplitHp & 0x00FF0000) >> 16; + storeLoc[3] = (painSplitHp & 0xFF000000) >> 24; + + gBattleMoveDamage = gBattleMons[gBankAttacker].hp - hpDiff; + gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#ifdef NONMATCHING +static void atkA6_settypetorandomresistance(void) // conversion 2 +{ + if (gUnknown_02024250[gBankAttacker] == 0 + || gUnknown_02024250[gBankAttacker] == 0xFFFF) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else if (IsTwoTurnsMove(gUnknown_02024250[gBankAttacker]) + && gBattleMons[gUnknown_02024270[gBankAttacker]].status2 & STATUS2_MULTIPLETURNS) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + s32 type = 0, rands = 0; + do + { + while (((type = (Random() & 0x7F)) > 0x70)); + + type *= 3; + + if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] + && gTypeEffectiveness[type + 2] <= 5 + && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] + && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) + { + gBattleMons[gBankAttacker].type1 = type; + gBattleMons[gBankAttacker].type2 = type; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, type) + + gBattlescriptCurrInstr += 5; + return; + } + + rands++; + } while (rands <= 999); + + type = 0, rands = 0; + do + { + s8 var = (s8)(gTypeEffectiveness[type]); + if (var > -1 || var < -2) + { + if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] + && gTypeEffectiveness[type + 2] <= 5 + && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] + && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) + { + gBattleMons[gBankAttacker].type1 = gTypeEffectiveness[rands + 1]; + gBattleMons[gBankAttacker].type2 = gTypeEffectiveness[rands + 1]; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, gTypeEffectiveness[rands + 1]) + + gBattlescriptCurrInstr += 5; + return; + } + } + type += 3, rands += 3; + } while (rands < 336); + + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#else +__attribute__((naked)) +static void atkA6_settypetorandomresistance(void) // conversion 2 +{ + 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\ + ldr r1, =gUnknown_02024250\n\ + ldr r4, =gBankAttacker\n\ + ldrb r0, [r4]\n\ + lsls r0, 1\n\ + adds r2, r0, r1\n\ + ldrh r1, [r2]\n\ + cmp r1, 0\n\ + beq _08052B7E\n\ + ldr r0, =0x0000ffff\n\ + cmp r1, r0\n\ + beq _08052B7E\n\ + ldrh r0, [r2]\n\ + bl IsTwoTurnsMove\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + beq _08052C1C\n\ + ldr r1, =gBattleMons\n\ + ldr r2, =gUnknown_02024270\n\ + ldrb r0, [r4]\n\ + adds r0, r2\n\ + ldrb r2, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r2\n\ + adds r1, 0x50\n\ + adds r0, r1\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 5\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08052C1C\n\ +_08052B7E:\n\ + ldr r3, =gBattlescriptCurrInstr\n\ + ldr r2, [r3]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + orrs r1, r0\n\ + str r1, [r3]\n\ + b _08052D08\n\ + .pool\n\ +_08052BB4:\n\ + mov r0, r12\n\ + strb r5, [r0]\n\ + mov r1, r10\n\ + ldrb r0, [r1]\n\ + muls r0, r2\n\ + adds r0, r7\n\ + adds r0, 0x22\n\ + strb r5, [r0]\n\ + ldr r1, =gBattleTextBuff1\n\ + movs r0, 0xFD\n\ + strb r0, [r1]\n\ + movs r0, 0x3\n\ + strb r0, [r1, 0x1]\n\ + strb r5, [r1, 0x2]\n\ + movs r0, 0xFF\n\ + strb r0, [r1, 0x3]\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + b _08052C0A\n\ + .pool\n\ +_08052BE0:\n\ + mov r0, r8\n\ + adds r0, 0x1\n\ + adds r0, r3\n\ + ldrb r2, [r0]\n\ + strb r2, [r4]\n\ + mov r4, r10\n\ + ldrb r0, [r4]\n\ + muls r0, r6\n\ + ldr r7, =gBattleMons\n\ + adds r0, r7\n\ + adds r0, 0x22\n\ + strb r2, [r0]\n\ + ldr r1, =gBattleTextBuff1\n\ + movs r0, 0xFD\n\ + strb r0, [r1]\n\ + movs r0, 0x3\n\ + strb r0, [r1, 0x1]\n\ + strb r2, [r1, 0x2]\n\ + movs r0, 0xFF\n\ + strb r0, [r1, 0x3]\n\ + mov r1, r12\n\ +_08052C0A:\n\ + ldr r0, [r1]\n\ + adds r0, 0x5\n\ + str r0, [r1]\n\ + b _08052D08\n\ + .pool\n\ +_08052C1C:\n\ + movs r4, 0\n\ + mov r8, r4\n\ + movs r7, 0x7F\n\ + mov r9, r7\n\ +_08052C24:\n\ + bl Random\n\ + mov r4, r9\n\ + ands r4, r0\n\ + cmp r4, 0x70\n\ + bhi _08052C24\n\ + lsls r0, r4, 1\n\ + adds r4, r0, r4\n\ + ldr r6, =gTypeEffectiveness\n\ + adds r3, r4, r6\n\ + ldr r1, =gUnknown_02024258\n\ + ldr r2, =gBankAttacker\n\ + ldrb r5, [r2]\n\ + lsls r0, r5, 1\n\ + adds r0, r1\n\ + ldrb r1, [r3]\n\ + mov r10, r2\n\ + ldrh r0, [r0]\n\ + cmp r1, r0\n\ + bne _08052C80\n\ + adds r0, r4, 0x2\n\ + adds r0, r6\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x5\n\ + bhi _08052C80\n\ + ldr r7, =gBattleMons\n\ + movs r2, 0x58\n\ + adds r0, r5, 0\n\ + muls r0, r2\n\ + adds r3, r0, r7\n\ + movs r0, 0x21\n\ + adds r0, r3\n\ + mov r12, r0\n\ + adds r0, r4, 0x1\n\ + adds r0, r6\n\ + ldrb r5, [r0]\n\ + mov r1, r12\n\ + ldrb r0, [r1]\n\ + adds r1, r5, 0\n\ + cmp r0, r1\n\ + beq _08052C80\n\ + adds r0, r3, 0\n\ + adds r0, 0x22\n\ + ldrb r0, [r0]\n\ + cmp r0, r1\n\ + bne _08052BB4\n\ +_08052C80:\n\ + movs r7, 0x1\n\ + add r8, r7\n\ + ldr r0, =0x000003e7\n\ + cmp r8, r0\n\ + ble _08052C24\n\ + movs r0, 0\n\ + mov r8, r0\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + mov r12, r1\n\ + ldr r3, =gTypeEffectiveness\n\ + adds r0, r4, 0x1\n\ + adds r0, r3\n\ + mov r9, r0\n\ + adds r5, r3, 0\n\ +_08052C9C:\n\ + ldrb r1, [r5]\n\ + cmp r1, 0xFF\n\ + bgt _08052CA6\n\ + cmp r1, 0xFE\n\ + bge _08052CE0\n\ +_08052CA6:\n\ + mov r4, r10\n\ + ldrb r2, [r4]\n\ + lsls r0, r2, 1\n\ + ldr r7, =gUnknown_02024258\n\ + adds r0, r7\n\ + ldrh r0, [r0]\n\ + cmp r1, r0\n\ + bne _08052CE0\n\ + ldrb r0, [r5, 0x2]\n\ + cmp r0, 0x5\n\ + bhi _08052CE0\n\ + movs r6, 0x58\n\ + adds r0, r2, 0\n\ + muls r0, r6\n\ + ldr r1, =gBattleMons\n\ + adds r2, r0, r1\n\ + adds r4, r2, 0\n\ + adds r4, 0x21\n\ + ldrb r0, [r4]\n\ + mov r7, r9\n\ + ldrb r1, [r7]\n\ + cmp r0, r1\n\ + beq _08052CE0\n\ + adds r0, r2, 0\n\ + adds r0, 0x22\n\ + ldrb r0, [r0]\n\ + cmp r0, r1\n\ + beq _08052CE0\n\ + b _08052BE0\n\ +_08052CE0:\n\ + adds r5, 0x3\n\ + movs r0, 0x3\n\ + add r8, r0\n\ + ldr r0, =0x0000014f\n\ + cmp r8, r0\n\ + bls _08052C9C\n\ + mov r1, r12\n\ + ldr r2, [r1]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + orrs r1, r0\n\ + mov r4, r12\n\ + str r1, [r4]\n\ +_08052D08:\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\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +static void atkA7_setalwayshitflag(void) +{ + gStatuses3[gBankTarget] &= ~(STATUS3_ALWAYS_HITS); + gStatuses3[gBankTarget] |= 0x10; + gDisableStructs[gBankTarget].bankWithSureHit = gBankAttacker; + gBattlescriptCurrInstr++; +} + +static void atkA8_copymovepermanently(void) // sketch +{ + gLastUsedMove = 0xFFFF; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) + && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_STRUGGLE + && gUnknownMovesUsedByBanks[gBankTarget] != 0 + && gUnknownMovesUsedByBanks[gBankTarget] != 0xFFFF + && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_SKETCH) + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == MOVE_SKETCH) + continue; + if (gBattleMons[gBankAttacker].moves[i] == gUnknownMovesUsedByBanks[gBankTarget]) + break; + } + + if (i != 4) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else // sketch worked + { + struct MovePpInfo movePpData; + + gBattleMons[gBankAttacker].moves[gCurrMovePos] = gUnknownMovesUsedByBanks[gBankTarget]; + gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gUnknownMovesUsedByBanks[gBankTarget]].pp; + gActiveBank = gBankAttacker; + + for (i = 0; i < 4; i++) + { + movePpData.move[i] = gBattleMons[gBankAttacker].moves[i]; + movePpData.pp[i] = gBattleMons[gBankAttacker].pp[i]; + } + movePpData.ppBonuses = gBattleMons[gBankAttacker].ppBonuses; + + EmitSetMonData(0, REQUEST_MOVES_PP_BATTLE, 0, sizeof(struct MovePpInfo), &movePpData); + MarkBufferBankForExecution(gActiveBank); + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gUnknownMovesUsedByBanks[gBankTarget]) + + gBattlescriptCurrInstr += 5; + } + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static bool8 IsTwoTurnsMove(u16 move) +{ + if (gBattleMoves[move].effect == EFFECT_SKULL_BASH + || gBattleMoves[move].effect == EFFECT_RAZOR_WIND + || gBattleMoves[move].effect == EFFECT_SKY_ATTACK + || gBattleMoves[move].effect == EFFECT_SOLARBEAM + || gBattleMoves[move].effect == EFFECT_FLY + || gBattleMoves[move].effect == EFFECT_BIDE) + return TRUE; + else + return FALSE; +} + +static bool8 IsInvalidForSleepTalkOrAssist(u16 move) +{ + if (move == 0 || move == MOVE_SLEEP_TALK || move == MOVE_ASSIST + || move == MOVE_MIRROR_MOVE || move == MOVE_METRONOME) + return TRUE; + else + return FALSE; +} + +static u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 +{ + // first argument is unused + if (gBattleMoves[move].effect == EFFECT_SOLARBEAM + && (gBattleWeather & WEATHER_SUN_ANY)) + return 2; + + if (gBattleMoves[move].effect == EFFECT_SKULL_BASH + || gBattleMoves[move].effect == EFFECT_RAZOR_WIND + || gBattleMoves[move].effect == EFFECT_SKY_ATTACK + || gBattleMoves[move].effect == EFFECT_SOLARBEAM + || gBattleMoves[move].effect == EFFECT_FLY + || gBattleMoves[move].effect == EFFECT_BIDE) + { + if ((gHitMarker & HITMARKER_x8000000)) + return 1; + } + return 2; +} + +static void atkA9_sleeptalk_choose_move(void) +{ + s32 i; + u8 unusableMovesBits = 0; + + for (i = 0; i < 4; i++) + { + if (IsInvalidForSleepTalkOrAssist(gBattleMons[gBankAttacker].moves[i]) + || gBattleMons[gBankAttacker].moves[i] == MOVE_FOCUS_PUNCH + || gBattleMons[gBankAttacker].moves[i] == MOVE_UPROAR + || IsTwoTurnsMove(gBattleMons[gBankAttacker].moves[i])) + { + unusableMovesBits |= gBitTable[i]; + } + + } + + unusableMovesBits = CheckMoveLimitations(gBankAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP)); + if (unusableMovesBits == 0xF) // all 4 moves cannot be chosen + { + gBattlescriptCurrInstr += 5; + } + else // at least one move can be chosen + { + u32 movePosition; + + do + { + movePosition = Random() & 3; + } while ((gBitTable[movePosition] & unusableMovesBits)); + + gRandomMove = gBattleMons[gBankAttacker].moves[movePosition]; + gCurrMovePos = movePosition; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gBankTarget = GetMoveTarget(gRandomMove, 0); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkAA_set_destinybond(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_DESTINY_BOND; + gBattlescriptCurrInstr++; +} + +static void DestinyBondFlagUpdate(void) +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gBankTarget); + if (gBattleMons[gBankTarget].status2 & STATUS2_DESTINY_BOND + && sideAttacker != sideTarget + && !(gHitMarker & HITMARKER_GRUDGE)) + { + gHitMarker |= HITMARKER_DESTINYBOND; + } +} + +static void atkAB_DestinyBondFlagUpdate(void) +{ + DestinyBondFlagUpdate(); + gBattlescriptCurrInstr++; +} + +static void atkAC_remaininghptopower(void) +{ + s32 i; + s32 hpFraction = GetScaledHPFraction(gBattleMons[gBankAttacker].hp, gBattleMons[gBankAttacker].maxHP, 48); + + for (i = 0; i < (s32) sizeof(sFlailHpScaleToPowerTable); i += 2) + { + if (hpFraction <= sFlailHpScaleToPowerTable[i]) + break; + } + + gDynamicBasePower = sFlailHpScaleToPowerTable[i + 1]; + gBattlescriptCurrInstr++; +} + +static void atkAD_spite_ppreduce(void) +{ + if (gLastUsedMovesByBanks[gBankTarget] != 0 + && gLastUsedMovesByBanks[gBankTarget] != 0xFFFF) + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gLastUsedMovesByBanks[gBankTarget] == gBattleMons[gBankTarget].moves[i]) + break; + } + + if (i != 4 && gBattleMons[gBankTarget].pp[i] > 1) + { + s32 ppToDeduct = (Random() & 3) + 2; + if (gBattleMons[gBankTarget].pp[i] < ppToDeduct) + ppToDeduct = gBattleMons[gBankTarget].pp[i]; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) + + ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, 0, 1); + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) + + gBattleMons[gBankTarget].pp[i] -= ppToDeduct; + gActiveBank = gBankTarget; + + if (!(gDisableStructs[gActiveBank].unk18_b & gBitTable[i]) + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBank].pp[i]); + MarkBufferBankForExecution(gActiveBank); + } + + gBattlescriptCurrInstr += 5; + + if (gBattleMons[gBankTarget].pp[i] == 0) + CancelMultiTurnMoves(gBankTarget); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkAE_heal_party_status(void) +{ + u32 zero = 0; + u8 toHeal = 0; + + if (gCurrentMove == MOVE_HEAL_BELL) + { + struct Pokemon* party; + s32 i; + + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleMons[gBankAttacker].ability != ABILITY_SOUNDPROOF) + { + gBattleMons[gBankAttacker].status1 = 0; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); + } + else + { + RecordAbilityBattle(gBankAttacker, gBattleMons[gBankAttacker].ability); + gBattleCommunication[MULTISTRING_CHOOSER] |= 1; + } + + gActiveBank = gBattleScripting.bank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + { + if (gBattleMons[gActiveBank].ability != ABILITY_SOUNDPROOF) + { + gBattleMons[gActiveBank].status1 = 0; + gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); + } + else + { + RecordAbilityBattle(gActiveBank, gBattleMons[gActiveBank].ability); + gBattleCommunication[MULTISTRING_CHOOSER] |= 2; + } + } + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES2); + u8 abilityBit = GetMonData(&party[i], MON_DATA_ALT_ABILITY); + + if (species != 0 && species != SPECIES_EGG) + { + u8 ability; + + if (gBattlePartyID[gBankAttacker] == i) + ability = gBattleMons[gBankAttacker].ability; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattlePartyID[gActiveBank] == i + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + ability = gBattleMons[gActiveBank].ability; + else + ability = GetAbilityBySpecies(species, abilityBit); + + if (ability != ABILITY_SOUNDPROOF) + toHeal |= (1 << i); + } + } + } + else // Aromatherapy + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + toHeal = 0x3F; + + gBattleMons[gBankAttacker].status1 = 0; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); + + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ 2); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + { + gBattleMons[gActiveBank].status1 = 0; + gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); + } + + } + + if (toHeal) + { + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, toHeal, 4, &zero); + MarkBufferBankForExecution(gActiveBank); + } + + gBattlescriptCurrInstr++; +} + +static void atkAF_cursetarget(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_CURSED) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_CURSED; + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr += 5; + } +} + +static void atkB0_set_spikes(void) +{ + u8 targetSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; + + if (gSideTimers[targetSide].spikesAmount == 3) + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gSideAffecting[targetSide] |= SIDE_STATUS_SPIKES; + gSideTimers[targetSide].spikesAmount++; + gBattlescriptCurrInstr += 5; + } +} + +static void atkB1_set_foresight(void) +{ + gBattleMons[gBankTarget].status2 |= STATUS2_FORESIGHT; + gBattlescriptCurrInstr++; +} + +static void atkB2_setperishsong(void) +{ + s32 i; + s32 notAffectedCount = 0; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gStatuses3[i] & STATUS3_PERISH_SONG + || gBattleMons[i].ability == ABILITY_SOUNDPROOF) + { + notAffectedCount++; + } + else + { + gStatuses3[i] |= STATUS3_PERISH_SONG; + gDisableStructs[i].perishSong1 = 3; + gDisableStructs[i].perishSong2 = 3; + } + } + + PressurePPLoseOnUsingPerishSong(gBankAttacker); + + if (notAffectedCount == gNoOfAllBanks) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +static void atkB3_rolloutdamagecalculation(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + CancelMultiTurnMoves(gBankAttacker); + gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; + } + else + { + s32 i; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) // first hit + { + gDisableStructs[gBankAttacker].rolloutCounter1 = 5; + gDisableStructs[gBankAttacker].rolloutCounter2 = 5; + gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gBankAttacker] = gCurrentMove; + } + if (--gDisableStructs[gBankAttacker].rolloutCounter1 == 0) // last hit + { + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_MULTIPLETURNS); + } + + gDynamicBasePower = gBattleMoves[gCurrentMove].power; + + for (i = 1; i < (5 - gDisableStructs[gBankAttacker].rolloutCounter1); i++) + gDynamicBasePower *= 2; + + if (gBattleMons[gBankAttacker].status2 & STATUS2_DEFENSE_CURL) + gDynamicBasePower *= 2; + + gBattlescriptCurrInstr++; + } +} + +static void atkB4_jumpifconfusedandstatmaxed(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_CONFUSION + && gBattleMons[gBankTarget].statStages[gBattlescriptCurrInstr[1]] == 0xC) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +static void atkB5_furycuttercalc(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gDisableStructs[gBankAttacker].furyCutterCounter = 0; + gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; + } + else + { + s32 i; + + if (gDisableStructs[gBankAttacker].furyCutterCounter != 5) + gDisableStructs[gBankAttacker].furyCutterCounter++; + + gDynamicBasePower = gBattleMoves[gCurrentMove].power; + + for (i = 1; i < gDisableStructs[gBankAttacker].furyCutterCounter; i++) + gDynamicBasePower *= 2; + + gBattlescriptCurrInstr++; + } +} + +static void atkB6_happinesstodamagecalculation(void) +{ + if (gBattleMoves[gCurrentMove].effect == EFFECT_RETURN) + gDynamicBasePower = 10 * (gBattleMons[gBankAttacker].friendship) / 25; + else // EFFECT_FRUSTRATION + gDynamicBasePower = 10 * (255 - gBattleMons[gBankAttacker].friendship) / 25; + + gBattlescriptCurrInstr++; +} + +static void atkB7_presentdamagecalculation(void) +{ + s32 rand = Random() & 0xFF; + + if (rand < 102) + gDynamicBasePower = 40; + else if (rand < 178) + gDynamicBasePower = 80; + else if (rand < 204) + gDynamicBasePower = 120; + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + } + if (rand < 204) + gBattlescriptCurrInstr = BattleScript_PresentDamageTarget; + else if (gBattleMons[gBankTarget].maxHP == gBattleMons[gBankTarget].hp) + gBattlescriptCurrInstr = BattleScript_AlreadyAtFullHp; + else + { + gBattleMoveFlags &= ~(MOVESTATUS_NOTAFFECTED); + gBattlescriptCurrInstr = BattleScript_PresentHealTarget; + } +} + +static void atkB8_set_safeguard(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_SAFEGUARD) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_SAFEGUARD; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardBank = gBankAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + + gBattlescriptCurrInstr++; +} + +static void atkB9_magnitudedamagecalculation(void) +{ + s32 magnitude = Random() % 100; + + if (magnitude < 5) + { + gDynamicBasePower = 10; + magnitude = 4; + } + else if (magnitude < 15) + { + gDynamicBasePower = 30; + magnitude = 5; + } + else if (magnitude < 35) + { + gDynamicBasePower = 50; + magnitude = 6; + } + else if (magnitude < 65) + { + gDynamicBasePower = 70; + magnitude = 7; + } + else if (magnitude < 85) + { + gDynamicBasePower = 90; + magnitude = 8; + } + else if (magnitude < 95) + { + gDynamicBasePower = 110; + magnitude = 9; + } + else + { + gDynamicBasePower = 150; + magnitude = 10; + } + + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 2, magnitude) + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) // a valid target was found + break; + } + + gBattlescriptCurrInstr++; +} + +static void atkBA_jumpifnopursuitswitchdmg(void) +{ + if (gMultiHitCounter == 1) + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1); + } + else + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2); + } + + if (gActionForBanks[gBankTarget] == 0 + && gBankAttacker == *(gBattleStruct->moveTarget + gBankTarget) + && !(gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) + && gBattleMons[gBankAttacker].hp + && !gDisableStructs[gBankTarget].truantCounter + && gChosenMovesByBanks[gBankTarget] == MOVE_PURSUIT) + { + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBanksByTurnOrder[i] == gBankTarget) + gActionsByTurnOrder[i] = 11; + } + + gCurrentMove = MOVE_PURSUIT; + gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovePositions + gBankTarget); + gBattlescriptCurrInstr += 5; + gBattleScripting.animTurn = 1; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkBB_setsunny(void) +{ + if (gBattleWeather & WEATHER_SUN_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_SUN_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gWishFutureKnock.weatherDuration = 5; + } + + gBattlescriptCurrInstr++; +} + +static void atkBC_maxattackhalvehp(void) // belly drum +{ + u32 halfHp = gBattleMons[gBankAttacker].maxHP / 2; + + if (!(gBattleMons[gBankAttacker].maxHP / 2)) + halfHp = 1; + + if (gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] < 12 + && gBattleMons[gBankAttacker].hp > halfHp) + { + gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] = 12; + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkBD_copyfoestats(void) // psych up +{ + s32 i; + + for (i = 0; i < BATTLE_STATS_NO; i++) + { + gBattleMons[gBankAttacker].statStages[i] = gBattleMons[gBankTarget].statStages[i]; + } + + gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter. +} + +static void atkBE_rapidspinfree(void) +{ + if (gBattleMons[gBankAttacker].status2 & STATUS2_WRAPPED) + { + gBattleScripting.bank = gBankTarget; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); + gBankTarget = *(gBattleStruct->wrappedBy + gBankAttacker); + + gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = B_BUFF_MOVE; + gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 0); + gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 1); + gBattleTextBuff1[4] = B_BUFF_EOS; + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_WrapFree; + } + else if (gStatuses3[gBankAttacker] & STATUS3_LEECHSEED) + { + gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED); + gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED_BANK); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_LeechSeedFree; + } + else if (gSideAffecting[GetBankSide(gBankAttacker)] & SIDE_STATUS_SPIKES) + { + gSideAffecting[GetBankSide(gBankAttacker)] &= ~(SIDE_STATUS_SPIKES); + gSideTimers[GetBankSide(gBankAttacker)].spikesAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SpikesFree; + } + else + { + gBattlescriptCurrInstr++; + } +} + +static void atkBF_set_defense_curl(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_DEFENSE_CURL; + gBattlescriptCurrInstr++; +} + +static void atkC0_recoverbasedonsunlight(void) +{ + gBankTarget = gBankAttacker; + + if (gBattleMons[gBankAttacker].hp != gBattleMons[gBankAttacker].maxHP) + { + if (gBattleWeather == 0 || !WEATHER_HAS_EFFECT) + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + else if (gBattleWeather & WEATHER_SUN_ANY) + gBattleMoveDamage = 20 * gBattleMons[gBankAttacker].maxHP / 30; + else // not sunny weather + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; + + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#ifdef NONMATCHING +static void atkC1_hidden_power(void) +{ + s32 powerBits; + s32 typeBits; + + powerBits = ((gBattleMons[gBankAttacker].hpIV & 2) >> 1) + | ((gBattleMons[gBankAttacker].attackIV & 2) << 0) + | ((gBattleMons[gBankAttacker].defenseIV & 2) << 1) + | ((gBattleMons[gBankAttacker].speedIV & 2) << 2) + | ((gBattleMons[gBankAttacker].spAttackIV & 2) << 3) + | ((gBattleMons[gBankAttacker].spDefenseIV & 2) << 4); + + typeBits = ((gBattleMons[gBankAttacker].hpIV & 1) << 0) + | ((gBattleMons[gBankAttacker].attackIV & 1) << 1) + | ((gBattleMons[gBankAttacker].defenseIV & 1) << 2) + | ((gBattleMons[gBankAttacker].speedIV & 1) << 3) + | ((gBattleMons[gBankAttacker].spAttackIV & 1) << 4) + | ((gBattleMons[gBankAttacker].spDefenseIV & 1) << 5); + + gDynamicBasePower = (40 * powerBits) / 63 + 30; + + gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1; + if (gBattleStruct->dynamicMoveType > 8) + gBattleStruct->dynamicMoveType++; + gBattleStruct->dynamicMoveType |= 0xC0; + + gBattlescriptCurrInstr++; +} + +#else +__attribute__((naked)) +static void atkC1_hidden_power(void) +{ + 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\ + ldr r2, =gBattleMons\n\ + ldr r0, =gBankAttacker\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + adds r4, r1, 0\n\ + muls r4, r0\n\ + adds r4, r2\n\ + ldrb r0, [r4, 0x14]\n\ + mov r10, r0\n\ + mov r7, r10\n\ + lsls r7, 27\n\ + adds r0, r7, 0\n\ + lsrs r0, 27\n\ + mov r10, r0\n\ + movs r1, 0x2\n\ + mov r2, r10\n\ + ands r2, r1\n\ + asrs r2, 1\n\ + ldrh r7, [r4, 0x14]\n\ + mov r9, r7\n\ + mov r0, r9\n\ + lsls r0, 22\n\ + mov r9, r0\n\ + lsrs r3, r0, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + orrs r2, r0\n\ + ldrb r7, [r4, 0x15]\n\ + mov r8, r7\n\ + mov r0, r8\n\ + lsls r0, 25\n\ + mov r8, r0\n\ + lsrs r3, r0, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 1\n\ + orrs r2, r0\n\ + ldr r6, [r4, 0x14]\n\ + lsls r6, 12\n\ + lsrs r3, r6, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 2\n\ + orrs r2, r0\n\ + ldrh r5, [r4, 0x16]\n\ + lsls r5, 23\n\ + lsrs r3, r5, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 3\n\ + orrs r2, r0\n\ + ldrb r3, [r4, 0x17]\n\ + lsls r3, 26\n\ + lsrs r0, r3, 27\n\ + ands r1, r0\n\ + lsls r1, 4\n\ + orrs r2, r1\n\ + movs r1, 0x1\n\ + adds r4, r1, 0\n\ + mov r7, r10\n\ + ands r4, r7\n\ + mov r0, r9\n\ + lsrs r0, 27\n\ + mov r9, r0\n\ + adds r0, r1, 0\n\ + mov r7, r9\n\ + ands r0, r7\n\ + lsls r0, 1\n\ + orrs r4, r0\n\ + mov r0, r8\n\ + lsrs r0, 27\n\ + mov r8, r0\n\ + adds r0, r1, 0\n\ + mov r7, r8\n\ + ands r0, r7\n\ + lsls r0, 2\n\ + orrs r4, r0\n\ + lsrs r6, 27\n\ + adds r0, r1, 0\n\ + ands r0, r6\n\ + lsls r0, 3\n\ + orrs r4, r0\n\ + lsrs r5, 27\n\ + adds r0, r1, 0\n\ + ands r0, r5\n\ + lsls r0, 4\n\ + orrs r4, r0\n\ + lsrs r3, 27\n\ + ands r1, r3\n\ + lsls r1, 5\n\ + orrs r4, r1\n\ + ldr r5, =gDynamicBasePower\n\ + lsls r0, r2, 2\n\ + adds r0, r2\n\ + lsls r0, 3\n\ + movs r1, 0x3F\n\ + bl __divsi3\n\ + adds r0, 0x1E\n\ + strh r0, [r5]\n\ + ldr r6, =gBattleStruct\n\ + ldr r5, [r6]\n\ + lsls r0, r4, 4\n\ + subs r0, r4\n\ + movs r1, 0x3F\n\ + bl __divsi3\n\ + adds r0, 0x1\n\ + strb r0, [r5, 0x13]\n\ + ldr r1, [r6]\n\ + ldrb r0, [r1, 0x13]\n\ + cmp r0, 0x8\n\ + bls _080544F0\n\ + adds r0, 0x1\n\ + strb r0, [r1, 0x13]\n\ +_080544F0:\n\ + ldr r2, [r6]\n\ + ldrb r0, [r2, 0x13]\n\ + movs r1, 0xC0\n\ + orrs r0, r1\n\ + strb r0, [r2, 0x13]\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + ldr r0, [r1]\n\ + adds r0, 0x1\n\ + str r0, [r1]\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\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +static void atkC2_selectnexttarget(void) +{ + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + gBattlescriptCurrInstr++; +} + +static void atkC3_setfutureattack(void) +{ + if (gWishFutureKnock.futureSightCounter[gBankTarget] != 0) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankTarget)] |= SIDE_STATUS_FUTUREATTACK; + gWishFutureKnock.futureSightMove[gBankTarget] = gCurrentMove; + gWishFutureKnock.futureSightAttacker[gBankTarget] = gBankAttacker; + gWishFutureKnock.futureSightCounter[gBankTarget] = 3; + gWishFutureKnock.futureSightDmg[gBankTarget] = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, + 0, gBankAttacker, gBankTarget); + + if (gProtectStructs[gBankAttacker].helpingHand) + gWishFutureKnock.futureSightDmg[gBankTarget] = gWishFutureKnock.futureSightDmg[gBankTarget] * 15 / 10; + + if (gCurrentMove == MOVE_DOOM_DESIRE) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + gBattlescriptCurrInstr += 5; + } +} + +static void atkC4_beat_up(void) +{ + struct Pokemon* party; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleMons[gBankTarget].hp == 0) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 beforeLoop = gBattleCommunication[0]; + for (;gBattleCommunication[0] < 6; gBattleCommunication[0]++) + { + if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) != SPECIES_EGG + && !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS)) + break; + } + if (gBattleCommunication[0] < 6) + { + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankAttacker, gBattleCommunication[0]) + + gBattlescriptCurrInstr += 9; + + gBattleMoveDamage = gBaseStats[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack; + gBattleMoveDamage *= gBattleMoves[gCurrentMove].power; + gBattleMoveDamage *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2); + gBattleMoveDamage /= gBaseStats[gBattleMons[gBankTarget].species].baseDefense; + gBattleMoveDamage = (gBattleMoveDamage / 50) + 2; + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + + gBattleCommunication[0]++; + } + else if (beforeLoop != 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 5); + } +} + +static void atkC5_setsemiinvulnerablebit(void) +{ + switch (gCurrentMove) + { + case MOVE_FLY: + case MOVE_BOUNCE: + gStatuses3[gBankAttacker] |= STATUS3_ON_AIR; + break; + case MOVE_DIG: + gStatuses3[gBankAttacker] |= STATUS3_UNDERGROUND; + break; + case MOVE_DIVE: + gStatuses3[gBankAttacker] |= STATUS3_UNDERWATER; + break; + } + + gBattlescriptCurrInstr++; +} + +static void atkC6_clearsemiinvulnerablebit(void) +{ + switch (gCurrentMove) + { + case MOVE_FLY: + case MOVE_BOUNCE: + gStatuses3[gBankAttacker] &= ~STATUS3_ON_AIR; + break; + case MOVE_DIG: + gStatuses3[gBankAttacker] &= ~STATUS3_UNDERGROUND; + break; + case MOVE_DIVE: + gStatuses3[gBankAttacker] &= ~STATUS3_UNDERWATER; + break; + } + + gBattlescriptCurrInstr++; +} + +static void atkC7_setminimize(void) +{ + if (gHitMarker & HITMARKER_OBEYS) + gStatuses3[gBankAttacker] |= STATUS3_MINIMIZED; + + gBattlescriptCurrInstr++; +} + +static void atkC8_sethail(void) +{ + if (gBattleWeather & WEATHER_HAIL_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_HAIL; + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + gWishFutureKnock.weatherDuration = 5; + } + + gBattlescriptCurrInstr++; +} + +static void atkC9_jumpifattackandspecialattackcannotfall(void) // memento +{ + if (gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] == 0 + && gBattleMons[gBankTarget].statStages[STAT_STAGE_SPATK] == 0 + && gBattleCommunication[6] != 1) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gActiveBank = gBankAttacker; + gBattleMoveDamage = gBattleMons[gActiveBank].hp; + EmitHealthBarUpdate(0, 0x7FFF); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 5; + } +} + +static void atkCA_setforcedtarget(void) // follow me +{ + gSideTimers[GetBankSide(gBankAttacker)].followmeTimer = 1; + gSideTimers[GetBankSide(gBankAttacker)].followmeTarget = gBankAttacker; + gBattlescriptCurrInstr++; +} + +static void atkCB_setcharge(void) +{ + gStatuses3[gBankAttacker] |= STATUS3_CHARGED_UP; + gDisableStructs[gBankAttacker].chargeTimer1 = 2; + gDisableStructs[gBankAttacker].chargeTimer2 = 2; + gBattlescriptCurrInstr++; +} + +static void atkCC_callterrainattack(void) // nature power +{ + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gCurrentMove = sNaturePowerMoves[gBattleTerrain]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattlescriptCurrInstr++; +} + +static void atkCD_cureifburnedparalysedorpoisoned(void) // refresh +{ + if (gBattleMons[gBankAttacker].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) + { + gBattleMons[gBankAttacker].status1 = 0; + gBattlescriptCurrInstr += 5; + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkCE_settorment(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_TORMENT) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_TORMENT; + gBattlescriptCurrInstr += 5; + } +} + +static void atkCF_jumpifnodamage(void) +{ + if (gProtectStructs[gBankAttacker].physicalDmg || gProtectStructs[gBankAttacker].specialDmg) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atkD0_settaunt(void) +{ + if (gDisableStructs[gBankTarget].tauntTimer1 == 0) + { + gDisableStructs[gBankTarget].tauntTimer1 = 2; + gDisableStructs[gBankTarget].tauntTimer2 = 2; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkD1_set_helpinghand(void) +{ + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gBankTarget]) + && !gProtectStructs[gBankAttacker].helpingHand + && !gProtectStructs[gBankTarget].helpingHand) + { + gProtectStructs[gBankTarget].helpingHand = 1; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkD2_swap_items(void) // trick +{ + // opponent can't swap items with player in regular battles + if (gBattleTypeFlags & BATTLE_TYPE_x4000000 + || (GetBankSide(gBankAttacker) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SECRET_BASE + | BATTLE_TYPE_x2000000)))) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gBankTarget); + + // you can't swap items if they were knocked off in regular battles + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SECRET_BASE + | BATTLE_TYPE_x2000000)) + && (gWishFutureKnock.knockedOffPokes[sideAttacker] & gBitTable[gBattlePartyID[gBankAttacker]] + || gWishFutureKnock.knockedOffPokes[sideTarget] & gBitTable[gBattlePartyID[gBankTarget]])) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + // can't swap if two pokemon don't have an item + // or if either of them is an enigma berry or a mail + else if ((gBattleMons[gBankAttacker].item == 0 && gBattleMons[gBankTarget].item == 0) + || gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY + || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY + || IS_ITEM_MAIL(gBattleMons[gBankAttacker].item) + || IS_ITEM_MAIL(gBattleMons[gBankTarget].item)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + // check if ability prevents swapping + else if (gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) + { + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; + gLastUsedAbility = gBattleMons[gBankTarget].ability; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + // took a while, but all checks passed and items can be safely swapped + else + { + u16 oldItemAtk, *newItemAtk; + + newItemAtk = &gBattleStruct->changedItems[gBankAttacker]; + oldItemAtk = gBattleMons[gBankAttacker].item; + *newItemAtk = gBattleMons[gBankTarget].item; + + gBattleMons[gBankAttacker].item = 0; + gBattleMons[gBankTarget].item = oldItemAtk; + + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk); + MarkBufferBankForExecution(gBankAttacker); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 1) = 0; + + gBattlescriptCurrInstr += 5; + + PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) + PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) + + if (oldItemAtk != 0 && *newItemAtk != 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; // attacker's item -> <- target's item + else if (oldItemAtk == 0 && *newItemAtk != 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; // nothing -> <- target's item + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; // attacker's item -> <- nothing + } + } +} + +static void atkD3_copy_ability(void) // role play +{ + if (gBattleMons[gBankTarget].ability != 0 + && gBattleMons[gBankTarget].ability != ABILITY_WONDER_GUARD) + { + gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkD4_wish_effect(void) +{ + switch (gBattlescriptCurrInstr[1]) + { + case 0: // use wish + if (gWishFutureKnock.wishCounter[gBankAttacker] == 0) + { + gWishFutureKnock.wishCounter[gBankAttacker] = 2; + gWishFutureKnock.wishUserID[gBankAttacker] = gBattlePartyID[gBankAttacker]; + gBattlescriptCurrInstr += 6; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + } + break; + case 1: // heal effect + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankTarget, gWishFutureKnock.wishUserID[gBankTarget]) + + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + + break; + } +} + +static void atkD5_setroots(void) // ingrain +{ + if (gStatuses3[gBankAttacker] & STATUS3_ROOTED) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankAttacker] |= STATUS3_ROOTED; + gBattlescriptCurrInstr += 5; + } +} + +static void atkD6_doubledamagedealtifdamaged(void) +{ + if ((gProtectStructs[gBankAttacker].physicalDmg + && gProtectStructs[gBankAttacker].physicalBank == gBankTarget) + || (gProtectStructs[gBankAttacker].specialDmg + && gProtectStructs[gBankAttacker].specialBank == gBankTarget)) + { + gBattleScripting.dmgMultiplier = 2; + } + + gBattlescriptCurrInstr++; +} + +static void atkD7_setyawn(void) +{ + if (gStatuses3[gBankTarget] & STATUS3_YAWN + || gBattleMons[gBankTarget].status1 & STATUS_ANY) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankTarget] |= 0x1000; + gBattlescriptCurrInstr += 5; + } +} + +static void atkD8_setdamagetohealthdifference(void) +{ + if (gBattleMons[gBankTarget].hp <= gBattleMons[gBankAttacker].hp) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - gBattleMons[gBankAttacker].hp; + gBattlescriptCurrInstr += 5; + } +} + +static void atkD9_scaledamagebyhealthratio(void) +{ + if (gDynamicBasePower == 0) + { + u8 power = gBattleMoves[gCurrentMove].power; + gDynamicBasePower = gBattleMons[gBankAttacker].hp * power / gBattleMons[gBankAttacker].maxHP; + if (gDynamicBasePower == 0) + gDynamicBasePower = 1; + } + gBattlescriptCurrInstr++; +} + +static void atkDA_abilityswap(void) // skill swap +{ + if ((gBattleMons[gBankAttacker].ability == 0 + && gBattleMons[gBankTarget].ability == 0) + || gBattleMons[gBankAttacker].ability == ABILITY_WONDER_GUARD + || gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD + || gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 abilityAtk = gBattleMons[gBankAttacker].ability; + gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; + gBattleMons[gBankTarget].ability = abilityAtk; + + gBattlescriptCurrInstr += 5; + } +} + +static void atkDB_imprisoneffect(void) +{ + if ((gStatuses3[gBankAttacker] & STATUS3_IMPRISONED_OTHERS)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 bank, sideAttacker; + + sideAttacker = GetBankSide(gBankAttacker); + PressurePPLoseOnUsingImprision(gBankAttacker); + for (bank = 0; bank < gNoOfAllBanks; bank++) + { + if (sideAttacker != GetBankSide(bank)) + { + s32 attackerMoveId; + for (attackerMoveId = 0; attackerMoveId < 4; attackerMoveId++) + { + s32 i; + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[attackerMoveId] == gBattleMons[bank].moves[i] + && gBattleMons[gBankAttacker].moves[attackerMoveId] != MOVE_NONE) + break; + } + if (i != 4) + break; + } + if (attackerMoveId != 4) + { + gStatuses3[gBankAttacker] |= STATUS3_IMPRISONED_OTHERS; + gBattlescriptCurrInstr += 5; + break; + } + } + } + if (bank == gNoOfAllBanks) // In Generation 3 games, Imprison fails if the user doesn't share any moves with any of the foes + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkDC_setgrudge(void) +{ + if (gStatuses3[gBankAttacker] & STATUS3_GRUDGE) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankAttacker] |= STATUS3_GRUDGE; + gBattlescriptCurrInstr += 5; + } +} + +static void atkDD_weightdamagecalculation(void) +{ + s32 i; + for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2) + { + if (sWeightToDamageTable[i] > GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), 1)) + break; + } + + if (sWeightToDamageTable[i] != 0xFFFF) + gDynamicBasePower = sWeightToDamageTable[i + 1]; + else + gDynamicBasePower = 120; + + gBattlescriptCurrInstr++; +} + +static void atkDE_asistattackselect(void) +{ + s32 chooseableMovesNo = 0; + struct Pokemon* party; + s32 monId, moveId; + u16* movesArray = gBattleStruct->assistPossibleMoves; + + if (GET_BANK_SIDE(gBankAttacker) != SIDE_PLAYER) + party = gEnemyParty; + else + party = gPlayerParty; + + for (monId = 0; monId < 6; monId++) + { + if (monId == gBattlePartyID[gBankAttacker]) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + + for (moveId = 0; moveId < 4; moveId++) + { + s32 i = 0; + u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); + + if (IsInvalidForSleepTalkOrAssist(move)) + continue; + + for (; sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != sMovesForbiddenToCopy[i]; i++); + + if (sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END) + continue; + if (move == MOVE_NONE) + continue; + + movesArray[chooseableMovesNo] = move; + chooseableMovesNo++; + } + } + if (chooseableMovesNo) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gRandomMove = movesArray[((Random() & 0xFF) * chooseableMovesNo) >> 8]; + gBankTarget = GetMoveTarget(gRandomMove, 0); + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkDF_setmagiccoat(void) +{ + gBankTarget = gBankAttacker; + gSpecialStatuses[gBankAttacker].flag20 = 1; + if (gCurrentTurnActionNumber == gNoOfAllBanks - 1) // moves last turn + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gProtectStructs[gBankAttacker].bounceMove = 1; + gBattlescriptCurrInstr += 5; + } +} + +static void atkE0_setstealstatchange(void) // snatch +{ + gSpecialStatuses[gBankAttacker].flag20 = 1; + if (gCurrentTurnActionNumber == gNoOfAllBanks - 1) // moves last turn + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gProtectStructs[gBankAttacker].stealMove = 1; + gBattlescriptCurrInstr += 5; + } +} + +static void atkE1_intimidate_string_loader(void) +{ + u8 side; + + gBattleScripting.bank = gBattleStruct->intimidateBank; + side = GetBankSide(gBattleScripting.bank); + + PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gBattleMons[gBattleScripting.bank].ability) + + for (;gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (GetBankSide(gBankTarget) == side) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + + if (gBankTarget >= gNoOfAllBanks) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +static void atkE2_switchout_abilities(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattleMons[gActiveBank].ability) + { + case ABILITY_NATURAL_CURE: + gBattleMons[gActiveBank].status1 = 0; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBank)], 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + break; + } + + gBattlescriptCurrInstr += 2; +} + +static void atkE3_jumpifhasnohp(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleMons[gActiveBank].hp == 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +static void atkE4_getsecretpowereffect(void) +{ + switch (gBattleTerrain) + { + case BATTLE_TERRAIN_GRASS: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_POISON; + break; + case BATTLE_TERRAIN_LONG_GRASS: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SLEEP; + break; + case BATTLE_TERRAIN_SAND: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ACC_MINUS_1; + break; + case BATTLE_TERRAIN_UNDERWATER: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_DEF_MINUS_1; + break; + case BATTLE_TERRAIN_WATER: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ATK_MINUS_1; + break; + case BATTLE_TERRAIN_POND: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1; + break; + case BATTLE_TERRAIN_ROCK: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION; + break; + case BATTLE_TERRAIN_CAVE: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH; + break; + default: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_PARALYSIS; + break; + } + gBattlescriptCurrInstr++; +} + +static void atkE5_pickup(void) +{ + if (!InBattlePike()) + { + s32 i; + u16 species, heldItem; + u8 ability; + + if (InBattlePyramid()) + { + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) + ability = gBaseStats[species].ability2; + else + ability = gBaseStats[species].ability1; + + if (ability == ABILITY_PICKUP + && species != 0 + && species != SPECIES_EGG + && heldItem == ITEM_NONE + && (Random() % 10) == 0) + { + heldItem = GetBattlePyramidPickupItemId(); + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &heldItem); + } + } + } + else + { + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) + ability = gBaseStats[species].ability2; + else + ability = gBaseStats[species].ability1; + + if (ability == ABILITY_PICKUP + && species != 0 + && species != SPECIES_EGG + && heldItem == ITEM_NONE + && (Random() % 10) == 0) + { + s32 j; + s32 rand = Random() % 100; + u8 lvlDivBy10 = (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) - 1) / 10; + if (lvlDivBy10 > 9) + lvlDivBy10 = 9; + + for (j = 0; j < 9; j++) + { + if (sPickupProbabilities[j] > rand) + { + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sPickupItems[lvlDivBy10 + j]); + break; + } + else if (rand == 99 || rand == 98) + { + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sRarePickupItems[lvlDivBy10 + (99 - rand)]); + break; + } + } + } + } + } + } + + gBattlescriptCurrInstr++; +} + +static void atkE6_castform_change_animation(void) +{ + gActiveBank = gBattleScripting.bank; + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) + *(&gBattleStruct->formToChangeInto) |= 0x80; + + EmitBattleAnimation(0, B_ANIM_CASTFORM_CHANGE, gBattleStruct->formToChangeInto); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr++; +} + +static void atkE7_castform_data_change(void) +{ + u8 form; + + gBattlescriptCurrInstr++; + form = CastformDataTypeChange(gBattleScripting.bank); + if (form) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + *(&gBattleStruct->formToChangeInto) = form - 1; + } +} + +static void atkE8_settypebasedhalvers(void) // water and mud sport +{ + bool8 worked = FALSE; + + if (gBattleMoves[gCurrentMove].effect == EFFECT_MUD_SPORT) + { + if (!(gStatuses3[gBankAttacker] & STATUS3_MUDSPORT)) + { + gStatuses3[gBankAttacker] |= STATUS3_MUDSPORT; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + worked = TRUE; + } + } + else // water sport + { + if (!(gStatuses3[gBankAttacker] & STATUS3_WATERSPORT)) + { + gStatuses3[gBankAttacker] |= STATUS3_WATERSPORT; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + worked = TRUE; + } + } + + if (worked) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atkE9_setweatherballtype(void) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleWeather & WEATHER_ANY) + gBattleScripting.dmgMultiplier = 2; + if (gBattleWeather & WEATHER_RAIN_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80; + else if (gBattleWeather & WEATHER_SANDSTORM_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80; + else if (gBattleWeather & WEATHER_SUN_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80; + else if (gBattleWeather & WEATHER_HAIL_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80; + else + *(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80; + } + + gBattlescriptCurrInstr++; +} + +static void atkEA_recycleitem(void) +{ + u16 *usedHeldItem; + + gActiveBank = gBankAttacker; + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; + if (*usedHeldItem != 0 && gBattleMons[gActiveBank].item == 0) + { + gLastUsedItem = *usedHeldItem; + *usedHeldItem = 0; + gBattleMons[gActiveBank].item = gLastUsedItem; + + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkEB_settypetoterrain(void) +{ + if (gBattleMons[gBankAttacker].type1 != sTerrainToType[gBattleTerrain] + && gBattleMons[gBankAttacker].type2 != sTerrainToType[gBattleTerrain]) + { + gBattleMons[gBankAttacker].type1 = sTerrainToType[gBattleTerrain]; + gBattleMons[gBankAttacker].type2 = sTerrainToType[gBattleTerrain]; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain]) + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkEC_pursuit_sth(void) +{ + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank]) + && gActionForBanks[gActiveBank] == 0 + && gChosenMovesByBanks[gActiveBank] == MOVE_PURSUIT) + { + gActionsByTurnOrder[gActiveBank] = 11; + gCurrentMove = MOVE_PURSUIT; + gBattlescriptCurrInstr += 5; + gBattleScripting.animTurn = 1; + gBattleScripting.field_20 = gBankAttacker; + gBankAttacker = gActiveBank; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkED_802B4B4(void) +{ + gEffectBank = gBankAttacker; + + if (gBankAttacker == gBankTarget) + gBankAttacker = gBankTarget = gBattleScripting.bank; + else + gBankTarget = gBattleScripting.bank; + + gBattleScripting.bank = gEffectBank; + gBattlescriptCurrInstr++; +} + +static void atkEE_removelightscreenreflect(void) // brick break +{ + u8 opposingSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; + + if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer) + { + gSideAffecting[opposingSide] &= ~(SIDE_STATUS_REFLECT); + gSideAffecting[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN); + gSideTimers[opposingSide].reflectTimer = 0; + gSideTimers[opposingSide].lightscreenTimer = 0; + gBattleScripting.animTurn = 1; + gBattleScripting.animTargetsHit = 1; + } + else + { + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + } + + gBattlescriptCurrInstr++; +} + +static void atkEF_pokeball_catch_calculation(void) +{ + u8 ballMultiplier = 0; + + if (gBattleExecBuffer) + return; + + gActiveBank = gBankAttacker; + gBankTarget = gBankAttacker ^ BIT_SIDE; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + EmitBallThrow(0, BALL_TRAINER_BLOCK); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_TrainerBallBlock; + } + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) + { + EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_WallyBallThrow; + } + else + { + u32 odds; + u8 catchRate; + + if (gLastUsedItem == ITEM_SAFARI_BALL) + catchRate = gBattleStruct->field_7C * 1275 / 100; + else + catchRate = gBaseStats[gBattleMons[gBankTarget].species].catchRate; + + if (gLastUsedItem > ITEM_SAFARI_BALL) + { + switch (gLastUsedItem) + { + case ITEM_NET_BALL: + if (gBattleMons[gBankTarget].type1 == TYPE_WATER + || gBattleMons[gBankTarget].type2 == TYPE_WATER + || gBattleMons[gBankTarget].type1 == TYPE_BUG + || gBattleMons[gBankTarget].type2 == TYPE_BUG) + ballMultiplier = 30; + else + ballMultiplier = 10; + break; + case ITEM_DIVE_BALL: + if (sav1_map_get_light_level() == 5) + ballMultiplier = 35; + else + ballMultiplier = 10; + break; + case ITEM_NEST_BALL: + if (gBattleMons[gBankTarget].level < 40) + { + ballMultiplier = 40 - gBattleMons[gBankTarget].level; + if (ballMultiplier <= 9) + ballMultiplier = 10; + } + else + { + ballMultiplier = 10; + } + break; + case ITEM_REPEAT_BALL: + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), FLAG_GET_CAUGHT)) + ballMultiplier = 30; + else + ballMultiplier = 10; + break; + case ITEM_TIMER_BALL: + ballMultiplier = gBattleResults.battleTurnCounter + 10; + if (ballMultiplier > 40) + ballMultiplier = 40; + break; + case ITEM_LUXURY_BALL: + case ITEM_PREMIER_BALL: + ballMultiplier = 10; + break; + } + } + else + ballMultiplier = sBallCatchBonuses[gLastUsedItem - 2]; + + odds = (catchRate * ballMultiplier / 10) + * (gBattleMons[gBankTarget].maxHP * 3 - gBattleMons[gBankTarget].hp * 2) + / (3 * gBattleMons[gBankTarget].maxHP); + + if (gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) + odds *= 2; + if (gBattleMons[gBankTarget].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) + odds = (odds * 15) / 10; + + if (gLastUsedItem != ITEM_SAFARI_BALL) + { + if (gLastUsedItem == ITEM_MASTER_BALL) + { + gBattleResults.usedMasterBall = TRUE; + } + else + { + if (gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL] < 0xFF) + gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]++; + } + } + + if (odds > 254) // mon caught + { + EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; + SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + + if (CalculatePlayerPartyCount() == 6) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else // mon may be caught, calculate shakes + { + u8 shakes; + + odds = Sqrt(Sqrt(16711680 / odds)); + odds = 1048560 / odds; + + for (shakes = 0; shakes < 4 && Random() < odds; shakes++); + + if (gLastUsedItem == ITEM_MASTER_BALL) + shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check? + + EmitBallThrow(0, shakes); + MarkBufferBankForExecution(gActiveBank); + + if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above + { + gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; + SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + + if (CalculatePlayerPartyCount() == 6) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else // not caught + { + gBattleCommunication[MULTISTRING_CHOOSER] = shakes; + gBattlescriptCurrInstr = BattleScript_ShakeBallThrow; + } + } + } +} + +static void atkF0_give_caught_mon(void) +{ + if (GiveMonToPlayer(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]) != MON_GIVEN_TO_PARTY) + { + if (!sub_813B21C()) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); + } + else + { + StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); + StringCopy(gStringVar3, GetBoxNamePtr(get_unknown_box_id())); + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + + if (FlagGet(SYS_PC_LANETTE)) + gBattleCommunication[MULTISTRING_CHOOSER]++; + } + + gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES, NULL); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick); + gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_POKEBALL, NULL); + + gBattlescriptCurrInstr++; +} + +static void atkF1_set_caught_mon_dex_flags(void) +{ + u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); + u32 personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY, NULL); + + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality); + gBattlescriptCurrInstr += 5; + } +} + +static void atkF2_display_dex_info(void) +{ + u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); + + switch (gBattleCommunication[0]) + { + case 0: + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleCommunication[0]++; + break; + case 1: + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + gBattleCommunication[TASK_ID] = CreateDexDisplayMonDataTask(SpeciesToNationalPokedexNum(species), + gBattleMons[gBankTarget].otId, + gBattleMons[gBankTarget].personality); + gBattleCommunication[0]++; + } + break; + case 2: + if (!gPaletteFade.active + && gMain.callback2 == BattleMainCB2 + && !gTasks[gBattleCommunication[TASK_ID]].isActive) + { + SetVBlankCallback(VBlankCB_Battle); + gBattleCommunication[0]++; + } + break; + case 3: + sub_80356D0(); + LoadBattleTextboxAndBackground(); + gBattle_BG3_X = 0x100; + gBattleCommunication[0]++; + break; + case 4: + if (!IsDma3ManagerBusyWithBgCopy()) + { + BeginNormalPaletteFade(0xFFFF, 0, 0x10, 0, 0); + ShowBg(0); + ShowBg(3); + gBattleCommunication[0]++; + } + break; + case 5: + if (!gPaletteFade.active) + gBattlescriptCurrInstr++; + break; + } +} + +void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags) +{ + s32 destY, destX; + u16 var = 0; + + for (destY = yStart; destY <= yEnd; destY++) + { + for (destX = xStart; destX <= xEnd; destX++) + { + if (destY == yStart) + { + if (destX == xStart) + var = 0x1022; + else if (destX == xEnd) + var = 0x1024; + else + var = 0x1023; + } + else if (destY == yEnd) + { + if (destX == xStart) + var = 0x1028; + else if (destX == xEnd) + var = 0x102A; + else + var = 0x1029; + } + else + { + if (destX == xStart) + var = 0x1025; + else if (destX == xEnd) + var = 0x1027; + else + var = 0x1026; + } + + if (flags & 1) + var = 0; + + if (flags & 0x80) + CopyToBgTilemapBufferRect_ChangePalette(1, &var, destX, destY, 1, 1, 0x11); + else + CopyToBgTilemapBufferRect_ChangePalette(0, &var, destX, destY, 1, 1, 0x11); + } + } +} + +void BattleCreateCursorAt(u8 cursorPosition) +{ + u16 src[2]; + src[0] = 1; + src[1] = 2; + + CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); + CopyBgTilemapBufferToVram(0); +} + +void BattleDestroyCursorAt(u8 cursorPosition) +{ + u16 src[2]; + src[0] = 0x1016; + src[1] = 0x1016; + + CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); + CopyBgTilemapBufferToVram(0); +} + +static void atkF3_nickname_caught_poke(void) +{ + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[MULTIUSE_STATE]++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[CURSOR_POSITION] == 0) + { + gBattleCommunication[MULTIUSE_STATE]++; + BeginFastPaletteFade(3); + } + else + { + gBattleCommunication[MULTIUSE_STATE] = 4; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleCommunication[MULTIUSE_STATE] = 4; + } + break; + case 2: + if (!gPaletteFade.active) + { + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); + FreeAllWindowBuffers(); + + DoNamingScreen(NAMING_SCREEN_CAUGHT_MON, gBattleStruct->caughtMonNick, + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES), + GetMonGender(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]), + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_PERSONALITY, NULL), + BattleMainCB2); + + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 3: + if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active ) + { + SetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + break; + case 4: + if (CalculatePlayerPartyCount() == 6) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + break; + } +} + +static void atkF4_subattackerhpbydmg(void) +{ + gBattleMons[gBankAttacker].hp -= gBattleMoveDamage; + gBattlescriptCurrInstr++; +} + +static void atkF5_removeattackerstatus1(void) +{ + gBattleMons[gBankAttacker].status1 = 0; + gBattlescriptCurrInstr++; +} + +static void atkF6_action_finished(void) +{ + gCurrentActionFuncId = ACTION_FINISHED; +} + +static void atkF7_turn_finished(void) +{ + gCurrentActionFuncId = ACTION_FINISHED; + gCurrentTurnActionNumber = gNoOfAllBanks; +} + +static void atkF8_trainer_slide_back(void) +{ + gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); + EmitTrainerSlideBack(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} diff --git a/src/battle_3.c b/src/battle_util.c index a2ddd1c2d..0a0badb33 100644 --- a/src/battle_3.c +++ b/src/battle_util.c @@ -13,11 +13,14 @@ #include "text.h" #include "string_util.h" #include "battle_message.h" -#include "battle_ai.h" +#include "battle_ai_script_commands.h" +#include "battle_controllers.h" #include "event_data.h" +#include "calculate_base_damage.h" +#include "link.h" extern const u8* gBattlescriptCurrInstr; -extern const u8* gUnknown_02024220[BATTLE_BANKS_COUNT]; +extern const u8* gBattlescriptPtrsForSelection[BATTLE_BANKS_COUNT]; extern const u8* gUnknown_02024230[BATTLE_BANKS_COUNT]; extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; extern u8 gActiveBank; @@ -30,8 +33,8 @@ extern u8 gBankAttacker; extern u8 gBankTarget; extern u8 gAbsentBankFlags; extern u16 gBattleWeather; -extern u8 gTurnOrder[BATTLE_BANKS_COUNT]; -extern u16 gSideAffecting[]; +extern u8 gBanksByTurnOrder[BATTLE_BANKS_COUNT]; +extern u16 gSideAffecting[2]; extern u8 gBattleCommunication[]; extern void (*gBattleMainFunc)(void); extern s32 gBattleMoveDamage; @@ -43,19 +46,19 @@ extern u32 gHitMarker; extern u8 gEffectBank; extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; extern u8 gBank1; -extern u16 gChosenMovesByBanks[]; +extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT]; extern u8 gBattleMoveFlags; extern s32 gTakenDmg[BATTLE_BANKS_COUNT]; extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT]; extern u8 gLastUsedAbility; -extern u8 gFightStateTracker; +extern u8 gCurrentActionFuncId; extern u32 gBattleExecBuffer; extern u16 gRandomMove; extern u8 gCurrMovePos; extern u8 gUnknown_020241E9; +extern u8 gSentPokesToOpponent[2]; extern const struct BattleMove gBattleMoves[]; -extern void (* const gBattleScriptingCommandsTable[])(void); // scripts extern const u8 gUnknown_082DAE2A[]; @@ -129,6 +132,8 @@ extern const u8 BattleScript_MoveHPDrain[]; extern const u8 BattleScript_MoveHPDrain_PPLoss[]; extern const u8 BattleScript_FlashFireBoost[]; extern const u8 BattleScript_FlashFireBoost_PPLoss[]; +extern const u8 gUnknown_082DB592[]; +extern const u8 gUnknown_082DB591[]; extern const u8 BattleScript_ColorChangeActivates[]; extern const u8 BattleScript_RoughSkinActivates[]; extern const u8 BattleScript_ApplySecondaryEffect[]; @@ -168,58 +173,295 @@ extern const u8 gUnknown_082DB6A5[]; //disobedient, uses a random move extern const u8 gUnknown_082DB6D9[]; //disobedient, went to sleep extern const u8 gUnknown_082DB6F0[]; //disobedient, hits itself -extern const u8 gStatusConditionString_PoisonJpn[]; -extern const u8 gStatusConditionString_SleepJpn[]; -extern const u8 gStatusConditionString_ParalysisJpn[]; -extern const u8 gStatusConditionString_BurnJpn[]; -extern const u8 gStatusConditionString_IceJpn[]; -extern const u8 gStatusConditionString_ConfusionJpn[]; -extern const u8 gStatusConditionString_LoveJpn[]; -extern const u16 gSoundMovesTable[]; - -extern void CancelMultiTurnMoves(u8 bank); -extern u8 b_first_side(u8, u8, u8); -extern void sub_803CEDC(u8, u8); -extern void b_call_bc_move_exec(const u8 *); -extern void BattleTurnPassed(void); -extern void EmitSetAttributes(u8 a, u8 request, u8 c, u8 bytes, void *data); -extern void SetMoveEffect(bool8 primary, u8 certainArg); -extern bool8 UproarWakeUpCheck(u8 bank); -extern void MarkBufferBankForExecution(u8 bank); -extern u8 sub_803F90C(u8 bank); -extern u8 GetBankIdentity(u8); -extern void sub_803F9EC(); -extern bool8 sub_80423F4(u8 bank, u8, u8); -extern s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideFlags, u16 powerOverride, u8 typeOverride, u8 bankAtk, u8 bankDef); -extern u8 GetBankByPlayerAI(u8); -extern u8 sub_806D864(u8); -extern u8 sub_806D82C(u8); extern u8 weather_get_current(void); -extern void sub_803E08C(void); -extern void bc_move_exec_returning(void); -extern s8 GetFlavourRelationByPersonality(u32 personality, u8 flavor); -u8 IsImprisoned(u8 bank, u16 move); -u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn); -u8 GetMoveTarget(u16 move, u8 useMoveTarget); -void b_push_move_exec(const u8* BS_ptr); +// rom const data +static const u16 sSoundMovesTable[] = +{ + MOVE_GROWL, MOVE_ROAR, MOVE_SING, MOVE_SUPERSONIC, MOVE_SCREECH, MOVE_SNORE, + MOVE_UPROAR, MOVE_METAL_SOUND, MOVE_GRASS_WHISTLE, MOVE_HYPER_VOICE, 0xFFFF +}; + +u8 GetBattleBank(u8 caseId) +{ + u8 ret = 0; + switch (caseId) + { + case BS_GET_TARGET: + ret = gBankTarget; + break; + case BS_GET_ATTACKER: + ret = gBankAttacker; + break; + case BS_GET_EFFECT_BANK: + ret = gEffectBank; + break; + case 7: + ret = 0; + break; + case BS_GET_SCRIPTING_BANK: + ret = gBattleScripting.bank; + break; + case 3: + ret = gBank1; + break; + case 5: + ret = gBank1; + break; + case 4: + case 6: + case 8: + case 9: + case BS_GET_PLAYER1: + ret = GetBankByIdentity(IDENTITY_PLAYER_MON1); + break; + case BS_GET_OPPONENT1: + ret = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + break; + case BS_GET_PLAYER2: + ret = GetBankByIdentity(IDENTITY_PLAYER_MON2); + break; + case BS_GET_OPPONENT2: + ret = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + break; + } + return ret; +} + +void PressurePPLose(u8 bankDef, u8 bankAtk, u16 move) +{ + s32 i; + + if (gBattleMons[bankDef].ability != ABILITY_PRESSURE) + return; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[bankAtk].moves[i] == move) + break; + } + + if (i == 4) // mons don't share any moves + return; + + if (gBattleMons[bankAtk].pp[i] != 0) + gBattleMons[bankAtk].pp[i]--; + + if (!(gBattleMons[bankAtk].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[bankAtk].unk18_b & gBitTable[i])) + { + gActiveBank = bankAtk; + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBank].pp[i]); + MarkBufferBankForExecution(gActiveBank); + } +} + +void PressurePPLoseOnUsingImprision(u8 bankAtk) +{ + s32 i, j; + s32 imprisionPos = 4; + u8 atkSide = GetBankSide(bankAtk); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (atkSide != GetBankSide(i) && gBattleMons[i].ability == ABILITY_PRESSURE) + { + for (j = 0; j < 4; j++) + { + if (gBattleMons[bankAtk].moves[j] == MOVE_IMPRISON) + break; + } + if (j != 4) + { + imprisionPos = j; + if (gBattleMons[bankAtk].pp[j] != 0) + gBattleMons[bankAtk].pp[j]--; + } + } + } + + if (imprisionPos != 4 + && !(gBattleMons[bankAtk].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[bankAtk].unk18_b & gBitTable[imprisionPos])) + { + gActiveBank = bankAtk; + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + imprisionPos, 0, 1, &gBattleMons[gActiveBank].pp[imprisionPos]); + MarkBufferBankForExecution(gActiveBank); + } +} + +void PressurePPLoseOnUsingPerishSong(u8 bankAtk) +{ + s32 i, j; + s32 perishSongPos = 4; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBattleMons[i].ability == ABILITY_PRESSURE && i != bankAtk) + { + for (j = 0; j < 4; j++) + { + if (gBattleMons[bankAtk].moves[j] == MOVE_PERISH_SONG) + break; + } + if (j != 4) + { + perishSongPos = j; + if (gBattleMons[bankAtk].pp[j] != 0) + gBattleMons[bankAtk].pp[j]--; + } + } + } + + if (perishSongPos != 4 + && !(gBattleMons[bankAtk].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[bankAtk].unk18_b & gBitTable[perishSongPos])) + { + gActiveBank = bankAtk; + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + perishSongPos, 0, 1, &gBattleMons[gActiveBank].pp[perishSongPos]); + MarkBufferBankForExecution(gActiveBank); + } +} + +void MarkAllBufferBanksForExecution(void) // unused +{ + s32 i; + + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + for (i = 0; i < gNoOfAllBanks; i++) + gBattleExecBuffer |= gBitTable[i] << 0x1C; + } + else + { + for (i = 0; i < gNoOfAllBanks; i++) + gBattleExecBuffer |= gBitTable[i]; + } +} + +void MarkBufferBankForExecution(u8 bank) +{ + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gBattleExecBuffer |= gBitTable[bank] << 0x1C; + } + else + { + gBattleExecBuffer |= gBitTable[bank]; + } +} + +void sub_803F850(u8 arg0) +{ + s32 i; + + for (i = 0; i < GetLinkPlayerCount(); i++) + gBattleExecBuffer |= gBitTable[arg0] << (i << 2); + + gBattleExecBuffer &= ~(0x10000000 << arg0); +} + +void CancelMultiTurnMoves(u8 bank) +{ + gBattleMons[bank].status2 &= ~(STATUS2_MULTIPLETURNS); + gBattleMons[bank].status2 &= ~(STATUS2_LOCK_CONFUSE); + gBattleMons[bank].status2 &= ~(STATUS2_UPROAR); + gBattleMons[bank].status2 &= ~(STATUS2_BIDE); + + gStatuses3[bank] &= ~(STATUS3_SEMI_INVULNERABLE); + + gDisableStructs[bank].rolloutCounter1 = 0; + gDisableStructs[bank].furyCutterCounter = 0; +} -void b_movescr_stack_push(const u8* bsPtr) +bool8 WasUnableToUseMove(u8 bank) +{ + if (gProtectStructs[bank].prlzImmobility + || gProtectStructs[bank].targetNotAffected + || gProtectStructs[bank].usedImprisionedMove + || gProtectStructs[bank].loveImmobility + || gProtectStructs[bank].usedDisabledMove + || gProtectStructs[bank].usedTauntedMove + || gProtectStructs[bank].flag2Unknown + || gProtectStructs[bank].flinchImmobility + || gProtectStructs[bank].confusionSelfDmg) + return TRUE; + else + return FALSE; +} + +void PrepareStringBattle(u16 stringId, u8 bank) +{ + gActiveBank = bank; + EmitPrintString(0, stringId); + MarkBufferBankForExecution(gActiveBank); +} + +void ResetSentPokesToOpponentValue(void) +{ + s32 i; + u32 bits = 0; + + gSentPokesToOpponent[0] = 0; + gSentPokesToOpponent[1] = 0; + + for (i = 0; i < gNoOfAllBanks; i += 2) + bits |= gBitTable[gBattlePartyID[i]]; + + for (i = 1; i < gNoOfAllBanks; i += 2) + gSentPokesToOpponent[(i & BIT_MON) >> 1] = bits; +} + +void sub_803F9EC(u8 bank) +{ + s32 i = 0; + u32 bits = 0; + + if (GetBankSide(bank) == SIDE_OPPONENT) + { + u8 id = ((bank & BIT_MON) >> 1); + gSentPokesToOpponent[id] = 0; + + for (i = 0; i < gNoOfAllBanks; i += 2) + { + if (!(gAbsentBankFlags & gBitTable[i])) + bits |= gBitTable[gBattlePartyID[i]]; + } + + gSentPokesToOpponent[id] = bits; + } +} + +void sub_803FA70(u8 bank) +{ + if (GetBankSide(bank) == SIDE_OPPONENT) + { + sub_803F9EC(bank); + } + else + { + s32 i; + for (i = 1; i < gNoOfAllBanks; i++) + gSentPokesToOpponent[(i & BIT_MON) >> 1] |= gBitTable[gBattlePartyID[bank]]; + } +} + +void BattleScriptPush(const u8* bsPtr) { BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = bsPtr; } -void b_movescr_stack_push_cursor(void) +void BattleScriptPushCursor(void) { BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = gBattlescriptCurrInstr; } -void b_movescr_stack_pop_cursor(void) +void BattleScriptPop(void) { gBattlescriptCurrInstr = BATTLESCRIPTS_STACK->ptr[--BATTLESCRIPTS_STACK->size]; } -u8 sub_803FB4C(void) // msg, can't select a move +u8 TrySetCantSelectMoveBattleScript(void) { u8 limitations = 0; u16 move = gBattleMons[gActiveBank].moves[gBattleBufferB[gActiveBank][2]]; @@ -237,7 +479,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DAE1F; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DAE1F; limitations = 1; } } @@ -252,7 +494,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB089; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB089; limitations++; } } @@ -267,12 +509,12 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB0A0; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB0A0; limitations++; } } - if (IsImprisoned(gActiveBank, move)) + if (GetImprisonedMovesCount(gActiveBank, move)) { gCurrentMove = move; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -282,7 +524,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB181; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB181; limitations++; } } @@ -304,7 +546,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB812; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB812; limitations++; } } @@ -317,7 +559,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB076; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB076; limitations++; } } @@ -325,13 +567,6 @@ u8 sub_803FB4C(void) // msg, can't select a move return limitations; } -#define MOVE_LIMITATION_ZEROMOVE (1 << 0) -#define MOVE_LIMITATION_PP (1 << 1) -#define MOVE_LIMITATION_DISABLED (1 << 2) -#define MOVE_LIMITATION_TORMENTED (1 << 3) -#define MOVE_LIMITATION_TAUNT (1 << 4) -#define MOVE_LIMITATION_IMPRISION (1 << 5) - u8 CheckMoveLimitations(u8 bank, u8 unusableMoves, u8 check) { u8 holdEffect; @@ -357,7 +592,7 @@ u8 CheckMoveLimitations(u8 bank, u8 unusableMoves, u8 check) unusableMoves |= gBitTable[i]; if (gDisableStructs[bank].tauntTimer1 && check & MOVE_LIMITATION_TAUNT && gBattleMoves[gBattleMons[bank].moves[i]].power == 0) unusableMoves |= gBitTable[i]; - if (IsImprisoned(bank, gBattleMons[bank].moves[i]) && check & MOVE_LIMITATION_IMPRISION) + if (GetImprisonedMovesCount(bank, gBattleMons[bank].moves[i]) && check & MOVE_LIMITATION_IMPRISION) unusableMoves |= gBitTable[i]; if (gDisableStructs[bank].encoreTimer1 && gDisableStructs[bank].encoredMove != gBattleMons[bank].moves[i]) unusableMoves |= gBitTable[i]; @@ -375,7 +610,7 @@ bool8 AreAllMovesUnusable(void) if (unusable == 0xF) // all moves are unusable { gProtectStructs[gActiveBank].onlyStruggle = 1; - gUnknown_02024220[gActiveBank] = BattleScript_NoMovesLeft; + gBattlescriptPtrsForSelection[gActiveBank] = BattleScript_NoMovesLeft; } else { @@ -385,7 +620,7 @@ bool8 AreAllMovesUnusable(void) return (unusable == 0xF); } -u8 IsImprisoned(u8 bank, u16 move) +u8 GetImprisonedMovesCount(u8 bank, u16 move) { s32 i; u8 imprisionedMoves = 0; @@ -393,7 +628,7 @@ u8 IsImprisoned(u8 bank, u16 move) for (i = 0; i < gNoOfAllBanks; i++) { - if (bankSide != GetBankSide(i) && gStatuses3[i] & STATUS3_IMPRISIONED) + if (bankSide != GetBankSide(i) && gStatuses3[i] & STATUS3_IMPRISONED_OTHERS) { s32 j; for (j = 0; j < 4; j++) @@ -430,15 +665,15 @@ u8 UpdateTurnCounters(void) case 0: for (i = 0; i < gNoOfAllBanks; i++) { - gTurnOrder[i] = i; + gBanksByTurnOrder[i] = i; } for (i = 0; i < gNoOfAllBanks - 1; i++) { s32 j; for (j = i + 1; j < gNoOfAllBanks; j++) { - if (b_first_side(gTurnOrder[i], gTurnOrder[j], 0)) - sub_803CEDC(i, j); + if (GetWhoStrikesFirst(gBanksByTurnOrder[i], gBanksByTurnOrder[j], 0)) + SwapTurnOrder(i, j); } } @@ -459,7 +694,7 @@ u8 UpdateTurnCounters(void) if (--gSideTimers[sideBank].reflectTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_REFLECT; - b_call_bc_move_exec(gUnknown_082DACFA); + BattleScriptExecute(gUnknown_082DACFA); gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 2; gBattleTextBuff1[2] = MOVE_REFLECT; @@ -488,7 +723,7 @@ u8 UpdateTurnCounters(void) if (--gSideTimers[sideBank].lightscreenTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_LIGHTSCREEN; - b_call_bc_move_exec(gUnknown_082DACFA); + BattleScriptExecute(gUnknown_082DACFA); gBattleCommunication[MULTISTRING_CHOOSER] = sideBank; gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 2; @@ -517,7 +752,7 @@ u8 UpdateTurnCounters(void) && --gSideTimers[sideBank].mistTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_MIST; - b_call_bc_move_exec(gUnknown_082DACFA); + BattleScriptExecute(gUnknown_082DACFA); gBattleCommunication[MULTISTRING_CHOOSER] = sideBank; gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 2; @@ -546,7 +781,7 @@ u8 UpdateTurnCounters(void) if (--gSideTimers[sideBank].safeguardTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_SAFEGUARD; - b_call_bc_move_exec(gUnknown_082DAD0B); + BattleScriptExecute(gUnknown_082DAD0B); effect++; } } @@ -563,13 +798,13 @@ u8 UpdateTurnCounters(void) case 5: while (gBattleStruct->turnSideTracker < gNoOfAllBanks) { - gActiveBank = gTurnOrder[gBattleStruct->turnSideTracker]; + gActiveBank = gBanksByTurnOrder[gBattleStruct->turnSideTracker]; if (gWishFutureKnock.wishCounter[gActiveBank] != 0 && --gWishFutureKnock.wishCounter[gActiveBank] == 0 && gBattleMons[gActiveBank].hp != 0) { gBankTarget = gActiveBank; - b_call_bc_move_exec(BattleScript_WishComesTrue); + BattleScriptExecute(BattleScript_WishComesTrue); effect++; } gBattleStruct->turnSideTracker++; @@ -601,7 +836,7 @@ u8 UpdateTurnCounters(void) gBattleCommunication[MULTISTRING_CHOOSER] = 1; else gBattleCommunication[MULTISTRING_CHOOSER] = 0; - b_call_bc_move_exec(gUnknown_082DAC2C); + BattleScriptExecute(gUnknown_082DAC2C); effect++; } gBattleStruct->turncountersTracker++; @@ -619,7 +854,7 @@ u8 UpdateTurnCounters(void) gBattleScripting.animArg1 = 0xC; gBattleCommunication[MULTISTRING_CHOOSER] = 0; - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turncountersTracker++; @@ -635,7 +870,7 @@ u8 UpdateTurnCounters(void) else gBattlescriptCurrInstr = gUnknown_082DACD2; - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turncountersTracker++; @@ -653,7 +888,7 @@ u8 UpdateTurnCounters(void) gBattleScripting.animArg1 = 0xD; gBattleCommunication[MULTISTRING_CHOOSER] = 1; - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turncountersTracker++; @@ -675,7 +910,7 @@ u8 TurnBasedEffects(void) gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_x20); while (gBattleStruct->turnEffectsBank < gNoOfAllBanks && gBattleStruct->turnEffectsTracker <= TURNBASED_MAX_CASE) { - gActiveBank = gBankAttacker = gTurnOrder[gBattleStruct->turnEffectsBank]; + gActiveBank = gBankAttacker = gBanksByTurnOrder[gBattleStruct->turnEffectsBank]; if (gAbsentBankFlags & gBitTable[gActiveBank]) { gBattleStruct->turnEffectsBank++; @@ -693,7 +928,7 @@ u8 TurnBasedEffects(void) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleMoveDamage *= -1; - b_call_bc_move_exec(BattleScript_IngrainTurnHeal); + BattleScriptExecute(BattleScript_IngrainTurnHeal); effect++; } gBattleStruct->turnEffectsTracker++; @@ -724,7 +959,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = 1; gBattleScripting.animArg1 = gBankTarget; gBattleScripting.animArg2 = gBankAttacker; - b_call_bc_move_exec(BattleScript_LeechSeedTurnDrain); + BattleScriptExecute(BattleScript_LeechSeedTurnDrain); effect++; } gBattleStruct->turnEffectsTracker++; @@ -735,7 +970,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_PoisonTurnDmg); + BattleScriptExecute(BattleScript_PoisonTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -749,7 +984,7 @@ u8 TurnBasedEffects(void) if ((gBattleMons[gActiveBank].status1 & 0xF00) != 0xF00) //not 16 turns gBattleMons[gActiveBank].status1 += 0x100; gBattleMoveDamage *= (gBattleMons[gActiveBank].status1 & 0xF00) >> 8; - b_call_bc_move_exec(BattleScript_PoisonTurnDmg); + BattleScriptExecute(BattleScript_PoisonTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -760,7 +995,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_BurnTurnDmg); + BattleScriptExecute(BattleScript_BurnTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -775,7 +1010,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_NightmareTurnDmg); + BattleScriptExecute(BattleScript_NightmareTurnDmg); effect++; } else @@ -791,7 +1026,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_CurseTurnDmg); + BattleScriptExecute(BattleScript_CurseTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -824,7 +1059,7 @@ u8 TurnBasedEffects(void) gBattleTextBuff1[4] = EOS; gBattlescriptCurrInstr = BattleScript_WrapEnds; } - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turnEffectsTracker++; @@ -840,9 +1075,9 @@ u8 TurnBasedEffects(void) gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP); gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); gBattleCommunication[MULTISTRING_CHOOSER] = 1; - b_call_bc_move_exec(gUnknown_082DB234); + BattleScriptExecute(gUnknown_082DB234); gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); break; } @@ -856,7 +1091,7 @@ u8 TurnBasedEffects(void) { gBankAttacker = gActiveBank; gBattleMons[gActiveBank].status2 -= 0x10; // uproar timer goes down - if (sub_803F90C(gActiveBank)) + if (WasUnableToUseMove(gActiveBank)) { CancelMultiTurnMoves(gActiveBank); gBattleCommunication[MULTISTRING_CHOOSER] = 1; @@ -871,7 +1106,7 @@ u8 TurnBasedEffects(void) gBattleCommunication[MULTISTRING_CHOOSER] = 1; CancelMultiTurnMoves(gActiveBank); } - b_call_bc_move_exec(gUnknown_082DB2A6); + BattleScriptExecute(gUnknown_082DB2A6); effect = 1; } } @@ -882,7 +1117,7 @@ u8 TurnBasedEffects(void) if (gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE) { gBattleMons[gActiveBank].status2 -= 0x400; - if (sub_803F90C(gActiveBank)) + if (WasUnableToUseMove(gActiveBank)) CancelMultiTurnMoves(gActiveBank); else if (!(gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE) && (gBattleMons[gActiveBank].status2 & STATUS2_MULTIPLETURNS)) @@ -893,7 +1128,7 @@ u8 TurnBasedEffects(void) gBattleCommunication[MOVE_EFFECT_BYTE] = 0x47; SetMoveEffect(1, 0); if (gBattleMons[gActiveBank].status2 & STATUS2_CONFUSION) - b_call_bc_move_exec(BattleScript_ThrashConfuses); + BattleScriptExecute(BattleScript_ThrashConfuses); effect++; } } @@ -917,7 +1152,7 @@ u8 TurnBasedEffects(void) else if (--gDisableStructs[gActiveBank].disableTimer1 == 0) // disable ends { gDisableStructs[gActiveBank].disabledMove = 0; - b_call_bc_move_exec(BattleScript_DisabledNoMore); + BattleScriptExecute(BattleScript_DisabledNoMore); effect++; } } @@ -936,7 +1171,7 @@ u8 TurnBasedEffects(void) { gDisableStructs[gActiveBank].encoredMove = 0; gDisableStructs[gActiveBank].encoreTimer1 = 0; - b_call_bc_move_exec(BattleScript_EncoredNoMore); + BattleScriptExecute(BattleScript_EncoredNoMore); effect++; } } @@ -967,10 +1202,10 @@ u8 TurnBasedEffects(void) { CancelMultiTurnMoves(gActiveBank); gBattleMons[gActiveBank].status1 |= (Random() & 3) + 2; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); gEffectBank = gActiveBank; - b_call_bc_move_exec(BattleScript_YawnMakesAsleep); + BattleScriptExecute(BattleScript_YawnMakesAsleep); effect++; } } @@ -1024,7 +1259,7 @@ bool8 sub_8041364(void) gBankAttacker = gWishFutureKnock.futureSightAttacker[gActiveBank]; gBattleMoveDamage = gWishFutureKnock.futureSightDmg[gActiveBank]; gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF; - b_call_bc_move_exec(gUnknown_082DAFE4); + BattleScriptExecute(gUnknown_082DAFE4); if (gWishFutureKnock.futureSightCounter[gActiveBank] == 0 && gWishFutureKnock.futureSightCounter[gActiveBank ^ 2] == 0) @@ -1044,7 +1279,7 @@ bool8 sub_8041364(void) case 1: while (gBattleStruct->field_1A1 < gNoOfAllBanks) { - gActiveBank = gBankAttacker = gTurnOrder[gBattleStruct->field_1A1]; + gActiveBank = gBankAttacker = gBanksByTurnOrder[gBattleStruct->field_1A1]; if (gAbsentBankFlags & gBitTable[gActiveBank]) { gBattleStruct->field_1A1++; @@ -1070,7 +1305,7 @@ bool8 sub_8041364(void) gDisableStructs[gActiveBank].perishSong1--; gBattlescriptCurrInstr = gUnknown_082DAF20; } - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); return 1; } } @@ -1092,7 +1327,7 @@ bool8 sub_8041364(void) CancelMultiTurnMoves(i); gBattlescriptCurrInstr = gUnknown_082DB8F3; - b_call_bc_move_exec(gUnknown_082DB8F3); + BattleScriptExecute(gUnknown_082DB8F3); gBattleStruct->field_1A0++; return 1; } @@ -1132,7 +1367,7 @@ bool8 sub_8041728(void) && !(gBattleStruct->field_DF & gBitTable[gBattlePartyID[gBattleStruct->field_4E]]) && !(gAbsentBankFlags & gBitTable[gBattleStruct->field_4E])) { - b_call_bc_move_exec(gUnknown_082DA7C4); + BattleScriptExecute(gUnknown_082DA7C4); gBattleStruct->field_4D = 2; return TRUE; } @@ -1153,11 +1388,11 @@ bool8 sub_8041728(void) case 4: do { - gBank1 = gBankTarget = gBattleStruct->field_4E; //or should banks be switched? + gBank1 = gBankTarget = gBattleStruct->field_4E; if (gBattleMons[gBattleStruct->field_4E].hp == 0 && !(gAbsentBankFlags & gBitTable[gBattleStruct->field_4E])) { - b_call_bc_move_exec(gUnknown_082DA7CD); + BattleScriptExecute(gUnknown_082DA7CD); gBattleStruct->field_4D = 5; return TRUE; } @@ -1182,7 +1417,7 @@ bool8 sub_8041728(void) return FALSE; } -void b_clear_atk_up_if_hit_flag_unless_enraged(void) +void TryClearRageStatuses(void) { int i; for (i = 0; i < gNoOfAllBanks; i++) @@ -1214,7 +1449,7 @@ u8 AtkCanceller_UnableToUseMove(void) { gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP); gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 1; gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; effect = 2; @@ -1242,7 +1477,7 @@ u8 AtkCanceller_UnableToUseMove(void) else { gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; effect = 2; @@ -1270,7 +1505,7 @@ u8 AtkCanceller_UnableToUseMove(void) else // unfreeze { gBattleMons[gBankAttacker].status1 &= ~(STATUS_FREEZE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; gBattleCommunication[MULTISTRING_CHOOSER] = 0; } @@ -1338,7 +1573,7 @@ u8 AtkCanceller_UnableToUseMove(void) gBattleStruct->atkCancellerTracker++; break; case 8: // imprisoned - if (IsImprisoned(gBankAttacker, gCurrentMove)) + if (GetImprisonedMovesCount(gBankAttacker, gCurrentMove)) { gProtectStructs[gBankAttacker].usedImprisionedMove = 1; CancelMultiTurnMoves(gBankAttacker); @@ -1357,7 +1592,7 @@ u8 AtkCanceller_UnableToUseMove(void) if (Random() & 1) { gBattleCommunication[MULTISTRING_CHOOSER] = 0; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); } else // confusion dmg { @@ -1371,7 +1606,7 @@ u8 AtkCanceller_UnableToUseMove(void) } else // snapped out of confusion { - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfusedNoMore; } effect = 1; @@ -1395,10 +1630,10 @@ u8 AtkCanceller_UnableToUseMove(void) { gBattleScripting.bank = CountTrailingZeroBits((gBattleMons[gBankAttacker].status2 & STATUS2_INFATUATION) >> 0x10); if (Random() & 1) - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); else { - b_movescr_stack_push(BattleScript_MoveUsedIsParalyzedCantAttack); + BattleScriptPush(BattleScript_MoveUsedIsParalyzedCantAttack); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gProtectStructs[gBankAttacker].loveImmobility = 1; CancelMultiTurnMoves(gBankAttacker); @@ -1440,7 +1675,7 @@ u8 AtkCanceller_UnableToUseMove(void) if (gBattleMoves[gCurrentMove].effect == EFFECT_THAW_HIT) { gBattleMons[gBankAttacker].status1 &= ~(STATUS_FREEZE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; gBattleCommunication[MULTISTRING_CHOOSER] = 1; } @@ -1457,7 +1692,7 @@ u8 AtkCanceller_UnableToUseMove(void) if (effect == 2) { gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); } return effect; @@ -1550,14 +1785,14 @@ bool8 sub_80423F4(u8 bank, u8 r1, u8 r2) { if (GetBankSide(bank) == SIDE_OPPONENT) { - r7 = GetBankByPlayerAI(1); - r6 = GetBankByPlayerAI(3); + r7 = GetBankByIdentity(1); + r6 = GetBankByIdentity(3); party = gEnemyParty; } else { - r7 = GetBankByPlayerAI(0); - r6 = GetBankByPlayerAI(2); + r7 = GetBankByIdentity(0); + r6 = GetBankByIdentity(2); party = gPlayerParty; } if (r1 == 6) @@ -1626,13 +1861,12 @@ u8 CastformDataTypeChange(u8 bank) return formChange; } -// We meet again, ABE. -#ifdef NONMATCHING +// The largest function in the game, but even it could not save itself from decompiling. u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { u8 effect = 0; - struct Pokemon* pokeAtk; - struct Pokemon* pokeDef; + struct Pokemon *pokeAtk; + struct Pokemon *pokeDef; u16 speciesAtk; u16 speciesDef; u32 pidAtk; @@ -1660,12 +1894,11 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) // why isn't that check done at the beginning? { - int i; // r4 + u8 moveType; + s32 i; u16 move; - // Hmm... - #define moveType moveArg - //u16 moveType; u8 side; + u8 target1; if (special) gLastUsedAbility = special; @@ -1685,83 +1918,80 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) switch (caseID) { case ABILITYEFFECT_ON_SWITCHIN: // 0 - //_08042A18 if (gBankAttacker >= gNoOfAllBanks) gBankAttacker = bank; switch (gLastUsedAbility) { - case 0xFF: //weather from overworld - //_08042A86 - switch (weather_get_current()) + case ABILITYEFFECT_SWITCH_IN_WEATHER: + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) { - case 3: - case 5: - case 13: - if (!(gBattleWeather & WEATHER_RAIN_ANY)) - { - gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT); - gBattleScripting.animArg1 = 0xA; - gBattleScripting.bank = bank; - effect++; - } - break; - case 8: - if (!(gBattleWeather & WEATHER_SANDSTORM_ANY)) + switch (weather_get_current()) { - gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); - gBattleScripting.animArg1 = 0xC; - gBattleScripting.bank = bank; - effect++; - } - break; - case 12: - if (!(gBattleWeather & WEATHER_SUN_ANY)) - { - gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); - gBattleScripting.animArg1 = 0xB; - gBattleScripting.bank = bank; - effect++; + case 3: + case 5: + case 13: + if (!(gBattleWeather & WEATHER_RAIN_ANY)) + { + gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT); + gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; + gBattleScripting.bank = bank; + effect++; + } + break; + case 8: + if (!(gBattleWeather & WEATHER_SANDSTORM_ANY)) + { + gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); + gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; + gBattleScripting.bank = bank; + effect++; + } + break; + case 12: + if (!(gBattleWeather & WEATHER_SUN_ANY)) + { + gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); + gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; + gBattleScripting.bank = bank; + effect++; + } + break; } - break; } if (effect) { gBattleCommunication[MULTISTRING_CHOOSER] = weather_get_current(); - b_push_move_exec(gUnknown_082DACE7); + BattleScriptPushCursorAndCallback(gUnknown_082DACE7); } break; case ABILITY_DRIZZLE: - //_08042B78 if (!(gBattleWeather & WEATHER_RAIN_PERMANENT)) { gBattleWeather = (WEATHER_RAIN_PERMANENT | WEATHER_RAIN_TEMPORARY); - b_push_move_exec(BattleScript_DrizzleActivates); + BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); gBattleScripting.bank = bank; effect++; } break; case ABILITY_SAND_STREAM: - //_08042BA8 if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT)) { gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); - b_push_move_exec(BattleScript_SandstreamActivates); + BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); gBattleScripting.bank = bank; effect++; } break; case ABILITY_DROUGHT: - //_08042BD8 if (!(gBattleWeather & WEATHER_SUN_PERMANENT)) { gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); - b_push_move_exec(BattleScript_DroughtActivates); + BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); gBattleScripting.bank = bank; effect++; } break; case ABILITY_INTIMIDATE: - //_08042C08 if (!(gSpecialStatuses[bank].intimidatedPoke)) { gStatuses3[bank] |= STATUS3_INTIMIDATE_POKES; @@ -1769,13 +1999,12 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } break; case ABILITY_FORECAST: - //_08042C3C effect = CastformDataTypeChange(bank); if (effect != 0) { - b_push_move_exec(BattleScript_CastformChange); + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); gBattleScripting.bank = bank; - gBattleStruct->formToChangeInto = effect - 1; + *(&gBattleStruct->formToChangeInto) = effect - 1; } break; case ABILITY_TRACE: @@ -1788,18 +2017,15 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) case ABILITY_CLOUD_NINE: case ABILITY_AIR_LOCK: { - u8 i; - - for (i = 0; i < gNoOfAllBanks; i++) + // that's a weird choice for a variable, why not use i or bank? + for (target1 = 0; target1 < gNoOfAllBanks; target1++) { - // TODO: i should be in r6 here - //asm("":::"r4","r5"); - effect = CastformDataTypeChange(i); + effect = CastformDataTypeChange(target1); if (effect != 0) { - b_push_move_exec(BattleScript_CastformChange); - gBattleScripting.bank = i; - gBattleStruct->formToChangeInto = effect - 1; + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.bank = target1; + *(&gBattleStruct->formToChangeInto) = effect - 1; break; } } @@ -1808,19 +2034,17 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } break; case ABILITYEFFECT_ENDTURN: // 1 - //_08042CDC if (gBattleMons[bank].hp != 0) { gBankAttacker = bank; switch (gLastUsedAbility) { case ABILITY_RAIN_DISH: - //_08042D22 if (WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) && gBattleMons[bank].maxHP > gBattleMons[bank].hp) { - gLastUsedAbility = ABILITY_RAIN_DISH; //why - b_push_move_exec(BattleScript_RainDishActivates); + gLastUsedAbility = ABILITY_RAIN_DISH; // why + BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates); gBattleMoveDamage = gBattleMons[bank].maxHP / 16; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; @@ -1829,7 +2053,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } break; case ABILITY_SHED_SKIN: - //_08042DA0 if ((gBattleMons[bank].status1 & STATUS_ANY) && (Random() % 3) == 0) { if (gBattleMons[bank].status1 & (STATUS_POISON | STATUS_TOXIC_POISON)) @@ -1843,22 +2066,21 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (gBattleMons[bank].status1 & STATUS_FREEZE) StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); gBattleMons[bank].status1 = 0; - gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); // fix nighmare glitch + gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); // fix nightmare glitch gBattleScripting.bank = gActiveBank = bank; - b_push_move_exec(BattleScript_ShedSkinActivates); - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); + BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); MarkBufferBankForExecution(gActiveBank); effect++; } break; case ABILITY_SPEED_BOOST: - //_08042E84 if (gBattleMons[bank].statStages[STAT_STAGE_SPEED] < 0xC && gDisableStructs[bank].isFirstTurn != 2) { gBattleMons[bank].statStages[STAT_STAGE_SPEED]++; gBattleScripting.animArg1 = 0x11; gBattleScripting.animArg2 = 0; - b_push_move_exec(BattleScript_SpeedBoostActivates); + BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates); gBattleScripting.bank = bank; effect++; } @@ -1870,15 +2092,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } break; case ABILITYEFFECT_MOVES_BLOCK: // 2 - //_08042EF8 if (gLastUsedAbility == ABILITY_SOUNDPROOF) { - for (i = 0; gSoundMovesTable[i] != 0xFFFF; i++) + for (i = 0; sSoundMovesTable[i] != 0xFFFF; i++) { - if (gSoundMovesTable[i] == move) + if (sSoundMovesTable[i] == move) break; } - if (gSoundMovesTable[i] != 0xFFFF) + if (sSoundMovesTable[i] != 0xFFFF) { if (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS) gHitMarker |= HITMARKER_NO_PPDEDUCT; @@ -1899,6 +2120,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattlescriptCurrInstr = BattleScript_MoveHPDrain; else gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; + effect = 1; } break; @@ -1909,11 +2131,11 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattlescriptCurrInstr = BattleScript_MoveHPDrain; else gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; + effect = 1; } break; case ABILITY_FLASH_FIRE: - //_0804305C if (moveType == TYPE_FIRE && !(gBattleMons[bank].status1 & STATUS_FREEZE)) { if (!(gBattleResources->flags->flags[bank] & UNKNOWN_FLAG_FLASH_FIRE)) @@ -1923,6 +2145,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattlescriptCurrInstr = BattleScript_FlashFireBoost; else gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; + gBattleResources->flags->flags[bank] |= UNKNOWN_FLAG_FLASH_FIRE; effect = 2; } @@ -1933,6 +2156,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattlescriptCurrInstr = BattleScript_FlashFireBoost; else gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; + effect = 2; } } @@ -1943,9 +2167,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (gBattleMons[bank].maxHP == gBattleMons[bank].hp) { if ((gProtectStructs[gBankAttacker].notFirstStrike)) - gBattlescriptCurrInstr = BattleScript_MoveHPDrain; + gBattlescriptCurrInstr = gUnknown_082DB592; else - gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; + gBattlescriptCurrInstr = gUnknown_082DB591; } else { @@ -1958,11 +2182,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } break; case ABILITYEFFECT_CONTACT: // 4 - //_080431AC switch (gLastUsedAbility) { case ABILITY_COLOR_CHANGE: - //_08043288 if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && move != MOVE_STRUGGLE && gBattleMoves[move].power != 0 @@ -1973,17 +2195,13 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { gBattleMons[bank].type1 = moveType; gBattleMons[bank].type2 = moveType; - gBattleTextBuff1[0] = 0xFD; - gBattleTextBuff1[1] = 3; - gBattleTextBuff1[2] = moveType; - gBattleTextBuff1[3] = 0xFF; - b_movescr_stack_push_cursor(); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType) + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ColorChangeActivates; effect++; } break; case ABILITY_ROUGH_SKIN: - //_08043350 if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && gBattleMons[gBankAttacker].hp != 0 && !gProtectStructs[gBankAttacker].confusionSelfDmg @@ -1993,13 +2211,12 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_RoughSkinActivates; effect++; } break; case ABILITY_EFFECT_SPORE: - //_08043410 if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && gBattleMons[gBankAttacker].hp != 0 && !gProtectStructs[gBankAttacker].confusionSelfDmg @@ -2011,10 +2228,12 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { gBattleCommunication[MOVE_EFFECT_BYTE] = Random() & 3; } while (gBattleCommunication[MOVE_EFFECT_BYTE] == 0); - if (gBattleCommunication[MOVE_EFFECT_BYTE] == 3) - gBattleCommunication[MOVE_EFFECT_BYTE] += 2; - gBattleCommunication[MOVE_EFFECT_BYTE] += 0x40; - b_movescr_stack_push_cursor(); + + if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) + gBattleCommunication[MOVE_EFFECT_BYTE] += 2; // 5 MOVE_EFFECT_PARALYSIS + + gBattleCommunication[MOVE_EFFECT_BYTE] += MOVE_EFFECT_AFFECTS_USER; + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2028,8 +2247,8 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) && (Random() % 3) == 0) { - gBattleCommunication[MOVE_EFFECT_BYTE] = 0x42; - b_movescr_stack_push_cursor(); + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2043,8 +2262,8 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) && (Random() % 3) == 0) { - gBattleCommunication[MOVE_EFFECT_BYTE] = 0x45; - b_movescr_stack_push_cursor(); + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2058,15 +2277,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special) && (Random() % 3) == 0) { - gBattleCommunication[MOVE_EFFECT_BYTE] = 0x43; - b_movescr_stack_push_cursor(); + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN; + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; } break; case ABILITY_CUTE_CHARM: - //_0804379C if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && gBattleMons[gBankAttacker].hp != 0 && !gProtectStructs[gBankAttacker].confusionSelfDmg @@ -2077,11 +2295,11 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && gBattleMons[gBankAttacker].ability != ABILITY_OBLIVIOUS && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) && !(gBattleMons[gBankAttacker].status2 & STATUS2_INFATUATION) - && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != 0xFF - && GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != 0xFF) + && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != MON_GENDERLESS + && GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != MON_GENDERLESS) { - gBattleMons[gBankAttacker].status2 |= (gBitTable[gBankTarget] << 0x10); - b_movescr_stack_push_cursor(); + gBattleMons[gBankAttacker].status2 |= STATUS2_INFATUATED_WITH(gBankTarget); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_CuteCharmActivates; effect++; } @@ -2090,28 +2308,26 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) break; case ABILITYEFFECT_IMMUNITY: // 5 { - #define i bank - for (i = 0; i < gNoOfAllBanks; i++) + for (bank = 0; bank < gNoOfAllBanks; bank++) { - switch (gBattleMons[i].ability) + switch (gBattleMons[bank].ability) { case ABILITY_IMMUNITY: - if (gBattleMons[i].status1 & (STATUS_POISON | STATUS_TOXIC_POISON | 0xF00)) // TODO: what is 0xF00? + if (gBattleMons[bank].status1 & (STATUS_POISON | STATUS_TOXIC_POISON | STATUS_TOXIC_COUNTER)) { StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); effect = 1; } break; case ABILITY_OWN_TEMPO: - //_08043A7C - if (gBattleMons[i].status2 & STATUS2_CONFUSION) + if (gBattleMons[bank].status2 & STATUS2_CONFUSION) { StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); effect = 2; } break; case ABILITY_LIMBER: - if (gBattleMons[i].status1 & STATUS_PARALYSIS) + if (gBattleMons[bank].status1 & STATUS_PARALYSIS) { StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); effect = 1; @@ -2119,30 +2335,29 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) break; case ABILITY_INSOMNIA: case ABILITY_VITAL_SPIRIT: - if (gBattleMons[i].status1 & STATUS_SLEEP) + if (gBattleMons[bank].status1 & STATUS_SLEEP) { - gBattleMons[i].status2 &= ~(STATUS2_NIGHTMARE); + gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); effect = 1; } break; case ABILITY_WATER_VEIL: - if (gBattleMons[i].status1 & STATUS_BURN) + if (gBattleMons[bank].status1 & STATUS_BURN) { StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); effect = 1; } break; case ABILITY_MAGMA_ARMOR: - if (gBattleMons[i].status1 & STATUS_FREEZE) + if (gBattleMons[bank].status1 & STATUS_FREEZE) { StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); effect = 1; } break; case ABILITY_OBLIVIOUS: - //_08043B70 - if (gBattleMons[i].status2 & STATUS2_INFATUATION) + if (gBattleMons[bank].status2 & STATUS2_INFATUATION) { StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); effect = 3; @@ -2154,58 +2369,54 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) switch (effect) { case 1: // status cleared - gBattleMons[i].status1 = 0; + gBattleMons[bank].status1 = 0; break; case 2: // get rid of confusion - gBattleMons[i].status2 &= ~(STATUS2_CONFUSION); + gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); break; case 3: // get rid of infatuation - gBattleMons[i].status2 &= ~(STATUS2_INFATUATION); + gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION); break; } - b_movescr_stack_push_cursor(); + + BattleScriptPushCursor(); gBattlescriptCurrInstr = gUnknown_082DB68C; - gBattleScripting.bank = i; - gActiveBank = i; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + gBattleScripting.bank = bank; + gActiveBank = bank; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); return effect; } } - #undef i } break; case ABILITYEFFECT_FORECAST: // 6 + for (bank = 0; bank < gNoOfAllBanks; bank++) { - #define i bank - for (i = 0; i < gNoOfAllBanks; i++) + if (gBattleMons[bank].ability == ABILITY_FORECAST) { - if (gBattleMons[i].ability == ABILITY_FORECAST) + effect = CastformDataTypeChange(bank); + if (effect) { - effect = CastformDataTypeChange(i); - if (effect) - { - b_push_move_exec(BattleScript_CastformChange); - gBattleScripting.bank = i; - gBattleStruct->formToChangeInto = effect - 1; - return effect; - } + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.bank = bank; + *(&gBattleStruct->formToChangeInto) = effect - 1; + return effect; } } - #undef i } break; case ABILITYEFFECT_SYNCHRONIZE: // 7 - //_08043CBC if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) { gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); - gBattleStruct->synchronizeMoveEffect &= 0x3F; - if (gBattleStruct->synchronizeMoveEffect == 6) - gBattleStruct->synchronizeMoveEffect = 2; - gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + 0x40; + gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + + gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + MOVE_EFFECT_AFFECTS_USER; gBattleScripting.bank = gBankTarget; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2215,12 +2426,13 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) { gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); - gBattleStruct->synchronizeMoveEffect &= 0x3F; - if (gBattleStruct->synchronizeMoveEffect == 6) - gBattleStruct->synchronizeMoveEffect = 2; + gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect; gBattleScripting.bank = gBankAttacker; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2233,7 +2445,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { gLastUsedAbility = ABILITY_INTIMIDATE; gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); - b_push_move_exec(gUnknown_082DB4B8); + BattleScriptPushCursorAndCallback(gUnknown_082DB4B8); gBattleStruct->intimidateBank = i; effect++; break; @@ -2245,15 +2457,16 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE)) { - u8 opposite = (GetBankIdentity(i) ^ 1) & 1; - u8 target1 = GetBankByPlayerAI(opposite); - u8 target2 = GetBankByPlayerAI(opposite + 2); + u8 target2; + side = (GetBankIdentity(i) ^ BIT_SIDE) & BIT_SIDE; // side of the opposing pokemon + target1 = GetBankByIdentity(side); + target2 = GetBankByIdentity(side + BIT_MON); if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0 && gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) { - gActiveBank = GetBankByPlayerAI(((Random() & 1) * 2) | opposite); + gActiveBank = GetBankByIdentity(((Random() & 1) * 2) | side); gBattleMons[i].ability = gBattleMons[gActiveBank].ability; gLastUsedAbility = gBattleMons[gActiveBank].ability; effect++; @@ -2285,20 +2498,12 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } if (effect) { - b_push_move_exec(BattleScript_TraceActivates); + BattleScriptPushCursorAndCallback(BattleScript_TraceActivates); gStatuses3[i] &= ~(STATUS3_TRACE); gBattleScripting.bank = i; - gBattleTextBuff1[0] = 0xFD; - gBattleTextBuff1[1] = 4; - gBattleTextBuff1[2] = gActiveBank; - gBattleTextBuff1[3] = gBattlePartyID[gActiveBank]; - gBattleTextBuff1[4] = EOS; - - gBattleTextBuff2[0] = 0xFD; - gBattleTextBuff2[1] = 9; - gBattleTextBuff2[2] = gLastUsedAbility; - gBattleTextBuff2[3] = EOS; + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBank, gBattlePartyID[gActiveBank]) + PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility) break; } } @@ -2311,7 +2516,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { gLastUsedAbility = ABILITY_INTIMIDATE; gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = gUnknown_082DB4C1; gBattleStruct->intimidateBank = i; effect++; @@ -2390,7 +2595,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } } break; - case ABILITYEFFECT_COUNT_OTHER_SIZE: // 16 + case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16 side = GetBankSide(bank); for (i = 0; i < gNoOfAllBanks; i++) { @@ -2423,3060 +2628,28 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } break; } - if (effect && caseID < 0xC && gLastUsedAbility != 0xFF) + + if (effect && caseID < ABILITYEFFECT_CHECK_OTHER_SIDE && gLastUsedAbility != 0xFF) RecordAbilityBattle(bank, gLastUsedAbility); } return effect; } -#else -__attribute__((naked)) -u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) -{ - asm( - "\n\ - .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, 0x28\n\ - ldr r4, [sp, 0x48]\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - str r0, [sp, 0x4]\n\ - lsls r1, 24\n\ - lsrs r1, 24\n\ - mov r10, r1\n\ - lsls r2, 24\n\ - lsrs r6, r2, 24\n\ - lsls r3, 24\n\ - lsrs r3, 24\n\ - mov r8, r3\n\ - lsls r4, 16\n\ - lsrs r4, 16\n\ - movs r0, 0\n\ - mov r9, r0\n\ - ldr r5, =gBankAttacker\n\ - ldr r1, =gNoOfAllBanks\n\ - ldrb r0, [r5]\n\ - ldrb r1, [r1]\n\ - cmp r0, r1\n\ - bcc _08042864\n\ - mov r1, r10\n\ - strb r1, [r5]\n\ -_08042864:\n\ - ldrb r0, [r5]\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - cmp r0, 0\n\ - bne _08042894\n\ - ldr r1, =gBattlePartyID\n\ - ldrb r0, [r5]\n\ - lsls r0, 1\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - movs r0, 0x64\n\ - muls r1, r0\n\ - ldr r0, =gPlayerParty\n\ - b _080428A4\n\ - .pool\n\ -_08042894:\n\ - ldr r1, =gBattlePartyID\n\ - ldrb r0, [r5]\n\ - lsls r0, 1\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - movs r0, 0x64\n\ - muls r1, r0\n\ - ldr r0, =gEnemyParty\n\ -_080428A4:\n\ - adds r7, r1, r0\n\ - ldr r5, =gBankTarget\n\ - ldr r1, =gNoOfAllBanks\n\ - ldrb r0, [r5]\n\ - ldrb r1, [r1]\n\ - cmp r0, r1\n\ - bcc _080428B6\n\ - mov r2, r10\n\ - strb r2, [r5]\n\ -_080428B6:\n\ - ldrb r0, [r5]\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - cmp r0, 0\n\ - bne _080428E8\n\ - ldr r1, =gBattlePartyID\n\ - ldrb r0, [r5]\n\ - lsls r0, 1\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - movs r0, 0x64\n\ - muls r1, r0\n\ - ldr r0, =gPlayerParty\n\ - b _080428F8\n\ - .pool\n\ -_080428E8:\n\ - ldr r1, =gBattlePartyID\n\ - ldrb r0, [r5]\n\ - lsls r0, 1\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - movs r0, 0x64\n\ - muls r1, r0\n\ - ldr r0, =gEnemyParty\n\ -_080428F8:\n\ - adds r5, r1, r0\n\ - adds r0, r7, 0\n\ - movs r1, 0xB\n\ - bl GetMonData\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - str r0, [sp, 0x8]\n\ - adds r0, r7, 0\n\ - movs r1, 0\n\ - bl GetMonData\n\ - str r0, [sp, 0x10]\n\ - adds r0, r5, 0\n\ - movs r1, 0xB\n\ - bl GetMonData\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - str r0, [sp, 0xC]\n\ - adds r0, r5, 0\n\ - movs r1, 0\n\ - bl GetMonData\n\ - str r0, [sp, 0x14]\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804293A\n\ - bl _0804443A\n\ -_0804293A:\n\ - mov r3, r8\n\ - cmp r3, 0\n\ - beq _08042958\n\ - ldr r0, =gLastUsedAbility\n\ - strb r3, [r0]\n\ - adds r7, r0, 0\n\ - b _0804296E\n\ - .pool\n\ -_08042958:\n\ - ldr r2, =gLastUsedAbility\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r5, r10\n\ - muls r5, r0\n\ - adds r0, r5, 0\n\ - adds r0, r1\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - strb r0, [r2]\n\ - adds r7, r2, 0\n\ -_0804296E:\n\ - cmp r4, 0\n\ - beq _08042980\n\ - adds r5, r4, 0\n\ - b _08042984\n\ - .pool\n\ -_08042980:\n\ - ldr r0, =gCurrentMove\n\ - ldrh r5, [r0]\n\ -_08042984:\n\ - ldr r1, =gBattleStruct\n\ - ldr r0, [r1]\n\ - ldrb r0, [r0, 0x13]\n\ - mov r8, r1\n\ - cmp r0, 0\n\ - beq _080429A0\n\ - movs r3, 0x3F\n\ - ands r3, r0\n\ - b _080429AC\n\ - .pool\n\ -_080429A0:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r3, [r0, 0x2]\n\ -_080429AC:\n\ - ldr r0, [sp, 0x4]\n\ - cmp r0, 0x13\n\ - bls _080429B6\n\ - bl _0804441E\n\ -_080429B6:\n\ - lsls r0, 2\n\ - ldr r1, =_080429C8\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - mov pc, r0\n\ - .pool\n\ - .align 2, 0\n\ -_080429C8:\n\ - .4byte _08042A18\n\ - .4byte _08042CDC\n\ - .4byte _08042EF8\n\ - .4byte _08042F8C\n\ - .4byte _080431AC\n\ - .4byte _08043908\n\ - .4byte _08043C6C\n\ - .4byte _08043CBC\n\ - .4byte _08043D40\n\ - .4byte _08043DC4\n\ - .4byte _08043FE4\n\ - .4byte _08043E08\n\ - .4byte _08044028\n\ - .4byte _08044084\n\ - .4byte _080440E0\n\ - .4byte _080441DC\n\ - .4byte _08044220\n\ - .4byte _0804427C\n\ - .4byte _080443EC\n\ - .4byte _08044196\n\ -_08042A18:\n\ - ldr r2, =gBankAttacker\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r1, [r2]\n\ - adds r5, r0, 0\n\ - ldrb r3, [r5]\n\ - cmp r1, r3\n\ - bcc _08042A2A\n\ - mov r0, r10\n\ - strb r0, [r2]\n\ -_08042A2A:\n\ - ldrb r0, [r7]\n\ - cmp r0, 0x2D\n\ - bne _08042A32\n\ - b _08042BA8\n\ -_08042A32:\n\ - cmp r0, 0x2D\n\ - bgt _08042A64\n\ - cmp r0, 0xD\n\ - bne _08042A3C\n\ - b _08042CA4\n\ -_08042A3C:\n\ - cmp r0, 0xD\n\ - bgt _08042A54\n\ - cmp r0, 0x2\n\ - bne _08042A46\n\ - b _08042B78\n\ -_08042A46:\n\ - bl _0804441E\n\ - .pool\n\ -_08042A54:\n\ - cmp r0, 0x16\n\ - bne _08042A5A\n\ - b _08042C08\n\ -_08042A5A:\n\ - cmp r0, 0x24\n\ - bne _08042A60\n\ - b _08042C68\n\ -_08042A60:\n\ - bl _0804441E\n\ -_08042A64:\n\ - cmp r0, 0x46\n\ - bne _08042A6A\n\ - b _08042BD8\n\ -_08042A6A:\n\ - cmp r0, 0x46\n\ - bgt _08042A78\n\ - cmp r0, 0x3B\n\ - bne _08042A74\n\ - b _08042C3C\n\ -_08042A74:\n\ - bl _0804441E\n\ -_08042A78:\n\ - cmp r0, 0x4D\n\ - bne _08042A7E\n\ - b _08042CA4\n\ -_08042A7E:\n\ - cmp r0, 0xFF\n\ - beq _08042A86\n\ - bl _0804441E\n\ -_08042A86:\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 17\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08042B4C\n\ - bl weather_get_current\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - subs r0, 0x3\n\ - cmp r0, 0xA\n\ - bhi _08042B4C\n\ - lsls r0, 2\n\ - ldr r1, =_08042AB4\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - mov pc, r0\n\ - .pool\n\ - .align 2, 0\n\ -_08042AB4:\n\ - .4byte _08042AE0\n\ - .4byte _08042B4C\n\ - .4byte _08042AE0\n\ - .4byte _08042B4C\n\ - .4byte _08042B4C\n\ - .4byte _08042B04\n\ - .4byte _08042B4C\n\ - .4byte _08042B4C\n\ - .4byte _08042B4C\n\ - .4byte _08042B28\n\ - .4byte _08042AE0\n\ -_08042AE0:\n\ - ldr r2, =gBattleWeather\n\ - ldrh r1, [r2]\n\ - movs r0, 0x7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08042B4C\n\ - movs r0, 0x5\n\ - strh r0, [r2]\n\ - ldr r1, =gBattleScripting\n\ - movs r0, 0xA\n\ - strb r0, [r1, 0x10]\n\ - mov r2, r10\n\ - strb r2, [r1, 0x17]\n\ - b _08042B42\n\ - .pool\n\ -_08042B04:\n\ - ldr r3, =gBattleWeather\n\ - ldrh r1, [r3]\n\ - movs r2, 0x18\n\ - adds r0, r2, 0\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08042B4C\n\ - strh r2, [r3]\n\ - ldr r1, =gBattleScripting\n\ - movs r0, 0xC\n\ - strb r0, [r1, 0x10]\n\ - mov r3, r10\n\ - strb r3, [r1, 0x17]\n\ - b _08042B42\n\ - .pool\n\ -_08042B28:\n\ - ldr r3, =gBattleWeather\n\ - ldrh r1, [r3]\n\ - movs r2, 0x60\n\ - adds r0, r2, 0\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08042B4C\n\ - strh r2, [r3]\n\ - ldr r1, =gBattleScripting\n\ - movs r0, 0xB\n\ - strb r0, [r1, 0x10]\n\ - mov r5, r10\n\ - strb r5, [r1, 0x17]\n\ -_08042B42:\n\ - mov r0, r9\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_08042B4C:\n\ - mov r0, r9\n\ - cmp r0, 0\n\ - bne _08042B56\n\ - bl _0804443A\n\ -_08042B56:\n\ - bl weather_get_current\n\ - ldr r1, =gBattleCommunication\n\ - strb r0, [r1, 0x5]\n\ - ldr r0, =gUnknown_082DACE7\n\ - bl b_push_move_exec\n\ - bl _0804441E\n\ - .pool\n\ -_08042B78:\n\ - ldr r2, =gBattleWeather\n\ - ldrh r1, [r2]\n\ - movs r0, 0x4\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042B88\n\ - bl _0804441E\n\ -_08042B88:\n\ - movs r0, 0x5\n\ - strh r0, [r2]\n\ - ldr r0, =BattleScript_DrizzleActivates\n\ - bl b_push_move_exec\n\ - ldr r0, =gBattleScripting\n\ - mov r1, r10\n\ - strb r1, [r0, 0x17]\n\ - bl _080443D0\n\ - .pool\n\ -_08042BA8:\n\ - ldr r2, =gBattleWeather\n\ - ldrh r1, [r2]\n\ - movs r0, 0x10\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042BB8\n\ - bl _0804441E\n\ -_08042BB8:\n\ - movs r0, 0x18\n\ - strh r0, [r2]\n\ - ldr r0, =BattleScript_SandstreamActivates\n\ - bl b_push_move_exec\n\ - ldr r0, =gBattleScripting\n\ - mov r2, r10\n\ - strb r2, [r0, 0x17]\n\ - bl _080443D0\n\ - .pool\n\ -_08042BD8:\n\ - ldr r2, =gBattleWeather\n\ - ldrh r1, [r2]\n\ - movs r0, 0x40\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042BE8\n\ - bl _0804441E\n\ -_08042BE8:\n\ - movs r0, 0x60\n\ - strh r0, [r2]\n\ - ldr r0, =BattleScript_DroughtActivates\n\ - bl b_push_move_exec\n\ - ldr r0, =gBattleScripting\n\ - mov r3, r10\n\ - strb r3, [r0, 0x17]\n\ - bl _080443D0\n\ - .pool\n\ -_08042C08:\n\ - ldr r0, =gSpecialStatuses\n\ - mov r5, r10\n\ - lsls r2, r5, 2\n\ - adds r1, r2, r5\n\ - lsls r1, 2\n\ - adds r3, r1, r0\n\ - ldrb r0, [r3]\n\ - lsls r0, 28\n\ - cmp r0, 0\n\ - bge _08042C20\n\ - bl _0804441E\n\ -_08042C20:\n\ - ldr r1, =gStatuses3\n\ - adds r1, r2, r1\n\ - ldr r0, [r1]\n\ - movs r2, 0x80\n\ - lsls r2, 12\n\ - orrs r0, r2\n\ - str r0, [r1]\n\ - ldrb r0, [r3]\n\ - movs r1, 0x8\n\ - b _08042C92\n\ - .pool\n\ -_08042C3C:\n\ - mov r0, r10\n\ - bl CastformDataTypeChange\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ - cmp r0, 0\n\ - bne _08042C50\n\ - bl _0804443A\n\ -_08042C50:\n\ - ldr r0, =BattleScript_CastformChange\n\ - bl b_push_move_exec\n\ - ldr r0, =gBattleScripting\n\ - mov r1, r10\n\ - strb r1, [r0, 0x17]\n\ - bl _080442E2\n\ - .pool\n\ -_08042C68:\n\ - ldr r0, =gSpecialStatuses\n\ - mov r3, r10\n\ - lsls r2, r3, 2\n\ - adds r1, r2, r3\n\ - lsls r1, 2\n\ - adds r3, r1, r0\n\ - ldrb r0, [r3]\n\ - lsls r0, 27\n\ - cmp r0, 0\n\ - bge _08042C80\n\ - bl _0804441E\n\ -_08042C80:\n\ - ldr r1, =gStatuses3\n\ - adds r1, r2, r1\n\ - ldr r0, [r1]\n\ - movs r2, 0x80\n\ - lsls r2, 13\n\ - orrs r0, r2\n\ - str r0, [r1]\n\ - ldrb r0, [r3]\n\ - movs r1, 0x10\n\ -_08042C92:\n\ - orrs r0, r1\n\ - strb r0, [r3]\n\ - bl _0804441E\n\ - .pool\n\ -_08042CA4:\n\ - movs r6, 0\n\ - ldrb r5, [r5]\n\ - cmp r6, r5\n\ - bcc _08042CB0\n\ - bl _0804441E\n\ -_08042CB0:\n\ - adds r0, r6, 0\n\ - bl CastformDataTypeChange\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ - cmp r0, 0\n\ - beq _08042CC4\n\ - bl _080442D8\n\ -_08042CC4:\n\ - adds r0, r6, 0x1\n\ - lsls r0, 24\n\ - lsrs r6, r0, 24\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r6, r0\n\ - bcc _08042CB0\n\ - bl _0804441E\n\ - .pool\n\ -_08042CDC:\n\ - ldr r5, =gBattleMons\n\ - mov r8, r5\n\ - movs r0, 0x58\n\ - mov r6, r10\n\ - muls r6, r0\n\ - adds r4, r6, r5\n\ - ldrh r0, [r4, 0x28]\n\ - cmp r0, 0\n\ - bne _08042CF2\n\ - bl _0804441E\n\ -_08042CF2:\n\ - ldr r0, =gBankAttacker\n\ - mov r1, r10\n\ - strb r1, [r0]\n\ - ldrb r5, [r7]\n\ - cmp r5, 0x2C\n\ - beq _08042D22\n\ - cmp r5, 0x2C\n\ - bgt _08042D14\n\ - cmp r5, 0x3\n\ - bne _08042D08\n\ - b _08042E84\n\ -_08042D08:\n\ - bl _0804441E\n\ - .pool\n\ -_08042D14:\n\ - cmp r5, 0x36\n\ - bne _08042D1A\n\ - b _08042ED0\n\ -_08042D1A:\n\ - cmp r5, 0x3D\n\ - beq _08042DA0\n\ - bl _0804441E\n\ -_08042D22:\n\ - movs r0, 0\n\ - str r0, [sp]\n\ - movs r0, 0x13\n\ - movs r1, 0\n\ - movs r2, 0xD\n\ - movs r3, 0\n\ - bl AbilityBattleEffects\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - cmp r0, 0\n\ - beq _08042D3E\n\ - bl _0804441E\n\ -_08042D3E:\n\ - str r0, [sp]\n\ - movs r0, 0x13\n\ - movs r1, 0\n\ - movs r2, 0x4D\n\ - movs r3, 0\n\ - bl AbilityBattleEffects\n\ - lsls r0, 24\n\ - cmp r0, 0\n\ - beq _08042D56\n\ - bl _0804441E\n\ -_08042D56:\n\ - ldr r0, =gBattleWeather\n\ - ldrh r1, [r0]\n\ - movs r0, 0x7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08042D66\n\ - bl _0804441E\n\ -_08042D66:\n\ - ldrh r0, [r4, 0x2C]\n\ - ldrh r2, [r4, 0x28]\n\ - cmp r0, r2\n\ - bhi _08042D72\n\ - bl _0804441E\n\ -_08042D72:\n\ - strb r5, [r7]\n\ - ldr r0, =BattleScript_RainDishActivates\n\ - bl b_push_move_exec\n\ - ldr r1, =gBattleMoveDamage\n\ - ldrh r0, [r4, 0x2C]\n\ - lsrs r0, 4\n\ - str r0, [r1]\n\ - cmp r0, 0\n\ - bne _08042D8A\n\ - movs r0, 0x1\n\ - str r0, [r1]\n\ -_08042D8A:\n\ - ldr r0, [r1]\n\ - negs r0, r0\n\ - str r0, [r1]\n\ - bl _080443D0\n\ - .pool\n\ -_08042DA0:\n\ - mov r0, r8\n\ - adds r0, 0x4C\n\ - adds r5, r6, r0\n\ - ldrb r0, [r5]\n\ - cmp r0, 0\n\ - bne _08042DB0\n\ - bl _0804441E\n\ -_08042DB0:\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0x3\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - lsrs r4, r0, 16\n\ - cmp r4, 0\n\ - beq _08042DCA\n\ - bl _0804441E\n\ -_08042DCA:\n\ - ldr r0, [r5]\n\ - movs r1, 0x88\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042DDC\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_PoisonJpn\n\ - bl StringCopy\n\ -_08042DDC:\n\ - ldr r0, [r5]\n\ - movs r1, 0x7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042DEE\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_SleepJpn\n\ - bl StringCopy\n\ -_08042DEE:\n\ - ldr r0, [r5]\n\ - movs r1, 0x40\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042E00\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_ParalysisJpn\n\ - bl StringCopy\n\ -_08042E00:\n\ - ldr r0, [r5]\n\ - movs r1, 0x10\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042E12\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_BurnJpn\n\ - bl StringCopy\n\ -_08042E12:\n\ - ldr r0, [r5]\n\ - movs r1, 0x20\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042E24\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_IceJpn\n\ - bl StringCopy\n\ -_08042E24:\n\ - str r4, [r5]\n\ - mov r1, r8\n\ - adds r1, 0x50\n\ - adds r1, r6, r1\n\ - ldr r0, [r1]\n\ - ldr r2, =0xf7ffffff\n\ - ands r0, r2\n\ - str r0, [r1]\n\ - ldr r0, =gBattleScripting\n\ - ldr r4, =gActiveBank\n\ - mov r3, r10\n\ - strb r3, [r4]\n\ - strb r3, [r0, 0x17]\n\ - ldr r0, =BattleScript_ShedSkinActivates\n\ - bl b_push_move_exec\n\ - str r5, [sp]\n\ - movs r0, 0\n\ - movs r1, 0x28\n\ - movs r2, 0\n\ - movs r3, 0x4\n\ - bl EmitSetAttributes\n\ - ldrb r0, [r4]\n\ - bl MarkBufferBankForExecution\n\ - bl _080443D0\n\ - .pool\n\ -_08042E84:\n\ - ldrb r2, [r4, 0x1B]\n\ - movs r0, 0x1B\n\ - ldrsb r0, [r4, r0]\n\ - cmp r0, 0xB\n\ - ble _08042E92\n\ - bl _0804441E\n\ -_08042E92:\n\ - ldr r0, =gDisableStructs\n\ - mov r5, r10\n\ - lsls r1, r5, 3\n\ - subs r1, r5\n\ - lsls r1, 2\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x16]\n\ - cmp r0, 0x2\n\ - bne _08042EA8\n\ - bl _0804441E\n\ -_08042EA8:\n\ - adds r0, r2, 0x1\n\ - movs r1, 0\n\ - strb r0, [r4, 0x1B]\n\ - ldr r4, =gBattleScripting\n\ - movs r0, 0x11\n\ - strb r0, [r4, 0x10]\n\ - strb r1, [r4, 0x11]\n\ - ldr r0, =BattleScript_SpeedBoostActivates\n\ - bl b_push_move_exec\n\ - strb r5, [r4, 0x17]\n\ - bl _080443D0\n\ - .pool\n\ -_08042ED0:\n\ - ldr r2, =gDisableStructs\n\ - ldrb r0, [r0]\n\ - lsls r1, r0, 3\n\ - subs r1, r0\n\ - lsls r1, 2\n\ - adds r1, r2\n\ - ldrb r3, [r1, 0x18]\n\ - lsls r0, r3, 31\n\ - lsrs r0, 31\n\ - movs r2, 0x1\n\ - eors r2, r0\n\ - movs r0, 0x2\n\ - negs r0, r0\n\ - ands r0, r3\n\ - orrs r0, r2\n\ - strb r0, [r1, 0x18]\n\ - bl _0804441E\n\ - .pool\n\ -_08042EF8:\n\ - ldrb r0, [r7]\n\ - cmp r0, 0x2B\n\ - beq _08042F02\n\ - bl _0804441E\n\ -_08042F02:\n\ - movs r4, 0\n\ - ldr r0, =gSoundMovesTable\n\ - ldrh r2, [r0]\n\ - ldr r3, =0x0000ffff\n\ - adds r1, r0, 0\n\ - cmp r2, r3\n\ - bne _08042F14\n\ - bl _0804441E\n\ -_08042F14:\n\ - cmp r2, r5\n\ - beq _08042F2C\n\ - adds r2, r1, 0\n\ -_08042F1A:\n\ - adds r2, 0x2\n\ - adds r4, 0x1\n\ - ldrh r0, [r2]\n\ - cmp r0, r3\n\ - bne _08042F28\n\ - bl _0804441E\n\ -_08042F28:\n\ - cmp r0, r5\n\ - bne _08042F1A\n\ -_08042F2C:\n\ - lsls r0, r4, 1\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - ldr r0, =0x0000ffff\n\ - cmp r1, r0\n\ - bne _08042F3C\n\ - bl _0804441E\n\ -_08042F3C:\n\ - ldr r1, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r1, 0x50\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 5\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08042F62\n\ - ldr r0, =gHitMarker\n\ - ldr r1, [r0]\n\ - movs r2, 0x80\n\ - lsls r2, 4\n\ - orrs r1, r2\n\ - str r1, [r0]\n\ -_08042F62:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_SoundproofProtected\n\ - str r0, [r1]\n\ - movs r0, 0x1\n\ - mov r9, r0\n\ - bl _08044424\n\ - .pool\n\ -_08042F8C:\n\ - cmp r5, 0\n\ - bne _08042F94\n\ - bl _0804441E\n\ -_08042F94:\n\ - ldrb r0, [r7]\n\ - cmp r0, 0xB\n\ - beq _08043004\n\ - cmp r0, 0xB\n\ - bgt _08042FA4\n\ - cmp r0, 0xA\n\ - beq _08042FAA\n\ - b _08043126\n\ -_08042FA4:\n\ - cmp r0, 0x12\n\ - beq _0804305C\n\ - b _08043126\n\ -_08042FAA:\n\ - cmp r3, 0xD\n\ - beq _08042FB0\n\ - b _08043126\n\ -_08042FB0:\n\ - ldr r0, =gBattleMoves\n\ - lsls r1, r5, 1\n\ - adds r1, r5\n\ - lsls r1, 2\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - cmp r0, 0\n\ - bne _08042FC2\n\ - b _08043126\n\ -_08042FC2:\n\ - ldr r1, =gProtectStructs\n\ - ldr r0, =gBankAttacker\n\ - ldrb r0, [r0]\n\ - lsls r0, 4\n\ - adds r0, r1\n\ - ldrb r0, [r0, 0x2]\n\ - lsls r0, 28\n\ - cmp r0, 0\n\ - bge _08042FF0\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_MoveHPDrain\n\ - b _08042FF4\n\ - .pool\n\ -_08042FF0:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_MoveHPDrain_PPLoss\n\ -_08042FF4:\n\ - str r0, [r1]\n\ - movs r1, 0x1\n\ - b _08043124\n\ - .pool\n\ -_08043004:\n\ - cmp r3, 0xB\n\ - beq _0804300A\n\ - b _08043126\n\ -_0804300A:\n\ - ldr r0, =gBattleMoves\n\ - lsls r1, r5, 1\n\ - adds r1, r5\n\ - lsls r1, 2\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - cmp r0, 0\n\ - bne _0804301C\n\ - b _08043126\n\ -_0804301C:\n\ - ldr r1, =gProtectStructs\n\ - ldr r0, =gBankAttacker\n\ - ldrb r0, [r0]\n\ - lsls r0, 4\n\ - adds r0, r1\n\ - ldrb r0, [r0, 0x2]\n\ - lsls r0, 28\n\ - cmp r0, 0\n\ - bge _08043048\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_MoveHPDrain\n\ - b _0804304C\n\ - .pool\n\ -_08043048:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_MoveHPDrain_PPLoss\n\ -_0804304C:\n\ - str r0, [r1]\n\ - movs r2, 0x1\n\ - mov r9, r2\n\ - b _08043126\n\ - .pool\n\ -_0804305C:\n\ - cmp r3, 0xA\n\ - bne _08043126\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r3, 0\n\ - adds r1, 0x4C\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x20\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043126\n\ - ldr r2, =gBattleResources\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x4]\n\ - mov r5, r10\n\ - lsls r1, r5, 2\n\ - adds r0, r1\n\ - ldr r3, [r0]\n\ - movs r4, 0x1\n\ - ands r3, r4\n\ - adds r5, r1, 0\n\ - cmp r3, 0\n\ - bne _080430EC\n\ - ldr r0, =gBattleCommunication\n\ - strb r3, [r0, 0x5]\n\ - ldr r1, =gProtectStructs\n\ - ldr r0, =gBankAttacker\n\ - ldrb r0, [r0]\n\ - lsls r0, 4\n\ - adds r0, r1\n\ - ldrb r0, [r0, 0x2]\n\ - lsls r0, 28\n\ - cmp r0, 0\n\ - bge _080430C8\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_FlashFireBoost\n\ - b _080430CC\n\ - .pool\n\ -_080430C8:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_FlashFireBoost_PPLoss\n\ -_080430CC:\n\ - str r0, [r1]\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x4]\n\ - adds r1, r5\n\ - ldr r0, [r1]\n\ - movs r2, 0x1\n\ - orrs r0, r2\n\ - str r0, [r1]\n\ - movs r0, 0x2\n\ - mov r9, r0\n\ - b _08043126\n\ - .pool\n\ -_080430EC:\n\ - ldr r0, =gBattleCommunication\n\ - strb r4, [r0, 0x5]\n\ - ldr r1, =gProtectStructs\n\ - ldr r0, =gBankAttacker\n\ - ldrb r0, [r0]\n\ - lsls r0, 4\n\ - adds r0, r1\n\ - ldrb r0, [r0, 0x2]\n\ - lsls r0, 28\n\ - cmp r0, 0\n\ - bge _0804311C\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_FlashFireBoost\n\ - b _08043120\n\ - .pool\n\ -_0804311C:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_FlashFireBoost_PPLoss\n\ -_08043120:\n\ - str r0, [r1]\n\ - movs r1, 0x2\n\ -_08043124:\n\ - mov r9, r1\n\ -_08043126:\n\ - mov r2, r9\n\ - cmp r2, 0x1\n\ - beq _08043130\n\ - bl _0804441E\n\ -_08043130:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r3, 0\n\ - adds r1, r0, r1\n\ - ldrh r0, [r1, 0x2C]\n\ - ldrh r5, [r1, 0x28]\n\ - cmp r0, r5\n\ - bne _0804318C\n\ - ldr r1, =gProtectStructs\n\ - ldr r0, =gBankAttacker\n\ - ldrb r0, [r0]\n\ - lsls r0, 4\n\ - adds r0, r1\n\ - ldrb r0, [r0, 0x2]\n\ - lsls r0, 28\n\ - cmp r0, 0\n\ - bge _08043178\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =gUnknown_082DB592\n\ - str r0, [r1]\n\ - bl _0804441E\n\ - .pool\n\ -_08043178:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =gUnknown_082DB591\n\ - str r0, [r1]\n\ - bl _0804441E\n\ - .pool\n\ -_0804318C:\n\ - ldr r2, =gBattleMoveDamage\n\ - ldrh r0, [r1, 0x2C]\n\ - lsrs r0, 2\n\ - str r0, [r2]\n\ - cmp r0, 0\n\ - bne _0804319C\n\ - mov r0, r9\n\ - str r0, [r2]\n\ -_0804319C:\n\ - ldr r0, [r2]\n\ - negs r0, r0\n\ - str r0, [r2]\n\ - bl _0804441E\n\ - .pool\n\ -_080431AC:\n\ - ldrb r0, [r7]\n\ - subs r0, 0x9\n\ - cmp r0, 0x2F\n\ - bls _080431B8\n\ - bl _0804441E\n\ -_080431B8:\n\ - lsls r0, 2\n\ - ldr r1, =_080431C8\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - mov pc, r0\n\ - .pool\n\ - .align 2, 0\n\ -_080431C8:\n\ - .4byte _080435E4\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _08043288\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _08043350\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _08043410\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _08043508\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _080436C0\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804441E\n\ - .4byte _0804379C\n\ -_08043288:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043298\n\ - bl _0804441E\n\ -_08043298:\n\ - cmp r5, 0xA5\n\ - bne _080432A0\n\ - bl _0804441E\n\ -_080432A0:\n\ - ldr r0, =gBattleMoves\n\ - lsls r1, r5, 1\n\ - adds r1, r5\n\ - lsls r1, 2\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - cmp r0, 0\n\ - bne _080432B4\n\ - bl _0804441E\n\ -_080432B4:\n\ - ldr r2, =gSpecialStatuses\n\ - ldr r0, =gBankTarget\n\ - ldrb r1, [r0]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r1, r0, 2\n\ - adds r0, r2, 0\n\ - adds r0, 0x8\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _080432DC\n\ - adds r0, r2, 0\n\ - adds r0, 0xC\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _080432DC\n\ - bl _0804441E\n\ -_080432DC:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r2, r10\n\ - muls r2, r0\n\ - adds r0, r2, 0\n\ - adds r1, r0, r1\n\ - adds r4, r1, 0\n\ - adds r4, 0x21\n\ - ldrb r0, [r4]\n\ - cmp r0, r3\n\ - bne _080432F6\n\ - bl _0804441E\n\ -_080432F6:\n\ - adds r2, r1, 0\n\ - adds r2, 0x22\n\ - ldrb r0, [r2]\n\ - cmp r0, r3\n\ - bne _08043304\n\ - bl _0804441E\n\ -_08043304:\n\ - ldrh r0, [r1, 0x28]\n\ - cmp r0, 0\n\ - bne _0804330E\n\ - bl _0804441E\n\ -_0804330E:\n\ - strb r3, [r4]\n\ - strb r3, [r2]\n\ - ldr r1, =gBattleTextBuff1\n\ - movs r0, 0xFD\n\ - strb r0, [r1]\n\ - movs r0, 0x3\n\ - strb r0, [r1, 0x1]\n\ - strb r3, [r1, 0x2]\n\ - movs r0, 0xFF\n\ - strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_ColorChangeActivates\n\ - str r0, [r1]\n\ - bl _080443D0\n\ - .pool\n\ -_08043350:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043360\n\ - bl _0804441E\n\ -_08043360:\n\ - ldr r1, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r3, r0, r1\n\ - ldrh r0, [r3, 0x28]\n\ - cmp r0, 0\n\ - bne _08043376\n\ - bl _0804441E\n\ -_08043376:\n\ - ldr r0, =gProtectStructs\n\ - lsls r1, r2, 4\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - lsls r0, 31\n\ - cmp r0, 0\n\ - beq _08043388\n\ - bl _0804441E\n\ -_08043388:\n\ - ldr r2, =gSpecialStatuses\n\ - ldr r0, =gBankTarget\n\ - ldrb r1, [r0]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r1, r0, 2\n\ - adds r0, r2, 0\n\ - adds r0, 0x8\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _080433B0\n\ - adds r0, r2, 0\n\ - adds r0, 0xC\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _080433B0\n\ - bl _0804441E\n\ -_080433B0:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0, 0x8]\n\ - movs r2, 0x1\n\ - adds r0, r2, 0\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _080433CA\n\ - bl _0804441E\n\ -_080433CA:\n\ - ldr r1, =gBattleMoveDamage\n\ - ldrh r0, [r3, 0x2C]\n\ - lsrs r0, 4\n\ - str r0, [r1]\n\ - cmp r0, 0\n\ - bne _080433D8\n\ - str r2, [r1]\n\ -_080433D8:\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_RoughSkinActivates\n\ - str r0, [r1]\n\ - bl _080443D0\n\ - .pool\n\ -_08043410:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043420\n\ - bl _0804441E\n\ -_08043420:\n\ - ldr r1, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r0, r1\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _08043436\n\ - bl _0804441E\n\ -_08043436:\n\ - ldr r0, =gProtectStructs\n\ - lsls r1, r2, 4\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - lsls r0, 31\n\ - cmp r0, 0\n\ - beq _08043448\n\ - bl _0804441E\n\ -_08043448:\n\ - ldr r2, =gSpecialStatuses\n\ - ldr r0, =gBankTarget\n\ - ldrb r1, [r0]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r1, r0, 2\n\ - adds r0, r2, 0\n\ - adds r0, 0x8\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043470\n\ - adds r0, r2, 0\n\ - adds r0, 0xC\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043470\n\ - bl _0804441E\n\ -_08043470:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0, 0x8]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043488\n\ - bl _0804441E\n\ -_08043488:\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0xA\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - cmp r0, 0\n\ - beq _080434A0\n\ - bl _0804441E\n\ -_080434A0:\n\ - ldr r5, =gBattleCommunication\n\ - movs r4, 0x3\n\ -_080434A4:\n\ - bl Random\n\ - ands r0, r4\n\ - strb r0, [r5, 0x3]\n\ - cmp r0, 0\n\ - beq _080434A4\n\ - ldr r1, =gBattleCommunication\n\ - ldrb r0, [r1, 0x3]\n\ - cmp r0, 0x3\n\ - bne _080434BC\n\ - adds r0, 0x2\n\ - strb r0, [r1, 0x3]\n\ -_080434BC:\n\ - ldrb r0, [r1, 0x3]\n\ - adds r0, 0x40\n\ - strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_ApplySecondaryEffect\n\ - str r0, [r1]\n\ - ldr r2, =gHitMarker\n\ - ldr r0, [r2]\n\ - movs r1, 0x80\n\ - lsls r1, 6\n\ - orrs r0, r1\n\ - str r0, [r2]\n\ - bl _080443D0\n\ - .pool\n\ -_08043508:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043518\n\ - bl _0804441E\n\ -_08043518:\n\ - ldr r1, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r0, r1\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _0804352E\n\ - bl _0804441E\n\ -_0804352E:\n\ - ldr r0, =gProtectStructs\n\ - lsls r1, r2, 4\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - lsls r0, 31\n\ - cmp r0, 0\n\ - beq _08043540\n\ - bl _0804441E\n\ -_08043540:\n\ - ldr r2, =gSpecialStatuses\n\ - ldr r0, =gBankTarget\n\ - ldrb r1, [r0]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r1, r0, 2\n\ - adds r0, r2, 0\n\ - adds r0, 0x8\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043568\n\ - adds r0, r2, 0\n\ - adds r0, 0xC\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043568\n\ - bl _0804441E\n\ -_08043568:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0, 0x8]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043580\n\ - bl _0804441E\n\ -_08043580:\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0x3\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - cmp r0, 0\n\ - beq _08043598\n\ - bl _0804441E\n\ -_08043598:\n\ - ldr r1, =gBattleCommunication\n\ - movs r0, 0x42\n\ - strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_ApplySecondaryEffect\n\ - str r0, [r1]\n\ - ldr r2, =gHitMarker\n\ - ldr r0, [r2]\n\ - movs r1, 0x80\n\ - lsls r1, 6\n\ - orrs r0, r1\n\ - str r0, [r2]\n\ - bl _080443D0\n\ - .pool\n\ -_080435E4:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _080435F4\n\ - bl _0804441E\n\ -_080435F4:\n\ - ldr r1, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r0, r1\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _0804360A\n\ - bl _0804441E\n\ -_0804360A:\n\ - ldr r0, =gProtectStructs\n\ - lsls r1, r2, 4\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - lsls r0, 31\n\ - cmp r0, 0\n\ - beq _0804361C\n\ - bl _0804441E\n\ -_0804361C:\n\ - ldr r2, =gSpecialStatuses\n\ - ldr r0, =gBankTarget\n\ - ldrb r1, [r0]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r1, r0, 2\n\ - adds r0, r2, 0\n\ - adds r0, 0x8\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043644\n\ - adds r0, r2, 0\n\ - adds r0, 0xC\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043644\n\ - bl _0804441E\n\ -_08043644:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0, 0x8]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _0804365C\n\ - bl _0804441E\n\ -_0804365C:\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0x3\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - cmp r0, 0\n\ - beq _08043674\n\ - bl _0804441E\n\ -_08043674:\n\ - ldr r1, =gBattleCommunication\n\ - movs r0, 0x45\n\ - strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_ApplySecondaryEffect\n\ - str r0, [r1]\n\ - ldr r2, =gHitMarker\n\ - ldr r0, [r2]\n\ - movs r1, 0x80\n\ - lsls r1, 6\n\ - orrs r0, r1\n\ - str r0, [r2]\n\ - bl _080443D0\n\ - .pool\n\ -_080436C0:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _080436D0\n\ - bl _0804441E\n\ -_080436D0:\n\ - ldr r1, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r0, r1\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _080436E6\n\ - bl _0804441E\n\ -_080436E6:\n\ - ldr r0, =gProtectStructs\n\ - lsls r1, r2, 4\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - lsls r0, 31\n\ - cmp r0, 0\n\ - beq _080436F8\n\ - bl _0804441E\n\ -_080436F8:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0, 0x8]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043710\n\ - bl _0804441E\n\ -_08043710:\n\ - ldr r2, =gSpecialStatuses\n\ - ldr r0, =gBankTarget\n\ - ldrb r1, [r0]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r1, r0, 2\n\ - adds r0, r2, 0\n\ - adds r0, 0x8\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043738\n\ - adds r0, r2, 0\n\ - adds r0, 0xC\n\ - adds r0, r1, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043738\n\ - bl _0804441E\n\ -_08043738:\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0x3\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - cmp r0, 0\n\ - beq _08043750\n\ - bl _0804441E\n\ -_08043750:\n\ - ldr r1, =gBattleCommunication\n\ - movs r0, 0x43\n\ - strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_ApplySecondaryEffect\n\ - str r0, [r1]\n\ - ldr r2, =gHitMarker\n\ - ldr r0, [r2]\n\ - movs r1, 0x80\n\ - lsls r1, 6\n\ - orrs r0, r1\n\ - str r0, [r2]\n\ - bl _080443D0\n\ - .pool\n\ -_0804379C:\n\ - ldr r0, =gBattleMoveFlags\n\ - ldrb r1, [r0]\n\ - movs r0, 0x29\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _080437AC\n\ - bl _0804441E\n\ -_080437AC:\n\ - ldr r6, =gBattleMons\n\ - ldr r3, =gBankAttacker\n\ - mov r8, r3\n\ - ldrb r1, [r3]\n\ - movs r7, 0x58\n\ - adds r0, r1, 0\n\ - muls r0, r7\n\ - adds r0, r6\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _080437C6\n\ - bl _0804441E\n\ -_080437C6:\n\ - ldr r0, =gProtectStructs\n\ - lsls r1, 4\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - lsls r0, 31\n\ - cmp r0, 0\n\ - beq _080437D8\n\ - bl _0804441E\n\ -_080437D8:\n\ - ldr r1, =gBattleMoves\n\ - lsls r0, r5, 1\n\ - adds r0, r5\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0, 0x8]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _080437F0\n\ - bl _0804441E\n\ -_080437F0:\n\ - ldr r3, =gSpecialStatuses\n\ - ldr r5, =gBankTarget\n\ - ldrb r1, [r5]\n\ - lsls r0, r1, 2\n\ - adds r0, r1\n\ - lsls r2, r0, 2\n\ - adds r0, r3, 0\n\ - adds r0, 0x8\n\ - adds r0, r2, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043818\n\ - adds r0, r3, 0\n\ - adds r0, 0xC\n\ - adds r0, r2, r0\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - bne _08043818\n\ - bl _0804441E\n\ -_08043818:\n\ - adds r0, r1, 0\n\ - muls r0, r7\n\ - adds r0, r6\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _08043828\n\ - bl _0804441E\n\ -_08043828:\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0x3\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - cmp r0, 0\n\ - beq _08043840\n\ - bl _0804441E\n\ -_08043840:\n\ - mov r1, r8\n\ - ldrb r0, [r1]\n\ - muls r0, r7\n\ - adds r0, r6\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0xC\n\ - bne _08043854\n\ - bl _0804441E\n\ -_08043854:\n\ - ldr r0, [sp, 0x8]\n\ - ldr r1, [sp, 0x10]\n\ - bl GetGenderFromSpeciesAndPersonality\n\ - adds r4, r0, 0\n\ - ldr r0, [sp, 0xC]\n\ - ldr r1, [sp, 0x14]\n\ - bl GetGenderFromSpeciesAndPersonality\n\ - lsls r4, 24\n\ - lsls r0, 24\n\ - cmp r4, r0\n\ - bne _08043872\n\ - bl _0804441E\n\ -_08043872:\n\ - mov r2, r8\n\ - ldrb r0, [r2]\n\ - muls r0, r7\n\ - adds r4, r6, 0\n\ - adds r4, 0x50\n\ - adds r0, r4\n\ - ldr r0, [r0]\n\ - movs r1, 0xF0\n\ - lsls r1, 12\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804388E\n\ - bl _0804441E\n\ -_0804388E:\n\ - ldr r0, [sp, 0x8]\n\ - ldr r1, [sp, 0x10]\n\ - bl GetGenderFromSpeciesAndPersonality\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - cmp r0, 0xFF\n\ - bne _080438A2\n\ - bl _0804441E\n\ -_080438A2:\n\ - ldr r0, [sp, 0xC]\n\ - ldr r1, [sp, 0x14]\n\ - bl GetGenderFromSpeciesAndPersonality\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - cmp r0, 0xFF\n\ - bne _080438B6\n\ - bl _0804441E\n\ -_080438B6:\n\ - mov r3, r8\n\ - ldrb r0, [r3]\n\ - adds r2, r0, 0\n\ - muls r2, r7\n\ - adds r2, r4\n\ - ldr r1, =gBitTable\n\ - ldrb r0, [r5]\n\ - lsls r0, 2\n\ - adds r0, r1\n\ - ldr r1, [r0]\n\ - lsls r1, 16\n\ - ldr r0, [r2]\n\ - orrs r0, r1\n\ - str r0, [r2]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_CuteCharmActivates\n\ - str r0, [r1]\n\ - bl _080443D0\n\ - .pool\n\ -_08043908:\n\ - movs r5, 0\n\ - mov r10, r5\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r10, r0\n\ - bcc _08043918\n\ - bl _0804441E\n\ -_08043918:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r2, r10\n\ - muls r2, r0\n\ - adds r0, r2, 0\n\ - adds r0, r1\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - subs r0, 0x7\n\ - adds r2, r1, 0\n\ - cmp r0, 0x41\n\ - bls _08043932\n\ - b _08043B96\n\ -_08043932:\n\ - lsls r0, 2\n\ - ldr r1, =_08043948\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - mov pc, r0\n\ - .pool\n\ - .align 2, 0\n\ -_08043948:\n\ - .4byte _08043AAC\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B70\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043AD4\n\ - .4byte _08043B96\n\ - .4byte _08043A50\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043A7C\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B40\n\ - .4byte _08043B10\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043B96\n\ - .4byte _08043AD4\n\ -_08043A50:\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r3, 0\n\ - adds r1, r2, 0\n\ - adds r1, 0x4C\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - ldr r1, =0x00000f88\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043A6A\n\ - b _08043B96\n\ -_08043A6A:\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_PoisonJpn\n\ - b _08043B5C\n\ - .pool\n\ -_08043A7C:\n\ - movs r0, 0x58\n\ - mov r1, r10\n\ - muls r1, r0\n\ - adds r0, r1, 0\n\ - adds r1, r2, 0\n\ - adds r1, 0x50\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043A96\n\ - b _08043B96\n\ -_08043A96:\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_ConfusionJpn\n\ - bl StringCopy\n\ - movs r2, 0x2\n\ - mov r9, r2\n\ - b _08043B9C\n\ - .pool\n\ -_08043AAC:\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r3, 0\n\ - adds r1, r2, 0\n\ - adds r1, 0x4C\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x40\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043B96\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_ParalysisJpn\n\ - b _08043B5C\n\ - .pool\n\ -_08043AD4:\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r2, 0\n\ - adds r0, 0x4C\n\ - adds r0, r3, r0\n\ - ldr r0, [r0]\n\ - movs r1, 0x7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043B96\n\ - adds r2, 0x50\n\ - adds r2, r3, r2\n\ - ldr r0, [r2]\n\ - ldr r1, =0xf7ffffff\n\ - ands r0, r1\n\ - str r0, [r2]\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_SleepJpn\n\ - bl StringCopy\n\ - movs r0, 0x1\n\ - mov r9, r0\n\ - b _08043B9C\n\ - .pool\n\ -_08043B10:\n\ - movs r0, 0x58\n\ - mov r1, r10\n\ - muls r1, r0\n\ - adds r0, r1, 0\n\ - adds r1, r2, 0\n\ - adds r1, 0x4C\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x10\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043B96\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_BurnJpn\n\ - bl StringCopy\n\ - movs r2, 0x1\n\ - mov r9, r2\n\ - b _08043B9C\n\ - .pool\n\ -_08043B40:\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r3, 0\n\ - adds r1, r2, 0\n\ - adds r1, 0x4C\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x20\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043B96\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_IceJpn\n\ -_08043B5C:\n\ - bl StringCopy\n\ - movs r5, 0x1\n\ - mov r9, r5\n\ - b _08043B9C\n\ - .pool\n\ -_08043B70:\n\ - movs r0, 0x58\n\ - mov r1, r10\n\ - muls r1, r0\n\ - adds r0, r1, 0\n\ - adds r1, r2, 0\n\ - adds r1, 0x50\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0xF0\n\ - lsls r1, 12\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08043B96\n\ - ldr r0, =gBattleTextBuff1\n\ - ldr r1, =gStatusConditionString_LoveJpn\n\ - bl StringCopy\n\ - movs r2, 0x3\n\ - mov r9, r2\n\ -_08043B96:\n\ - mov r3, r9\n\ - cmp r3, 0\n\ - beq _08043C50\n\ -_08043B9C:\n\ - mov r5, r9\n\ - cmp r5, 0x2\n\ - beq _08043BD0\n\ - cmp r5, 0x2\n\ - bgt _08043BB4\n\ - cmp r5, 0x1\n\ - beq _08043BBC\n\ - b _08043BFC\n\ - .pool\n\ -_08043BB4:\n\ - mov r0, r9\n\ - cmp r0, 0x3\n\ - beq _08043BE8\n\ - b _08043BFC\n\ -_08043BBC:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r2, r10\n\ - muls r2, r0\n\ - adds r1, 0x4C\n\ - adds r2, r1\n\ - movs r0, 0\n\ - b _08043BFA\n\ - .pool\n\ -_08043BD0:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r2, r10\n\ - muls r2, r0\n\ - adds r1, 0x50\n\ - adds r2, r1\n\ - ldr r0, [r2]\n\ - movs r1, 0x8\n\ - negs r1, r1\n\ - b _08043BF8\n\ - .pool\n\ -_08043BE8:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - mov r2, r10\n\ - muls r2, r0\n\ - adds r1, 0x50\n\ - adds r2, r1\n\ - ldr r0, [r2]\n\ - ldr r1, =0xfff0ffff\n\ -_08043BF8:\n\ - ands r0, r1\n\ -_08043BFA:\n\ - str r0, [r2]\n\ -_08043BFC:\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =gUnknown_082DB68C\n\ - str r0, [r1]\n\ - ldr r0, =gBattleScripting\n\ - mov r1, r10\n\ - strb r1, [r0, 0x17]\n\ - ldr r4, =gActiveBank\n\ - strb r1, [r4]\n\ - ldrb r1, [r4]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - ldr r1, =gBattleMons + 0x4C\n\ - adds r0, r1\n\ - str r0, [sp]\n\ - movs r0, 0\n\ - movs r1, 0x28\n\ - movs r2, 0\n\ - movs r3, 0x4\n\ - bl EmitSetAttributes\n\ - ldrb r0, [r4]\n\ - bl MarkBufferBankForExecution\n\ - bl _0804443A\n\ - .pool\n\ -_08043C50:\n\ - mov r0, r10\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r10, r0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r10, r0\n\ - bcs _08043C64\n\ - b _08043918\n\ -_08043C64:\n\ - bl _0804441E\n\ - .pool\n\ -_08043C6C:\n\ - movs r2, 0\n\ - mov r10, r2\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r10, r0\n\ - bcc _08043C7A\n\ - b _0804441E\n\ -_08043C7A:\n\ - ldr r4, =gBattleMons\n\ -_08043C7C:\n\ - movs r0, 0x58\n\ - mov r3, r10\n\ - muls r3, r0\n\ - adds r0, r3, 0\n\ - adds r0, r4\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0x3B\n\ - bne _08043CA0\n\ - mov r0, r10\n\ - bl CastformDataTypeChange\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ - cmp r0, 0\n\ - beq _08043CA0\n\ - b _080442FC\n\ -_08043CA0:\n\ - mov r0, r10\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r10, r0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r10, r0\n\ - bcc _08043C7C\n\ - b _0804441E\n\ - .pool\n\ -_08043CBC:\n\ - ldrb r0, [r7]\n\ - cmp r0, 0x1C\n\ - beq _08043CC4\n\ - b _0804441E\n\ -_08043CC4:\n\ - ldr r4, =gHitMarker\n\ - ldr r1, [r4]\n\ - movs r0, 0x80\n\ - lsls r0, 7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043CD4\n\ - b _0804441E\n\ -_08043CD4:\n\ - ldr r0, =0xffffbfff\n\ - ands r1, r0\n\ - str r1, [r4]\n\ - mov r5, r8\n\ - ldr r1, [r5]\n\ - adds r1, 0xB2\n\ - ldrb r2, [r1]\n\ - movs r0, 0x3F\n\ - ands r0, r2\n\ - strb r0, [r1]\n\ - ldr r0, [r5]\n\ - adds r1, r0, 0\n\ - adds r1, 0xB2\n\ - ldrb r0, [r1]\n\ - cmp r0, 0x6\n\ - bne _08043CF8\n\ - movs r0, 0x2\n\ - strb r0, [r1]\n\ -_08043CF8:\n\ - ldr r1, =gBattleCommunication\n\ - mov r2, r8\n\ - ldr r0, [r2]\n\ - adds r0, 0xB2\n\ - ldrb r0, [r0]\n\ - adds r0, 0x40\n\ - strb r0, [r1, 0x3]\n\ - ldr r1, =gBattleScripting\n\ - ldr r0, =gBankTarget\n\ - ldrb r0, [r0]\n\ - strb r0, [r1, 0x17]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_SynchronizeActivates\n\ - str r0, [r1]\n\ - ldr r0, [r4]\n\ - movs r1, 0x80\n\ - lsls r1, 6\n\ - orrs r0, r1\n\ - str r0, [r4]\n\ - b _080443D0\n\ - .pool\n\ -_08043D40:\n\ - ldrb r0, [r7]\n\ - cmp r0, 0x1C\n\ - beq _08043D48\n\ - b _0804441E\n\ -_08043D48:\n\ - ldr r4, =gHitMarker\n\ - ldr r1, [r4]\n\ - movs r0, 0x80\n\ - lsls r0, 7\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _08043D58\n\ - b _0804441E\n\ -_08043D58:\n\ - ldr r0, =0xffffbfff\n\ - ands r1, r0\n\ - str r1, [r4]\n\ - mov r3, r8\n\ - ldr r1, [r3]\n\ - adds r1, 0xB2\n\ - ldrb r2, [r1]\n\ - movs r0, 0x3F\n\ - ands r0, r2\n\ - strb r0, [r1]\n\ - ldr r0, [r3]\n\ - adds r1, r0, 0\n\ - adds r1, 0xB2\n\ - ldrb r0, [r1]\n\ - cmp r0, 0x6\n\ - bne _08043D7C\n\ - movs r0, 0x2\n\ - strb r0, [r1]\n\ -_08043D7C:\n\ - ldr r1, =gBattleCommunication\n\ - mov r3, r8\n\ - ldr r0, [r3]\n\ - adds r0, 0xB2\n\ - ldrb r0, [r0]\n\ - strb r0, [r1, 0x3]\n\ - ldr r1, =gBattleScripting\n\ - ldr r0, =gBankAttacker\n\ - ldrb r0, [r0]\n\ - strb r0, [r1, 0x17]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =BattleScript_SynchronizeActivates\n\ - str r0, [r1]\n\ - ldr r0, [r4]\n\ - movs r1, 0x80\n\ - lsls r1, 6\n\ - orrs r0, r1\n\ - str r0, [r4]\n\ - b _080443D0\n\ - .pool\n\ -_08043DC4:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r1, [r0]\n\ - cmp r4, r1\n\ - blt _08043DD0\n\ - b _0804441E\n\ -_08043DD0:\n\ - ldr r0, =gBattleMons\n\ - adds r5, r1, 0\n\ - ldr r2, =gStatuses3\n\ - adds r3, r0, 0\n\ - adds r3, 0x20\n\ - movs r6, 0x80\n\ - lsls r6, 12\n\ -_08043DDE:\n\ - ldrb r1, [r3]\n\ - cmp r1, 0x16\n\ - bne _08043DEE\n\ - ldr r0, [r2]\n\ - ands r0, r6\n\ - cmp r0, 0\n\ - beq _08043DEE\n\ - b _08044324\n\ -_08043DEE:\n\ - adds r2, 0x4\n\ - adds r3, 0x58\n\ - adds r4, 0x1\n\ - cmp r4, r5\n\ - blt _08043DDE\n\ - b _0804441E\n\ - .pool\n\ -_08043E08:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08043E14\n\ - b _0804441E\n\ -_08043E14:\n\ - ldr r5, =gActiveBank\n\ - mov r8, r5\n\ - ldr r0, =gBattleMons\n\ - adds r0, 0x20\n\ - str r0, [sp, 0x1C]\n\ - movs r1, 0\n\ - str r1, [sp, 0x20]\n\ -_08043E22:\n\ - ldr r2, [sp, 0x1C]\n\ - ldrb r0, [r2]\n\ - cmp r0, 0x24\n\ - beq _08043E2C\n\ - b _08043FBE\n\ -_08043E2C:\n\ - ldr r0, =gStatuses3\n\ - ldr r3, [sp, 0x20]\n\ - adds r0, r3, r0\n\ - ldr r1, [r0]\n\ - movs r0, 0x80\n\ - lsls r0, 13\n\ - ands r1, r0\n\ - str r3, [sp, 0x18]\n\ - cmp r1, 0\n\ - bne _08043E42\n\ - b _08043FBE\n\ -_08043E42:\n\ - lsls r0, r4, 24\n\ - lsrs r0, 24\n\ - bl GetBankIdentity\n\ - movs r1, 0x1\n\ - adds r5, r0, 0\n\ - eors r5, r1\n\ - ands r5, r1\n\ - adds r0, r5, 0\n\ - bl GetBankByPlayerAI\n\ - lsls r0, 24\n\ - lsrs r6, r0, 24\n\ - adds r0, r5, 0x2\n\ - bl GetBankByPlayerAI\n\ - lsls r0, 24\n\ - lsrs r7, r0, 24\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r2, 0x1\n\ - ands r0, r2\n\ - cmp r0, 0\n\ - bne _08043E74\n\ - b _08043F84\n\ -_08043E74:\n\ - movs r1, 0x58\n\ - adds r0, r6, 0\n\ - muls r0, r1\n\ - ldr r3, =gBattleMons\n\ - adds r1, r0, r3\n\ - adds r0, r1, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0\n\ - beq _08043F40\n\ - ldrh r0, [r1, 0x28]\n\ - cmp r0, 0\n\ - beq _08043EFC\n\ - movs r1, 0x58\n\ - adds r0, r7, 0\n\ - muls r0, r1\n\ - adds r1, r0, r3\n\ - adds r0, r1, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0\n\ - beq _08043EFC\n\ - ldrh r0, [r1, 0x28]\n\ - cmp r0, 0\n\ - beq _08043EFC\n\ - str r2, [sp, 0x24]\n\ - bl Random\n\ - ldr r2, [sp, 0x24]\n\ - adds r1, r2, 0\n\ - ands r1, r0\n\ - lsls r1, 1\n\ - orrs r5, r1\n\ - adds r0, r5, 0\n\ - bl GetBankByPlayerAI\n\ - mov r2, r8\n\ - strb r0, [r2]\n\ - ldrb r0, [r2]\n\ - movs r3, 0x58\n\ - muls r0, r3\n\ - ldr r5, =gBattleMons\n\ - adds r0, r5\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - ldr r1, [sp, 0x1C]\n\ - strb r0, [r1]\n\ - ldrb r0, [r2]\n\ - muls r0, r3\n\ - adds r0, r5\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - ldr r2, =gLastUsedAbility\n\ - strb r0, [r2]\n\ - b _08043FAC\n\ - .pool\n\ -_08043EFC:\n\ - ldr r3, =gBattleMons\n\ - movs r2, 0x58\n\ - adds r0, r6, 0\n\ - muls r0, r2\n\ - adds r1, r0, r3\n\ - adds r0, r1, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0\n\ - beq _08043F40\n\ - ldrh r0, [r1, 0x28]\n\ - cmp r0, 0\n\ - beq _08043F40\n\ - mov r5, r8\n\ - strb r6, [r5]\n\ - adds r1, r4, 0\n\ - muls r1, r2\n\ - adds r1, r3\n\ - ldrb r0, [r5]\n\ - muls r0, r2\n\ - adds r0, r3\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - adds r1, 0x20\n\ - strb r0, [r1]\n\ - ldrb r0, [r5]\n\ - muls r0, r2\n\ - adds r0, r3\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - b _08043FA8\n\ - .pool\n\ -_08043F40:\n\ - ldr r3, =gBattleMons\n\ - movs r2, 0x58\n\ - adds r0, r7, 0\n\ - muls r0, r2\n\ - adds r1, r0, r3\n\ - adds r0, r1, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0\n\ - beq _08043FB6\n\ - ldrh r0, [r1, 0x28]\n\ - cmp r0, 0\n\ - beq _08043FB6\n\ - mov r5, r8\n\ - strb r7, [r5]\n\ - adds r1, r4, 0\n\ - muls r1, r2\n\ - adds r1, r3\n\ - ldrb r0, [r5]\n\ - muls r0, r2\n\ - adds r0, r3\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - adds r1, 0x20\n\ - strb r0, [r1]\n\ - ldrb r0, [r5]\n\ - muls r0, r2\n\ - adds r0, r3\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - b _08043FA8\n\ - .pool\n\ -_08043F84:\n\ - mov r2, r8\n\ - strb r6, [r2]\n\ - movs r3, 0x58\n\ - adds r0, r6, 0\n\ - muls r0, r3\n\ - ldr r5, =gBattleMons\n\ - adds r0, r5\n\ - adds r2, r0, 0\n\ - adds r2, 0x20\n\ - ldrb r1, [r2]\n\ - cmp r1, 0\n\ - beq _08043FB6\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - beq _08043FB6\n\ - ldr r0, [sp, 0x1C]\n\ - strb r1, [r0]\n\ - ldrb r0, [r2]\n\ -_08043FA8:\n\ - ldr r1, =gLastUsedAbility\n\ - strb r0, [r1]\n\ -_08043FAC:\n\ - mov r0, r9\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_08043FB6:\n\ - mov r2, r9\n\ - cmp r2, 0\n\ - beq _08043FBE\n\ - b _08044340\n\ -_08043FBE:\n\ - ldr r3, [sp, 0x1C]\n\ - adds r3, 0x58\n\ - str r3, [sp, 0x1C]\n\ - ldr r5, [sp, 0x20]\n\ - adds r5, 0x4\n\ - str r5, [sp, 0x20]\n\ - adds r4, 0x1\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - bge _08043FD6\n\ - b _08043E22\n\ -_08043FD6:\n\ - b _0804441E\n\ - .pool\n\ -_08043FE4:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r1, [r0]\n\ - cmp r4, r1\n\ - blt _08043FF0\n\ - b _0804441E\n\ -_08043FF0:\n\ - ldr r0, =gBattleMons\n\ - adds r5, r1, 0\n\ - ldr r2, =gStatuses3\n\ - adds r3, r0, 0\n\ - adds r3, 0x20\n\ - movs r6, 0x80\n\ - lsls r6, 12\n\ -_08043FFE:\n\ - ldrb r1, [r3]\n\ - cmp r1, 0x16\n\ - bne _0804400E\n\ - ldr r0, [r2]\n\ - ands r0, r6\n\ - cmp r0, 0\n\ - beq _0804400E\n\ - b _080443B4\n\ -_0804400E:\n\ - adds r2, 0x4\n\ - adds r3, 0x58\n\ - adds r4, 0x1\n\ - cmp r4, r5\n\ - blt _08043FFE\n\ - b _0804441E\n\ - .pool\n\ -_08044028:\n\ - mov r0, r10\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r5, r0, 24\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _0804403E\n\ - b _0804441E\n\ -_0804403E:\n\ - ldr r7, =gBattleMons\n\ -_08044040:\n\ - lsls r0, r4, 24\n\ - lsrs r0, 24\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - adds r3, r4, 0x1\n\ - cmp r0, r5\n\ - beq _0804406A\n\ - movs r0, 0x58\n\ - muls r0, r4\n\ - adds r0, r7\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, r6\n\ - bne _0804406A\n\ - ldr r0, =gLastUsedAbility\n\ - strb r6, [r0]\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_0804406A:\n\ - adds r4, r3, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044040\n\ - b _0804441E\n\ - .pool\n\ -_08044084:\n\ - mov r0, r10\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r5, r0, 24\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _0804409A\n\ - b _0804441E\n\ -_0804409A:\n\ - ldr r7, =gBattleMons\n\ -_0804409C:\n\ - lsls r0, r4, 24\n\ - lsrs r0, 24\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - adds r3, r4, 0x1\n\ - cmp r0, r5\n\ - bne _080440C6\n\ - movs r0, 0x58\n\ - muls r0, r4\n\ - adds r0, r7\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, r6\n\ - bne _080440C6\n\ - ldr r0, =gLastUsedAbility\n\ - strb r6, [r0]\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_080440C6:\n\ - adds r4, r3, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _0804409C\n\ - b _0804441E\n\ - .pool\n\ -_080440E0:\n\ - ldrb r0, [r7]\n\ - cmp r0, 0xFD\n\ - beq _08044104\n\ - cmp r0, 0xFE\n\ - beq _0804413C\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - adds r5, r0, 0\n\ - ldrb r0, [r5]\n\ - cmp r4, r0\n\ - blt _080440F8\n\ - b _0804441E\n\ -_080440F8:\n\ - ldr r2, =gBattleMons\n\ - b _08044174\n\ - .pool\n\ -_08044104:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044110\n\ - b _0804441E\n\ -_08044110:\n\ - ldr r5, =gStatuses3\n\ - movs r2, 0x80\n\ - lsls r2, 9\n\ - adds r1, r0, 0\n\ -_08044118:\n\ - lsls r0, r4, 2\n\ - adds r0, r5\n\ - ldr r0, [r0]\n\ - ands r0, r2\n\ - adds r3, r4, 0x1\n\ - cmp r0, 0\n\ - beq _0804412C\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_0804412C:\n\ - adds r4, r3, 0\n\ - cmp r4, r1\n\ - blt _08044118\n\ - b _0804441E\n\ - .pool\n\ -_0804413C:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044148\n\ - b _0804441E\n\ -_08044148:\n\ - ldr r5, =gStatuses3\n\ - movs r2, 0x80\n\ - lsls r2, 10\n\ - adds r1, r0, 0\n\ -_08044150:\n\ - lsls r0, r4, 2\n\ - adds r0, r5\n\ - ldr r0, [r0]\n\ - ands r0, r2\n\ - adds r3, r4, 0x1\n\ - cmp r0, 0\n\ - beq _08044164\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_08044164:\n\ - adds r4, r3, 0\n\ - cmp r4, r1\n\ - blt _08044150\n\ - b _0804441E\n\ - .pool\n\ -_08044174:\n\ - movs r0, 0x58\n\ - muls r0, r4\n\ - adds r0, r2\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - adds r3, r4, 0x1\n\ - cmp r0, r6\n\ - bne _0804418C\n\ - strb r6, [r7]\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_0804418C:\n\ - adds r4, r3, 0\n\ - ldrb r1, [r5]\n\ - cmp r4, r1\n\ - blt _08044174\n\ - b _0804441E\n\ -_08044196:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _080441A2\n\ - b _0804441E\n\ -_080441A2:\n\ - ldr r2, =gBattleMons\n\ - mov r8, r2\n\ - adds r2, r0, 0\n\ - movs r5, 0x58\n\ -_080441AA:\n\ - adds r0, r4, 0\n\ - muls r0, r5\n\ - mov r3, r8\n\ - adds r1, r0, r3\n\ - adds r0, r1, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - adds r3, r4, 0x1\n\ - cmp r0, r6\n\ - bne _080441CC\n\ - ldrh r0, [r1, 0x28]\n\ - cmp r0, 0\n\ - beq _080441CC\n\ - strb r6, [r7]\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_080441CC:\n\ - adds r4, r3, 0\n\ - cmp r4, r2\n\ - blt _080441AA\n\ - b _0804441E\n\ - .pool\n\ -_080441DC:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _080441E8\n\ - b _0804441E\n\ -_080441E8:\n\ - ldr r7, =gBattleMons\n\ - adds r1, r0, 0\n\ - movs r5, 0x58\n\ - ldr r2, =gLastUsedAbility\n\ -_080441F0:\n\ - adds r0, r4, 0\n\ - muls r0, r5\n\ - adds r0, r7\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - adds r3, r4, 0x1\n\ - cmp r0, r6\n\ - bne _0804420C\n\ - cmp r4, r10\n\ - beq _0804420C\n\ - strb r6, [r2]\n\ - lsls r0, r3, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_0804420C:\n\ - adds r4, r3, 0\n\ - cmp r4, r1\n\ - blt _080441F0\n\ - b _0804441E\n\ - .pool\n\ -_08044220:\n\ - mov r0, r10\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r5, r0, 24\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044236\n\ - b _0804441E\n\ -_08044236:\n\ - ldr r7, =gBattleMons\n\ -_08044238:\n\ - lsls r0, r4, 24\n\ - lsrs r0, 24\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - cmp r0, r5\n\ - beq _08044264\n\ - movs r0, 0x58\n\ - muls r0, r4\n\ - adds r0, r7\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, r6\n\ - bne _08044264\n\ - ldr r0, =gLastUsedAbility\n\ - strb r6, [r0]\n\ - mov r0, r9\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_08044264:\n\ - adds r4, 0x1\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044238\n\ - b _0804441E\n\ - .pool\n\ -_0804427C:\n\ - mov r0, r10\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r5, r0, 24\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044292\n\ - b _0804441E\n\ -_08044292:\n\ - ldr r7, =gBattleMons\n\ -_08044294:\n\ - lsls r0, r4, 24\n\ - lsrs r0, 24\n\ - bl GetBankSide\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - cmp r0, r5\n\ - bne _080442C0\n\ - movs r0, 0x58\n\ - muls r0, r4\n\ - adds r0, r7\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, r6\n\ - bne _080442C0\n\ - ldr r0, =gLastUsedAbility\n\ - strb r6, [r0]\n\ - mov r0, r9\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_080442C0:\n\ - adds r4, 0x1\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r0, [r0]\n\ - cmp r4, r0\n\ - blt _08044294\n\ - b _0804441E\n\ - .pool\n\ -_080442D8:\n\ - ldr r0, =BattleScript_CastformChange\n\ - bl b_push_move_exec\n\ - ldr r0, =gBattleScripting\n\ - strb r6, [r0, 0x17]\n\ -_080442E2:\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - adds r0, 0x7F\n\ - mov r1, r9\n\ - subs r1, 0x1\n\ - strb r1, [r0]\n\ - b _0804441E\n\ - .pool\n\ -_080442FC:\n\ - ldr r0, =BattleScript_CastformChange\n\ - bl b_push_move_exec\n\ - ldr r0, =gBattleScripting\n\ - mov r5, r10\n\ - strb r5, [r0, 0x17]\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - adds r0, 0x7F\n\ - mov r1, r9\n\ - subs r1, 0x1\n\ - strb r1, [r0]\n\ - b _0804443A\n\ - .pool\n\ -_08044324:\n\ - strb r1, [r7]\n\ - ldr r0, [r2]\n\ - ldr r1, =0xfff7ffff\n\ - ands r0, r1\n\ - str r0, [r2]\n\ - ldr r0, =gUnknown_082DB4B8\n\ - bl b_push_move_exec\n\ - b _080443C8\n\ - .pool\n\ -_08044340:\n\ - ldr r0, =BattleScript_TraceActivates\n\ - bl b_push_move_exec\n\ - ldr r1, =gStatuses3\n\ - ldr r0, [sp, 0x18]\n\ - adds r1, r0, r1\n\ - ldr r0, [r1]\n\ - ldr r2, =0xffefffff\n\ - ands r0, r2\n\ - str r0, [r1]\n\ - ldr r0, =gBattleScripting\n\ - strb r4, [r0, 0x17]\n\ - ldr r1, =gBattleTextBuff1\n\ - movs r4, 0xFD\n\ - strb r4, [r1]\n\ - movs r0, 0x4\n\ - strb r0, [r1, 0x1]\n\ - ldr r2, =gActiveBank\n\ - ldrb r0, [r2]\n\ - strb r0, [r1, 0x2]\n\ - ldr r3, =gBattlePartyID\n\ - ldrb r0, [r2]\n\ - lsls r0, 1\n\ - adds r0, r3\n\ - ldrh r0, [r0]\n\ - strb r0, [r1, 0x3]\n\ - movs r0, 0xFF\n\ - strb r0, [r1, 0x4]\n\ - ldr r1, =gBattleTextBuff2\n\ - strb r4, [r1]\n\ - movs r0, 0x9\n\ - strb r0, [r1, 0x1]\n\ - ldr r0, =gLastUsedAbility\n\ - ldrb r0, [r0]\n\ - strb r0, [r1, 0x2]\n\ - movs r0, 0x1\n\ - negs r0, r0\n\ - strb r0, [r1, 0x3]\n\ - b _0804441E\n\ - .pool\n\ -_080443B4:\n\ - strb r1, [r7]\n\ - ldr r0, [r2]\n\ - ldr r1, =0xfff7ffff\n\ - ands r0, r1\n\ - str r0, [r2]\n\ - bl b_movescr_stack_push_cursor\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, =gUnknown_082DB4C1\n\ - str r0, [r1]\n\ -_080443C8:\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - adds r0, 0xD8\n\ - strb r4, [r0]\n\ -_080443D0:\n\ - mov r0, r9\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ - b _0804441E\n\ - .pool\n\ -_080443EC:\n\ - movs r4, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r1, [r0]\n\ - cmp r4, r1\n\ - bge _0804441E\n\ - ldr r0, =gBattleMons\n\ - adds r2, r1, 0\n\ - adds r1, r0, 0\n\ - adds r1, 0x20\n\ - ldr r3, =gLastUsedAbility\n\ -_08044400:\n\ - ldrb r0, [r1]\n\ - cmp r0, r6\n\ - bne _08044416\n\ - cmp r4, r10\n\ - beq _08044416\n\ - strb r6, [r3]\n\ - mov r0, r9\n\ - adds r0, 0x1\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - mov r9, r0\n\ -_08044416:\n\ - adds r1, 0x58\n\ - adds r4, 0x1\n\ - cmp r4, r2\n\ - blt _08044400\n\ -_0804441E:\n\ - mov r1, r9\n\ - cmp r1, 0\n\ - beq _0804443A\n\ -_08044424:\n\ - ldr r2, [sp, 0x4]\n\ - cmp r2, 0xB\n\ - bhi _0804443A\n\ - ldr r1, =gLastUsedAbility\n\ - ldrb r0, [r1]\n\ - cmp r0, 0xFF\n\ - beq _0804443A\n\ - adds r1, r0, 0\n\ - mov r0, r10\n\ - bl RecordAbilityBattle\n\ -_0804443A:\n\ - mov r0, r9\n\ - add sp, 0x28\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r1}\n\ - bx r1\n\ - .pool\n\ - .syntax divided"); -} -#endif // NONMATCHING -void b_call_bc_move_exec(const u8* BS_ptr) +void BattleScriptExecute(const u8* BS_ptr) { gBattlescriptCurrInstr = BS_ptr; BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size++] = gBattleMainFunc; - gBattleMainFunc = bc_move_exec_returning; - gFightStateTracker = 0; + gBattleMainFunc = RunBattleScriptCommands_PopCallbacksStack; + gCurrentActionFuncId = 0; } -void b_push_move_exec(const u8* BS_ptr) +void BattleScriptPushCursorAndCallback(const u8* BS_ptr) { - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BS_ptr; BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size++] = gBattleMainFunc; - gBattleMainFunc = sub_803E08C; + gBattleMainFunc = RunBattleScriptCommands; } enum @@ -5546,7 +2719,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) switch (caseID) { - case 0: + case ITEMEFFECT_ON_SWITCH_IN: switch (bankHoldEffect) { case HOLD_EFFECT_DOUBLE_PRIZE: @@ -5567,7 +2740,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.bank = bank; gStringBank = bank; gActiveBank = gBankAttacker = bank; - b_call_bc_move_exec(BattleScript_WhiteHerbEnd2); + BattleScriptExecute(BattleScript_WhiteHerbEnd2); } break; } @@ -5584,7 +2757,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].hp + bankQuality > gBattleMons[bank].maxHP) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = 4; } break; @@ -5619,8 +2792,8 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleTextBuff1[2] = move; gBattleTextBuff1[3] = move >> 8; gBattleTextBuff1[4] = 0xFF; - b_call_bc_move_exec(BattleScript_BerryPPHealEnd2); - EmitSetAttributes(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); + BattleScriptExecute(BattleScript_BerryPPHealEnd2); + EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); MarkBufferBankForExecution(gActiveBank); effect = ITEM_PP_CHANGE; } @@ -5640,7 +2813,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.bank = bank; gStringBank = bank; gActiveBank = gBankAttacker = bank; - b_call_bc_move_exec(BattleScript_WhiteHerbEnd2); + BattleScriptExecute(BattleScript_WhiteHerbEnd2); } break; case HOLD_EFFECT_LEFTOVERS: @@ -5652,7 +2825,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; - b_call_bc_move_exec(BattleScript_ItemHealHP_End2); + BattleScriptExecute(BattleScript_ItemHealHP_End2); effect = ITEM_HP_CHANGE; RecordItemEffectBattle(bank, bankHoldEffect); } @@ -5672,9 +2845,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SPICY) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5692,9 +2865,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_DRY) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5712,9 +2885,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SWEET) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5732,9 +2905,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_BITTER) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5752,9 +2925,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SOUR) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5777,7 +2950,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_ATK; gBattleScripting.animArg1 = 0xE + STAT_STAGE_ATK; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5793,7 +2966,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_DEF; gBattleScripting.animArg1 = 0xE + STAT_STAGE_DEF; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5809,7 +2982,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_SPEED; gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPEED; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5825,7 +2998,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_SPATK; gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPATK; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5841,7 +3014,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_SPDEF; gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPDEF; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5849,7 +3022,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && !(gBattleMons[bank].status2 & STATUS2_FOCUS_ENERGY)) { gBattleMons[bank].status2 |= STATUS2_FOCUS_ENERGY; - b_call_bc_move_exec(BattleScript_BerryFocusEnergyEnd2); + BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); effect = ITEM_EFFECT_OTHER; } break; @@ -5886,7 +3059,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x21 + i; gBattleScripting.animArg1 = 0x21 + i + 6; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } } @@ -5895,7 +3068,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PARALYSIS) { gBattleMons[bank].status1 &= ~(STATUS_PARALYSIS); - b_call_bc_move_exec(BattleScript_BerryCurePrlzEnd2); + BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5903,7 +3076,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PSN_ANY) { gBattleMons[bank].status1 &= ~(STATUS_PSN_ANY | STATUS_TOXIC_COUNTER); - b_call_bc_move_exec(BattleScript_BerryCurePsnEnd2); + BattleScriptExecute(BattleScript_BerryCurePsnEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5911,7 +3084,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_BURN) { gBattleMons[bank].status1 &= ~(STATUS_BURN); - b_call_bc_move_exec(BattleScript_BerryCureBrnEnd2); + BattleScriptExecute(BattleScript_BerryCureBrnEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5919,7 +3092,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_FREEZE) { gBattleMons[bank].status1 &= ~(STATUS_FREEZE); - b_call_bc_move_exec(BattleScript_BerryCureFrzEnd2); + BattleScriptExecute(BattleScript_BerryCureFrzEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5928,7 +3101,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status1 &= ~(STATUS_SLEEP); gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); - b_call_bc_move_exec(BattleScript_BerryCureSlpEnd2); + BattleScriptExecute(BattleScript_BerryCureSlpEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5936,7 +3109,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status2 & STATUS2_CONFUSION) { gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_call_bc_move_exec(BattleScript_BerryCureConfusionEnd2); + BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); effect = ITEM_EFFECT_OTHER; } break; @@ -5981,7 +3154,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleCommunication[MULTISTRING_CHOOSER] = 1; gBattleMons[bank].status1 = 0; gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_call_bc_move_exec(BattleScript_BerryCureChosenStatusEnd2); + BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5990,7 +3163,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION); StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - b_call_bc_move_exec(BattleScript_BerryCureChosenStatusEnd2); + BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); gBattleCommunication[MULTISTRING_CHOOSER] = 0; effect = ITEM_EFFECT_OTHER; } @@ -6004,7 +3177,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) switch (effect) { case ITEM_STATUS_CHANGE: - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); MarkBufferBankForExecution(gActiveBank); break; case ITEM_PP_CHANGE: @@ -6037,7 +3210,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PARALYSIS) { gBattleMons[bank].status1 &= ~(STATUS_PARALYSIS); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureParRet; effect = ITEM_STATUS_CHANGE; } @@ -6046,7 +3219,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PSN_ANY) { gBattleMons[bank].status1 &= ~(STATUS_PSN_ANY | STATUS_TOXIC_COUNTER); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCurePsnRet; effect = ITEM_STATUS_CHANGE; } @@ -6055,7 +3228,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_BURN) { gBattleMons[bank].status1 &= ~(STATUS_BURN); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureBrnRet; effect = ITEM_STATUS_CHANGE; } @@ -6064,7 +3237,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_FREEZE) { gBattleMons[bank].status1 &= ~(STATUS_FREEZE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet; effect = ITEM_STATUS_CHANGE; } @@ -6074,7 +3247,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status1 &= ~(STATUS_SLEEP); gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet; effect = ITEM_STATUS_CHANGE; } @@ -6083,7 +3256,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status2 & STATUS2_CONFUSION) { gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureConfusionRet; effect = ITEM_EFFECT_OTHER; } @@ -6093,7 +3266,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION); StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet; effect = ITEM_EFFECT_OTHER; @@ -6129,7 +3302,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) } gBattleMons[bank].status1 = 0; gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet; effect = ITEM_STATUS_CHANGE; @@ -6148,7 +3321,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleScripting.bank = bank; gStringBank = bank; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_WhiteHerbRet; return effect; // unnecessary return } @@ -6159,7 +3332,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.bank = bank; gStringBank = bank; gActiveBank = bank; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); break; } @@ -6178,9 +3351,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) && gBattleMons[gBankTarget].hp) { gBattleCommunication[MOVE_EFFECT_BYTE] = 8; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); SetMoveEffect(0, 0); - b_movescr_stack_pop_cursor(); + BattleScriptPop(); } break; case HOLD_EFFECT_SHELL_BELL: @@ -6198,7 +3371,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMoveDamage == 0) gBattleMoveDamage = -1; gSpecialStatuses[gBankTarget].moveturnLostHP = 0; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret; effect++; } @@ -6211,14 +3384,14 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) return effect; } -void sub_8045868(u8 bank) +void ClearFuryCutterDestinyBondGrudge(u8 bank) { gDisableStructs[bank].furyCutterCounter = 0; gBattleMons[bank].status2 &= ~(STATUS2_DESTINY_BOND); gStatuses3[bank] &= ~(STATUS3_GRUDGE); } -void sub_80458B4(void) +void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands { if (gBattleExecBuffer == 0) gBattleScriptingCommandsTable[*gBattlescriptCurrInstr](); @@ -6237,7 +3410,7 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) switch (moveTarget) { - case 0: + case MOVE_TARGET_SELECTED: side = GetBankSide(gBankAttacker) ^ 1; if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) targetBank = gSideTimers[side].followmeTarget; @@ -6249,7 +3422,7 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) targetBank = Random() % gNoOfAllBanks; } while (targetBank == gBankAttacker || side == GetBankSide(targetBank) || gAbsentBankFlags & gBitTable[targetBank]); if (gBattleMoves[move].type == TYPE_ELECTRIC - && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0) + && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0) && gBattleMons[targetBank].ability != ABILITY_LIGHTNING_ROD) { targetBank ^= 2; @@ -6258,42 +3431,42 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) } } break; - case 1: - case 8: - case 32: - case 64: - targetBank = GetBankByPlayerAI((GetBankIdentity(gBankAttacker) & 1) ^ 1); + case MOVE_TARGET_DEPENDS: + case MOVE_TARGET_BOTH: + case MOVE_TARGET_FOES_AND_ALLY: + case MOVE_TARGET_OPPONENTS_FIELD: + targetBank = GetBankByIdentity((GetBankIdentity(gBankAttacker) & 1) ^ 1); if (gAbsentBankFlags & gBitTable[targetBank]) targetBank ^= 2; break; - case 4: + case MOVE_TARGET_RANDOM: side = GetBankSide(gBankAttacker) ^ 1; if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) targetBank = gSideTimers[side].followmeTarget; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & 4) + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM) { if (GetBankSide(gBankAttacker) == SIDE_PLAYER) { if (Random() & 1) - targetBank = GetBankByPlayerAI(1); + targetBank = GetBankByIdentity(1); else - targetBank = GetBankByPlayerAI(3); + targetBank = GetBankByIdentity(3); } else { if (Random() & 1) - targetBank = GetBankByPlayerAI(0); + targetBank = GetBankByIdentity(0); else - targetBank = GetBankByPlayerAI(2); + targetBank = GetBankByIdentity(2); } if (gAbsentBankFlags & gBitTable[targetBank]) targetBank ^= 2; } else - targetBank = GetBankByPlayerAI((GetBankIdentity(gBankAttacker) & 1) ^ 1); + targetBank = GetBankByIdentity((GetBankIdentity(gBankAttacker) & 1) ^ 1); break; - case 2: - case 16: + case MOVE_TARGET_USER: + case MOVE_TARGET_x10: targetBank = gBankAttacker; break; } diff --git a/src/berry_blender.c b/src/berry_blender.c new file mode 100644 index 000000000..db50fe4c4 --- /dev/null +++ b/src/berry_blender.c @@ -0,0 +1,18 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations +IWRAM_DATA void *berry_blender_c_unused_03000de4; +IWRAM_DATA s16 gUnknown_03000DE8[8]; +IWRAM_DATA s16 gUnknown_03000DF8[6]; +IWRAM_DATA s16 gUnknown_03000E04; +IWRAM_DATA s16 gUnknown_03000E06; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/braille_puzzles.c b/src/braille_puzzles.c new file mode 100755 index 000000000..9a6f0371c --- /dev/null +++ b/src/braille_puzzles.c @@ -0,0 +1,583 @@ +#include "global.h" +#include "event_data.h" +#include "songs.h" +#include "sound.h" +#include "script.h" +#include "species.h" +#include "task.h" +#include "field_effect.h" +#include "flags.h" + +extern void MapGridSetMetatileIdAt(s32 x, s32 y, u16 metatileId); // fieldmap +extern void DrawWholeMapView(); // field_camera +extern void SetCameraPanningCallback(void ( *callback)()); // field_camera +extern void InstallCameraPanAheadCallback(void); +extern void SetCameraPanning(s16 x, s16 y); +extern u8 brm_get_pokemon_selection(void); +extern void FieldEffectActiveListRemove(u8 id); // field_effect +extern u8 oei_task_add(void); + +// why do this, GF? +enum +{ + STRENGTH_PUZZLE, + FLY_PUZZLE +}; + +extern u8 gBraillePuzzleCallbackFlag; +extern u8 gUnknown_085EFE74[][2]; + +void SealedChamberShakingEffect(u8); +void sub_8179860(void); +void sub_8179944(void); + +bool8 ShouldDoBrailleDigEffect(void) +{ + if (!FlagGet(SYS_BRAILLE_DIG) + && (gSaveBlock1Ptr->location.mapGroup == 0x18 + && gSaveBlock1Ptr->location.mapNum == 0x47)) + { + if (gSaveBlock1Ptr->pos.x == 10 && gSaveBlock1Ptr->pos.y == 3) + return TRUE; + if (gSaveBlock1Ptr->pos.x == 9 && gSaveBlock1Ptr->pos.y == 3) + return TRUE; + if (gSaveBlock1Ptr->pos.x == 11 && gSaveBlock1Ptr->pos.y == 3) + return TRUE; + } + + return FALSE; +} + +void DoBrailleDigEffect(void) +{ + MapGridSetMetatileIdAt(16, 8, 554); + MapGridSetMetatileIdAt(17, 8, 555); + MapGridSetMetatileIdAt(18, 8, 556); + MapGridSetMetatileIdAt(16, 9, 3634); + MapGridSetMetatileIdAt(17, 9, 563); + MapGridSetMetatileIdAt(18, 9, 3636); + DrawWholeMapView(); + PlaySE(SE_BAN); + FlagSet(SYS_BRAILLE_DIG); + ScriptContext2_Disable(); +} + +bool8 CheckRelicanthWailord(void) +{ + // Emerald change: why did they flip it? + // First comes Wailord + if (GetMonData(&gPlayerParty[0], MON_DATA_SPECIES2, 0) == SPECIES_WAILORD) + { + CalculatePlayerPartyCount(); + // Last comes Relicanth + if (GetMonData(&gPlayerParty[gPlayerPartyCount - 1], MON_DATA_SPECIES2, 0) == SPECIES_RELICANTH) + return TRUE; + } + return FALSE; +} + +// THEORY: this was caused by block commenting out all of the older R/S braille functions but leaving the call to it itself, which creates the nullsub. +// the code is shown below to show what this might look like. +void ShouldDoBrailleStrengthEffectOld(void) +{ + /* + if (!FlagGet(SYS_BRAILLE_STRENGTH) && (gSaveBlock1.location.mapGroup == MAP_GROUP_DESERT_RUINS && gSaveBlock1.location.mapNum == MAP_ID_DESERT_RUINS)) + { + if (gSaveBlock1.pos.x == 10 && gSaveBlock1.pos.y == 23) + return TRUE; + else if (gSaveBlock1.pos.x == 9 && gSaveBlock1.pos.y == 23) + return TRUE; + else if (gSaveBlock1.pos.x == 11 && gSaveBlock1.pos.y == 23) + return TRUE; + } + + return FALSE; +} + +void DoBrailleStrengthEffect(void) +{ + FieldEffectActiveListRemove(FLDEFF_USE_STRENGTH); + MapGridSetMetatileIdAt(14, 26, 554); + MapGridSetMetatileIdAt(15, 26, 555); + MapGridSetMetatileIdAt(16, 26, 556); + MapGridSetMetatileIdAt(14, 27, 3634); + MapGridSetMetatileIdAt(15, 27, 563); + MapGridSetMetatileIdAt(16, 27, 3636); + DrawWholeMapView(); + PlaySE(SE_BAN); + FlagSet(SYS_BRAILLE_STRENGTH); + ScriptContext2_Disable(); +} + +bool8 ShouldDoBrailleFlyEffect(void) +{ + if (!FlagGet(SYS_BRAILLE_FLY) && (gSaveBlock1.location.mapGroup == MAP_GROUP_ANCIENT_TOMB && gSaveBlock1.location.mapNum == MAP_ID_ANCIENT_TOMB)) + { + if (gSaveBlock1.pos.x == 8 && gSaveBlock1.pos.y == 25) + return TRUE; + } + + return FALSE; +} + +void DoBrailleFlyEffect(void) +{ + gFieldEffectArguments[0] = gLastFieldPokeMenuOpened; + FieldEffectStart(FLDEFF_USE_FLY_ANCIENT_TOMB); +} + +bool8 FldEff_UseFlyAncientTomb(void) +{ + u8 taskId = oei_task_add(); + + gTasks[taskId].data[8] = (u32)UseFlyAncientTomb_Callback >> 16; + gTasks[taskId].data[9] = (u32)UseFlyAncientTomb_Callback; + return FALSE; +} + +void UseFlyAncientTomb_Callback(void) +{ + FieldEffectActiveListRemove(FLDEFF_USE_FLY_ANCIENT_TOMB); + UseFlyAncientTomb_Finish(); +} + +void UseFlyAncientTomb_Finish(void) +{ + MapGridSetMetatileIdAt(14, 26, 554); + MapGridSetMetatileIdAt(15, 26, 555); + MapGridSetMetatileIdAt(16, 26, 556); + MapGridSetMetatileIdAt(14, 27, 3634); + MapGridSetMetatileIdAt(15, 27, 563); + MapGridSetMetatileIdAt(16, 27, 3636); + DrawWholeMapView(); + PlaySE(SE_BAN); + FlagSet(SYS_BRAILLE_FLY); + ScriptContext2_Disable(); +} + */ +} + +void DoSealedChamberShakingEffect1(void) +{ + u8 taskId = CreateTask(SealedChamberShakingEffect, 9); + + gTasks[taskId].data[1] = 0; + gTasks[taskId].data[2] = 0; + gTasks[taskId].data[4] = 2; + gTasks[taskId].data[5] = 5; + gTasks[taskId].data[6] = 50; + SetCameraPanningCallback(0); +} + +void DoSealedChamberShakingEffect2(void) +{ + u8 taskId = CreateTask(SealedChamberShakingEffect, 9); + + gTasks[taskId].data[1] = 0; + gTasks[taskId].data[2] = 0; + gTasks[taskId].data[4] = 3; + gTasks[taskId].data[5] = 5; + gTasks[taskId].data[6] = 2; + SetCameraPanningCallback(0); +} + +void SealedChamberShakingEffect(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + + task->data[1]++; + + if (!(task->data[1] % task->data[5])) + { + task->data[1] = 0; + task->data[2]++; + task->data[4] = -task->data[4]; + SetCameraPanning(0, task->data[4]); + if (task->data[2] == task->data[6]) + { + DestroyTask(taskId); + EnableBothScriptContexts(); + InstallCameraPanAheadCallback(); + } + } +} + +// moved later in the function because it was rewritten. +bool8 ShouldDoBrailleStrengthEffect(void) +{ + if (!FlagGet(SYS_BRAILLE_STRENGTH) && (gSaveBlock1Ptr->location.mapGroup == 0x18 && gSaveBlock1Ptr->location.mapNum == 0x06)) + { + if (gSaveBlock1Ptr->pos.x == 6 && gSaveBlock1Ptr->pos.y == 23) + { gBraillePuzzleCallbackFlag = STRENGTH_PUZZLE; return TRUE; } + else if (gSaveBlock1Ptr->pos.x == 5 && gSaveBlock1Ptr->pos.y == 23) + { gBraillePuzzleCallbackFlag = STRENGTH_PUZZLE; return TRUE; } + else if (gSaveBlock1Ptr->pos.x == 7 && gSaveBlock1Ptr->pos.y == 23) + { gBraillePuzzleCallbackFlag = STRENGTH_PUZZLE; return TRUE; } + } + + return FALSE; +} + +void sub_8179834(void) +{ + gFieldEffectArguments[0] = brm_get_pokemon_selection(); + FieldEffectStart(FLDEFF_USE_FLY_ANCIENT_TOMB); +} + +void UseStrengthDesertRuins_Callback(void) +{ + FieldEffectActiveListRemove(FLDEFF_USE_FLY_ANCIENT_TOMB); + sub_8179860(); +} + +void sub_8179860(void) +{ + MapGridSetMetatileIdAt(14, 26, 554); + MapGridSetMetatileIdAt(15, 26, 555); + MapGridSetMetatileIdAt(16, 26, 556); + MapGridSetMetatileIdAt(14, 27, 3634); + MapGridSetMetatileIdAt(15, 27, 563); + MapGridSetMetatileIdAt(16, 27, 3636); + DrawWholeMapView(); + PlaySE(SE_BAN); + FlagSet(SYS_BRAILLE_STRENGTH); + ScriptContext2_Disable(); +} + +bool8 ShouldDoBrailleFlyEffect(void) +{ + if (!FlagGet(SYS_BRAILLE_FLY) && (gSaveBlock1Ptr->location.mapGroup == 0x18 && gSaveBlock1Ptr->location.mapNum == 0x44)) + { + if (gSaveBlock1Ptr->pos.x == 8 && gSaveBlock1Ptr->pos.y == 25) + { gBraillePuzzleCallbackFlag = FLY_PUZZLE; return TRUE; } + } + return FALSE; +} + +void sub_8179918(void) +{ + gFieldEffectArguments[0] = brm_get_pokemon_selection(); + FieldEffectStart(FLDEFF_USE_FLY_ANCIENT_TOMB); +} + +void UseFlyAncientTomb_Callback(void) +{ + FieldEffectActiveListRemove(FLDEFF_USE_FLY_ANCIENT_TOMB); + sub_8179944(); +} + +void sub_8179944(void) +{ + MapGridSetMetatileIdAt(14, 26, 554); + MapGridSetMetatileIdAt(15, 26, 555); + MapGridSetMetatileIdAt(16, 26, 556); + MapGridSetMetatileIdAt(14, 27, 3634); + MapGridSetMetatileIdAt(15, 27, 563); + MapGridSetMetatileIdAt(16, 27, 3636); + DrawWholeMapView(); + PlaySE(SE_BAN); + FlagSet(SYS_BRAILLE_FLY); + ScriptContext2_Disable(); +} + +// theory: another commented out DoBrailleWait and Task_BrailleWait. +void DoBrailleWait(void) +{ + /* + if (!FlagGet(SYS_BRAILLE_WAIT)) + CreateTask(Task_BrailleWait, 0x50); +} + +void Task_BrailleWait(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + switch (data[0]) + { + case 0: + data[1] = 7200; + data[0] = 1; + break; + case 1: + if (BrailleWait_CheckButtonPress() != FALSE) + { + MenuZeroFillScreen(); + PlaySE(SE_SELECT); + data[0] = 2; + } + else + { + data[1] = data[1] - 1; + if (data[1] == 0) + { + MenuZeroFillScreen(); + data[0] = 3; + data[1] = 30; + } + } + break; + case 2: + if (BrailleWait_CheckButtonPress() == FALSE) + { + data[1] = data[1] - 1; + if (data[1] == 0) + data[0] = 4; + break; + } + sub_8064E2C(); + DestroyTask(taskId); + ScriptContext2_Disable(); + break; + case 3: + data[1] = data[1] - 1; + if (data[1] == 0) + data[0] = 4; + break; + case 4: + sub_8064E2C(); + ScriptContext1_SetupScript(S_OpenRegiceChamber); + DestroyTask(taskId); + break; + } +} + +bool32 BrailleWait_CheckButtonPress(void) +{ + u16 keyMask = A_BUTTON | B_BUTTON | START_BUTTON | SELECT_BUTTON | DPAD_ANY; + + if (gSaveBlock2.optionsButtonMode == OPTIONS_BUTTON_MODE_LR) + keyMask |= L_BUTTON | R_BUTTON; + if (gSaveBlock2.optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A) + keyMask |= L_BUTTON; + + if (gMain.newKeys & keyMask) + return TRUE; + else + return FALSE; + */ +} + +// this used to be FldEff_UseFlyAncientTomb . why did GF merge the 2 functions? +bool8 FldEff_UsePuzzleEffect(void) +{ + u8 taskId = oei_task_add(); + + if (gBraillePuzzleCallbackFlag == FLY_PUZZLE) + { + gTasks[taskId].data[8] = (u32)UseFlyAncientTomb_Callback >> 16; + gTasks[taskId].data[9] = (u32)UseFlyAncientTomb_Callback; + } + else + { + gTasks[taskId].data[8] = (u32)UseStrengthDesertRuins_Callback >> 16; + gTasks[taskId].data[9] = (u32)UseStrengthDesertRuins_Callback; + } + return FALSE; +} + +// can't get this one to match due to the weird macro-like varsets with strange bitshifting. +// to note: 0x10000 is loaded in, and its obviously supposed to be 1, but i cant get 0x80 << 9 to be loaded in without using it directly. +// maybe there's some way of writing it that works? +#ifdef NONMATCHING +// ShouldDoBrailleRegicePuzzle +bool8 ShouldDoBrailleRegicePuzzle(void) +{ + u8 i; + + if (gSaveBlock1Ptr->location.mapGroup == 0x18 && gSaveBlock1Ptr->location.mapNum == 0x43) + { + // _08179A1A + if (FlagGet(SYS_BRAILLE_WAIT) != FALSE) + return FALSE; + if (FlagGet(2) == FALSE) + return FALSE; + if (FlagGet(3) == TRUE) + return FALSE; + + for (i = 0; i < 36; i++) + { + if (gSaveBlock1Ptr->pos.x == gUnknown_085EFE74[i][0] && gSaveBlock1Ptr->pos.y == gUnknown_085EFE74[i][1]) + { + if (i < 16) + VarSet(0x403B, (0x10000 << i | VarGet(0x403B) << 16) >> 16); // correct + else if (i < 32) + VarSet(0x403C, (0x10000 << (i - 16) | VarGet(0x403C) << 16) >> 16); // hmm? + else + VarSet(0x403D, (0x10000 << (i - 32) | VarGet(0x403D) << 16) >> 16); // hmm? + + if (VarGet(0x403B) != 0xFFFF || VarGet(0x403C) != 0xFF || VarGet(0x403D) != 0xF) + return FALSE; + + if (gSaveBlock1Ptr->pos.x == 8 && gSaveBlock1Ptr->pos.y == 21) + return TRUE; + else + return FALSE; + } + } + } + // TODO: Find what flags 2 and 3 are. + FlagSet(3); + FlagClear(2); + return FALSE; +} +#else +__attribute__((naked)) +bool8 ShouldDoBrailleRegicePuzzle(void) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r9\n\ + mov r6, r8\n\ + push {r6,r7}\n\ + ldr r4, =gSaveBlock1Ptr\n\ + ldr r0, [r4]\n\ + ldrh r1, [r0, 0x4]\n\ + ldr r0, =0x00004318\n\ + cmp r1, r0\n\ + beq _08179A1A\n\ + b _08179B5A\n\ +_08179A1A:\n\ + ldr r0, =0x000008b1\n\ + bl FlagGet\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + beq _08179A28\n\ + b _08179B5A\n\ +_08179A28:\n\ + movs r0, 0x2\n\ + bl FlagGet\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + bne _08179A36\n\ + b _08179B5A\n\ +_08179A36:\n\ + movs r0, 0x3\n\ + bl FlagGet\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + cmp r0, 0x1\n\ + bne _08179A58\n\ + b _08179B5A\n\ + .pool\n\ +_08179A54:\n\ + movs r0, 0x1\n\ + b _08179B5C\n\ +_08179A58:\n\ + movs r5, 0\n\ + mov r8, r4\n\ + ldr r4, =gUnknown_085EFE74\n\ + adds r0, r4, 0x1\n\ + mov r12, r0\n\ + ldr r6, =0x0000403b\n\ + ldr r1, =0x0000403c\n\ + mov r9, r1\n\ +_08179A68:\n\ + lsls r0, r5, 1\n\ + adds r1, r0, r4\n\ + add r0, r12\n\ + ldrb r3, [r0]\n\ + mov r7, r8\n\ + ldr r2, [r7]\n\ + movs r7, 0\n\ + ldrsh r0, [r2, r7]\n\ + ldrb r1, [r1]\n\ + cmp r0, r1\n\ + bne _08179B44\n\ + movs r1, 0x2\n\ + ldrsh r0, [r2, r1]\n\ + cmp r0, r3\n\ + bne _08179B44\n\ + cmp r5, 0xF\n\ + bhi _08179AB0\n\ + adds r0, r6, 0\n\ + bl VarGet\n\ + lsls r0, 16\n\ + movs r1, 0x80\n\ + lsls r1, 9\n\ + lsls r1, r5\n\ + orrs r1, r0\n\ + lsrs r1, 16\n\ + adds r0, r6, 0\n\ + bl VarSet\n\ + b _08179AF0\n\ + .pool\n\ +_08179AB0:\n\ + cmp r5, 0x1F\n\ + bhi _08179AD2\n\ + mov r0, r9\n\ + bl VarGet\n\ + lsls r0, 16\n\ + adds r2, r5, 0\n\ + subs r2, 0x10\n\ + movs r1, 0x80\n\ + lsls r1, 9\n\ + lsls r1, r2\n\ + orrs r1, r0\n\ + lsrs r1, 16\n\ + mov r0, r9\n\ + bl VarSet\n\ + b _08179AF0\n\ +_08179AD2:\n\ + ldr r4, =0x0000403d\n\ + adds r0, r4, 0\n\ + bl VarGet\n\ + lsls r0, 16\n\ + adds r2, r5, 0\n\ + subs r2, 0x20\n\ + movs r1, 0x80\n\ + lsls r1, 9\n\ + lsls r1, r2\n\ + orrs r1, r0\n\ + lsrs r1, 16\n\ + adds r0, r4, 0\n\ + bl VarSet\n\ +_08179AF0:\n\ + ldr r0, =0x0000403b\n\ + bl VarGet\n\ + lsls r0, 16\n\ + lsrs r4, r0, 16\n\ + ldr r0, =0x0000ffff\n\ + cmp r4, r0\n\ + bne _08179B5A\n\ + ldr r0, =0x0000403c\n\ + bl VarGet\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + cmp r0, r4\n\ + bne _08179B5A\n\ + ldr r0, =0x0000403d\n\ + bl VarGet\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + cmp r0, 0xF\n\ + bne _08179B5A\n\ + ldr r0, =gSaveBlock1Ptr\n\ + ldr r0, [r0]\n\ + ldr r1, [r0]\n\ + ldr r0, =0x00150008\n\ + cmp r1, r0\n\ + beq _08179A54\n\ + b _08179B5A\n\ + .pool\n\ +_08179B44:\n\ + adds r0, r5, 0x1\n\ + lsls r0, 24\n\ + lsrs r5, r0, 24\n\ + cmp r5, 0x23\n\ + bls _08179A68\n\ + movs r0, 0x3\n\ + bl FlagSet\n\ + movs r0, 0x2\n\ + bl FlagClear\n\ +_08179B5A:\n\ + movs r0, 0\n\ +_08179B5C:\n\ + pop {r3,r4}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + pop {r4-r7}\n\ + pop {r1}\n\ + bx r1\n\ + .syntax divided"); +} +#endif diff --git a/src/calculate_base_damage.c b/src/calculate_base_damage.c index 105b334f2..8996059f9 100644 --- a/src/calculate_base_damage.c +++ b/src/calculate_base_damage.c @@ -19,7 +19,6 @@ extern struct BattleEnigmaBerry gEnigmaBerries[]; extern u16 gBattleMovePower; extern u16 gTrainerBattleOpponent_A; -u8 CountAliveMonsInBattle(u8); bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 bank); extern const struct BattleMove gBattleMoves[]; diff --git a/src/clear_save_data_screen.c b/src/clear_save_data_screen.c new file mode 100755 index 000000000..3192e0e11 --- /dev/null +++ b/src/clear_save_data_screen.c @@ -0,0 +1,209 @@ +#include "global.h" +#include "task.h" +#include "menu.h" +#include "text.h" +#include "sound.h" +#include "main.h" +#include "save.h" +#include "palette.h" +#include "gpu_regs.h" +#include "bg.h" +#include "text_window.h" +#include "songs.h" + +extern u8 gText_ClearAllSaveData[]; +extern u8 gText_ClearingData[]; + +extern u16 gUnknown_0860F074[]; + +static void Task_DoClearSaveDataScreenYesNo(u8); +static void Task_ClearSaveDataScreenYesNoChoice(u8); +static void Task_ClearSaveData(u8); +static bool8 SetupClearSaveDataScreen(void); +static void CB2_FadeAndDoReset(void); +static void InitClearSaveDataScreenWindows(void); + +static const struct BgTemplate sClearSaveBgTemplates[2] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0, + }, + { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0, + }, +}; + +static const struct WindowTemplate sClearSaveTextWindow[] = +{ + { + .priority = 0, + .tilemapLeft = 3, + .tilemapTop = 15, + .width = 26, + .height = 4, + .paletteNum = 15, + .baseBlock = 11, + }, + DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sClearSaveYesNo[] = +{ + { + .priority = 0, + .tilemapLeft = 3, + .tilemapTop = 2, + .width = 5, + .height = 4, + .paletteNum = 15, + .baseBlock = 115, + } +}; + +void CB2_InitClearSaveDataScreen(void) +{ + if(SetupClearSaveDataScreen()) + CreateTask(Task_DoClearSaveDataScreenYesNo, 0); +} + +static void Task_DoClearSaveDataScreenYesNo(u8 taskId) +{ + SetWindowBorderStyle(0, 0, 2, 14); + PrintTextOnWindow(0, 1, gText_ClearAllSaveData, 0, 1, 0, 0); + CreateYesNoMenu(sClearSaveYesNo, 2, 14, 1); + gTasks[taskId].func = Task_ClearSaveDataScreenYesNoChoice; +} + +static void Task_ClearSaveDataScreenYesNoChoice(u8 taskId) +{ + switch(sub_8198C58()) + { + case 0: + FillWindowPixelBuffer(0, 17); + PrintTextOnWindow(0, 1, gText_ClearingData, 0, 1, 0, 0); + gTasks[taskId].func = Task_ClearSaveData; + break; + case 1: + case -1: + PlaySE(SE_SELECT); + DestroyTask(taskId); + SetMainCallback2(CB2_FadeAndDoReset); + } +} + +static void Task_ClearSaveData(u8 taskId) +{ + ClearSaveData(); + DestroyTask(taskId); + SetMainCallback2(CB2_FadeAndDoReset); +} + +static void MainCB(void) +{ + RunTasks(); + UpdatePaletteFade(); +} + +static void VBlankCB(void) +{ + TransferPlttBuffer(); +} + +static bool8 SetupClearSaveDataScreen(void) +{ + u16 i; + + switch(gMain.state) + { + case 0: + default: + SetVBlankCallback(NULL); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + SetGpuReg(REG_OFFSET_BG3HOFS, 0); + SetGpuReg(REG_OFFSET_BG3VOFS, 0); + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); + DmaFill16(3, 0, (void *)VRAM, VRAM_SIZE); + DmaFill32(3, 0, (void *)OAM, OAM_SIZE); + DmaFill16(3, 0, (void *)(PLTT + 2), PLTT_SIZE - 2); + ResetPaletteFade(); + gPlttBufferUnfaded[0] = 0x7fff; + gPlttBufferFaded[0] = 0x7fff; + gPlttBufferUnfaded[1] = 0x3945; + gPlttBufferFaded[1] = 0x3945; + for (i = 0; i < 0x10; i++) + ((u16 *)(VRAM + 0x20))[i] = 0x1111; + + for (i = 0; i < 0x400; i++) + ((u16 *)(VRAM + 0xF000))[i] = 0x0001; + ResetTasks(); + ResetSpriteData(); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sClearSaveBgTemplates, ARRAY_COUNT(sClearSaveBgTemplates)); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + ShowBg(0); + ShowBg(3); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + InitClearSaveDataScreenWindows(); + BeginNormalPaletteFade(0x0000FFFF, 0, 0x10, 0, 0xFFFF); + EnableInterrupts(1); + SetVBlankCallback(VBlankCB); + gMain.state = 1; + break; + case 1: + UpdatePaletteFade(); + if(!gPaletteFade.active) + { + SetMainCallback2(MainCB); + return TRUE; + } + } + return FALSE; +} + +static void CB2_FadeAndDoReset(void) +{ + switch(gMain.state) + { + case 0: + default: + BeginNormalPaletteFade(0x0000FFFF, 0, 0, 0x10, 0xFFFF); + gMain.state = 1; + break; + case 1: + UpdatePaletteFade(); + if(!gPaletteFade.active) + { + FreeAllWindowBuffers(); + DoSoftReset(); + } + } +} + +static void InitClearSaveDataScreenWindows(void) +{ + InitWindows(sClearSaveTextWindow); + DeactivateAllTextPrinters(); + FillWindowPixelBuffer(0, 0); + sub_80987D4(0, 0, 2, 224); + LoadPalette(gUnknown_0860F074, 0xF0, 0x20); +} diff --git a/src/coins.c b/src/coins.c index 84a79f5f2..e1694b29c 100644 --- a/src/coins.c +++ b/src/coins.c @@ -4,14 +4,13 @@ #include "window.h" #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 SetWindowTemplateFields(struct WindowTemplate* template, u8 priority, u8 tilemapLeft, u8 tilemapTop, u8 width, u8 height, u8 palNum, u16 baseBlock); -extern void SetWindowBorderStyle(u8 windowId, bool8 copyToVram, s16 tileStart, s8 palette); extern void sub_819746C(u8 windowId, bool8 copyToVram); extern const u8 gText_Coins[]; @@ -55,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/decoration.c b/src/decoration.c new file mode 100644 index 000000000..0179d36a1 --- /dev/null +++ b/src/decoration.c @@ -0,0 +1,2781 @@ + +// Includes +#include "global.h" +#include "decompress.h" +#include "malloc.h" +#include "string_util.h" +#include "international_string_util.h" +#include "script.h" +#include "task.h" +#include "main.h" +#include "palette.h" +#include "songs.h" +#include "overworld.h" +#include "fieldmap.h" +#include "metatile_behavior.h" +#include "field_weather.h" +#include "field_player_avatar.h" +#include "field_camera.h" +#include "field_screen.h" +#include "field_map_obj.h" +#include "list_menu.h" +#include "menu_helpers.h" +#include "new_menu_helpers.h" +#include "menu_indicators.h" +#include "sound.h" +#include "event_scripts.h" +#include "event_data.h" +#include "region_map.h" +#include "player_pc.h" +#include "strings.h" +#include "tv.h" +#include "secret_base.h" +#include "tilesets.h" +#include "item_icon.h" +#include "trader.h" +#include "map_object_constants.h" +#include "decoration_inventory.h" +#include "decoration.h" +#include "graphics.h" + +// Static type declarations + +#define OVERWORLD_PLACE_DECOR_SELECTOR_PAL_TAG 0xbe5 +#define OVERWORLD_PLACE_DECOR_PLAYER_PAL_TAG 0x008 + +struct DecorPCBuffer { + struct ListMenuItem items[41]; + u8 names[41][24]; + u8 unk_520; + u8 unk_521; + u8 unk_522; +}; + +struct PlaceDecorationGraphicsDataBuffer { + /*0x000; 0x0203a190*/ const struct Decoration *decoration; + /*0x004; 0x0203a194*/ u16 tiles[0x40]; + /*0x084; 0x0203a214*/ u8 image[0x800]; + /*0x884; 0x0203aa14*/ u16 palette[16]; +}; + +struct DecorRearrangementDataBuffer { + u8 idx; + u8 width; + u8 height; + u16 flagId; +}; + +// Static RAM declarations + +EWRAM_DATA u8 *gCurDecorInventoryItems = NULL; +EWRAM_DATA u8 sSecretBasePCMenuCursorPos = 0; +EWRAM_DATA u8 sCurDecorCatCount = 0; +EWRAM_DATA u8 sSecretBaseItemsIndicesBuffer[16] = {}; +EWRAM_DATA u8 sPlayerRoomItemsIndicesBuffer[12] = {}; +EWRAM_DATA u16 sSecretBasePCSelectDecorLineNo = 0; +EWRAM_DATA u16 sSecretBasePCSelectDecorPageNo = 0; +EWRAM_DATA u8 gCurDecorationIndex = 0; +EWRAM_DATA u8 sCurDecorationCategory = DECORCAT_DESK; +EWRAM_DATA u32 filler_0203a174[2] = {}; +EWRAM_DATA struct DecorPCPointers gUnknown_0203A17C = {}; +EWRAM_DATA u8 sDecorMenuWindowIndices[4] = {}; +EWRAM_DATA struct DecorPCBuffer *sDecorPCBuffer = NULL; +EWRAM_DATA struct PlaceDecorationGraphicsDataBuffer sPlaceDecorationGraphicsDataBuffer = {}; +EWRAM_DATA u16 sCurDecorMapX = 0; +EWRAM_DATA u16 sCurDecorMapY = 0; +EWRAM_DATA u8 sDecor_CameraSpriteObjectIdx1 = 0; +EWRAM_DATA u8 sDecor_CameraSpriteObjectIdx2 = 0; +EWRAM_DATA u8 sDecorationLastDirectionMoved = 0; +EWRAM_DATA struct OamData sDecorSelectorOam = {}; +EWRAM_DATA struct DecorRearrangementDataBuffer sDecorRearrangementDataBuffer[16] = {}; +EWRAM_DATA u8 sCurDecorSelectedInRearrangement = 0; + +// Static ROM declarations + +void sub_8126B80(u8 taskId); +void sub_8126C08(void); +void SecretBasePC_Decorate(u8 taskId); +void SecretBasePC_PutAway(u8 taskId); +void SecretBasePC_Toss(u8 taskId); +void sub_8126DA4(u8 taskId); +void SecretBasePC_Cancel(u8 taskId); +void SecretBasePC_PrepMenuForSelectingStoredDecors(u8 taskId); +void sub_8126DFC(u8 taskId); +void sub_8126E8C(u8 taskId); +void sub_8126F68(u8 winid, u8 decorCat, u8 x, u8 y, bool8 flag, u8 speed); +void sub_8127058(u8 *str, bool8 flag); +void sub_8127088(u8 taskId); +void sub_81270E8(u8 taskId); +void sub_8127180(u8 taskId); +void sub_812719C(u8 taskId); +void sub_81271CC(u8 taskId); +void sub_8127268(u8 taskId); +void sub_8127454(u8 *dest, u16 decorId); +void sub_8127480(u32 a0, bool8 flag, struct ListMenu *menu); +void sub_81274A0(u8 a0, s32 a1, u8 a2); +void sub_8127620(u8 taskId); +void sub_812764C(u8 taskId); +void sub_8127744(u32 a0); +void sub_81277A8(void); +bool8 sub_81277BC(u8 idx); +bool8 sub_81277E8(u8 idx); +void IdentifyOwnedDecorationsCurrentlyInUse(u8 taskId); +void sub_812759C(u8 taskId); +void sub_8127718(u8 decorCat); +void sub_8127A30(u8 taskId); +void sub_8127A8C(u8 taskId); +void sub_8127F68(u8 taskId); +void sub_8128060(u8 taskId); +void ConfigureCameraObjectForPlacingDecoration(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor); +void SetUpPlacingDecorationPlayerAvatar(u8 taskId, struct PlaceDecorationGraphicsDataBuffer *data); +void sub_812826C(u8 taskId); +void sub_81283BC(u8 taskId); +void sub_8128414(u8 taskId); +void sub_8128950(u8 taskId); +void sub_81289D0(u8 taskId); +void sub_81289F0(u8 taskId); +void sub_8128AAC(u8 taskId); +void sub_8128B80(u8 taskId); +void sub_8128BA0(u8 taskId); +void sub_8128BBC(u8 taskId); +void c1_overworld_prev_quest(u8 taskId); +void sub_8128CD4(void); +void sub_8128DE0(void); +void sub_8128FD8(u8 taskId); +void sub_8129020(u8 taskId); +void sub_81292D0(struct Sprite *sprite); +void sub_81292E8(struct Sprite *sprite); +u8 gpu_pal_decompress_alloc_tag_and_upload(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor); +const u8 *GetDecorationIconPicOrPalette(u16 decor, u8 mode); +bool8 sub_81299AC(u8 taskId); +void sub_8129ABC(u8 taskId); +void sub_8129B34(u8 taskId); +void sub_8129BCC(u8 taskId); +void sub_8129BF8(u8 taskId); +void sub_8129C74(u8 taskId); +void sub_8129D64(u8 taskId); +void sub_812A0E8(u8 taskId); +void sub_812A1A0(u8 taskId); +void sub_812A1C0(u8 taskId); +void sub_812A1F0(u8 taskId); +void sub_812A210(u8 taskId); +void sub_812A22C(u8 taskId); +void sub_812A25C(u8 taskId); +void sub_812A334(void); +void sub_812A36C(struct Sprite *sprite); +void sub_812A39C(void); +void sub_812A3C8(void); +void sub_812A3D4(u8 taskId); +void sub_812A458(u8 taskId); +void sub_812A478(u8 taskId); + +// .rodata + +#include "data/decoration/tiles.h" +#include "data/decoration/description.h" +#include "data/decoration/header.h" + +const u8 *const sDecorCatNames[] = { + gText_Desk, + gText_Chair, + gText_Plant, + gText_Ornament, + gText_Mat, + gText_Poster, + gText_Doll, + gText_Cushion +}; + +const struct MenuAction sSecretBasePCMenuActions[] = { + { + gText_Decorate, {.void_u8=SecretBasePC_Decorate} + }, { + gText_PutAway, {.void_u8=SecretBasePC_PutAway} + }, { + gText_Toss2, {.void_u8=SecretBasePC_Toss} + }, { + gText_Cancel, {.void_u8=SecretBasePC_Cancel} + } +}; + +const u8 *const sSecretBasePCMenuItemDescriptions[] = { + gText_PutOutSelectedDecorItem, + gText_StoreChosenDecorInPC, + gText_ThrowAwayUnwantedDecors, + gText_GoBackPrevMenu +}; + +void (*const SecretBasePC_SelectedDecorActions[][2])(u8 taskId) = { + { + sub_8127F68, sub_8127A8C + }, { + sub_812A3D4, sub_8127A8C + }, { + sub_8133DA0, sub_8127A8C + } +}; + +const struct WindowTemplate gUnknown_085A6B90[4] = { + { 0, 1, 1, 18, 8, 15, 0x0001 }, + { 0, 1, 1, 13, 18, 13, 0x0091 }, + { 0, 17, 1, 12, 2, 15, 0x017b }, + { 0, 16, 13, 13, 6, 15, 0x0193 } +}; + +const u16 gUnknown_085A6BB0[] = INCBIN_U16("graphics/decorations/unk_85a6bb0.gbapal"); + +const struct ListMenuTemplate gUnknown_085A6BD0 = { + NULL, + sub_8127480, + sub_81274A0, + 0, 0, + 0, 0, 8, 0, + 9, 2, 1, 3, FALSE, 0, FALSE, 7 +}; + +#include "data/decoration/icon.h" +#include "data/decoration/tilemaps.h" + +const struct { + u8 shape; + u8 size; + u8 x; + u8 y; +} gUnknown_085A7250[] = { + {0, 1, 0x78, 0x4e}, + {1, 2, 0x80, 0x4e}, + {1, 3, 0x90, 0x56}, + {1, 3, 0x90, 0x46}, + {0, 2, 0x80, 0x46}, + {2, 2, 0x78, 0x46}, + {2, 3, 0x80, 0x56}, + {2, 3, 0x80, 0x36}, + {0, 3, 0x90, 0x46}, + {1, 3, 0x90, 0x46} +}; + +const union AnimCmd gUnknown_085A7278[] = { + ANIMCMD_FRAME(0, 0, FALSE, FALSE), + ANIMCMD_END +}; + +const union AnimCmd *const sDecorSelectorAnims[] = { + gUnknown_085A7278 +}; + +const struct SpriteFrameImage sDecorSelectorSpriteFrameImages = { + (const u8 *)&sPlaceDecorationGraphicsDataBuffer.image, 0x800 +}; + +const struct SpriteTemplate sDecorSelectorSpriteTemplate = { + 0xffff, + OVERWORLD_PLACE_DECOR_SELECTOR_PAL_TAG, + &sDecorSelectorOam, + sDecorSelectorAnims, + &sDecorSelectorSpriteFrameImages, + gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +const struct SpriteTemplate sDecorWhilePlacingSpriteTemplate = { + 0x0000, + 0x0000, + &sDecorSelectorOam, + sDecorSelectorAnims, + NULL, + gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +const struct SpritePalette gUnknown_085A72BC = { + (const u16 *)&sPlaceDecorationGraphicsDataBuffer.palette, OVERWORLD_PLACE_DECOR_SELECTOR_PAL_TAG +}; + +const struct YesNoFuncTable gUnknown_085A72C4 = { + sub_81289F0, + sub_8128FD8 +}; + +const struct YesNoFuncTable gUnknown_085A72CC = { + sub_8128BA0, + sub_8128FD8 +}; + +const struct YesNoFuncTable gUnknown_085A72D4[] = { + { + sub_81283BC, + sub_8128414 + }, { + sub_8129BCC, + sub_8129BF8 + } +}; + +const u8 gUnknown_085A72E4[] = { + 0x04, 0x04, 0x04, 0x04, 0x00, 0x03, 0x03, 0x00 +}; + +const u8 gUnknown_085A72EC[] = { + 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x03, 0x00 +}; + +const u16 gUnknown_085A72F4[] = { + 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x20 +}; + +const u16 Unknown_085A7308[] = INCBIN_U16("graphics/decorations/unk_85a7308.gbapal"); + +const u16 Unknown_085A7328[] = INCBIN_U16("graphics/decorations/unk_85a7328.gbapal"); + +const struct YesNoFuncTable gUnknown_085A7348 = { + sub_812A1C0, + sub_8129B34 +}; + +const struct YesNoFuncTable gUnknown_085A7350 = { + sub_812A210, + sub_8129B34 +}; + +const u8 Unknown_085A7358[] = INCBIN_U8("graphics/misc/decoration_unk_85a7358.4bpp"); + +const struct SpritePalette gUnknown_085A73D8 = { + Unknown_085A7308, OVERWORLD_PLACE_DECOR_PLAYER_PAL_TAG +}; + +const struct SpritePalette gUnknown_085A73E0 = { + Unknown_085A7328, OVERWORLD_PLACE_DECOR_PLAYER_PAL_TAG +}; + +const struct OamData Unknown_085A73E8 = { + .size = 1, .priority = 1 +}; + +const union AnimCmd Unknown_085A73F0[] = { + ANIMCMD_FRAME(0, 0, 0), + ANIMCMD_END +}; + +const union AnimCmd *const Unknown_085A73F8[] = { + Unknown_085A73F0 +}; + +const struct SpriteFrameImage Unknown_085A73FC = { + Unknown_085A7358, 0x80 +}; + +const struct SpriteTemplate gUnknown_085A7404 = { + 0xFFFF, + OVERWORLD_PLACE_DECOR_PLAYER_PAL_TAG, + &Unknown_085A73E8, + Unknown_085A73F8, + &Unknown_085A73FC, + gDummySpriteAffineAnimTable, + sub_812A36C +}; + +const struct YesNoFuncTable gUnknown_085A741C = { + sub_812A478, + sub_8127A30 +}; + +// .text + +void sub_8126968(void) +{ + if (sCurDecorationCategory < 8) + { + gCurDecorInventoryItems = gDecorationInventories[sCurDecorationCategory].items; + } + if (gUnknown_0203A17C.isPlayerRoom == FALSE) + { + gUnknown_0203A17C.items = gSaveBlock1Ptr->secretBases[0].decorations; + gUnknown_0203A17C.pos = gSaveBlock1Ptr->secretBases[0].decorationPos; + } + if (gUnknown_0203A17C.isPlayerRoom == TRUE) + { + gUnknown_0203A17C.items = gSaveBlock1Ptr->playerRoomDecor; + gUnknown_0203A17C.pos = gSaveBlock1Ptr->playerRoomDecorPos; + } +} + +u8 sub_81269D4(u8 idx) +{ + u8 *winidx; + struct WindowTemplate template; + + winidx = &sDecorMenuWindowIndices[idx]; + if (idx == 0) + { + template = gUnknown_085A6B90[0]; + template.width = GetMaxWidthInMenuTable(sSecretBasePCMenuActions, 4); + if (template.width > 18) + { + template.width = 18; + } + *winidx = AddWindow(&template); + } + else + { + *winidx = AddWindow(&gUnknown_085A6B90[idx]); + } + SetWindowBorderStyle(*winidx, 0, 0x214, 0xe); + schedule_bg_copy_tilemap_to_vram(0); + return *winidx; +} + +void sub_8126A58(u8 idx) +{ + sub_8198070(sDecorMenuWindowIndices[idx], FALSE); + ClearWindowTilemap(sDecorMenuWindowIndices[idx]); + RemoveWindow(sDecorMenuWindowIndices[idx]); + schedule_bg_copy_tilemap_to_vram(0); +} + +void sub_8126A88(void) +{ + u8 idx; + + idx = sub_81269D4(0); + PrintMenuTable(idx, 4, sSecretBasePCMenuActions); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(idx, 4, sSecretBasePCMenuCursorPos); +} + +void sub_8126ABC(void) +{ + sSecretBasePCMenuCursorPos = 0; + ScriptContext2_Enable(); + sub_8126A88(); + sub_8126C08(); +} + +void sub_8126AD8(u8 taskId) +{ + sub_8126ABC(); + gUnknown_0203A17C.items = gSaveBlock1Ptr->secretBases[0].decorations; + gUnknown_0203A17C.pos = gSaveBlock1Ptr->secretBases[0].decorationPos; + gUnknown_0203A17C.size = sizeof(gSaveBlock1Ptr->secretBases[0].decorations); + gUnknown_0203A17C.isPlayerRoom = FALSE; + gTasks[taskId].func = sub_8126B80; +} + +void sub_8126B2C(u8 taskId) +{ + sub_8126ABC(); + gUnknown_0203A17C.items = gSaveBlock1Ptr->playerRoomDecor; + gUnknown_0203A17C.pos = gSaveBlock1Ptr->playerRoomDecorPos; + gUnknown_0203A17C.size = sizeof(gSaveBlock1Ptr->playerRoomDecor); + gUnknown_0203A17C.isPlayerRoom = TRUE; + gTasks[taskId].func = sub_8126B80; +} + +void sub_8126B80(u8 taskId) +{ + u8 menuPos; + + if (!gPaletteFade.active) + { + menuPos = GetMenuCursorPos(); + switch (ProcessMenuInput()) + { + default: + PlaySE(SE_SELECT); + sSecretBasePCMenuActions[sSecretBasePCMenuCursorPos].func.void_u8(taskId); + break; + case -2: + sSecretBasePCMenuCursorPos = GetMenuCursorPos(); + if ((s8)menuPos != sSecretBasePCMenuCursorPos) + { + sub_8126C08(); + } + break; + case -1: + PlaySE(SE_SELECT); + SecretBasePC_Cancel(taskId); + break; + } + } +} + +void sub_8126C08(void) +{ + FillWindowPixelBuffer(0, 0x11); + AddTextPrinterParametrized(0, 1, sSecretBasePCMenuItemDescriptions[sSecretBasePCMenuCursorPos], 0, 0, 2, 1, 3); +} + +void SecretBasePC_Decorate(u8 taskId) +{ + if (CountDecorations() == 0) + { + StringExpandPlaceholders(gStringVar4, gText_NoDecorations); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8126DA4); + } + else + { + gTasks[taskId].data[11] = 0; + sCurDecorationCategory = DECORCAT_DESK; + SecretBasePC_PrepMenuForSelectingStoredDecors(taskId); + } +} + +void SecretBasePC_PutAway(u8 taskId) +{ + if (!sub_81299AC(taskId)) + { + StringExpandPlaceholders(gStringVar4, gText_NoDecorationsInUse); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8126DA4); + } + else + { + sub_8126A58(0); + sub_8197434(0, 0); + fade_screen(1, 0); + gTasks[taskId].data[2] = 0; + gTasks[taskId].func = sub_8129ABC; + } +} + +void SecretBasePC_Toss(u8 taskId) +{ + if (CountDecorations() == 0) + { + StringExpandPlaceholders(gStringVar4, gText_NoDecorations); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8126DA4); + } + else + { + gTasks[taskId].data[11] = 1; + sCurDecorationCategory = DECORCAT_DESK; + SecretBasePC_PrepMenuForSelectingStoredDecors(taskId); + } +} + +void SecretBasePC_Cancel(u8 taskId) +{ + sub_8126A58(0); + if (!gUnknown_0203A17C.isPlayerRoom) + { + ScriptContext1_SetupScript(gUnknown_0823B4E8); + DestroyTask(taskId); + } + else + { + sub_816B060(taskId); + } +} + +void sub_8126DA4(u8 taskId) +{ + sub_8126C08(); + gTasks[taskId].func = sub_8126B80; +} + +void SecretBasePC_PrepMenuForSelectingStoredDecors(u8 taskId) +{ + LoadPalette(gUnknown_085A6BB0, 0xd0, 0x20); + sub_8197434(0, 0); + sub_8126A58(0); + sub_8126DFC(taskId); +} + +void sub_8126DFC(u8 taskId) +{ + u8 winIdx; + + winIdx = sub_81269D4(1); + sub_8126E8C(taskId); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(winIdx, 9, sCurDecorationCategory); + gTasks[taskId].func = sub_8127088; +} + +void sub_8126E44(u8 taskId) +{ + FillWindowPixelBuffer(sDecorMenuWindowIndices[1], 0x11); + sub_8126E8C(taskId); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(sDecorMenuWindowIndices[1], 9, sCurDecorationCategory); + gTasks[taskId].func = sub_8127088; +} + +void sub_8126E8C(u8 taskId) +{ + s16 *data; + u8 r5; + bool8 r8; + u8 i; + bool8 fl; + + data = gTasks[taskId].data; + r5 = sDecorMenuWindowIndices[1]; + fl = gUnknown_0203A17C.isPlayerRoom; + r8 = FALSE; + if (fl == TRUE && data[11] == 0) + { + r8 = TRUE; + } + for (i = 0; i < 8; i ++) + { + if (r8 == TRUE && i != DECORCAT_DOLL && i != DECORCAT_CUSHION) + { + sub_8126F68(r5, i, 8, i << 4, TRUE, 0xFF); + } + else + { + sub_8126F68(r5, i, 8, i << 4, FALSE, 0xFF); + } + } + PrintTextOnWindow(r5, 1, gTasks[taskId].data[11] == 2 ? gText_Exit : gText_Cancel, 8, (i << 4) + 1, 0, 0); + schedule_bg_copy_tilemap_to_vram(0); +} + +void sub_8126F68(u8 winid, u8 decorCat, u8 x, u8 y, bool8 flag, u8 speed) +{ + u8 width; + u8 *strbuf; + + width = x == 8 ? 0x68 : 0x60; + y ++; + sub_8127058(gStringVar4, flag); + strbuf = StringLength(gStringVar4) + gStringVar4; + StringCopy(strbuf, sDecorCatNames[decorCat]); + PrintTextOnWindow(winid, 1, gStringVar4, x, y, speed, NULL); + strbuf = ConvertIntToDecimalStringN(strbuf, CountDecorationCategoryN(decorCat), STR_CONV_MODE_RIGHT_ALIGN, 2); + *strbuf++ = CHAR_SLASH; + ConvertIntToDecimalStringN(strbuf, gDecorationInventories[decorCat].size, STR_CONV_MODE_RIGHT_ALIGN, 2); + x = GetStringRightAlignXOffset(1, gStringVar4, width); + PrintTextOnWindow(winid, 1, gStringVar4, x, y, speed, NULL); +} + +void sub_8127058(u8 *str, bool8 flag) +{ + StringCopy(str, gText_Color161Shadow161); + if (flag == TRUE) + { + str[2] = 0x04; // RED + str[5] = 0x05; // LIGHT_RED + } + else + { + str[2] = 0x02; // DARK_GREY + str[5] = 0x03; // LIGHT_GREY + } +} + +void sub_8127088(u8 taskId) +{ + s8 input; + + if (!gPaletteFade.active) + { + input = ProcessMenuInput(); + switch (input) + { + case -1: + case 8: + PlaySE(SE_SELECT); + sub_812719C(taskId); + break; + case -2: + break; + default: + PlaySE(SE_SELECT); + sCurDecorationCategory = input; + sub_81270E8(taskId); + break; + } + } +} + +void sub_81270E8(u8 taskId) +{ + sCurDecorCatCount = CountDecorationCategoryN(sCurDecorationCategory); + if (sCurDecorCatCount != 0) + { + CondenseDecorationCategoryN(sCurDecorationCategory); + gCurDecorInventoryItems = gDecorationInventories[sCurDecorationCategory].items; + IdentifyOwnedDecorationsCurrentlyInUse(taskId); + sSecretBasePCSelectDecorPageNo = 0; + sSecretBasePCSelectDecorLineNo = 0; + gTasks[taskId].func = sub_8127620; + } + else + { + sub_8126A58(1); + StringExpandPlaceholders(gStringVar4, gText_NoDecorations); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8127180); + } +} + +void sub_8127180(u8 taskId) +{ + sub_8197434(0, 0); + sub_8126DFC(taskId); +} + +void sub_812719C(u8 taskId) +{ + if (gTasks[taskId].data[11] != 2) + { + sub_81271CC(taskId); + } + else + { + sub_8127268(taskId); + } +} + +void sub_81271CC(u8 taskId) +{ + sub_8126A58(1); + sub_8126A88(); + sub_81973C4(0, 0); + sub_8126C08(); + gTasks[taskId].func = sub_8126B80; +} + +void sub_8127208(u8 taskId) +{ + LoadPalette(gUnknown_085A6BB0, 0xd0, 0x20); + sub_8197434(0, 0); + gTasks[taskId].data[11] = 2; + sCurDecorationCategory = DECORCAT_DESK; + sub_8126DFC(taskId); +} + +void sub_8127250(u8 *dest, u8 decorCat) +{ + StringCopy(dest, sDecorCatNames[decorCat]); +} + +void sub_8127268(u8 taskId) +{ + sub_8126A58(1); + sub_8133E1C(taskId); +} + +void sub_8127284(void) +{ + sDecorPCBuffer->unk_520 = sCurDecorCatCount + 1; + if (sDecorPCBuffer->unk_520 > 8) + { + sDecorPCBuffer->unk_521 = 8; + } + else + { + sDecorPCBuffer->unk_521 = sDecorPCBuffer->unk_520; + } +} + +void sub_81272C8(void) +{ + sub_812225C(&sSecretBasePCSelectDecorPageNo, &sSecretBasePCSelectDecorLineNo, sDecorPCBuffer->unk_521, sDecorPCBuffer->unk_520); +} + +void sub_81272F8(void) +{ + sub_8122298(&sSecretBasePCSelectDecorPageNo, &sSecretBasePCSelectDecorLineNo, sDecorPCBuffer->unk_521, sDecorPCBuffer->unk_520, 8); +} + +void sub_8127330(u8 taskId) +{ + s16 *data; + u16 i; + + data = gTasks[taskId].data; + if ((sCurDecorationCategory < DECORCAT_DOLL || sCurDecorationCategory > DECORCAT_CUSHION) && gUnknown_0203A17C.isPlayerRoom == TRUE && data[11] == 0) + { + sub_8127058(gStringVar1, TRUE); + } + else + { + sub_8127058(gStringVar1, FALSE); + } + for (i = 0; i < sDecorPCBuffer->unk_520 - 1; i ++) + { + sub_8127454(sDecorPCBuffer->names[i], gCurDecorInventoryItems[i]); + sDecorPCBuffer->items[i].unk_00 = sDecorPCBuffer->names[i]; + sDecorPCBuffer->items[i].unk_04 = i; + } + StringCopy(sDecorPCBuffer->names[i], gText_Cancel); + sDecorPCBuffer->items[i].unk_00 = sDecorPCBuffer->names[i]; + sDecorPCBuffer->items[i].unk_04 = -2; + gUnknown_03006310 = gUnknown_085A6BD0; + gUnknown_03006310.unk_10 = sDecorMenuWindowIndices[1]; + gUnknown_03006310.unk_0c = sDecorPCBuffer->unk_520; + gUnknown_03006310.unk_00 = sDecorPCBuffer->items; + gUnknown_03006310.unk_0e = sDecorPCBuffer->unk_521; +} + +void sub_8127454(u8 *dest, u16 decorId) +{ + StringCopy(dest, gStringVar1); + StringAppend(dest, gDecorations[decorId].name); +} + +void sub_8127480(u32 a0, bool8 flag, struct ListMenu *menu) +{ + if (flag != TRUE) + { + PlaySE(SE_SELECT); + } + sub_8127744(a0); +} + +void sub_81274A0(u8 a0, s32 a1, u8 a2) +{ + if (a1 != -2) + { + if (sub_81277BC(a1 + 1) == TRUE) + { + blit_move_info_icon(a0, 0x18, 0x5c, a2 + 2); + } + else if (sub_81277E8(a1 + 1) == TRUE) + { + blit_move_info_icon(a0, 0x19, 0x5c, a2 + 2); + } + } +} + +void sub_8127500(void) +{ + if (sDecorPCBuffer->unk_522 == 0xFF) + { + sDecorPCBuffer->unk_522 = AddScrollIndicatorArrowPairParametrized(0x02, 0x3c, 0x0c, 0x94, sDecorPCBuffer->unk_520 - sDecorPCBuffer->unk_521, 0x6e, 0x6e, &sSecretBasePCSelectDecorPageNo); + } +} + +void sub_8127554(void) +{ + if (sDecorPCBuffer->unk_522 != 0xFF) + { + RemoveScrollIndicatorArrowPair(sDecorPCBuffer->unk_522); + sDecorPCBuffer->unk_522 = 0xFF; + } +} + +void sub_8127580(u8 taskId) +{ + sub_81269D4(1); + sub_812759C(taskId); +} + +void sub_812759C(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + sub_81269D4(3); + sub_8127718(sCurDecorationCategory); + sDecorPCBuffer = calloc(1, sizeof(struct DecorPCBuffer)); + sDecorPCBuffer->unk_522 = 0xFF; + sub_8127284(); + sub_81272C8(); + sub_81272F8(); + sub_8127330(taskId); + data[13] = ListMenuInit(&gUnknown_03006310, sSecretBasePCSelectDecorPageNo, sSecretBasePCSelectDecorLineNo); + sub_8127500(); +} + +void sub_8127620(u8 taskId) +{ + sub_812759C(taskId); + gTasks[taskId].func = sub_812764C; +} + +void sub_812764C(u8 taskId) +{ + s16 *data; + s32 input; + + data = gTasks[taskId].data; + if (!gPaletteFade.active) + { + input = ListMenuHandleInput(data[13]); + get_coro_args_x18_x1A(data[13], &sSecretBasePCSelectDecorPageNo, &sSecretBasePCSelectDecorLineNo); + switch (input) + { + case -1: + break; + case -2: + PlaySE(SE_SELECT); + SecretBasePC_SelectedDecorActions[data[11]][1](taskId); + break; + default: + PlaySE(SE_SELECT); + gCurDecorationIndex = input; + sub_8127554(); + sub_81AE6C8(data[13], &sSecretBasePCSelectDecorPageNo, &sSecretBasePCSelectDecorLineNo); + sub_8126A58(1); + sub_81277A8(); + free(sDecorPCBuffer); + SecretBasePC_SelectedDecorActions[data[11]][0](taskId); + break; + } + } +} + +void sub_8127718(u8 decorCat) +{ + sub_8126F68(sub_81269D4(2), decorCat, 0, 0, 0, 0); +} + +void sub_8127744(u32 a0) +{ + u8 winidx; + const u8 *txt; + + winidx = sDecorMenuWindowIndices[3]; + FillWindowPixelBuffer(winidx, 0x11); + if (a0 >= sCurDecorCatCount) + { + txt = gText_GoBackPrevMenu; + } + else + { + txt = gDecorations[gCurDecorInventoryItems[a0]].description; + } + PrintTextOnWindow(winidx, 1, txt, 0, 1, 0, 0); +} + +void sub_81277A8(void) +{ + sub_8126A58(3); + sub_8126A58(2); +} + +bool8 sub_81277BC(u8 idx) +{ + u8 i; + + for (i = 0; i < 16; i ++) + { + if (sSecretBaseItemsIndicesBuffer[i] == idx) + { + return TRUE; + } + } + return FALSE; +} + +bool8 sub_81277E8(u8 idx) +{ + u8 i; + + for (i = 0; i < 12; i ++) + { + if (sPlayerRoomItemsIndicesBuffer[i] == idx) + { + return TRUE; + } + } + return FALSE; +} + +void IdentifyOwnedDecorationsCurrentlyInUseInternal(u8 taskId) +{ + u16 i; + u16 j; + u16 k; + u16 cnt; + + cnt = 0; + memset(sSecretBaseItemsIndicesBuffer, 0, 16); + memset(sPlayerRoomItemsIndicesBuffer, 0, 12); + for (i = 0; i < 16; i ++) + { + if (gSaveBlock1Ptr->secretBases[0].decorations[i] != DECOR_NONE) + { + for (j = 0; j < gDecorationInventories[sCurDecorationCategory].size; j ++) + { + if (gCurDecorInventoryItems[j] == gSaveBlock1Ptr->secretBases[0].decorations[i]) + { + for (k = 0; k < cnt && sSecretBaseItemsIndicesBuffer[k] != j + 1; k ++); + if (k == cnt) + { + sSecretBaseItemsIndicesBuffer[cnt] = j + 1; + cnt ++; + break; + } + } + } + } + } + cnt = 0; + for (i = 0; i < 12; i ++) + { + if (gSaveBlock1Ptr->playerRoomDecor[i] != DECOR_NONE) + { + for (j = 0; j < gDecorationInventories[sCurDecorationCategory].size; j ++) + { + if (gCurDecorInventoryItems[j] == gSaveBlock1Ptr->playerRoomDecor[i] && sub_81277BC(j + 1) != TRUE) + { + for (k = 0; k < cnt && sPlayerRoomItemsIndicesBuffer[k] != j + 1; k ++); + if (k == cnt) + { + sPlayerRoomItemsIndicesBuffer[cnt] = j + 1; + cnt ++; + break; + } + } + } + } + } +} + +void IdentifyOwnedDecorationsCurrentlyInUse(u8 taskId) +{ + IdentifyOwnedDecorationsCurrentlyInUseInternal(taskId); +} + +bool8 IsSelectedDecorInThePC(void) +{ + u16 i; + for (i = 0; i < 16; i ++) + { + if (sSecretBaseItemsIndicesBuffer[i] == sSecretBasePCSelectDecorPageNo + sSecretBasePCSelectDecorLineNo + 1) + { + return FALSE; + } + if (i < 12 && sPlayerRoomItemsIndicesBuffer[i] == sSecretBasePCSelectDecorPageNo + sSecretBasePCSelectDecorLineNo + 1) + { + return FALSE; + } + } + return TRUE; +} + +void sub_8127A14(u8 taskId) +{ + sub_81269D4(1); + sub_8127620(taskId); +} + +void sub_8127A30(u8 taskId) +{ + sub_8197434(0, 0); + gTasks[taskId].func = sub_8127A14; +} + +void sub_8127A5C(u8 taskId) +{ + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + sub_8197434(0, 0); + sub_81269D4(1); + sub_8127620(taskId); + } +} + +void sub_8127A8C(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + sub_8127554(); + sub_81277A8(); + sub_81AE6C8(data[13], NULL, NULL); + free(sDecorPCBuffer); + sub_8126E44(taskId); +} + +void sub_8127ACC(u8 taskId) +{ + gTasks[taskId].data[3] = gSaveBlock1Ptr->pos.x; + gTasks[taskId].data[4] = gSaveBlock1Ptr->pos.y; + PlayerGetDestCoords(&gTasks[taskId].data[0], &gTasks[taskId].data[1]); +} + +void sub_8127B04(u8 taskId) +{ + DrawWholeMapView(); + Overworld_SetWarpDestination(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, -1, gTasks[taskId].data[3], gTasks[taskId].data[4]); + warp_in(); +} + +u16 sub_8127B54(u8 decor, u8 a1) +{ + u16 resp; + + resp = -1; + switch (decor) + { + case DECOR_STAND: + resp = gUnknown_085A72E4[a1] << 12; + return resp; + case DECOR_SLIDE: + resp = gUnknown_085A72EC[a1] << 12; + return resp; + default: + return resp; + } +} + +void sub_8127B90(u16 mapX, u16 mapY, u8 decWidth, u8 decHeight, u16 decor) +{ + u16 i; + u16 j; + u16 behavior; + u16 flags; + u16 v0; + u16 v1; + s16 decLeft; + s16 decBottom; + + for (i = 0; i < decHeight; i ++) + { + decBottom = mapY - decHeight + 1 + i; + for (j = 0; j < decWidth; j ++) + { + decLeft = mapX + j; + behavior = GetBehaviorByMetatileId(0x200 + gDecorations[decor].tiles[i * decWidth + j]); + if (MetatileBehavior_IsMB_B9(behavior) == TRUE || (gDecorations[decor].permission != DECORPERM_PASS_FLOOR && (behavior >> 12))) + { + flags = 0xc00; + } + else + { + flags = 0x000; + } + if (gDecorations[decor].permission != DECORPERM_NA_WALL && MetatileBehavior_IsMB_B7(MapGridGetMetatileBehaviorAt(decLeft, decBottom)) == TRUE) + { + v0 = 1; + } + else + { + v0 = 0; + } + v1 = sub_8127B54(gDecorations[decor].id, i * decWidth + j); + if (v1 != 0xFFFF) + { + MapGridSetMetatileEntryAt(decLeft, decBottom, (gDecorations[decor].tiles[i * decWidth + j] + (0x200 | v0)) | flags | v1); + } + else + { + MapGridSetMetatileIdAt(decLeft, decBottom, (gDecorations[decor].tiles[i * decWidth + j] + (0x200 | v0)) | flags); + } + } + } +} + +void sub_8127D38(u16 mapX, u16 mapY, u16 decor) +{ + switch (gDecorations[decor].shape) + { + case DECORSHAPE_1x1: + sub_8127B90(mapX, mapY, 1, 1, decor); + break; + case DECORSHAPE_2x1: + sub_8127B90(mapX, mapY, 2, 1, decor); + break; + case DECORSHAPE_3x1: // unused + sub_8127B90(mapX, mapY, 3, 1, decor); + break; + case DECORSHAPE_4x2: + sub_8127B90(mapX, mapY, 4, 2, decor); + break; + case DECORSHAPE_2x2: + sub_8127B90(mapX, mapY, 2, 2, decor); + break; + case DECORSHAPE_1x2: + sub_8127B90(mapX, mapY, 1, 2, decor); + break; + case DECORSHAPE_1x3: // unused + sub_8127B90(mapX, mapY, 1, 3, decor); + break; + case DECORSHAPE_2x4: + sub_8127B90(mapX, mapY, 2, 4, decor); + break; + case DECORSHAPE_3x3: + sub_8127B90(mapX, mapY, 3, 3, decor); + break; + case DECORSHAPE_3x2: + sub_8127B90(mapX, mapY, 3, 2, decor); + break; + } +} + +void sub_8127E18(void) +{ + u8 i; + u8 j; + + for (i = 0; i < 14; i ++) + { + if (FlagGet(0xAE + i) == TRUE) + { + FlagClear(0xAE + i); + for (j = 0; j < gMapHeader.events->mapObjectCount; j ++) + { + if (gMapHeader.events->mapObjects[j].flagId == 0xAE + i) + { + break; + } + } + VarSet(0x3F20 + gMapHeader.events->mapObjects[j].graphicsId, sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0]); + gSpecialVar_0x8005 = gMapHeader.events->mapObjects[j].localId; + gSpecialVar_0x8006 = sCurDecorMapX; + gSpecialVar_0x8007 = sCurDecorMapY; + show_sprite(gSpecialVar_0x8005, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + sub_808EBA8(gSpecialVar_0x8005, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, gSpecialVar_0x8006, gSpecialVar_0x8007); + sub_808F254(gSpecialVar_0x8005, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + break; + } + } +} + +bool8 sub_8127F38(void) +{ + u16 i; + + for (i = 0; i < gUnknown_0203A17C.size; i ++) + { + if (gUnknown_0203A17C.items[i] == DECOR_NONE) + { + return TRUE; + } + } + return FALSE; +} + +void sub_8127F68(u8 taskId) +{ + if (gUnknown_0203A17C.isPlayerRoom == TRUE && sCurDecorationCategory != DECORCAT_DOLL && sCurDecorationCategory != DECORCAT_CUSHION) + { + StringExpandPlaceholders(gStringVar4, gText_CantPlaceInRoom); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8127A5C); + } + else if (IsSelectedDecorInThePC() == TRUE) + { + if (sub_8127F38() == TRUE) + { + fade_screen(1, 0); + gTasks[taskId].data[2] = 0; + gTasks[taskId].func = sub_8128060; + } + else + { + ConvertIntToDecimalStringN(gStringVar1, gUnknown_0203A17C.size, STR_CONV_MODE_RIGHT_ALIGN, 2); + if (gUnknown_0203A17C.isPlayerRoom == FALSE) { + StringExpandPlaceholders(gStringVar4, gText_NoMoreDecorations); + } + else + { + StringExpandPlaceholders(gStringVar4, gText_NoMoreDecorations2); + } + DisplayItemMessageOnField(taskId, gStringVar4, sub_8127A5C); + } + } + else + { + StringExpandPlaceholders(gStringVar4, gText_InUseAlready); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8127A5C); + } +} + +void sub_8128060(u8 taskId) +{ + switch (gTasks[taskId].data[2]) + { + case 0: + if (!gPaletteFade.active) + { + sub_8127ACC(taskId); + gTasks[taskId].data[2] = 1; + } + break; + case 1: + gPaletteFade.bufferTransferDisabled = TRUE; + ConfigureCameraObjectForPlacingDecoration(&sPlaceDecorationGraphicsDataBuffer, gCurDecorInventoryItems[gCurDecorationIndex]); + sub_812826C(taskId); + SetUpPlacingDecorationPlayerAvatar(taskId, &sPlaceDecorationGraphicsDataBuffer); + pal_fill_black(); + gPaletteFade.bufferTransferDisabled = FALSE; + gTasks[taskId].data[2] = 2; + break; + case 2: + if (sub_80ABDFC() == TRUE) + { + gTasks[taskId].data[12] = 0; + sub_8128FD8(taskId); + } + break; + } +} + +void ConfigureCameraObjectForPlacingDecoration(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor) +{ + sDecor_CameraSpriteObjectIdx1 = gSprites[gUnknown_03005DD0.unk4].data0; + gUnknown_03005DD0.unk4 = gpu_pal_decompress_alloc_tag_and_upload(data, decor); + gSprites[gUnknown_03005DD0.unk4].oam.priority = 1; + gSprites[gUnknown_03005DD0.unk4].callback = sub_81292D0; + gSprites[gUnknown_03005DD0.unk4].pos1.x = gUnknown_085A7250[data->decoration->shape].x; + gSprites[gUnknown_03005DD0.unk4].pos1.y = gUnknown_085A7250[data->decoration->shape].y; +} + +void SetUpPlacingDecorationPlayerAvatar(u8 taskId, struct PlaceDecorationGraphicsDataBuffer *data) +{ + u8 v0; + + v0 = 16 * (u8)gTasks[taskId].data[5] + gUnknown_085A7250[data->decoration->shape].x - 8 * ((u8)gTasks[taskId].data[5] - 1); + if (data->decoration->shape == DECORSHAPE_3x1 || data->decoration->shape == DECORSHAPE_3x3 || data->decoration->shape == DECORSHAPE_3x2) + { + v0 -= 8; + } + if (gSaveBlock2Ptr->playerGender == MALE) + { + sDecor_CameraSpriteObjectIdx2 = AddPseudoFieldObject(0xC1, SpriteCallbackDummy, v0, 0x48, 0); + } + else + { + sDecor_CameraSpriteObjectIdx2 = AddPseudoFieldObject(0xC2, SpriteCallbackDummy, v0, 0x48, 0); + } + gSprites[sDecor_CameraSpriteObjectIdx2].oam.priority = 1; + DestroySprite(&gSprites[sDecor_CameraSpriteObjectIdx1]); + sDecor_CameraSpriteObjectIdx1 = gUnknown_03005DD0.unk4; +} + +void sub_812826C(u8 taskId) +{ + switch (gDecorations[gCurDecorInventoryItems[gCurDecorationIndex]].shape) + { + case DECORSHAPE_1x1: + gTasks[taskId].data[5] = 1; + gTasks[taskId].data[6] = 1; + break; + case DECORSHAPE_2x1: + gTasks[taskId].data[5] = 2; + gTasks[taskId].data[6] = 1; + break; + case DECORSHAPE_3x1: + gTasks[taskId].data[5] = 3; + gTasks[taskId].data[6] = 1; + break; + case DECORSHAPE_4x2: + gTasks[taskId].data[5] = 4; + gTasks[taskId].data[6] = 2; + break; + case DECORSHAPE_2x2: + gTasks[taskId].data[5] = 2; + gTasks[taskId].data[6] = 2; + break; + case DECORSHAPE_1x2: + gTasks[taskId].data[5] = 1; + gTasks[taskId].data[6] = 2; + break; + case DECORSHAPE_1x3: + gTasks[taskId].data[5] = 1; + gTasks[taskId].data[6] = 3; + gTasks[taskId].data[1]++; + break; + case DECORSHAPE_2x4: + gTasks[taskId].data[5] = 2; + gTasks[taskId].data[6] = 4; + break; + case DECORSHAPE_3x3: + gTasks[taskId].data[5] = 3; + gTasks[taskId].data[6] = 3; + break; + case DECORSHAPE_3x2: + gTasks[taskId].data[5] = 3; + gTasks[taskId].data[6] = 2; + break; + } +} + +void sub_81283BC(u8 taskId) +{ + gTasks[taskId].data[10] = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].data7 = 1; + gSprites[sDecor_CameraSpriteObjectIdx2].data7 = 1; + sub_8128DE0(); + sub_8128950(taskId); +} + +void sub_8128414(u8 taskId) +{ + gTasks[taskId].data[10] = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].data7 = 1; + gSprites[sDecor_CameraSpriteObjectIdx2].data7 = 1; + sub_8128DE0(); + StringExpandPlaceholders(gStringVar4, gText_CancelDecorating); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8128B80); +} + +bool8 sub_8128484(u8 behaviorAt, u16 behaviorBy) +{ + if (MetatileBehavior_IsMB_B3(behaviorAt) != TRUE || behaviorBy != 0) + { + return FALSE; + } + return TRUE; +} + +bool8 sub_81284AC(u8 taskId, s16 x, s16 y, u16 decor) +{ + if (x == gTasks[taskId].data[3] + 7 && y == gTasks[taskId].data[4] + 7 && decor != DECOR_NONE) + { + return FALSE; + } + return TRUE; +} + +bool8 sub_81284F4(u16 behaviorAt, const struct Decoration *decoration) +{ + if (MetatileBehavior_IsMB_B3(behaviorAt) != TRUE) + { + if (decoration->id == DECOR_SOLID_BOARD && MetatileBehavior_IsMB_C2(behaviorAt) == TRUE) + { + return TRUE; + } + if (MetatileBehavior_IsNormal(behaviorAt)) + { + return TRUE; + } + } + return FALSE; +} + +bool8 sub_812853C(u8 taskId, const struct Decoration *decoration) +{ + u8 i; + u8 j; + u8 behaviorAt; + u16 behaviorBy; + u8 mapY; + u8 mapX; + s16 curY; + s16 curX; + mapY = gTasks[taskId].data[6]; + mapX = gTasks[taskId].data[5]; + + switch (decoration->permission) + { + case DECORPERM_SOLID_FLOOR: + case DECORPERM_PASS_FLOOR: + for (i=0; i<mapY; i++) + { + curY = gTasks[taskId].data[1] - i; + for (j=0; j<mapX; j++) + { + curX = gTasks[taskId].data[0] + j; + behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY); + behaviorBy = GetBehaviorByMetatileId(0x200 + decoration->tiles[(mapY - 1 - i) * mapX + j]) & 0xf000; + if (!sub_81284F4(behaviorAt, decoration)) + { + return FALSE; + } + if (!sub_81284AC(taskId, curX, curY, behaviorBy)) + { + return FALSE; + } + behaviorAt = GetFieldObjectIdByXYZ(curX, curY, 0); + if (behaviorAt != 0 && behaviorAt != 16) + { + return FALSE; + } + } + } + break; + case DECORPERM_BEHIND_FLOOR: + for (i=0; i<mapY-1; i++) + { + curY = gTasks[taskId].data[1] - i; + for (j=0; j<mapX; j++) + { + curX = gTasks[taskId].data[0] + j; + behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY); + behaviorBy = GetBehaviorByMetatileId(0x200 + decoration->tiles[(mapY - 1 - i) * mapX + j]) & 0xf000; + if (!MetatileBehavior_IsNormal(behaviorAt) && !sub_8128484(behaviorAt, behaviorBy)) + { + return FALSE; + } + if (!sub_81284AC(taskId, curX, curY, behaviorBy)) + { + return FALSE; + } + if (GetFieldObjectIdByXYZ(curX, curY, 0) != 16) + { + return FALSE; + } + } + } + curY = gTasks[taskId].data[1] - mapY + 1; + for (j=0; j<mapX; j++) + { + curX = gTasks[taskId].data[0] + j; + behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY); + behaviorBy = GetBehaviorByMetatileId(0x200 + decoration->tiles[j]) & 0xf000; + if (!MetatileBehavior_IsNormal(behaviorAt) && !MetatileBehavior_IsMB_B7(behaviorAt)) + { + return FALSE; + } + if (!sub_81284AC(taskId, curX, curY, behaviorBy)) + { + return FALSE; + } + behaviorAt = GetFieldObjectIdByXYZ(curX, curY, 0); + if (behaviorAt != 0 && behaviorAt != 16) + { + return FALSE; + } + } + break; + case DECORPERM_NA_WALL: + for (i=0; i<mapY; i++) + { + curY = gTasks[taskId].data[1] - i; + for (j=0; j<mapX; j++) + { + curX = gTasks[taskId].data[0] + j; + if (!MetatileBehavior_IsMB_B7(MapGridGetMetatileBehaviorAt(curX, curY))) + { + return FALSE; + } + if (MapGridGetMetatileIdAt(curX, curY + 1) == 0x28c) + { + return FALSE; + } + } + } + break; + case DECORPERM_SOLID_MAT: + curY = gTasks[taskId].data[1]; + for (j=0; j<mapX; j++) + { + curX = gTasks[taskId].data[0] + j; + behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY); + if (decoration->shape == DECORSHAPE_1x2) + { + if (!MetatileBehavior_IsMB_C3(behaviorAt)) + { + return FALSE; + } + } + else if (!MetatileBehavior_IsMB_B5(behaviorAt)) + { + if (!MetatileBehavior_IsMB_C3(behaviorAt)) + { + return FALSE; + } + } + if (GetFieldObjectIdByXYZ(curX, curY, 0) != 16) + { + return FALSE; + } + } + break; + } + return TRUE; +} + +void sub_8128950(u8 taskId) +{ + if (sub_812853C(taskId, &gDecorations[gCurDecorInventoryItems[gCurDecorationIndex]]) == TRUE) + { + StringExpandPlaceholders(gStringVar4, gText_PlaceItHere); + DisplayItemMessageOnField(taskId, gStringVar4, sub_81289D0); + } + else + { + PlaySE(SE_HAZURE); + StringExpandPlaceholders(gStringVar4, gText_CantBePlacedHere); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8129020); + } +} + +void sub_81289D0(u8 taskId) +{ + sub_8197930(); + sub_8121F68(taskId, &gUnknown_085A72C4); +} + +void sub_81289F0(u8 taskId) +{ + sub_8197434(0, 0); + sub_8128AAC(taskId); + if (gDecorations[gCurDecorInventoryItems[gCurDecorationIndex]].permission != DECORPERM_SOLID_MAT) + { + sub_8127D38(gTasks[taskId].data[0], gTasks[taskId].data[1], gCurDecorInventoryItems[gCurDecorationIndex]); + } + else + { + sCurDecorMapX = gTasks[taskId].data[0] - 7; + sCurDecorMapY = gTasks[taskId].data[1] - 7; + ScriptContext1_SetupScript(gUnknown_08275D1F); + } + gSprites[sDecor_CameraSpriteObjectIdx1].pos1.y += 2; + if (gMapHeader.regionMapSectionId == REGION_MAP_SECRET_BASE) + { + TV_PutSecretBaseVisitOnTheAir(); + } + sub_8128BBC(taskId); +} + +void sub_8128AAC(u8 taskId) +{ + u16 i; + + for (i = 0; i < gUnknown_0203A17C.size; i ++) + { + if (gUnknown_0203A17C.items[i] == DECOR_NONE) + { + gUnknown_0203A17C.items[i] = gCurDecorInventoryItems[gCurDecorationIndex]; + gUnknown_0203A17C.pos[i] = ((gTasks[taskId].data[0] - 7) << 4) + (gTasks[taskId].data[1] - 7); + break; + } + } + if (!gUnknown_0203A17C.isPlayerRoom) + { + for (i = 0; i < 16; i ++) + { + if (sSecretBaseItemsIndicesBuffer[i] == 0) + { + sSecretBaseItemsIndicesBuffer[i] = gCurDecorationIndex + 1; + break; + } + } + } + else + { + for (i = 0; i < 12; i ++) + { + if (sPlayerRoomItemsIndicesBuffer[i] == 0) + { + sPlayerRoomItemsIndicesBuffer[i] = gCurDecorationIndex + 1; + break; + } + } + } +} + +void sub_8128B80(u8 taskId) +{ + sub_8197930(); + sub_8121F68(taskId, &gUnknown_085A72CC); +} + +void sub_8128BA0(u8 taskId) +{ + sub_8197434(0, 0); + sub_8128BBC(taskId); +} + +void sub_8128BBC(u8 taskId) +{ + fade_screen(1, 0); + gTasks[taskId].data[2] = 0; + gTasks[taskId].func = c1_overworld_prev_quest; +} + +void c1_overworld_prev_quest(u8 taskId) +{ + switch (gTasks[taskId].data[2]) + { + case 0: + ScriptContext2_Enable(); + if (!gPaletteFade.active) + { + sub_8127B04(taskId); + gTasks[taskId].data[2] = 1; + } + break; + case 1: + sub_812A3C8(); + FreeSpritePaletteByTag(OVERWORLD_PLACE_DECOR_SELECTOR_PAL_TAG); + gFieldCallback = sub_8128CD4; + SetMainCallback2(c2_exit_to_overworld_2_switch); + DestroyTask(taskId); + break; + } +} + +void sub_8128C64(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + switch (data[2]) + { + case 0: + sub_80E9578(); + data[2] ++; + break; + case 1: + ScriptContext1_SetupScript(gUnknown_08275D0C); + data[2] ++; + break; + case 2: + ScriptContext2_Enable(); + data[2] ++; + break; + case 3: + if (sub_80ABDFC() == TRUE) + { + gTasks[taskId].func = sub_812764C; + } + break; + } +} + +void sub_8128CD4(void) +{ + u8 taskId; + + ScriptContext2_Enable(); + pal_fill_black(); + taskId = CreateTask(sub_8128C64, 8); + sub_8127580(taskId); + gTasks[taskId].data[2] = 0; +} + +bool8 sub_8128D10(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + if (sDecorationLastDirectionMoved == DIR_SOUTH && data[1] - data[6] - 6 < 0) + { + data[1] ++; + return FALSE; + } + if (sDecorationLastDirectionMoved == DIR_NORTH && data[1] - 7 >= gMapHeader.mapData->height) + { + data[1] --; + return FALSE; + } + if (sDecorationLastDirectionMoved == DIR_WEST && data[0] - 7 < 0) + { + data[0] ++; + return FALSE; + } + if (sDecorationLastDirectionMoved == DIR_EAST && data[0] + data[5] - 8 >= gMapHeader.mapData->width) + { + data[0] --; + return FALSE; + } + return TRUE; +} + +bool8 sub_8128DB4(void) +{ + u16 heldKeys; + + heldKeys = gMain.heldKeys & 0x0F0; + if (heldKeys != DPAD_UP && heldKeys != DPAD_DOWN && heldKeys != DPAD_LEFT && heldKeys != DPAD_RIGHT) + { + return FALSE; + } + return TRUE; +} + +void sub_8128DE0(void) +{ + sDecorationLastDirectionMoved = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].data2 = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].data3 = 0; +} + +void sub_8128E18(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + if (!gSprites[sDecor_CameraSpriteObjectIdx1].data4) + { + if (data[10] == 1) + { + gUnknown_085A72D4[data[12]].yesFunc(taskId); + return; + } else if (data[10] == 2) + { + gUnknown_085A72D4[data[12]].noFunc(taskId); + return; + } + if ((gMain.heldKeys & 0x0F0) == DPAD_UP) + { + sDecorationLastDirectionMoved = DIR_SOUTH; + gSprites[sDecor_CameraSpriteObjectIdx1].data2 = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].data3 = -2; + data[1]--; + } + if ((gMain.heldKeys & 0x0F0) == DPAD_DOWN) + { + sDecorationLastDirectionMoved = DIR_NORTH; + gSprites[sDecor_CameraSpriteObjectIdx1].data2 = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].data3 = 2; + data[1]++; + } + if ((gMain.heldKeys & 0x0F0) == DPAD_LEFT) + { + sDecorationLastDirectionMoved = DIR_WEST; + gSprites[sDecor_CameraSpriteObjectIdx1].data2 = -2; + gSprites[sDecor_CameraSpriteObjectIdx1].data3 = 0; + data[0]--; + } + if ((gMain.heldKeys & 0x0F0) == DPAD_RIGHT) + { + sDecorationLastDirectionMoved = DIR_EAST; + gSprites[sDecor_CameraSpriteObjectIdx1].data2 = 2; + gSprites[sDecor_CameraSpriteObjectIdx1].data3 = 0; + data[0]++; + } + if (!sub_8128DB4() || !sub_8128D10(taskId)) + { + sub_8128DE0(); + } + } + if (sDecorationLastDirectionMoved) + { + gSprites[sDecor_CameraSpriteObjectIdx1].data4++; + gSprites[sDecor_CameraSpriteObjectIdx1].data4 &= 7; + } + if (!data[10]) + { + if (gMain.newKeys & A_BUTTON) + { + data[10] = A_BUTTON; + } + if (gMain.newKeys & B_BUTTON) + { + data[10] = B_BUTTON; + } + } +} + +void sub_8128FD8(u8 taskId) +{ + sub_8197434(0, 1); + gSprites[sDecor_CameraSpriteObjectIdx1].data7 = 0; + gTasks[taskId].data[10] = 0; + gTasks[taskId].func = sub_8128E18; +} + +void sub_8129020(u8 taskId) +{ + if (gMain.newKeys & A_BUTTON || gMain.newKeys & B_BUTTON) + { + sub_8128FD8(taskId); + } +} + +void sub_8129048(struct PlaceDecorationGraphicsDataBuffer *data) +{ + CpuFill16(0, data, sizeof(*data)); +} + +void sub_8129068(u16 *dest, u16 pal) +{ + CpuFastCopy(&((u16 *)gTilesetPointer_SecretBase->palettes)[pal << 4], dest, 32); +} + +void sub_8129088(u8 *dest, u16 tile) +{ + u8 buffer[32]; + u16 mode; + u16 i; + + mode = tile >> 10; + if (tile != 0) + { + tile &= 0x03FF; + } + CpuFastCopy(&((u8 *)gTilesetPointer_SecretBase->tiles)[tile << 5], buffer, 32); + switch (mode) + { + case 0: + CpuFastCopy(buffer, dest, 32); + break; + case 1: + for (i = 0; i < 8; i ++) + { + dest[4 * i] = (buffer[4 * (i + 1) - 1] >> 4) + ((buffer[4 * (i + 1) - 1] & 0x0F) << 4); + dest[4 * i + 1] = (buffer[4 * (i + 1) - 2] >> 4) + ((buffer[4 * (i + 1) - 2] & 0x0F) << 4); + dest[4 * i + 2] = (buffer[4 * (i + 1) - 3] >> 4) + ((buffer[4 * (i + 1) - 3] & 0x0F) << 4); + dest[4 * i + 3] = (buffer[4 * (i + 1) - 4] >> 4) + ((buffer[4 * (i + 1) - 4] & 0x0F) << 4); + } + break; + case 2: + for (i = 0; i < 8; i ++) + { + dest[4 * i] = buffer[4 * (7 - i)]; + dest[4 * i + 1] = buffer[4 * (7 - i) + 1]; + dest[4 * i + 2] = buffer[4 * (7 - i) + 2]; + dest[4 * i + 3] = buffer[4 * (7 - i) + 3]; + } + break; + case 3: + for (i = 0; i < 32; i ++) + { + dest[i] = (buffer[31 - i] >> 4) + ((buffer[31 - i] & 0x0F) << 4); + } + break; + } +} + +void sub_81291A4(struct PlaceDecorationGraphicsDataBuffer *data) +{ + u16 i; + for (i = 0; i < 64; i ++) + { + sub_8129088(&data->image[i * 32], data->tiles[i]); + } +} + +u16 sub_81291CC(u16 tile) +{ + return ((u16 *)gTilesetPointer_SecretBaseRedCave->metatiles)[tile] & 0xFFF; +} + +void sub_81291E8(struct PlaceDecorationGraphicsDataBuffer *data) +{ + u8 i; + u8 shape; + + shape = data->decoration->shape; + for (i = 0; i < gUnknown_085A71B0[shape].size; i ++) + { + data->tiles[gUnknown_085A71B0[shape].tiles[i]] = sub_81291CC(data->decoration->tiles[gUnknown_085A71B0[shape].y[i]] * 8 + gUnknown_085A71B0[shape].x[i]); + } +} + +void SetDecorSelectionBoxOamAttributes(u8 decorShape) +{ + sDecorSelectorOam.y = 0; + sDecorSelectorOam.affineMode = ST_OAM_AFFINE_OFF; + sDecorSelectorOam.objMode = ST_OAM_OBJ_NORMAL; + sDecorSelectorOam.mosaic = 0; + sDecorSelectorOam.bpp = ST_OAM_4BPP; + sDecorSelectorOam.shape = gUnknown_085A7250[decorShape].shape; + sDecorSelectorOam.x = 0; + sDecorSelectorOam.matrixNum = 0; + sDecorSelectorOam.size = gUnknown_085A7250[decorShape].size; + sDecorSelectorOam.tileNum = 0; + sDecorSelectorOam.priority = 0; + sDecorSelectorOam.paletteNum = 0; +} + +void sub_81292D0(struct Sprite *sprite) +{ + sprite->data2 = 0; + sprite->data3 = 0; + sprite->data4 = 0; + sprite->data5 = 0; + sprite->data6 = 0; + sprite->data7 = 0; + sprite->callback = sub_81292E8; +} + +void sub_81292E8(struct Sprite *sprite) +{ + if (sprite->data7 == 0) + { + if (sprite->data6 < 15) + { + sprite->invisible = FALSE; + } + else + { + sprite->invisible = TRUE; + } + sprite->data6 ++; + sprite->data6 &= 0x1F; + } + else + { + sprite->invisible = FALSE; + } +} + +u8 gpu_pal_decompress_alloc_tag_and_upload(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor) +{ + sub_8129048(data); + data->decoration = &gDecorations[decor]; + if (data->decoration->permission == DECORPERM_SOLID_MAT) + { + return AddPseudoFieldObject(data->decoration->tiles[0], SpriteCallbackDummy, 0, 0, 1); + } + FreeSpritePaletteByTag(OVERWORLD_PLACE_DECOR_SELECTOR_PAL_TAG); + sub_81291E8(data); + SetDecorSelectionBoxOamAttributes(data->decoration->shape); + sub_81291A4(data); + sub_8129068(data->palette, ((u16 *)gTilesetPointer_SecretBaseRedCave->metatiles)[(data->decoration->tiles[0] * 8) + 7] >> 12); + LoadSpritePalette(&gUnknown_085A72BC); + return CreateSprite(&sDecorSelectorSpriteTemplate, 0, 0, 0); +} + +u8 AddDecorationIconObjectFromIconTable(u16 tilesTag, u16 paletteTag, u8 decor) +{ + struct SpriteSheet sheet; + struct CompressedSpritePalette palette; + struct SpriteTemplate *template; + u8 spriteId; + + if (!AllocItemIconTemporaryBuffers()) + { + return MAX_SPRITES; + } + LZDecompressWram(GetDecorationIconPicOrPalette(decor, 0), gUnknown_0203CEBC); + CopyItemIconPicTo4x4Buffer(gUnknown_0203CEBC, gUnknown_0203CEC0); + sheet.data = gUnknown_0203CEC0; + sheet.size = 0x200; + sheet.tag = tilesTag; + LoadSpriteSheet(&sheet); + palette.data = GetDecorationIconPicOrPalette(decor, 1); + palette.tag = paletteTag; + LoadCompressedObjectPalette(&palette); + template = malloc(sizeof(struct SpriteTemplate)); + *template = gUnknown_08614FF4; + template->tileTag = tilesTag; + template->paletteTag = paletteTag; + spriteId = CreateSprite(template, 0, 0, 0); + FreeItemIconTemporaryBuffers(); + free(template); + return spriteId; +} + +const u8 *GetDecorationIconPicOrPalette(u16 decor, u8 mode) +{ + if (decor > 120) + { + decor = DECOR_NONE; + } + return gUnknown_085A6BE8[decor][mode]; +} + +u8 AddDecorationIconObjectFromFieldObject(u16 tilesTag, u16 paletteTag, u8 decor) +{ + u8 spriteId; + struct SpriteSheet sheet; + struct SpritePalette palette; + struct SpriteTemplate *template; + + sub_8129048(&sPlaceDecorationGraphicsDataBuffer); + sPlaceDecorationGraphicsDataBuffer.decoration = &gDecorations[decor]; + if (sPlaceDecorationGraphicsDataBuffer.decoration->permission != DECORPERM_SOLID_MAT) + { + sub_81291E8(&sPlaceDecorationGraphicsDataBuffer); + SetDecorSelectionBoxOamAttributes(sPlaceDecorationGraphicsDataBuffer.decoration->shape); + sub_81291A4(&sPlaceDecorationGraphicsDataBuffer); + sub_8129068(sPlaceDecorationGraphicsDataBuffer.palette, ((u16 *)gTilesetPointer_SecretBaseRedCave->metatiles)[(sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0] * 8) + 7] >> 12); + sheet.data = sPlaceDecorationGraphicsDataBuffer.image; + sheet.size = gUnknown_085A72F4[sPlaceDecorationGraphicsDataBuffer.decoration->shape] << 5; + sheet.tag = tilesTag; + LoadSpriteSheet(&sheet); + palette.data = sPlaceDecorationGraphicsDataBuffer.palette; + palette.tag = paletteTag; + LoadSpritePalette(&palette); + template = Alloc(sizeof(struct SpriteTemplate)); + *template = sDecorWhilePlacingSpriteTemplate; + template->tileTag = tilesTag; + template->paletteTag = paletteTag; + spriteId = CreateSprite(template, 0, 0, 0); + free(template); + } + else + { + spriteId = AddPseudoFieldObject(sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0], SpriteCallbackDummy, 0, 0, 1); + } + return spriteId; +} + +u8 AddDecorationIconObject(u8 decor, s16 x, s16 y, u8 priority, u16 tilesTag, u16 paletteTag) +{ + u8 spriteId; + + if (decor > 120) + { + spriteId = AddDecorationIconObjectFromIconTable(tilesTag, paletteTag, DECOR_NONE); + if (spriteId == MAX_SPRITES) + { + return MAX_SPRITES; + } + gSprites[spriteId].pos2.x = x + 4; + gSprites[spriteId].pos2.y = y + 4; + } + else if (gUnknown_085A6BE8[decor][0] == NULL) + { + spriteId = AddDecorationIconObjectFromFieldObject(tilesTag, paletteTag, decor); + if (spriteId == MAX_SPRITES) + { + return MAX_SPRITES; + } + gSprites[spriteId].pos2.x = x; + if (decor == DECOR_SILVER_SHIELD || decor == DECOR_GOLD_SHIELD) + { + gSprites[spriteId].pos2.y = y - 4; + } + else + { + gSprites[spriteId].pos2.y = y; + } + } + else + { + spriteId = AddDecorationIconObjectFromIconTable(tilesTag, paletteTag, decor); + if (spriteId == MAX_SPRITES) + { + return MAX_SPRITES; + } + gSprites[spriteId].pos2.x = x + 4; + gSprites[spriteId].pos2.y = y + 4; + } + gSprites[spriteId].oam.priority = priority; + return spriteId; +} + +void sub_81296EC(u8 idx) +{ + gUnknown_0203A17C.items[idx] = 0; + gUnknown_0203A17C.pos[idx] = 0; +} + +void sub_8129708(void) +{ + u16 i; + + gSpecialVar_0x8005 = 0; + gScriptResult = 0; + if (gSpecialVar_0x8004 == sCurDecorSelectedInRearrangement) + { + gScriptResult = 1; + } + else if (gDecorations[gUnknown_0203A17C.items[sDecorRearrangementDataBuffer[gSpecialVar_0x8004].idx]].permission == DECORPERM_SOLID_MAT) + { + gSpecialVar_0x8005 = sDecorRearrangementDataBuffer[gSpecialVar_0x8004].flagId; + sub_81296EC(sDecorRearrangementDataBuffer[gSpecialVar_0x8004].idx); + for (i = 0; i < gMapHeader.events->mapObjectCount; i ++) + { + if (gMapHeader.events->mapObjects[i].flagId == gSpecialVar_0x8005) + { + gSpecialVar_0x8006 = gMapHeader.events->mapObjects[i].localId; + break; + } + } + } +} + +void sub_81297AC(void) +{ + u8 i; + + for (i = 0; i < gMapHeader.events->mapObjectCount; i ++) + { + if (gMapHeader.events->mapObjects[i].flagId == gSpecialVar_0x8004) + { + gSpecialVar_0x8005 = gMapHeader.events->mapObjects[i].localId; + break; + } + } +} + +void sub_81297F8(void) +{ + u8 i; + u8 y; + u8 x; + int posX; + int posY; + u8 perm; + + for (i = 0; i < sCurDecorSelectedInRearrangement; i ++) + { + perm = gDecorations[gUnknown_0203A17C.items[sDecorRearrangementDataBuffer[i].idx]].permission; + posX = gUnknown_0203A17C.pos[sDecorRearrangementDataBuffer[i].idx] >> 4; + posY = gUnknown_0203A17C.pos[sDecorRearrangementDataBuffer[i].idx] & 0x0F; + if (perm != DECORPERM_SOLID_MAT) + { + for (y = 0; y < sDecorRearrangementDataBuffer[i].height; y ++) + { + for (x = 0; x < sDecorRearrangementDataBuffer[i].width; x ++) + { + MapGridSetMetatileEntryAt(posX + 7 + x, posY + 7 - y, gMapHeader.mapData->map[posX + x + gMapHeader.mapData->width * (posY - y)] | 0x3000); + } + } + sub_81296EC(sDecorRearrangementDataBuffer[i].idx); + } + } +} + +void sub_81298EC(u8 taskId) +{ + switch (gTasks[taskId].data[2]) + { + case 0: + sub_81297F8(); + gTasks[taskId].data[2] = 1; + break; + case 1: + if (!gPaletteFade.active) { + DrawWholeMapView(); + ScriptContext1_SetupScript(gUnknown_08275D2E); + sub_8197434(0, 1); + gTasks[taskId].data[2] = 2; + } + break; + case 2: + ScriptContext2_Enable(); + IdentifyOwnedDecorationsCurrentlyInUseInternal(taskId); + pal_fill_black(); + gTasks[taskId].data[2] = 3; + break; + case 3: + if (sub_80ABDFC() == TRUE) + { + StringExpandPlaceholders(gStringVar4, gText_DecorationReturnedToPC); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8129D64); + if (gMapHeader.regionMapSectionId == REGION_MAP_SECRET_BASE) + { + TV_PutSecretBaseVisitOnTheAir(); + } + } + break; + } +} + + +bool8 sub_81299AC(u8 taskId) +{ + u16 i; + + for (i = 0; i < gUnknown_0203A17C.size; i ++) + { + if (gUnknown_0203A17C.items[i] != DECOR_NONE) + { + return TRUE; + } + } + return FALSE; +} + +void SetUpPuttingAwayDecorationPlayerAvatar(void) +{ + player_get_direction_lower_nybble(); + sDecor_CameraSpriteObjectIdx1 = gSprites[gUnknown_03005DD0.unk4].data0; + sub_812A39C(); + gUnknown_03005DD0.unk4 = CreateSprite(&gUnknown_085A7404, 0x78, 0x50, 0); + if (gSaveBlock2Ptr->playerGender == MALE) + { + sDecor_CameraSpriteObjectIdx2 = AddPseudoFieldObject(0xC1, SpriteCallbackDummy, 0x88, 0x48, 0); + } + else + { + sDecor_CameraSpriteObjectIdx2 = AddPseudoFieldObject(0xC2, SpriteCallbackDummy, 0x88, 0x48, 0); + } + gSprites[sDecor_CameraSpriteObjectIdx2].oam.priority = 1; + DestroySprite(&gSprites[sDecor_CameraSpriteObjectIdx1]); + sDecor_CameraSpriteObjectIdx1 = gUnknown_03005DD0.unk4; + gSprites[sDecor_CameraSpriteObjectIdx1].oam.priority = 1; +} + +void sub_8129ABC(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + switch (data[2]) + { + case 0: + if (!gPaletteFade.active) + { + sub_8127ACC(taskId); + data[2] = 1; + data[6] = 1; + data[5] = 1; + } + break; + case 1: + SetUpPuttingAwayDecorationPlayerAvatar(); + pal_fill_black(); + data[2] = 2; + break; + case 2: + if (sub_80ABDFC() == TRUE) + { + data[12] = 1; + sub_8129B34(taskId); + } + break; + } +} + +void sub_8129B34(u8 taskId) +{ + sub_8197434(0, 1); + gSprites[sDecor_CameraSpriteObjectIdx1].data7 = 0; + gSprites[sDecor_CameraSpriteObjectIdx1].invisible = FALSE; + gSprites[sDecor_CameraSpriteObjectIdx1].callback = sub_812A36C; + gSprites[sDecor_CameraSpriteObjectIdx2].pos1.x = 0x88; + gSprites[sDecor_CameraSpriteObjectIdx2].pos1.y = 0x48; + gTasks[taskId].data[10] = 0; + gTasks[taskId].func = sub_8128E18; +} + +void sub_8129BCC(u8 taskId) +{ + gTasks[taskId].data[10] = 0; + sub_8128DE0(); + sub_8129C74(taskId); +} + +void sub_8129BF8(u8 taskId) +{ + gTasks[taskId].data[10] = 0; + sub_8128DE0(); + gSprites[sDecor_CameraSpriteObjectIdx1].invisible = FALSE; + gSprites[sDecor_CameraSpriteObjectIdx1].callback = SpriteCallbackDummy; + StringExpandPlaceholders(gStringVar4, gText_StopPuttingAwayDecorations); + DisplayItemMessageOnField(taskId, gStringVar4, sub_812A1F0); +} + +void sub_8129C74(u8 taskId) +{ + s16 *data; + u8 behavior; + + sub_812A0E8(taskId); + if (sCurDecorSelectedInRearrangement != 0) + { + StringExpandPlaceholders(gStringVar4, gText_ReturnDecorationToPC); + DisplayItemMessageOnField(taskId, gStringVar4, sub_812A1A0); + } + else + { + data = gTasks[taskId].data; + behavior = MapGridGetMetatileBehaviorAt(data[0], data[1]); + if (MetatileBehavior_IsSecretBasePC(behavior) == TRUE || MetatileBehavior_IsMB_C5(behavior) == TRUE) + { + gSprites[sDecor_CameraSpriteObjectIdx1].invisible = FALSE; + gSprites[sDecor_CameraSpriteObjectIdx1].callback = SpriteCallbackDummy; + StringExpandPlaceholders(gStringVar4, gText_StopPuttingAwayDecorations); + DisplayItemMessageOnField(taskId, gStringVar4, sub_812A1F0); + } + else + { + StringExpandPlaceholders(gStringVar4, gText_NoDecorationHere); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8129D64); + } + } +} + +void sub_8129D64(u8 taskId) +{ + if (gMain.newKeys & A_BUTTON || gMain.newKeys & B_BUTTON) + { + sub_8129B34(taskId); + } +} + +void sub_8129D8C(u8 decor, struct DecorRearrangementDataBuffer *data) +{ + if (gDecorations[decor].shape == DECORSHAPE_1x1) + { + data->width = 1; + data->height = 1; + } else if (gDecorations[decor].shape == DECORSHAPE_2x1) + { + data->width = 2; + data->height = 1; + } else if (gDecorations[decor].shape == DECORSHAPE_3x1) + { + data->width = 3; + data->height = 1; + } else if (gDecorations[decor].shape == DECORSHAPE_4x2) + { + data->width = 4; + data->height = 2; + } else if (gDecorations[decor].shape == DECORSHAPE_2x2) + { + data->width = 2; + data->height = 2; + } else if (gDecorations[decor].shape == DECORSHAPE_1x2) + { + data->width = 1; + data->height = 2; + } else if (gDecorations[decor].shape == DECORSHAPE_1x3) + { + data->width = 1; + data->height = 3; + } else if (gDecorations[decor].shape == DECORSHAPE_2x4) + { + data->width = 2; + data->height = 4; + } else if (gDecorations[decor].shape == DECORSHAPE_3x3) + { + data->width = 3; + data->height = 3; + } else if (gDecorations[decor].shape == DECORSHAPE_3x2) + { + data->width = 3; + data->height = 2; + } +} + +void sub_8129E0C(u8 x, u8 y) +{ + gSprites[sDecor_CameraSpriteObjectIdx1].invisible = TRUE; + gSprites[sDecor_CameraSpriteObjectIdx1].callback = SpriteCallbackDummy; + gSprites[sDecor_CameraSpriteObjectIdx2].pos1.x = (x << 4) + 0x88; + gSprites[sDecor_CameraSpriteObjectIdx2].pos1.y = (y << 4) + 0x48; +} + +bool8 sub_8129E74(u8 taskId, u8 idx, struct DecorRearrangementDataBuffer *data) +{ + u8 x; + u8 y; + u8 xOff; + u8 yOff; + u8 ht; + + x = gTasks[taskId].data[0] - 7; + y = gTasks[taskId].data[1] - 7; + xOff = gUnknown_0203A17C.pos[idx] >> 4; + yOff = gUnknown_0203A17C.pos[idx] & 0x0F; + ht = data->height; + if (gUnknown_0203A17C.items[idx] == DECOR_SAND_ORNAMENT && MapGridGetMetatileIdAt(xOff + 7, yOff + 7) == 0x28C) + { + ht --; + } + if (x >= xOff && x < xOff + data->width && y > yOff - ht && y <= yOff) + { + sub_8129E0C(data->width - (x - xOff + 1), yOff - y); + return TRUE; + } + return FALSE; +} + +void sub_8129F20(void) +{ + u8 xOff; + u8 yOff; + u16 i; + + xOff = gUnknown_0203A17C.pos[sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].idx] >> 4; + yOff = gUnknown_0203A17C.pos[sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].idx] & 0x0F; + for (i = 0; i < 0x40; i ++) + { + if (gSaveBlock1Ptr->mapObjectTemplates[i].x == xOff && gSaveBlock1Ptr->mapObjectTemplates[i].y == yOff && !FlagGet(gSaveBlock1Ptr->mapObjectTemplates[i].flagId)) + { + sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].flagId = gSaveBlock1Ptr->mapObjectTemplates[i].flagId; + break; + } + } +} + +bool8 sub_8129FC8(u8 taskId) +{ + u16 i; + + for (i = 0; i < gUnknown_0203A17C.size; i ++) + { + if (gUnknown_0203A17C.items[i] != 0) + { + if (gDecorations[gUnknown_0203A17C.items[i]].permission == DECORPERM_SOLID_MAT) + { + sub_8129D8C(gUnknown_0203A17C.items[i], sDecorRearrangementDataBuffer); + if (sub_8129E74(taskId, i, sDecorRearrangementDataBuffer) == TRUE) + { + sDecorRearrangementDataBuffer->idx = i; + sub_8129F20(); + sCurDecorSelectedInRearrangement = 1; + return TRUE; + } + } + } + } + return FALSE; +} + +void sub_812A040(u8 left, u8 top, u8 right, u8 bottom) +{ + u8 i; + u8 xOff; + u8 yOff; + u8 decorIdx; + + for (i = 0; i < gUnknown_0203A17C.size; i ++) + { + decorIdx = gUnknown_0203A17C.items[i]; + xOff = gUnknown_0203A17C.pos[i] >> 4; + yOff = gUnknown_0203A17C.pos[i] & 0x0F; + if (decorIdx != 0 && gDecorations[decorIdx].permission == DECORPERM_SOLID_MAT && left <= xOff && top <= yOff && right >= xOff && bottom >= yOff) + { + sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].idx = i; + sub_8129F20(); + sCurDecorSelectedInRearrangement++; + } + } +} + +#ifdef NONMATCHING +void sub_812A0E8(u8 taskId) +{ + u8 i; + u8 xOff; + u8 yOff; + u8 decor; + register u8 decor asm("r1"); + struct DecorRearrangementDataBuffer *data; + + sCurDecorSelectedInRearrangement = 0; + if (sub_8129FC8(taskId) != TRUE) + { + for (i = 0; i < gUnknown_0203A17C.size; i ++) + { + decor = gUnknown_0203A17C.items[i]; + if (decor != DECOR_NONE) + { + data = &sDecorRearrangementDataBuffer[0]; + sub_8129D8C(decor, data); + if (sub_8129E74(taskId, i, data) == TRUE) + { + data->idx = i; + sCurDecorSelectedInRearrangement ++; + break; + } + } + } + if (sCurDecorSelectedInRearrangement != 0) + { + xOff = gUnknown_0203A17C.pos[sDecorRearrangementDataBuffer[0].idx] >> 4; + yOff = gUnknown_0203A17C.pos[sDecorRearrangementDataBuffer[0].idx] & 0x0F; + sub_812A040(xOff, yOff - sDecorRearrangementDataBuffer[0].height + 1, xOff + sDecorRearrangementDataBuffer[0].width - 1, yOff); // Arithmetic register swap at the r2 argument: `add r2, r0, r2` instead of `add r2, r2, r0` + } + } +} +#else +__attribute__((naked)) void sub_812A0E8(u8 taskId) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tlsls r0, 24\n" + "\tlsrs r6, r0, 24\n" + "\tldr r4, =sCurDecorSelectedInRearrangement\n" + "\tmovs r0, 0\n" + "\tstrb r0, [r4]\n" + "\tadds r0, r6, 0\n" + "\tbl sub_8129FC8\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tcmp r0, 0x1\n" + "\tbeq _0812A18C\n" + "\tmovs r5, 0\n" + "\tldr r0, =gUnknown_0203A17C\n" + "\tldrb r1, [r0, 0x8]\n" + "\tcmp r5, r1\n" + "\tbcs _0812A15A\n" + "\tadds r7, r4, 0\n" + "_0812A10E:\n" + "\tldr r0, [r0]\n" + "\tadds r0, r5\n" + "\tldrb r1, [r0]\n" + "\tcmp r1, 0\n" + "\tbeq _0812A14C\n" + "\tldr r4, =sDecorRearrangementDataBuffer\n" + "\tadds r0, r1, 0\n" + "\tadds r1, r4, 0\n" + "\tbl sub_8129D8C\n" + "\tadds r0, r6, 0\n" + "\tadds r1, r5, 0\n" + "\tadds r2, r4, 0\n" + "\tbl sub_8129E74\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tcmp r0, 0x1\n" + "\tbne _0812A14C\n" + "\tstrb r5, [r4]\n" + "\tldrb r0, [r7]\n" + "\tadds r0, 0x1\n" + "\tstrb r0, [r7]\n" + "\tb _0812A15A\n" + "\t.pool\n" + "_0812A14C:\n" + "\tadds r0, r5, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r5, r0, 24\n" + "\tldr r0, =gUnknown_0203A17C\n" + "\tldrb r1, [r0, 0x8]\n" + "\tcmp r5, r1\n" + "\tbcc _0812A10E\n" + "_0812A15A:\n" + "\tldr r0, =sCurDecorSelectedInRearrangement\n" + "\tldrb r0, [r0]\n" + "\tcmp r0, 0\n" + "\tbeq _0812A18C\n" + "\tldr r0, =gUnknown_0203A17C\n" + "\tldr r2, =sDecorRearrangementDataBuffer\n" + "\tldrb r1, [r2]\n" + "\tldr r0, [r0, 0x4]\n" + "\tadds r0, r1\n" + "\tldrb r1, [r0]\n" + "\tlsrs r0, r1, 4\n" + "\tmovs r3, 0xF\n" + "\tands r3, r1\n" + "\tldrb r1, [r2, 0x2]\n" + "\tsubs r1, r3, r1\n" + "\tadds r1, 0x1\n" + "\tlsls r1, 24\n" + "\tlsrs r1, 24\n" + "\tldrb r2, [r2, 0x1]\n" + "\tadds r2, r0\n" + "\tsubs r2, 0x1\n" + "\tlsls r2, 24\n" + "\tlsrs r2, 24\n" + "\tbl sub_812A040\n" + "_0812A18C:\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0\n" + "\t.pool"); +} +#endif + +void sub_812A1A0(u8 taskId) +{ + sub_8197930(); + sub_8121F68(taskId, &gUnknown_085A7348); +} + +void sub_812A1C0(u8 taskId) +{ + fade_screen(1, 0); + gTasks[taskId].data[2] = 0; + gTasks[taskId].func = sub_81298EC; +} + +void sub_812A1F0(u8 taskId) +{ + sub_8197930(); + sub_8121F68(taskId, &gUnknown_085A7350); +} + +void sub_812A210(u8 taskId) +{ + sub_8197434(0, 0); + sub_812A22C(taskId); +} + +void sub_812A22C(u8 taskId) +{ + fade_screen(1, 0); + gTasks[taskId].data[2] = 0; + gTasks[taskId].func = sub_812A25C; +} + +void sub_812A25C(u8 taskId) +{ + switch (gTasks[taskId].data[2]) + { + case 0: + if (!gPaletteFade.active) + { + sub_8127B04(taskId); + gTasks[taskId].data[2] = 1; + } + break; + case 1: + sub_812A3C8(); + gFieldCallback = sub_812A334; + SetMainCallback2(c2_exit_to_overworld_2_switch); + DestroyTask(taskId); + break; + } +} + +void sub_812A2C4(u8 taskId) +{ + s16 *data; + + data = gTasks[taskId].data; + switch (data[2]) + { + case 0: + sub_80E9578(); + data[2] ++; + break; + case 1: + ScriptContext1_SetupScript(gUnknown_08275D0C); + data[2] ++; + break; + case 2: + ScriptContext2_Enable(); + data[2] ++; + break; + case 3: + if (sub_80ABDFC() == TRUE) + { + gTasks[taskId].func = sub_8126B80; + } + break; + } +} + +void sub_812A334(void) +{ + u8 taskId; + + pal_fill_black(); + sub_81973C4(0, 1); + sub_8126ABC(); + taskId = CreateTask(sub_812A2C4, 8); + gTasks[taskId].data[2] = 0; +} + +void sub_812A36C(struct Sprite *sprite) +{ + sprite->data0 ++; + sprite->data0 &= 0x1F; + if (sprite->data0 > 15) + { + sprite->invisible = TRUE; + } + else + { + sprite->invisible = FALSE; + } +} + +void sub_812A39C(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + { + LoadSpritePalette(&gUnknown_085A73D8); + } + else + { + LoadSpritePalette(&gUnknown_085A73E0); + } +} + +void sub_812A3C8(void) +{ + FreeSpritePaletteByTag(OVERWORLD_PLACE_DECOR_PLAYER_PAL_TAG); +} + +void sub_812A3D4(u8 taskId) +{ + if (IsSelectedDecorInThePC() == TRUE) + { + StringCopy(gStringVar1, gDecorations[gCurDecorInventoryItems[gCurDecorationIndex]].name); + StringExpandPlaceholders(gStringVar4, gText_DecorationWillBeDiscarded); + DisplayItemMessageOnField(taskId, gStringVar4, sub_812A458); + } + else + { + StringExpandPlaceholders(gStringVar4, gText_CantThrowAwayInUse); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8127A5C); + } +} + +void sub_812A458(u8 taskId) +{ + sub_8197930(); + sub_8121F68(taskId, &gUnknown_085A741C); +} + +void sub_812A478(u8 taskId) +{ + gCurDecorInventoryItems[gCurDecorationIndex] = DECOR_NONE; + sCurDecorCatCount = CountDecorationCategoryN(sCurDecorationCategory); + CondenseDecorationCategoryN(sCurDecorationCategory); + IdentifyOwnedDecorationsCurrentlyInUseInternal(taskId); + StringExpandPlaceholders(gStringVar4, gText_DecorationThrownAway); + DisplayItemMessageOnField(taskId, gStringVar4, sub_8127A5C); +} diff --git a/src/decoration_inventory.c b/src/decoration_inventory.c new file mode 100644 index 000000000..03ab6c00c --- /dev/null +++ b/src/decoration_inventory.c @@ -0,0 +1,189 @@ + +// Includes +#include "global.h" +#include "decoration.h" +#include "decoration_inventory.h" + +// Static type declarations + +// Static RAM declarations + +EWRAM_DATA struct DecorationInventory gDecorationInventories[8] = {}; + +// Static ROM declarations + +// .rodata + +// .text + +#define SET_DECOR_INV(i, ptr) {\ + gDecorationInventories[i].items = ptr;\ + gDecorationInventories[i].size = sizeof(ptr);\ +} + +void SetDecorationInventoriesPointers(void) +{ + SET_DECOR_INV(0, gSaveBlock1Ptr->decorDesk); + SET_DECOR_INV(1, gSaveBlock1Ptr->decorChair); + SET_DECOR_INV(2, gSaveBlock1Ptr->decorPlant); + SET_DECOR_INV(3, gSaveBlock1Ptr->decorOrnament); + SET_DECOR_INV(4, gSaveBlock1Ptr->decorMat); + SET_DECOR_INV(5, gSaveBlock1Ptr->decorPoster); + SET_DECOR_INV(6, gSaveBlock1Ptr->decorDoll); + SET_DECOR_INV(7, gSaveBlock1Ptr->decorCushion); + sub_8126968(); +} + +static void ClearDecorationInventory(u8 idx) +{ + u8 i; + + for (i = 0; i < gDecorationInventories[idx].size; i ++) + { + gDecorationInventories[idx].items[i] = DECOR_NONE; + } +} + +void ClearDecorationInventories(void) +{ + u8 idx; + + for (idx = 0; idx < 8; idx ++) + { + ClearDecorationInventory(idx); + } +} + +s8 GetFirstEmptyDecorSlot(u8 idx) +{ + s8 i; + + for (i = 0; i < (s8)gDecorationInventories[idx].size; i ++) + { + if (gDecorationInventories[idx].items[i] == DECOR_NONE) + { + return i; + } + } + return -1; +} + +bool8 CheckHasDecoration(u8 decor) +{ + u8 i; + u8 category; + + category = gDecorations[decor].category; + for (i = 0; i < gDecorationInventories[category].size; i ++) + { + if (gDecorationInventories[category].items[i] == decor) + { + return TRUE; + } + } + return FALSE; +} + +bool8 DecorationAdd(u8 decor) +{ + u8 category; + s8 idx; + + if (decor == DECOR_NONE) + { + return FALSE; + } + category = gDecorations[decor].category; + idx = GetFirstEmptyDecorSlot(category); + if (idx == -1) + { + return FALSE; + } + gDecorationInventories[category].items[idx] = decor; + return TRUE; +} + +bool8 DecorationCheckSpace(u8 decor) +{ + if (decor == DECOR_NONE) + { + return FALSE; + } + if (GetFirstEmptyDecorSlot(gDecorations[decor].category) == -1) + { + return FALSE; + } + return TRUE; +} + +s8 DecorationRemove(u8 decor) +{ + u8 i; + u8 idx; + + i = 0; + if (decor == DECOR_NONE) + { + return 0; + } + for (i = 0; i < gDecorationInventories[gDecorations[decor].category].size; i ++) + { + idx = gDecorations[decor].category; + if (gDecorationInventories[idx].items[i] == decor) + { + gDecorationInventories[idx].items[i] = DECOR_NONE; + CondenseDecorationCategoryN(idx); + return 1; + } + } + return 0; +} + +void CondenseDecorationCategoryN(u8 idx) +{ + u8 i; + u8 j; + u8 tmp; + + for (i = 0; i < gDecorationInventories[idx].size; i ++) + { + for (j = i + 1; j < gDecorationInventories[idx].size; j ++) + { + if (gDecorationInventories[idx].items[j] != DECOR_NONE && (gDecorationInventories[idx].items[i] == DECOR_NONE || gDecorationInventories[idx].items[i] > gDecorationInventories[idx].items[j])) + { + tmp = gDecorationInventories[idx].items[i]; + gDecorationInventories[idx].items[i] = gDecorationInventories[idx].items[j]; + gDecorationInventories[idx].items[j] = tmp; + } + } + } +} + +u8 CountDecorationCategoryN(u8 idx) +{ + u8 i; + u8 ct; + + ct = 0; + for (i = 0; i < gDecorationInventories[idx].size; i ++) + { + if (gDecorationInventories[idx].items[i] != DECOR_NONE) + { + ct ++; + } + } + return ct; +} + +u8 CountDecorations(void) +{ + u8 idx; + u8 ct; + + ct = 0; + for (idx = 0; idx < 8; idx ++) + { + ct += CountDecorationCategoryN(idx); + } + return ct; +} diff --git a/src/diploma.c b/src/diploma.c new file mode 100755 index 000000000..d4a269757 --- /dev/null +++ b/src/diploma.c @@ -0,0 +1,219 @@ +#include "global.h" +#include "diploma.h" +#include "palette.h" +#include "main.h" +#include "gpu_regs.h" +#include "unknown_task.h" +#include "task.h" +#include "malloc.h" +#include "decompress.h" +#include "bg.h" +#include "window.h" +#include "string_util.h" +#include "text.h" + +extern void reset_temp_tile_data_buffers(void); +extern int decompress_and_copy_tile_data_to_vram(u8 bg_id, void *src, int size, u16 offset, u8 mode); +extern bool8 free_temp_tile_data_buffers_if_possible(void); +extern void sub_80861E8(void); // rom4 +extern bool16 sub_80C0944(void); +extern void AddTextPrinterParametrized2(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, struct TextColor *color, s8 speed, u8 *str); + +extern u16 gUnknown_0860F074[]; + +extern u8 gText_DexNational[]; +extern u8 gText_DexHoenn[]; +extern u8 gText_PokedexDiploma[]; + +static void MainCB2(void); +static void Task_DiplomaFadeIn(u8); +static void Task_DiplomaWaitForKeyPress(u8); +static void Task_DiplomaFadeOut(u8); +static void DisplayDiplomaText(void); +static void InitDiplomaBg(void); +static void InitDiplomaWindow(void); +static void PrintDiplomaText(u8 *, u8, u8); + +EWRAM_DATA static void **sDiplomaTilemapPtr = {NULL}; + +static void VBlankCB(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static const u16 sDiplomaPalettes[][16] = +{ + INCBIN_U16("graphics/misc/diploma_national.gbapal"), + INCBIN_U16("graphics/misc/diploma_hoenn.gbapal"), +}; + +static const u8 sDiplomaTilemap[] = INCBIN_U8("graphics/misc/diploma_map.bin.lz"); +static const u8 sDiplomaTiles[] = INCBIN_U8("graphics/misc/diploma.4bpp.lz"); + +void CB2_ShowDiploma(void) +{ + SetVBlankCallback(NULL); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG3CNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG2CNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG1CNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG0CNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG3HOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG3VOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG2HOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG2VOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG1HOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG1VOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG0HOFS, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BG0VOFS, DISPCNT_MODE_0); + // why doesn't this one use the dma manager either? + DmaFill16(3, 0, VRAM, VRAM_SIZE); + DmaFill32(3, 0, OAM, OAM_SIZE); + DmaFill16(3, 0, PLTT, PLTT_SIZE); + remove_some_task(); + ResetTasks(); + ResetSpriteData(); + ResetPaletteFade(); + FreeAllSpritePalettes(); + LoadPalette(sDiplomaPalettes, 0, 64); + sDiplomaTilemapPtr = malloc(0x1000); + InitDiplomaBg(); + InitDiplomaWindow(); + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, &sDiplomaTiles, 0, 0, 0); + while (free_temp_tile_data_buffers_if_possible()) + ; + LZDecompressWram(&sDiplomaTilemap, sDiplomaTilemapPtr); + CopyBgTilemapBufferToVram(1); + DisplayDiplomaText(); + BlendPalettes(-1, 16, 0); + BeginNormalPaletteFade(-1, 0, 16, 0, 0); + EnableInterrupts(1); + SetVBlankCallback(VBlankCB); + SetMainCallback2(MainCB2); + CreateTask(Task_DiplomaFadeIn, 0); +} + +static void MainCB2(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void Task_DiplomaFadeIn(u8 taskId) +{ + if (!gPaletteFade.active) + gTasks[taskId].func = Task_DiplomaWaitForKeyPress; +} + +static void Task_DiplomaWaitForKeyPress(u8 taskId) +{ + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gTasks[taskId].func = Task_DiplomaFadeOut; + } +} + +static void Task_DiplomaFadeOut(u8 taskId) +{ + if (!gPaletteFade.active) + { + Free(sDiplomaTilemapPtr); + FreeAllWindowBuffers(); + DestroyTask(taskId); + SetMainCallback2(sub_80861E8); + } +} + +static void DisplayDiplomaText(void) +{ + if (sub_80C0944()) + { + SetGpuReg(REG_OFFSET_BG1HOFS, DISPCNT_BG0_ON); + StringCopy(gStringVar1, gText_DexNational); + } + else + { + SetGpuReg(REG_OFFSET_BG1HOFS, DISPCNT_MODE_0); + StringCopy(gStringVar1, gText_DexHoenn); + } + StringExpandPlaceholders(gStringVar4, gText_PokedexDiploma); + PrintDiplomaText(gStringVar4, 0, 1); + PutWindowTilemap(0); + CopyWindowToVram(0, 3); +} + +static const struct BgTemplate sDiplomaBgTemplates[2] = +{ + { + .bg = 0, + .charBaseIndex = 1, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0, + }, + { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 6, + .screenSize = 1, + .paletteMode = 0, + .priority = 1, + .baseTile = 0, + }, +}; + +static void InitDiplomaBg(void) +{ + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sDiplomaBgTemplates, 2); + SetBgTilemapBuffer(1, sDiplomaTilemapPtr); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + ShowBg(0); + ShowBg(1); + SetGpuReg(REG_OFFSET_BLDCNT, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BLDALPHA, DISPCNT_MODE_0); + SetGpuReg(REG_OFFSET_BLDY, DISPCNT_MODE_0); +} + +static const struct WindowTemplate sDiplomaWinTemplates[2] = +{ + { + .priority = 0, + .tilemapLeft = 5, + .tilemapTop = 2, + .width = 20, + .height = 16, + .paletteNum = 15, + .baseBlock = 1, + }, + DUMMY_WIN_TEMPLATE, +}; + +static void InitDiplomaWindow(void) +{ + InitWindows(sDiplomaWinTemplates); + DeactivateAllTextPrinters(); + LoadPalette(gUnknown_0860F074, 0xF0, 0x20); + FillWindowPixelBuffer(0, 0); + PutWindowTilemap(0); +} + +static void PrintDiplomaText(u8 *text, u8 var1, u8 var2) +{ + struct TextColor color = + { + .fgColor = 0, + .bgColor = 2, + .shadowColor = 3, + }; + + AddTextPrinterParametrized2(0, 1, var1, var2, 0, 0, &color, -1, text); +} diff --git a/src/dma3_manager.c b/src/dma3_manager.c index 7cce06c15..bb015c5cf 100644 --- a/src/dma3_manager.c +++ b/src/dma3_manager.c @@ -1,12 +1,23 @@ #include "global.h" #include "dma3.h" +IWRAM_DATA struct { + /* 0x00 */ const u8 *src; + /* 0x04 */ u8 *dest; + /* 0x08 */ u16 size; + /* 0x0A */ u16 mode; + /* 0x0C */ u32 value; +} gDma3Requests[128]; + +static bool8 gDma3ManagerLocked; +static u8 gDma3RequestCursor; + void ClearDma3Requests(void) { int i; gDma3ManagerLocked = TRUE; - gDma3RequestCursor = FALSE; + gDma3RequestCursor = 0; for(i = 0; i < (u8)ARRAY_COUNT(gDma3Requests); i++) { @@ -22,7 +33,6 @@ void ClearDma3Requests(void) void ProcessDma3Requests(void) { // NOTE: the fillerA member of the DMA struct is actually u32 value; - // NOTE: gUnknown_0300001C is just a pointer inside the gDma3Requests structure, not a true symbol; feel free to remove u16 total_size; if (gDma3ManagerLocked) @@ -331,7 +341,7 @@ _08000DB2:\n\ mov r5, r12\n\ ldrb r0, [r5]\n\ lsls r0, 4\n\ - ldr r3, =gUnknown_0300001C\n\ + ldr r3, =gDma3Requests + 0x0C\n\ adds r0, r3\n\ ldr r0, [r0]\n\ strh r0, [r1]\n\ @@ -347,7 +357,7 @@ _08000DB2:\n\ bhi _08000DB2\n\ ldrb r0, [r5]\n\ lsls r0, 4\n\ - ldr r5, =gUnknown_0300001C\n\ + ldr r5, =gDma3Requests + 0x0C\n\ adds r0, r5\n\ ldr r0, [r0]\n\ strh r0, [r1]\n\ diff --git a/src/easy_chat.c b/src/easy_chat.c index dd490ddf8..24f1a2b57 100644 --- a/src/easy_chat.c +++ b/src/easy_chat.c @@ -3,7 +3,7 @@ #include "global.h" #include "songs.h" #include "sound.h" -#include "rom4.h" +#include "overworld.h" #include "task.h" #include "main.h" #include "window.h" diff --git a/src/egg_hatch.c b/src/egg_hatch.c index 6d14e92f0..589e8901d 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -59,13 +59,13 @@ extern u8* GetMonNick(struct Pokemon* mon, u8* dst); extern u8* GetBoxMonNick(struct BoxPokemon* boxMon, u8* dst); extern u8 sav1_map_get_name(void); extern s8 sub_8198C58(void); -extern void sub_81DB5E8(u8* str1, u8* str2, u8); +extern void TVShowConvertInternationalString(u8* str1, u8* str2, u8); extern void sub_806A068(u16, u8); extern void fade_screen(u8, u8); extern void overworld_free_bg_tilemaps(void); extern void sub_80AF168(void); -extern void init_uns_table_pokemon_copy(void); -extern void sub_805F094(void); +extern void AllocateMonSpritesGfx(void); +extern void FreeMonSpritesGfx(void); extern void remove_some_task(void); extern void reset_temp_tile_data_buffers(void); extern void c2_exit_to_overworld_2_switch(void); @@ -404,8 +404,8 @@ static bool8 sub_807158C(struct DaycareData* daycare, u8 daycareId) || StringCompareWithoutExtCtrlCodes(gSaveBlock2Ptr->playerName, daycareMon->OT_name) != 0)) { StringCopy(gStringVar1, nick); - sub_81DB5E8(gStringVar2, daycareMon->OT_name, daycareMon->language_maybe); - sub_81DB5E8(gStringVar3, daycareMon->monName, daycareMon->unknown); + TVShowConvertInternationalString(gStringVar2, daycareMon->OT_name, daycareMon->language_maybe); + TVShowConvertInternationalString(gStringVar3, daycareMon->monName, daycareMon->unknown); return TRUE; } return FALSE; @@ -439,7 +439,7 @@ static u8 EggHatchCreateMonSprite(u8 a0, u8 switchID, u8 pokeID, u16* speciesLoc u16 species = GetMonData(mon, MON_DATA_SPECIES); u32 pid = GetMonData(mon, MON_DATA_PERSONALITY); HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[species], - gBattleSpritesGfx->sprites[(a0 * 2) + 1], + gMonSpritesGfxPtr->sprites[(a0 * 2) + 1], species, pid); LoadCompressedObjectPalette(sub_806E794(mon)); *speciesLoc = species; @@ -462,7 +462,7 @@ static void VBlankCB_EggHatch(void) TransferPlttBuffer(); } -static void EggHatch(void) +void EggHatch(void) { ScriptContext2_Enable(); CreateTask(Task_EggHatch, 10); @@ -488,7 +488,7 @@ static void CB2_EggHatch_0(void) SetGpuReg(REG_OFFSET_DISPCNT, 0); sEggHatchData = Alloc(sizeof(struct EggHatchData)); - init_uns_table_pokemon_copy(); + AllocateMonSpritesGfx(); sEggHatchData->eggPartyID = gSpecialVar_0x8004; sEggHatchData->eggShardVelocityID = 0; @@ -570,7 +570,7 @@ static void CB2_EggHatch_0(void) static void EggHatchSetMonNickname(void) { SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar3); - sub_805F094(); + FreeMonSpritesGfx(); Free(sEggHatchData); SetMainCallback2(c2_exit_to_overworld_2_switch); } @@ -691,7 +691,7 @@ static void CB2_EggHatch_1(void) case 12: if (!gPaletteFade.active) { - sub_805F094(); + FreeMonSpritesGfx(); RemoveWindow(sEggHatchData->windowId); UnsetBgTilemapBuffer(0); UnsetBgTilemapBuffer(1); 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_camera.c b/src/field_camera.c new file mode 100644 index 000000000..17ced6aa5 --- /dev/null +++ b/src/field_camera.c @@ -0,0 +1,28 @@ + +// Includes +#include "global.h" + +// Static type declarations + +struct FieldCameraUnknownStruct +{ + u8 unk0; + u8 unk1; + u8 unk2; + u8 unk3; + bool8 unk4; +}; + +// Static RAM declarations + +IWRAM_DATA struct FieldCameraUnknownStruct gUnknown_03000E20; +IWRAM_DATA s16 gUnknown_03000E28; +IWRAM_DATA s16 gUnknown_03000E2A; +IWRAM_DATA u8 gUnknown_03000E2C; +IWRAM_DATA void (*gUnknown_03000E30)(void); + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/field_effect.c b/src/field_effect.c new file mode 100644 index 000000000..628dc776a --- /dev/null +++ b/src/field_effect.c @@ -0,0 +1,15 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u8 gUnknown_03000F58[32]; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/field_map_obj.c b/src/field_map_obj.c index 26bc513fb..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; } @@ -3413,7 +3413,7 @@ bool8 mss_08062EA4(struct MapObject *mapObject, struct Sprite *sprite) { return FALSE; } - return gUnknown_0850DA64[player_get_x22()](mapObject, sprite, player_get_direction_upper_nybble(), sub_8088E64); + return gUnknown_0850DA64[player_get_x22()](mapObject, sprite, player_get_direction_upper_nybble(), MetatileBehavior_IsPokeGrass); } bool8 sub_80925AC(struct MapObject *, struct Sprite *); @@ -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_screen.c b/src/field_screen.c new file mode 100644 index 000000000..2d33d237f --- /dev/null +++ b/src/field_screen.c @@ -0,0 +1,15 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations +IWRAM_DATA u8 *gUnknown_03000F50; +IWRAM_DATA u32 filler_03000f54; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/field_special_scene.c b/src/field_special_scene.c new file mode 100755 index 000000000..54c1d8144 --- /dev/null +++ b/src/field_special_scene.c @@ -0,0 +1,363 @@ +#include "global.h" +#include "task.h" +#include "sprite.h" +#include "field_map_obj.h" +#include "songs.h" +#include "sound.h" +#include "palette.h" +#include "script.h" +#include "vars.h" +#include "event_data.h" +#include "main.h" + +#define SECONDS(value) ((signed) (60.0 * value + 0.5)) + +extern u8 GetSSTidalLocation(s8 *, s8 *, s16 *, s16 *); // should be in field_specials.h +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 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); +extern void sub_80AF8B8(void); + +// porthole states +enum +{ + INIT_PORTHOLE, + IDLE_CHECK, + EXECUTE_MOVEMENT, + EXIT_PORTHOLE, +}; + +extern void SetCameraPanning(s16 x, s16 y); +extern void SetCameraPanningCallback(void ( *callback)()); +extern void InstallCameraPanAheadCallback(); +extern void pal_fill_black(void); +extern void MapGridSetMetatileIdAt(s32 x, s32 y, u16 metatileId); +extern void DrawWholeMapView(); + +extern s8 gTruckCamera_HorizontalTable[]; + +extern u8 gUnknown_0858E8AB[]; +extern u8 gUnknown_0858E8AD[]; + +void Task_Truck3(u8); + +s16 GetTruckCameraBobbingY(int a1) +{ + if (!(a1 % 120)) + return -1; + else if ((a1 % 10) <= 4) + return 1; + + return 0; +} + +s16 GetTruckBoxMovement(int a1) // for the box movement? +{ + if (!((a1 + 120) % 180)) + return -1; + + return 0; +} + +// smh STILL BROKEN IN EMERALD +void Task_Truck1(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 cameraYpan; + s16 box1 = 0; + s16 box2 = 0; + s16 box3 = 0; + u8 mapNum, mapGroup; + register s16 zero asm("r4"); + + box1 = GetTruckBoxMovement(data[0] + 30) * 4; // top box. + sub_808E82C(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3, box1 + 3); + box2 = GetTruckBoxMovement(data[0]) * 2; // bottom left box. + sub_808E82C(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 0, box2 - 3); + box3 = GetTruckBoxMovement(data[0]) * 4; // bottom right box. + mapNum = gSaveBlock1Ptr->location.mapNum; + mapGroup = gSaveBlock1Ptr->location.mapGroup; + zero = 0; + sub_808E82C(3, mapNum, mapGroup, -3, box3); + + if (++data[0] == SECONDS(500)) // this will never run + data[0] = zero; // reset the timer if it gets stuck. + + cameraYpan = GetTruckCameraBobbingY(data[0]); + SetCameraPanning(0, cameraYpan); +} + +void Task_Truck2(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 cameraYpan; + s16 cameraXpan; + s16 box1; + s16 box2; + s16 box3; + + data[0]++; + data[2]++; + + if (data[0] > 5) + { + data[0] = 0; + data[1]++; + } + if ((u16)data[1] == 19) + { + DestroyTask(taskId); + } + else + { + if (gTruckCamera_HorizontalTable[data[1]] == 2) + gTasks[taskId].func = Task_Truck3; + + cameraXpan = gTruckCamera_HorizontalTable[data[1]]; + cameraYpan = GetTruckCameraBobbingY(data[2]); + SetCameraPanning(cameraXpan, cameraYpan); + box1 = GetTruckBoxMovement(data[2] + 30) * 4; + sub_808E82C(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, box1 + 3); + box2 = GetTruckBoxMovement(data[2]) * 2; + sub_808E82C(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, box2 - 3); + box3 = GetTruckBoxMovement(data[2]) * 4; + sub_808E82C(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, box3); + } +} + +void Task_Truck3(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 cameraXpan; + s16 cameraYpan; + + data[0]++; + + if (data[0] > 5) + { + data[0] = 0; + data[1]++; + } + + if ((u16)data[1] == 19) + { + DestroyTask(taskId); + } + else + { + cameraXpan = gTruckCamera_HorizontalTable[data[1]]; + cameraYpan = 0; + SetCameraPanning(cameraXpan, 0); + sub_808E82C(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, cameraYpan + 3); + sub_808E82C(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, cameraYpan - 3); + sub_808E82C(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, cameraYpan); + } +} + +void Task_HandleTruckSequence(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + switch (data[0]) + { + /* + Each case has a timer which is handled with data[1], incrementing + until it reaches the if function's condition, which sets the next task up. + */ + case 0: + data[1]++; + if (data[1] == SECONDS(1.5)) + { + SetCameraPanningCallback(NULL); + data[1] = 0; // reset the timer. + data[2] = CreateTask(Task_Truck1, 0xA); + data[0] = 1; // run the next case. + PlaySE(SE_TRACK_MOVE); + } + break; + case 1: + data[1]++; + if (data[1] == SECONDS(2.5)) + { + pal_fill_black(); + data[1] = 0; + data[0] = 2; + } + break; + case 2: + data[1]++; + if (!gPaletteFade.active && data[1] > SECONDS(5)) + { + data[1] = 0; + DestroyTask(data[2]); + data[3] = CreateTask(Task_Truck2, 0xA); + data[0] = 3; + PlaySE(SE_TRACK_STOP); + } + break; + case 3: + if (!gTasks[data[3]].isActive) // is Truck2 no longer active (is Truck3 active?) + { + InstallCameraPanAheadCallback(); + data[1] = 0; + data[0] = 4; + } + break; + case 4: + data[1]++; + if (data[1] == 90) + { + PlaySE(SE_TRACK_HAIK); + data[1] = 0; + data[0] = 5; + } + break; + case 5: + data[1]++; + if (data[1] == 120) + { + MapGridSetMetatileIdAt(11, 8, 520); + MapGridSetMetatileIdAt(11, 9, 528); + MapGridSetMetatileIdAt(11, 10, 536); + DrawWholeMapView(); + PlaySE(SE_TRACK_DOOR); + DestroyTask(taskId); + ScriptContext2_Disable(); + } + break; + } +} + +void ExecuteTruckSequence(void) +{ + MapGridSetMetatileIdAt(11, 8, 525); + MapGridSetMetatileIdAt(11, 9, 533); + MapGridSetMetatileIdAt(11, 10, 541); + DrawWholeMapView(); + ScriptContext2_Enable(); + CpuFastFill(0, gPlttBufferFaded, 0x400); + CreateTask(Task_HandleTruckSequence, 0xA); +} + +void EndTruckSequence(u8 taskId) +{ + if (!FuncIsActiveTask(Task_HandleTruckSequence)) + { + sub_808E82C(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3, 3); + sub_808E82C(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 0, -3); + sub_808E82C(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3, 0); + } +} + +bool8 sub_80FB59C(void) +{ + s8 mapGroup, mapNum; + s16 x, y; + + if (GetSSTidalLocation(&mapGroup, &mapNum, &x, &y)) + { + return FALSE; + } + else + { + Overworld_SetWarpDestination(mapGroup, mapNum, -1, x, y); + return TRUE; + } +} + +void Task_HandlePorthole(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + u16 *var = GetVarPointer(VAR_PORTHOLE); + struct WarpData *location = &gSaveBlock1Ptr->location; + + switch (data[0]) + { + case INIT_PORTHOLE: // finish fading before making porthole finish. + if (!gPaletteFade.active) + { + data[1] = 0; + data[0] = EXECUTE_MOVEMENT; // execute movement before checking if should be exited. strange? + } + break; + case IDLE_CHECK: // idle and move. + if (gMain.newKeys & A_BUTTON) + data[1] = 1; + if (!ScriptMovement_IsObjectMovementFinished(0xFF, location->mapNum, location->mapGroup)) + return; + if (CountSSTidalStep(1) == TRUE) + { + if (*var == 2) + *var = 9; + else + *var = 10; + data[0] = 3; + return; + } + data[0] = 2; + case EXECUTE_MOVEMENT: // execute movement. + if (data[1]) + { + data[0] = EXIT_PORTHOLE; // exit porthole. + return; + } + // run this once. + if (*var == 2) // which direction? + { + ScriptMovement_StartObjectMovementScript(0xFF, location->mapNum, location->mapGroup, gUnknown_0858E8AB); + data[0] = IDLE_CHECK; // run case 1. + } + else + { + ScriptMovement_StartObjectMovementScript(0xFF, location->mapNum, location->mapGroup, gUnknown_0858E8AD); + data[0] = IDLE_CHECK; // run case 1. + } + break; + case EXIT_PORTHOLE: // exit porthole. + FlagClear(0x4001); + FlagClear(0x4000); + copy_saved_warp2_bank_and_enter_x_to_warp1(0); + sp13E_warp_to_last_warp(); + DestroyTask(taskId); + break; + } +} + +void sub_80FB6EC(void) +{ + u8 spriteId = AddPseudoFieldObject(0x8C, SpriteCallbackDummy, 112, 80, 0); + + gSprites[spriteId].coordOffsetEnabled = FALSE; + + if (VarGet(0x40B4) == 2) + { + StartSpriteAnim(&gSprites[spriteId], FieldObjectDirectionToImageAnimId(4)); + } + else + { + StartSpriteAnim(&gSprites[spriteId], FieldObjectDirectionToImageAnimId(3)); + } +} + +void sub_80FB768(void) +{ + sub_80FB6EC(); + gMapObjects[gPlayerAvatar.mapObjectId].mapobj_bit_13 = TRUE; + pal_fill_black(); + CreateTask(Task_HandlePorthole, 80); + ScriptContext2_Enable(); +} + +void sub_80FB7A4(void) +{ + FlagSet(SYS_CRUISE_MODE); + FlagSet(0x4001); + FlagSet(0x4000); + saved_warp2_set(0, gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, -1); + sub_80FB59C(); + sub_80AF8B8(); +} diff --git a/src/fldeff_cut.c b/src/fldeff_cut.c new file mode 100644 index 000000000..9929dd6f9 --- /dev/null +++ b/src/fldeff_cut.c @@ -0,0 +1,19 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u8 gUnknown_03001100; +IWRAM_DATA u8 gUnknown_03001101; +IWRAM_DATA u8 gUnknown_03001102; +IWRAM_DATA u32 fldeff_cut_unused_03001104; +IWRAM_DATA u8 gUnknown_03001108[25]; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/international_string_util.c b/src/international_string_util.c new file mode 100644 index 000000000..81985d614 --- /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 struct MenuAction *str, s32 arg1) +{ + s32 i, var; + + for (var = 0, i = 0; i < arg1; i++) + { + s32 stringWidth = GetStringWidth(1, str[i].text, 0); + if (stringWidth > var) + var = stringWidth; + } + + return convert_pixel_width_to_tile_width(var); +} + +s32 sub_81DB3D8(const struct MenuAction *str, u8* arg1, s32 arg2) +{ + s32 i, var; + + for (var = 0, i = 0; i < arg2; i++) + { + s32 stringWidth = GetStringWidth(1, str[arg1[i]].text, 0); + if (stringWidth > var) + var = stringWidth; + } + + return convert_pixel_width_to_tile_width(var); +} diff --git a/src/librfu_intr.c b/src/librfu_intr.c new file mode 100644 index 000000000..bdf8b072a --- /dev/null +++ b/src/librfu_intr.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "main.h" + +//TODO: decompile asm/librfu_intr.s to here diff --git a/src/librfu_rfu.c b/src/librfu_rfu.c new file mode 100644 index 000000000..cf3fe12ad --- /dev/null +++ b/src/librfu_rfu.c @@ -0,0 +1,109 @@ +#include "global.h" +#include "main.h" + +#include "librfu.h" + +struct RfuUnk1 +{ + u8 unk_0[0x14]; + u32 unk_14; + u32 unk_18; + struct RfuIntrStruct unk_1c; +}; + +struct RfuUnk2 +{ + u8 unk_0[0x68]; + u32 unk_68; + u32 unk_6c; + u8 unk_70[0x70]; +}; + +struct RfuUnk3 +{ + u32 unk_0; + u32 unk_4; + u8 unk_8[0xD4]; + u32 unk_dc; +}; + +extern u32 *gUnknown_03007890; +extern u32 *gUnknown_03007894; +extern struct RfuUnk3* gUnknown_03007898; +extern struct RfuUnk2* gUnknown_03007880[4]; +extern struct RfuUnk1* gUnknown_03007870[4]; +extern void* sub_82E53F4; +extern void rfu_STC_clearAPIVariables(void); + +// Nonmatching, only register differences +/*u16 rfu_initializeAPI(u32 *unk0, u16 unk1, IntrFunc *interrupt, bool8 copyInterruptToRam) +{ + u16 i; + u16 *v13; + u16 *v12; + u16 num; + + if (((u32)unk0 & 0xF000000) == 0x2000000 && copyInterruptToRam) + { + return 2; + } + + if ((u32)unk0 & 3) + return 2; + + // Nintendo pls, just use a ternary for once + if (copyInterruptToRam) + { + // An assert/debug print may have existed before, ie + // printf("%s %u < %u", "somefile.c:12345", unk1, num) + // to push this into r3? + num = 0xe64; + if (unk1 < num) + return 1; + } + + if (copyInterruptToRam == FALSE) + { + num = 0x504; // same as above, this should be r3 not r0 + if (unk1 < num) + return 1; + } + gUnknown_03007890 = unk0; + gUnknown_03007894 = unk0 + (0xB4 / sizeof(u32)); + gUnknown_03007898 = (struct RfuUnk3*)(unk0 + (0xDC / sizeof(u32))); + gUnknown_03007880[0] = (struct RfuUnk2*)(unk0 + (0x1BC / sizeof(u32))); + gUnknown_03007870[0] = (struct RfuUnk1*)(unk0 + (0x37C / sizeof(u32))); + + for (i = 1; i < 4; i++, num) + { + gUnknown_03007880[i] = (struct RfuUnk2*)&gUnknown_03007880[i-1]->unk_70; + gUnknown_03007870[i] = (struct RfuUnk1*)&gUnknown_03007870[i-1]->unk_1c; + } + + gUnknown_03007898->unk_dc = (u32)&gUnknown_03007870[3]->unk_1c; + STWI_init_all(&gUnknown_03007870[3]->unk_1c, interrupt, copyInterruptToRam); + rfu_STC_clearAPIVariables(); + + for (i = 0; i < 4; i++) + { + gUnknown_03007880[i]->unk_68 = 0; + gUnknown_03007880[i]->unk_6c = 0; + gUnknown_03007870[i]->unk_14 = 0; + gUnknown_03007870[i]->unk_18 = 0; + } + + // Not matching, register differences + v12 = (u16*)((u32)&sub_82E53F4 & ~1); + v13 = (u16*)gUnknown_03007898->unk_8; + + for (i = 47; i != 0xFFFF; i--) + { + *v13 = *v12; + ++v12; + ++v13; + } + + gUnknown_03007898->unk_4 = (u32)(&gUnknown_03007898->unk_8[1]); + + return 0; +}*/ diff --git a/src/librfu_stwi.c b/src/librfu_stwi.c new file mode 100644 index 000000000..21d38bb38 --- /dev/null +++ b/src/librfu_stwi.c @@ -0,0 +1,687 @@ +#include "global.h" +#include "librfu.h" + +extern IntrFunc IntrSIO32(void); + +extern void STWI_stop_timer(void); + +void STWI_init_Callback_M(void); +void STWI_init_Callback_S(void); +void STWI_set_Callback_M(void * callback); +void STWI_set_Callback_S(void * callback); +u16 STWI_init(u8 request); +int STWI_start_Command(void); +void STWI_intr_timer(void); +void STWI_set_timer(u8 unk); + +int STWI_restart_Command(void); +int STWI_reset_ClockCounter(void); + +void STWI_init_all(struct RfuIntrStruct *interruptStruct, IntrFunc *interrupt, bool8 copyInterruptToRam) +{ + // If we're copying our interrupt into RAM, DMA it to block1 and use + // block2 for our RfuStruct, otherwise block1 holds the RfuStruct. + // interrupt usually is a pointer to gIntrTable[1] + if (copyInterruptToRam == TRUE) + { + *interrupt = (IntrFunc)interruptStruct->block1; + DmaCopy16(3, &IntrSIO32, interruptStruct->block1, 0x960); + gRfuState = (struct RfuStruct*)interruptStruct->block2; + } + else + { + *interrupt = (IntrFunc)IntrSIO32; + gRfuState = (struct RfuStruct*)interruptStruct->block1; + } + + gRfuState->rxPacket = (union RfuPacket*)interruptStruct->rxPacketAlloc; + gRfuState->txPacket = (union RfuPacket*)interruptStruct->txPacketAlloc; + gRfuState->msMode = 1; + gRfuState->unk_0 = 0; + gRfuState->txParams = 0; + gRfuState->unk_5 = 0; + gRfuState->unk_7 = 0; + gRfuState->unk_8 = 0; + gRfuState->unk_9 = 0; + gRfuState->timerState = 0; + gRfuState->timerActive = 0; + gRfuState->unk_12 = 0; + gRfuState->unk_15 = 0; + gRfuState->unk_2c = 0; + + REG_RCNT = 0x100; //TODO: mystery bit? + REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE | SIO_115200_BPS; + STWI_init_Callback_M(); + STWI_init_Callback_S(); + + IntrEnable(INTR_FLAG_SERIAL); +} + +void STWI_init_timer(IntrFunc *interrupt, int timerSelect) +{ + *interrupt = STWI_intr_timer; + gRfuState->timerSelect = timerSelect; + + IntrEnable(INTR_FLAG_TIMER0 << gRfuState->timerSelect); +} + +void AgbRFU_SoftReset(void) +{ + vu16 *timerL; + vu16 *timerH; + + REG_RCNT = 0x8000; + REG_RCNT = 0x80A0; // all these bits are undocumented + timerL = ®_TMCNT_L(gRfuState->timerSelect); + timerH = ®_TMCNT_H(gRfuState->timerSelect); + *timerH = 0; + *timerL = 0; + *timerH = 0x83; + while (*timerL <= 0x11) + REG_RCNT = 0x80A2; + *timerH = 3; + REG_RCNT = 0x80A0; + REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE | SIO_115200_BPS; + + gRfuState->unk_0 = 0; + gRfuState->txParams = 0; + gRfuState->unk_5 = 0; + gRfuState->activeCommand = 0; + gRfuState->unk_7 = 0; + gRfuState->unk_8 = 0; + gRfuState->unk_9 = 0; + gRfuState->timerState = 0; + gRfuState->timerActive = 0; + gRfuState->unk_12 = 0; + gRfuState->msMode = 1; + gRfuState->unk_15 = 0; + gRfuState->unk_2c = 0; +} + +void STWI_set_MS_mode(u8 mode) +{ + gRfuState->msMode = mode; +} + +u16 STWI_read_status(u8 index) +{ + switch (index) + { + case 0: + return gRfuState->unk_12; + case 1: + return gRfuState->msMode; + case 2: + return gRfuState->unk_0; + case 3: + return gRfuState->activeCommand; + default: + return 0xFFFF; + } +} + +void STWI_init_Callback_M(void) +{ + STWI_set_Callback_M(0); +} + +void STWI_init_Callback_S(void) +{ + STWI_set_Callback_S(0); +} + +void STWI_set_Callback_M(void *callback) +{ + gRfuState->callbackM = callback; +} + +void STWI_set_Callback_S(void *callback) +{ + gRfuState->callbackS = callback; +} + +void STWI_set_Callback_ID(u32 id) +{ + gRfuState->callbackID = id; +} + +u16 STWI_poll_CommandEnd(void) +{ + while (gRfuState->unk_2c == TRUE) + ; + return gRfuState->unk_12; +} + +void STWI_send_ResetREQ(void) +{ + if (!STWI_init(RFU_RESET)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_LinkStatusREQ(void) +{ + if (!STWI_init(RFU_LINK_STATUS)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_VersionStatusREQ(void) +{ + if (!STWI_init(RFU_VERSION_STATUS)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SystemStatusREQ(void) +{ + if (!STWI_init(RFU_SYSTEM_STATUS)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SlotStatusREQ(void) +{ + if (!STWI_init(RFU_SLOT_STATUS)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_ConfigStatusREQ(void) +{ + if (!STWI_init(RFU_CONFIG_STATUS)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_GameConfigREQ(u8 * unk1, u8 *data) +{ + u8 *packetBytes; + int i; + + if (!STWI_init(RFU_GAME_CONFIG)) + { + gRfuState->txParams = 6; + + //TODO: what is unk1 + packetBytes = gRfuState->txPacket->rfuPacket8.data; + packetBytes += sizeof(u32); + *(u16*)packetBytes = *(u16*)unk1; + + packetBytes += sizeof(u16); + unk1 += sizeof(u16); + + for (i = 0; i < 14; i++) + { + *packetBytes = *unk1; + packetBytes++; + unk1++; + } + + for (i = 0; i < 8; i++) + { + *packetBytes = *data; + packetBytes++; + data++; + } + + STWI_start_Command(); + } +} + +void STWI_send_SystemConfigREQ(u16 unk1, u8 unk2, u8 unk3) +{ + if (!STWI_init(RFU_SYSTEM_CONFIG)) + { + u8 *packetBytes; + + gRfuState->txParams = 1; + + packetBytes = gRfuState->txPacket->rfuPacket8.data; + packetBytes += sizeof(u32); + + *packetBytes++ = unk3; + *packetBytes++ = unk2; + *(u16*)packetBytes = unk1; + STWI_start_Command(); + } +} + +void STWI_send_SC_StartREQ(void) +{ + if (!STWI_init(RFU_SC_START)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SC_PollingREQ(void) +{ + if (!STWI_init(RFU_SC_POLLING)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SC_EndREQ(void) +{ + if (!STWI_init(RFU_SC_END)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SP_StartREQ(void) +{ + if (!STWI_init(RFU_SP_START)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SP_PollingREQ(void) +{ + if (!STWI_init(RFU_SP_POLLING)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_SP_EndREQ(void) +{ + if (!STWI_init(RFU_SP_END)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_CP_StartREQ(u16 unk1) +{ + if (!STWI_init(RFU_CP_START)) + { + gRfuState->txParams = 1; + gRfuState->txPacket->rfuPacket32.data[0] = unk1; + STWI_start_Command(); + } +} + +void STWI_send_CP_PollingREQ(void) +{ + if (!STWI_init(RFU_CP_POLLING)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_CP_EndREQ(void) +{ + if (!STWI_init(RFU_CP_END)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_DataTxREQ(void *in, u8 size) +{ + if (!STWI_init(RFU_DATA_TX)) + { + u8 txParams = (size / sizeof(u32)); + if (size & (sizeof(u32) - 1)) + txParams += 1; + + gRfuState->txParams = txParams; + CpuCopy32(in, gRfuState->txPacket->rfuPacket32.data, gRfuState->txParams * sizeof(u32)); + STWI_start_Command(); + } +} + +void STWI_send_DataTxAndChangeREQ(void *in, u8 size) +{ + if (!STWI_init(RFU_DATA_TX_AND_CHANGE)) + { + u8 txParams = (size / sizeof(u32)); + if (size & (sizeof(u32) - 1)) + txParams += 1; + + gRfuState->txParams = txParams; + CpuCopy32(in, gRfuState->txPacket->rfuPacket32.data, gRfuState->txParams * sizeof(u32)); + STWI_start_Command(); + } +} + +void STWI_send_DataRxREQ(void) +{ + if (!STWI_init(RFU_DATA_RX)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_MS_ChangeREQ(void) +{ + if (!STWI_init(RFU_MS_CHANGE)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_DataReadyAndChangeREQ(u8 unk) +{ + if (!STWI_init(RFU_DATA_READY_AND_CHANGE)) + { + if (!unk) + { + gRfuState->txParams = 0; + } + else + { + u8 *packetBytes; + + gRfuState->txParams = 1; + + packetBytes = gRfuState->txPacket->rfuPacket8.data; + packetBytes += sizeof(u32); + + *packetBytes++ = unk; + *packetBytes++ = 0; + *packetBytes++ = 0; + *packetBytes = 0; + } + + STWI_start_Command(); + } +} + +void STWI_send_DisconnectedAndChangeREQ(u8 unk0, u8 unk1) +{ + if (!STWI_init(RFU_DISCONNECTED_AND_CHANGE)) + { + u8 *packetBytes; + + gRfuState->txParams = 1; + + packetBytes = gRfuState->txPacket->rfuPacket8.data; + packetBytes += sizeof(u32); + + *packetBytes++ = unk0; + *packetBytes++ = unk1; + *packetBytes++ = 0; + *packetBytes = 0; + + STWI_start_Command(); + } +} + +void STWI_send_ResumeRetransmitAndChangeREQ(void) +{ + if (!STWI_init(RFU_RESUME_RETRANSMIT_AND_CHANGE)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_DisconnectREQ(u8 unk) +{ + if (!STWI_init(RFU_DISCONNECT)) + { + gRfuState->txParams = 1; + gRfuState->txPacket->rfuPacket32.data[0] = unk; + + STWI_start_Command(); + } +} + +void STWI_send_TestModeREQ(u8 unk0, u8 unk1) +{ + if (!STWI_init(RFU_TEST_MODE)) + { + gRfuState->txParams = 1; + gRfuState->txPacket->rfuPacket32.data[0] = unk0 | (unk1 << 8); + + STWI_start_Command(); + } +} + +void STWI_send_CPR_StartREQ(u16 unk0, u16 unk1, u8 unk2) +{ + u32 *packetData; + u32 arg1; + + if (!STWI_init(RFU_CPR_START)) + { + gRfuState->txParams = 2; + + arg1 = unk1 | (unk0 << 16); + packetData = gRfuState->txPacket->rfuPacket32.data; + packetData[0] = arg1; + packetData[1] = unk2; + + STWI_start_Command(); + } +} + +void STWI_send_CPR_PollingREQ(void) +{ + if (!STWI_init(RFU_CPR_POLLING)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_CPR_EndREQ(void) +{ + if (!STWI_init(RFU_CPR_END)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_send_StopModeREQ(void) +{ + if (!STWI_init(RFU_STOP_MODE)) + { + gRfuState->txParams = 0; + STWI_start_Command(); + } +} + +void STWI_intr_timer(void) +{ + switch (gRfuState->timerState) + { + //TODO: Make an enum for these + case 2: + gRfuState->timerActive = 1; + STWI_set_timer(50); + break; + case 1: + case 4: + STWI_stop_timer(); + STWI_restart_Command(); + break; + case 3: + gRfuState->timerActive = 1; + STWI_stop_timer(); + STWI_reset_ClockCounter(); + if (gRfuState->callbackM) + gRfuState->callbackM(255, 0); + break; + } +} + +void STWI_set_timer(u8 unk) +{ + vu16 *timerL; + vu16 *timerH; + + timerL = ®_TMCNT_L(gRfuState->timerSelect); + timerH = ®_TMCNT_H(gRfuState->timerSelect); + REG_IME = 0; + switch (unk) + { + case 50: + *timerL = 0xFCCB; + gRfuState->timerState = 1; + break; + case 80: + *timerL = 0xFAE0; + gRfuState->timerState = 2; + break; + case 100: + *timerL = 0xF996; + gRfuState->timerState = 3; + break; + case 130: + *timerL = 0xF7AD; + gRfuState->timerState = 4; + break; + } + *timerH = TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_1024CLK; + REG_IF = INTR_FLAG_TIMER0 << gRfuState->timerSelect; + REG_IME = 1; +} + +void STWI_stop_timer(void) +{ + gRfuState->timerState = 0; + + REG_TMCNT_L(gRfuState->timerSelect) = 0; + REG_TMCNT_H(gRfuState->timerSelect) = 0; +} + +u16 STWI_init(u8 request) +{ + if (!REG_IME) + { + gRfuState->unk_12 = 6; + if (gRfuState->callbackM) + gRfuState->callbackM(request, gRfuState->unk_12); + return TRUE; + } + else if (gRfuState->unk_2c == TRUE) + { + gRfuState->unk_12 = 2; + gRfuState->unk_2c = FALSE; + if (gRfuState->callbackM) + gRfuState->callbackM(request, gRfuState->unk_12); + return TRUE; + } + else if(!gRfuState->msMode) + { + gRfuState->unk_12 = 4; + if (gRfuState->callbackM) + gRfuState->callbackM(request, gRfuState->unk_12, gRfuState); + return TRUE; + } + else + { + gRfuState->unk_2c = TRUE; + gRfuState->activeCommand = request; + gRfuState->unk_0 = 0; + gRfuState->txParams = 0; + gRfuState->unk_5 = 0; + gRfuState->unk_7 = 0; + gRfuState->unk_8 = 0; + gRfuState->unk_9 = 0; + gRfuState->timerState = 0; + gRfuState->timerActive = 0; + gRfuState->unk_12 = 0; + gRfuState->unk_15 = 0; + + REG_RCNT = 0x100; + REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE | SIO_115200_BPS; + return FALSE; + } +} + +int STWI_start_Command() +{ + u16 imeTemp; + + // Yes, it matters that it's casted to a u32... + *(u32*)gRfuState->txPacket->rfuPacket8.data = 0x99660000 | (gRfuState->txParams << 8) | gRfuState->activeCommand; + REG_SIODATA32 = gRfuState->txPacket->rfuPacket32.command; + + gRfuState->unk_0 = 0; + gRfuState->unk_5 = 1; + + imeTemp = REG_IME; + REG_IME = 0; + REG_IE |= (INTR_FLAG_TIMER0 << gRfuState->timerSelect); + REG_IE |= INTR_FLAG_SERIAL; + REG_IME = imeTemp; + + REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE | SIO_MULTI_BUSY | SIO_115200_BPS; + + return 0; +} + +int STWI_restart_Command(void) +{ + if (gRfuState->unk_15 <= 1) + { + gRfuState->unk_15++; + STWI_start_Command(); + } + else + { + if (gRfuState->activeCommand == RFU_MS_CHANGE || gRfuState->activeCommand == RFU_DATA_TX_AND_CHANGE || gRfuState->activeCommand == RFU_UNK35 || gRfuState->activeCommand == RFU_RESUME_RETRANSMIT_AND_CHANGE) + { + gRfuState->unk_12 = 1; + gRfuState->unk_2c = 0; + + if (gRfuState->callbackM) + gRfuState->callbackM(gRfuState->activeCommand, gRfuState->unk_12); + } + else + { + gRfuState->unk_12 = 1; + gRfuState->unk_2c = 0; + + if (gRfuState->callbackM) + gRfuState->callbackM(gRfuState->activeCommand, gRfuState->unk_12); + + gRfuState->unk_0 = 4; //TODO: what's 4 + } + } + + return 0; +} + +int STWI_reset_ClockCounter() +{ + gRfuState->unk_0 = 5; //TODO: what is 5 + gRfuState->txParams = 0; + gRfuState->unk_5 = 0; + REG_SIODATA32 = (1 << 31); + REG_SIOCNT = 0; + REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE | SIO_115200_BPS; + REG_SIOCNT = (SIO_INTR_ENABLE | SIO_32BIT_MODE | SIO_115200_BPS) + 0x7F; + + return 0; +} 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/link.c b/src/link.c new file mode 100644 index 000000000..ae2cd1992 --- /dev/null +++ b/src/link.c @@ -0,0 +1,56 @@ + +// Includes +#include "global.h" + +// Static type declarations + +struct BlockTransfer +{ + u16 pos; + u16 size; + void *src; + bool8 active; + u8 multiplayerId; +}; + +struct LinkTestBGInfo +{ + u32 screenBaseBlock; + u32 paletteNum; + u32 dummy_8; + u32 dummy_C; +}; + +// Static RAM declarations + +IWRAM_DATA struct BlockTransfer gUnknown_03000D10; +IWRAM_DATA u32 link_c_unused_03000d1c; +IWRAM_DATA struct BlockTransfer gUnknown_03000D20[4]; +IWRAM_DATA u32 gUnknown_03000D50; +IWRAM_DATA u32 gUnknown_03000D54; +IWRAM_DATA u8 gUnknown_03000D58; +IWRAM_DATA u32 gUnknown_03000D5C; +IWRAM_DATA u32 gUnknown_03000D60; +IWRAM_DATA u8 gUnknown_03000D64[4]; // not really, but won't match otherwise +IWRAM_DATA u8 gUnknown_03000D68[4]; +IWRAM_DATA u8 gUnknown_03000D6C; +IWRAM_DATA bool8 gUnknown_03000D6D; +IWRAM_DATA u16 gUnknown_03000D6E; +IWRAM_DATA u16 gUnknown_03000D70; +IWRAM_DATA u8 gUnknown_03000D72; +IWRAM_DATA u8 gUnknown_03000D73; +IWRAM_DATA u8 gUnknown_03000D74[4]; // not really, but won't match otherwise +IWRAM_DATA u8 gUnknown_03000D78[8]; // not really, but won't match otherwise +IWRAM_DATA u8 gUnknown_03000D80[16]; +IWRAM_DATA u16 gUnknown_03000D90[8]; +IWRAM_DATA u32 gUnknown_03000DA0; +IWRAM_DATA u32 gUnknown_03000DA4; +IWRAM_DATA void *gUnknown_03000DA8; +IWRAM_DATA void *gUnknown_03000DAC; +IWRAM_DATA bool32 gUnknown_03000DB0; + +// Static ROM declarations + +// .rodata + +// .text 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/main.c b/src/main.c index 5707e18af..665a4dd84 100644 --- a/src/main.c +++ b/src/main.c @@ -77,7 +77,7 @@ const IntrFunc gIntrTableTemplate[] = #define INTR_COUNT ((int)(sizeof(gIntrTableTemplate)/sizeof(IntrFunc))) -extern u16 gUnknown_03000000; +static u16 gUnknown_03000000; extern u16 gKeyRepeatStartDelay; extern u8 gUnknown_030022B4; diff --git a/src/main_menu.c b/src/main_menu.c new file mode 100644 index 000000000..8608159c2 --- /dev/null +++ b/src/main_menu.c @@ -0,0 +1,15 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u8 gUnknown_03000DD0; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/malloc.c b/src/malloc.c index ccb2f7d20..1d64351c3 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -2,6 +2,7 @@ static void *sHeapStart; static u32 sHeapSize; +static u32 malloc_c_unused_0300000c; // needed to align dma3_manager.o(.bss) #define MALLOC_SYSTEM_ID 0xA3A3 diff --git a/src/metatile_behavior.c b/src/metatile_behavior.c new file mode 100644 index 000000000..b9760f522 --- /dev/null +++ b/src/metatile_behavior.c @@ -0,0 +1,1436 @@ +#include "global.h" +#include "metatile_behavior.h" +#include "metatile_behaviors.h" + +#define TILE_FLAG_ENCOUNTER_TILE 1 +#define TILE_FLAG_SURFABLE 2 + +#define TILE_ATTRIBUTES(three, two, one) (((one) ? 1 : 0) | ((two) ? 2 : 0) | ((three) ? 4 : 0)) + +// wonder what the third flag is supposed to do +static const u8 sTileBitAttributes[] = +{ + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_NORMAL 0x00 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x01 + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_TALL_GRASS 0x02 + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_LONG_GRASS 0x03 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_04 0x04 + TILE_ATTRIBUTES(FALSE, FALSE, TRUE), // MB_05 0x05 + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_DEEP_SAND 0x06 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SHORT_GRASS 0x07 + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_CAVE 0x08 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_LONG_GRASS_SOUTH_EDGE 0x09 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_NO_RUNNING 0x0A + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_0B 0x0B + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_MOUNTAIN_TOP 0x0C + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_BATTLE_PYRAMID_WARP 0x0D + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_MOSSDEEP_GYM_WARP 0x0E + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_MT_PYRE_HOLE 0x0F + TILE_ATTRIBUTES(TRUE, TRUE, TRUE), // MB_POND_WATER 0x10 + TILE_ATTRIBUTES(TRUE, TRUE, TRUE), // MB_SEMI_DEEP_WATER 0x11 + TILE_ATTRIBUTES(TRUE, TRUE, TRUE), // MB_DEEP_WATER 0x12 + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_WATERFALL 0x13 + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_SOOTOPOLIS_DEEP_WATER 0x14 + TILE_ATTRIBUTES(TRUE, TRUE, TRUE), // MB_OCEAN_WATER 0x15 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_PUDDLE 0x16 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SHALLOW_WATER 0x17 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_18 0x18 + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_NO_SURFACING 0x19 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_1A 0x1A + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_STAIRS_OUTSIDE_ABANDONED_SHIP 0x1B + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SHOAL_CAVE_ENTRANCE 0x1C + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x1D + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x1E + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x1F + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ICE 0x20 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SAND 0x21 + TILE_ATTRIBUTES(TRUE, TRUE, TRUE), // MB_SEAWEED 0x22 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // ? 0x23 + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_ASHGRASS 0x24 + TILE_ATTRIBUTES(TRUE, FALSE, TRUE), // MB_25 0x25 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_THIN_ICE 0x26 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_CRACKED_ICE 0x27 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_HOT_SPRINGS 0x28 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_LAVARIDGE_GYM_B1F_WARP 0x29 + TILE_ATTRIBUTES(TRUE, TRUE, TRUE), // MB_SEAWEED_NO_SURFACING 0x2A + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_REFLECTION_UNDER_BRIDGE 0x2B + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x2C + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x2D + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x2E + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x2F + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_EAST 0x30 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_WEST 0x31 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_NORTH 0x32 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_SOUTH 0x33 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_NORTHEAST 0x34 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_NORTHWEST 0x35 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_SOUTHEAST 0x36 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_IMPASSABLE_SOUTHWEST 0x37 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_JUMP_EAST 0x38 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_JUMP_WEST 0x39 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_JUMP_NORTH 0x3A + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_JUMP_SOUTH 0x3B + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // ? 0x3C + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // ? 0x3D + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_JUMP_SOUTHEAST 0x3E + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_JUMP_SOUTHWEST 0x3F + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_WALK_EAST 0x40 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_WALK_WEST 0x41 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_WALK_NORTH 0x42 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_WALK_SOUTH 0x43 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SLIDE_EAST 0x44 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SLIDE_WEST 0x45 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SLIDE_NORTH 0x46 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SLIDE_SOUTH 0x47 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_TRICK_HOUSE_PUZZLE_8_FLOOR 0x48 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // ? 0x49 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // ? 0x4A + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x4B + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x4C + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x4D + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x4E + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x4F + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_EASTWARD_CURRENT 0x50 + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_WESTWARD_CURRENT 0x51 + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_NORTHWARD_CURRENT 0x52 + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_SOUTHWARD_CURRENT 0x53 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x54 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x55 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x56 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x57 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x58 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x59 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x5A + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x5B + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x5C + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x5D + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x5E + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x5F + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_NON_ANIMATED_DOOR 0x60 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_LADDER 0x61 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_EAST_ARROW_WARP 0x62 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_WEST_ARROW_WARP 0x63 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_NORTH_ARROW_WARP 0x64 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SOUTH_ARROW_WARP 0x65 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_CRACKED_FLOOR_HOLE 0x66 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_AQUA_HIDEOUT_WARP 0x67 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_LAVARIDGE_GYM_1F_WARP 0x68 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ANIMATED_DOOR 0x69 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_UP_ESCALATOR 0x6A + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_DOWN_ESCALATOR 0x6B + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_WATER_DOOR 0x6C + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // MB_WATER_SOUTH_ARROW_WARP 0x6D + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_DEEP_SOUTH_WARP 0x6E + TILE_ATTRIBUTES(TRUE, TRUE, FALSE), // ? 0x6F + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_WARP_OR_BRIDGE 0x70 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_71 0x71 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE120_NORTH_BRIDGE_1 0x72 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE120_NORTH_BRIDGE_2 0x73 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_PACIFIDLOG_VERTICAL_LOG_1 0x74 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_PACIFIDLOG_VERTICAL_LOG_2 0x75 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_PACIFIDLOG_HORIZONTAL_LOG_1 0x76 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_PACIFIDLOG_HORIZONTAL_LOG_2 0x77 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_FORTREE_BRIDGE 0x78 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x79 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE120_SOUTH_BRIDGE_1 0x7A + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE120_SOUTH_BRIDGE_2 0x7B + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE120_NORTH_BRIDGE_3 0x7C + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE120_NORTH_BRIDGE_4 0x7D + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_7E 0x7E + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ROUTE110_BRIDGE 0x7F + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_COUNTER 0x80 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x81 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x82 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_PC 0x83 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CABLE_BOX_RESULTS_1 0x84 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_REGION_MAP 0x85 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_TELEVISION 0x86 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_POKEBLOCK_FEEDER 0x87 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x88 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SLOT_MACHINE 0x89 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_ROULETTE 0x8A + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CLOSED_SOOTOPOLIS_GYM_DOOR 0x8B + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_TRICK_HOUSE_PUZZLE_DOOR 0x8C + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_8D 0x8D + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_RUNNING_SHOES_INSTRUCTION 0x8E + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_QUESTIONNAIRE 0x8F + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_RED_CAVE 0x90 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_RED_CAVE_OPEN 0x91 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_BROWN_CAVE 0x92 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_BROWN_CAVE_OPEN 0x93 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_YELLOW_CAVE 0x94 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_YELLOW_CAVE_OPEN 0x95 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_TREE_LEFT 0x96 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_TREE_LEFT_OPEN 0x97 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_SHRUB 0x98 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_SHRUB_OPEN 0x99 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_BLUE_CAVE 0x9A + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_BLUE_CAVE_OPEN 0x9B + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_TREE_RIGHT 0x9C + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_SPOT_TREE_RIGHT_OPEN 0x9D + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x9E + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0x9F + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_BERRY_TREE_SOIL 0xA0 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA1 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA2 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA3 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA4 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA5 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA6 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA7 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA8 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xA9 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xAA + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xAB + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xAC + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xAD + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xAE + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xAF A + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_PC 0xB0 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_REGISTER_PC 0xB1 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_B2 0xB2 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_B3 0xB3 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_B4 0xB4 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_B5 0xB5 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_B6 0xB6 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_B7 0xB7 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SECRET_BASE_BALLOON 0xB8 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_B9 0xB9 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SECRET_BASE_GLITTER_MAT 0xBA + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SECRET_BASE_JUMP_MAT 0xBB + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SECRET_BASE_SPIN_MAT 0xBC + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SECRET_BASE_SOUND_MAT 0xBD + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_BE 0xBE + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_BF 0xBF + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_BED 0xC0 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_C1 0xC1 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_C2 0xC2 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_C3 0xC3 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_SECRET_BASE_TV_SHIELD 0xC4 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_C5 0xC5 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_C6 0xC6 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SECRET_BASE_POSTER 0xC7 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_C8 0xC8 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_C9 0xC9 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CA 0xCA + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CB 0xCB + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CC 0xCC + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CD 0xCD + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CE 0xCE + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CF 0xCF + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_MUDDY_SLOPE 0xD0 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_BUMPY_SLOPE 0xD1 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_CRACKED_FLOOR 0xD2 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ISOLATED_VERTICAL_RAIL 0xD3 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_ISOLATED_HORIZONTAL_RAIL 0xD4 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_VERTICAL_RAIL 0xD5 + TILE_ATTRIBUTES(TRUE, FALSE, FALSE), // MB_HORIZONTAL_RAIL 0xD6 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xD7 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xD8 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xD9 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xDA + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xDB + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xDC + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xDD + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xDE + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xDF + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_PICTURE_BOOK_SHELF 0xE0 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_BOOKSHELF 0xE1 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_POKEMON_CENTER_BOOKSHELF 0xE2 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_VASE 0xE3 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_TRASH_CAN 0xE4 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_SHOP_SHELF 0xE5 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_BLUEPRINT 0xE6 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_CABLE_BOX_RESULTS_2 0xE7 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_WIRELESS_BOX_RESULTS 0xE8 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_TRAINER_HILL_TIMER 0xE9 + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // MB_UNKNOWN_CLOSED_DOOR 0xEA + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xEB + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xEC + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xED + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xEE + TILE_ATTRIBUTES(FALSE, FALSE, FALSE), // ? 0xEF +}; + +// only used as default case for checking jump landing in field_ground_effect. +bool8 ShouldDoJumpLandingDustEffect(u8 var) +{ + return TRUE; +} + +bool8 MetatileBehavior_IsEncounterTile(u8 var) +{ + if ((sTileBitAttributes[var] & TILE_FLAG_ENCOUNTER_TILE) != 0) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsJumpEast(u8 var) +{ + if (var == MB_JUMP_EAST) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsJumpWest(u8 var) +{ + if (var == MB_JUMP_WEST) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsJumpNorth(u8 var) +{ + if (var == MB_JUMP_NORTH) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsJumpSouth(u8 var) +{ + if (var == MB_JUMP_SOUTH) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPokeGrass(u8 var) +{ + if (var == MB_TALL_GRASS || var == MB_LONG_GRASS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSandOrDeepSand(u8 var) +{ + if (var == MB_SAND || var == MB_DEEP_SAND) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsDeepSand(u8 var) +{ + if (var == MB_DEEP_SAND) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsReflective(u8 var) +{ + if (var == MB_POND_WATER || var == MB_PUDDLE || var == MB_1A || var == MB_ICE || var == MB_SOOTOPOLIS_DEEP_WATER || var == MB_REFLECTION_UNDER_BRIDGE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsIce(u8 var) +{ + if (var == MB_ICE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWarpDoor(u8 var) +{ + if (var == MB_ANIMATED_DOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsDoor(u8 var) +{ + if (var == MB_8D || var == MB_ANIMATED_DOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsEscalator(u8 var) +{ + if (var == MB_UP_ESCALATOR || var == MB_DOWN_ESCALATOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_04(u8 var) // unused +{ + if (var == MB_04) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsLadder(u8 var) +{ + if (var == MB_LADDER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsNonAnimDoor(u8 var) +{ + if (var == MB_NON_ANIMATED_DOOR || var == MB_WATER_DOOR || var == MB_DEEP_SOUTH_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsDeepSouthWarp(u8 var) +{ + if (var == MB_DEEP_SOUTH_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSurfableWaterOrUnderwater(u8 var) +{ + if ((sTileBitAttributes[var] & TILE_FLAG_SURFABLE) != 0) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsEastArrowWarp(u8 var) +{ + if (var == MB_EAST_ARROW_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWestArrowWarp(u8 var) +{ + if (var == MB_WEST_ARROW_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsNorthArrowWarp(u8 var) +{ + if (var == MB_NORTH_ARROW_WARP || var == MB_STAIRS_OUTSIDE_ABANDONED_SHIP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSouthArrowWarp(u8 var) +{ + if (var == MB_SOUTH_ARROW_WARP || var == MB_WATER_SOUTH_ARROW_WARP || var == MB_SHOAL_CAVE_ENTRANCE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsArrowWarp(u8 var) // unused +{ + u8 ret = FALSE; + + if (MetatileBehavior_IsEastArrowWarp(var) + || MetatileBehavior_IsWestArrowWarp(var) + || MetatileBehavior_IsNorthArrowWarp(var) + || MetatileBehavior_IsSouthArrowWarp(var)) + { + ret = TRUE; + } + + return ret; +} + +bool8 MetatileBehavior_IsMoveTile(u8 var) +{ + if ((var >= MB_WALK_EAST && var <= MB_TRICK_HOUSE_PUZZLE_8_FLOOR) || (var >= MB_EASTWARD_CURRENT && var <= MB_SOUTHWARD_CURRENT) + || var == MB_MUDDY_SLOPE || var == MB_CRACKED_FLOOR || var == MB_WATERFALL || var == MB_ICE || var == MB_SECRET_BASE_JUMP_MAT || var == MB_SECRET_BASE_SPIN_MAT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsIce_2(u8 var) +{ + if (var == MB_ICE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsTrickHouseSlipperyFloor(u8 var) +{ + if (var == MB_TRICK_HOUSE_PUZZLE_8_FLOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_05(u8 var) +{ + if (var == MB_05) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWalkNorth(u8 var) +{ + if (var == MB_WALK_NORTH) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWalkSouth(u8 var) +{ + if (var == MB_WALK_SOUTH) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWalkWest(u8 var) +{ + if (var == MB_WALK_WEST) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWalkEast(u8 var) +{ + if (var == MB_WALK_EAST) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsNorthwardCurrent(u8 var) +{ + if (var == MB_NORTHWARD_CURRENT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSouthwardCurrent(u8 var) +{ + if (var == MB_SOUTHWARD_CURRENT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWestwardCurrent(u8 var) +{ + if (var == MB_WESTWARD_CURRENT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsEastwardCurrent(u8 var) +{ + if (var == MB_EASTWARD_CURRENT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSlideNorth(u8 var) +{ + if (var == MB_SLIDE_NORTH) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSlideSouth(u8 var) +{ + if (var == MB_SLIDE_SOUTH) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSlideWest(u8 var) +{ + if (var == MB_SLIDE_WEST) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSlideEast(u8 var) +{ + if (var == MB_SLIDE_EAST) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCounter(u8 var) +{ + if (var == MB_COUNTER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPlayerFacingTVScreen(u8 tile, u8 playerDir) +{ + if (playerDir != CONNECTION_NORTH) // if the player isn't facing north, forget about it. + return FALSE; + else if (tile == MB_TELEVISION) // is the player's north tile a TV? + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPC(u8 var) +{ + if (var == MB_PC) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCableBoxResults1(u8 var) +{ + if (var == MB_CABLE_BOX_RESULTS_1) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseOpen(u8 var) +{ + if (var == MB_SECRET_BASE_SPOT_RED_CAVE_OPEN || var == MB_SECRET_BASE_SPOT_BROWN_CAVE_OPEN + || var == MB_SECRET_BASE_SPOT_YELLOW_CAVE_OPEN || var == MB_SECRET_BASE_SPOT_TREE_LEFT_OPEN + || var == MB_SECRET_BASE_SPOT_SHRUB_OPEN || var == MB_SECRET_BASE_SPOT_BLUE_CAVE_OPEN + || var == MB_SECRET_BASE_SPOT_TREE_RIGHT_OPEN) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseCave(u8 var) +{ + if (var == MB_SECRET_BASE_SPOT_RED_CAVE || var == MB_SECRET_BASE_SPOT_BROWN_CAVE || var == MB_SECRET_BASE_SPOT_YELLOW_CAVE || var == MB_SECRET_BASE_SPOT_BLUE_CAVE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseTree(u8 var) +{ + if (var == MB_SECRET_BASE_SPOT_TREE_LEFT || var == MB_SECRET_BASE_SPOT_TREE_RIGHT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseShrub(u8 var) +{ + if (var == MB_SECRET_BASE_SPOT_SHRUB) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBasePC(u8 var) +{ + if (var == MB_SECRET_BASE_PC) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseRegisterPC(u8 var) +{ + if (var == MB_SECRET_BASE_REGISTER_PC) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_B2(u8 var) // unused +{ + if (var == MB_B2) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_B3(u8 var) +{ + if (var == MB_B3) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_B9(u8 var) +{ + if (var == MB_B9) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_C6(u8 var) +{ + if (var == MB_C6) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBasePoster(u8 var) +{ + if (var == MB_SECRET_BASE_POSTER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsNormal(u8 var) +{ + if (var == MB_NORMAL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_B7(u8 var) +{ + if (var == MB_B7) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_B2_Duplicate(u8 var) // unused +{ + if (var == MB_B2) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_B5(u8 var) +{ + if (var == MB_B5) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_C3(u8 var) +{ + if (var == MB_C3) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_C2(u8 var) +{ + if (var == MB_C2) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseBalloon(u8 var) +{ + if (var == MB_SECRET_BASE_BALLOON) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_BE(u8 var) +{ + if (var == MB_BE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseSoundMat(u8 var) +{ + if (var == MB_SECRET_BASE_SOUND_MAT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseGlitterMat(u8 var) +{ + if (var == MB_SECRET_BASE_GLITTER_MAT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_BF(u8 var) +{ + if (var == MB_BF) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseTvOrShield(u8 var) +{ + if (var == MB_SECRET_BASE_TV_SHIELD) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_C5(u8 var) +{ + if (var == MB_C5) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_HasRipples(u8 var) +{ + if (var == MB_POND_WATER || var == MB_PUDDLE || var == MB_SOOTOPOLIS_DEEP_WATER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPuddle(u8 var) +{ + if (var == MB_PUDDLE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsTallGrass(u8 var) +{ + if (var == MB_TALL_GRASS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsLongGrass(u8 var) +{ + if (var == MB_LONG_GRASS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsBerryTreeSoil(u8 var) +{ + if (var == MB_BERRY_TREE_SOIL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsAsh(u8 var) +{ + if (var == MB_ASHGRASS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsUnusedFootprintMetatile(u8 var) +{ + if (var == MB_25) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsBridge(u8 var) +{ + if ((var == MB_WARP_OR_BRIDGE || var == MB_71 || var == MB_ROUTE120_NORTH_BRIDGE_1 || var == MB_ROUTE120_NORTH_BRIDGE_2) + || (var == MB_ROUTE120_NORTH_BRIDGE_3 || var == MB_ROUTE120_NORTH_BRIDGE_4 || var == MB_7E || var == MB_ROUTE110_BRIDGE)) + return TRUE; + else + return FALSE; +} + +u8 MetatileBehavior_GetBridgeSth(u8 var) +{ + u8 result = var - MB_WARP_OR_BRIDGE; + if (result < 4) + return result; + + result = var - MB_ROUTE120_SOUTH_BRIDGE_1; + if (result < 2) + return 2; + + result = var - MB_ROUTE120_NORTH_BRIDGE_3; + if (result < 2) + return 3; + + return 0; +} + +u8 MetatileBehavior_8089510(u8 var) +{ + u8 result = var - MB_WARP_OR_BRIDGE; + + if (result < 4) + return 1; + else + return 0; +} + +bool8 MetatileBehavior_IsLandWildEncounter(u8 var) +{ + if (MetatileBehavior_IsSurfableWaterOrUnderwater(var) == FALSE && MetatileBehavior_IsEncounterTile(var) == TRUE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWaterWildEncounter(u8 var) +{ + if (MetatileBehavior_IsSurfableWaterOrUnderwater(var) == TRUE && MetatileBehavior_IsEncounterTile(var) == TRUE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_0B(u8 var) +{ + if (var == MB_0B) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMountain(u8 var) +{ + if (var == MB_MOUNTAIN_TOP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsDiveable(u8 var) +{ + if (var == MB_SEMI_DEEP_WATER || var == MB_DEEP_WATER || var == MB_SOOTOPOLIS_DEEP_WATER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsUnableToEmerge(u8 var) +{ + if (var == MB_NO_SURFACING || var == MB_SEAWEED_NO_SURFACING) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsShallowFlowingWater(u8 var) +{ + if (var == MB_SHALLOW_WATER || var == MB_STAIRS_OUTSIDE_ABANDONED_SHIP || var == MB_SHOAL_CAVE_ENTRANCE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsThinIce(u8 var) +{ + if (var == MB_THIN_ICE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCrackedIce(u8 var) +{ + if (var == MB_CRACKED_ICE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsDeepOrOceanWater(u8 var) +{ + if (var == MB_OCEAN_WATER || var == MB_SEMI_DEEP_WATER || var == MB_DEEP_WATER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMB_18_OrMB_1A(u8 var) // unused +{ + if (var == MB_18 || var == MB_1A) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSurfableAndNotWaterfall(u8 var) +{ + if (MetatileBehavior_IsSurfableWaterOrUnderwater(var) && MetatileBehavior_IsWaterfall(var) == FALSE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsEastBlocked(u8 var) +{ + if (var == MB_IMPASSABLE_EAST || var == MB_IMPASSABLE_NORTHEAST || var == MB_IMPASSABLE_SOUTHEAST || var == MB_C1 || var == MB_BE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWestBlocked(u8 var) +{ + if (var == MB_IMPASSABLE_WEST || var == MB_IMPASSABLE_NORTHWEST || var == MB_IMPASSABLE_SOUTHWEST || var == MB_C1 || var == MB_BE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsNorthBlocked(u8 var) +{ + if (var == MB_IMPASSABLE_NORTH || var == MB_IMPASSABLE_NORTHEAST || var == MB_IMPASSABLE_NORTHWEST || var == MB_BED) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSouthBlocked(u8 var) +{ + if (var == MB_IMPASSABLE_SOUTH || var == MB_IMPASSABLE_SOUTHEAST || var == MB_IMPASSABLE_SOUTHWEST || var == MB_BED) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsShortGrass(u8 var) +{ + if (var == MB_SHORT_GRASS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsHotSprings(u8 var) +{ + if (var == MB_HOT_SPRINGS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWaterfall(u8 var) +{ + if (var == MB_WATERFALL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsFortreeBridge(u8 var) +{ + if (var == MB_FORTREE_BRIDGE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPacifilogVerticalLog1(u8 var) +{ + if (var == MB_PACIFIDLOG_VERTICAL_LOG_1) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPacifilogVerticalLog2(u8 var) +{ + if (var == MB_PACIFIDLOG_VERTICAL_LOG_2) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPacifilogHorizontalLog1(u8 var) +{ + if (var == MB_PACIFIDLOG_HORIZONTAL_LOG_1) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPacifilogHorizontalLog2(u8 var) +{ + if (var == MB_PACIFIDLOG_HORIZONTAL_LOG_2) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPacifidlogLog(u8 var) +{ + if (var == MB_PACIFIDLOG_VERTICAL_LOG_1 || var == MB_PACIFIDLOG_VERTICAL_LOG_2 + || var == MB_PACIFIDLOG_HORIZONTAL_LOG_1 || var == MB_PACIFIDLOG_HORIZONTAL_LOG_2) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsTrickHousePuzzleDoor(u8 var) +{ + if (var == MB_TRICK_HOUSE_PUZZLE_DOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsRegionMap(u8 var) +{ + if (var == MB_REGION_MAP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsClosedSootopolisGymDoor(u8 var) +{ + if (var == MB_CLOSED_SOOTOPOLIS_GYM_DOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsUnknownClosedDoor(u8 var) +{ + if (var == MB_UNKNOWN_CLOSED_DOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsRoulette(u8 var) // unused +{ + if (var == MB_ROULETTE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPokeblockFeeder(u8 var) +{ + if (var == MB_POKEBLOCK_FEEDER) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseJumpMat(u8 var) +{ + if (var == MB_SECRET_BASE_JUMP_MAT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSecretBaseSpinMat(u8 var) +{ + if (var == MB_SECRET_BASE_SPIN_MAT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsLavaridgeB1FWarp(u8 var) +{ + if (var == MB_LAVARIDGE_GYM_B1F_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsLavaridge1FWarp(u8 var) +{ + if (var == MB_LAVARIDGE_GYM_1F_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsAquaHideoutWarp(u8 var) +{ + if (var == MB_AQUA_HIDEOUT_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsWarpOrBridge(u8 var) +{ + if (var == MB_WARP_OR_BRIDGE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMossdeepGymWarp(u8 var) +{ + if (var == MB_MOSSDEEP_GYM_WARP) + return TRUE; + else + return FALSE; +} + + +bool8 MetatileBehavior_IsSurfableFishableWater(u8 var) +{ + if (var == MB_POND_WATER || var == MB_OCEAN_WATER || var == MB_SEMI_DEEP_WATER || var == MB_DEEP_WATER + || var == MB_SOOTOPOLIS_DEEP_WATER || (var == MB_EASTWARD_CURRENT || var == MB_WESTWARD_CURRENT + || var == MB_NORTHWARD_CURRENT || var == MB_SOUTHWARD_CURRENT)) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMtPyreHole(u8 var) +{ + if (var == MB_MT_PYRE_HOLE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCrackedFloorHole(u8 var) +{ + if (var == MB_CRACKED_FLOOR_HOLE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCrackedFloor(u8 var) +{ + if (var == MB_CRACKED_FLOOR) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsMuddySlope(u8 var) +{ + if (var == MB_MUDDY_SLOPE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsBumpySlope(u8 var) +{ + if (var == MB_BUMPY_SLOPE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsIsolatedVerticalRail(u8 var) +{ + if (var == MB_ISOLATED_VERTICAL_RAIL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsIsolatedHorizontalRail(u8 var) +{ + if (var == MB_ISOLATED_HORIZONTAL_RAIL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsVerticalRail(u8 var) +{ + if (var == MB_VERTICAL_RAIL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsHorizontalRail(u8 var) +{ + if (var == MB_HORIZONTAL_RAIL) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSeaweed(u8 var) +{ + if (var == MB_SEAWEED || var == MB_SEAWEED_NO_SURFACING) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsRunningDisallowed(u8 var) +{ + if (var == MB_NO_RUNNING || var == MB_LONG_GRASS || var == MB_HOT_SPRINGS || MetatileBehavior_IsPacifidlogLog(var) != FALSE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCuttableGrass(u8 var) +{ + if (var == MB_TALL_GRASS || var == MB_LONG_GRASS || var == MB_ASHGRASS || var == MB_LONG_GRASS_SOUTH_EDGE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsRunningShoesInstruction(u8 var) +{ + if (var == MB_RUNNING_SHOES_INSTRUCTION) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPictureBookShelf(u8 var) +{ + if (var == MB_PICTURE_BOOK_SHELF) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsBookShelf(u8 var) +{ + if (var == MB_BOOKSHELF) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPokeCenterBookShelf(u8 var) +{ + if (var == MB_POKEMON_CENTER_BOOKSHELF) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsVase(u8 var) +{ + if (var == MB_VASE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsTrashCan(u8 var) +{ + if (var == MB_TRASH_CAN) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsShopShelf(u8 var) +{ + if (var == MB_SHOP_SHELF) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsBlueprint(u8 var) +{ + if (var == MB_BLUEPRINT) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsBattlePyramidWarp(u8 var) +{ + if (var == MB_BATTLE_PYRAMID_WARP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsPlayerFacingWirelessBoxResults(u8 tile, u8 playerDir) +{ + if (playerDir != CONNECTION_NORTH) // if the player isn't facing north, forget about it. + return FALSE; + else if (tile == MB_WIRELESS_BOX_RESULTS) // is the player's north tile the monitor with results? + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsCableBoxResults2(u8 tile, u8 playerDir) +{ + if (playerDir != CONNECTION_NORTH) // if the player isn't facing north, forget about it. + return FALSE; + else if (tile == MB_CABLE_BOX_RESULTS_2) // is the player's north tile the monitor with results? + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsQuestionnaire(u8 var) +{ + if (var == MB_QUESTIONNAIRE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsLongGrass_Duplicate(u8 var) +{ + if (var == MB_LONG_GRASS) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsLongGrassSouthEdge(u8 var) +{ + if (var == MB_LONG_GRASS_SOUTH_EDGE) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsTrainerHillTimer(u8 var) +{ + if (var == MB_TRAINER_HILL_TIMER) + return TRUE; + else + return FALSE; +} diff --git a/src/money.c b/src/money.c index be64d9633..98f25a42a 100644 --- a/src/money.c +++ b/src/money.c @@ -1,8 +1,77 @@ #include "global.h" #include "money.h" +#include "event_data.h" +#include "string_util.h" +#include "text.h" +#include "menu.h" +#include "window.h" +#include "sprite.h" +#include "decompress.h" + +extern const u8 gText_PokedollarVar1[]; + +extern const u8 gMenuMoneyGfx[]; +extern const u8 gMenuMoneyPal[]; #define MAX_MONEY 999999 +EWRAM_DATA static u8 sMoneyBoxWindowId = 0; +EWRAM_DATA static u8 sMoneyLabelSpriteId = 0; + +#define MONEY_LABEL_TAG 0x2722 + +static const struct OamData sOamData_MoneyLabel = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 1, + .x = 0, + .matrixNum = 0, + .size = 2, + .tileNum = 0, + .priority = 0, + .paletteNum = 0, + .affineParam = 0, +}; + +static const union AnimCmd sSpriteAnim_MoneyLabel[] = +{ + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const sSpriteAnimTable_MoneyLabel[] = +{ + sSpriteAnim_MoneyLabel, +}; + +static const struct SpriteTemplate sSpriteTemplate_MoneyLabel = +{ + .tileTag = MONEY_LABEL_TAG, + .paletteTag = MONEY_LABEL_TAG, + .oam = &sOamData_MoneyLabel, + .anims = sSpriteAnimTable_MoneyLabel, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy +}; + +static const struct CompressedSpriteSheet sSpriteSheet_MoneyLabel = +{ + .data = gMenuMoneyGfx, + .size = 256, + .tag = MONEY_LABEL_TAG, +}; + +static const struct CompressedSpritePalette sSpritePalette_MoneyLabel = +{ + .data = gMenuMoneyPal, + .tag = MONEY_LABEL_TAG +}; + u32 GetMoney(u32* moneyPtr) { return *moneyPtr ^ gSaveBlock2Ptr->encryptionKey; @@ -41,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); @@ -53,3 +122,79 @@ void SubtractMoney(u32* moneyPtr, u32 toSub) SetMoney(moneyPtr, toSet); } + +bool8 IsEnoughForCostInVar0x8005(void) +{ + return IsEnoughMoney(&gSaveBlock1Ptr->money, gSpecialVar_0x8005); +} + +void SubtractMoneyFromVar0x8005(void) +{ + RemoveMoney(&gSaveBlock1Ptr->money, gSpecialVar_0x8005); +} + +void PrintMoneyAmountInMoneyBox(u8 windowId, int amount, u8 speed) +{ + PrintMoneyAmount(windowId, 0x26, 1, amount, speed); +} + +void PrintMoneyAmount(u8 windowId, u8 x, u8 y, int amount, u8 speed) +{ + u8 *txtPtr; + s32 strLength; + + ConvertIntToDecimalStringN(gStringVar1, amount, STR_CONV_MODE_LEFT_ALIGN, 6); + + strLength = 6 - StringLength(gStringVar1); + txtPtr = gStringVar4; + + while (strLength-- > 0) + *(txtPtr++) = 0x77; + + StringExpandPlaceholders(txtPtr, gText_PokedollarVar1); + PrintTextOnWindow(windowId, 1, gStringVar4, x, y, speed, NULL); +} + +void PrintMoneyAmountInMoneyBoxWithBorder(u8 windowId, u16 tileStart, u8 pallete, int amount) +{ + SetWindowBorderStyle(windowId, FALSE, tileStart, pallete); + PrintMoneyAmountInMoneyBox(windowId, amount, 0); +} + +void ChangeAmountInMoneyBox(int amount) +{ + PrintMoneyAmountInMoneyBox(sMoneyBoxWindowId, amount, 0); +} + +void DrawMoneyBox(int amount, u8 x, u8 y) +{ + struct WindowTemplate template; + + SetWindowTemplateFields(&template, 0, x + 1, y + 1, 10, 2, 15, 8); + sMoneyBoxWindowId = AddWindow(&template); + FillWindowPixelBuffer(sMoneyBoxWindowId, 0); + PutWindowTilemap(sMoneyBoxWindowId); + CopyWindowToVram(sMoneyBoxWindowId, 1); + PrintMoneyAmountInMoneyBoxWithBorder(sMoneyBoxWindowId, 0x214, 14, amount); + AddMoneyLabelObject((8 * x) + 19, (8 * y) + 11); +} + +void HideMoneyBox(void) +{ + RemoveMoneyLabelObject(); + sub_8198070(sMoneyBoxWindowId, FALSE); + CopyWindowToVram(sMoneyBoxWindowId, 2); + RemoveWindow(sMoneyBoxWindowId); +} + +void AddMoneyLabelObject(u16 x, u16 y) +{ + LoadCompressedObjectPic(&sSpriteSheet_MoneyLabel); + LoadCompressedObjectPalette(&sSpritePalette_MoneyLabel); + sMoneyLabelSpriteId = CreateSprite(&sSpriteTemplate_MoneyLabel, x, y, 0); +} + +void RemoveMoneyLabelObject(void) +{ + DestroySpriteAndFreeResources(&gSprites[sMoneyLabelSpriteId]); +} diff --git a/src/new_game.c b/src/new_game.c index 5a482c593..d0666dd71 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -17,6 +17,7 @@ #include "easy_chat.h" #include "event_data.h" #include "money.h" +#include "tv.h" #include "coins.h" #include "text.h" @@ -28,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); @@ -36,7 +37,6 @@ extern void sub_813624C(void); // clears something pokeblock related extern void ResetPokedex(void); extern void sub_8084400(void); extern void ClearMailData(void); -extern void ClearTVShowData(void); extern void ResetGabbyAndTy(void); extern void ResetSecretBases(void); extern void ResetLinkContestBoolean(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 aa9a84e4c..d4bb593da 100644 --- a/src/palette.c +++ b/src/palette.c @@ -1,5 +1,8 @@ #include "global.h" +#include "blend_palette.h" #include "palette.h" +#include "decompress.h" +#include "gpu_regs.h" #include "task.h" enum @@ -28,7 +31,7 @@ struct PaletteStructTemplate struct PaletteStruct { - struct PaletteStructTemplate *base; + const struct PaletteStructTemplate *base; u32 ps_field_4_0:1; u16 ps_field_4_1:1; u32 baseDestOffset:9; @@ -38,31 +41,6 @@ struct PaletteStruct u8 ps_field_9; }; -extern void LZDecompressWram(const void *src, void *dest); -extern void SetGpuReg(u8 regOffset, u16 value); -extern void sub_8149DFC(u8 a1); -extern void sub_80A1670(u16 a1); -extern void sub_80A2D54(u8 a1); -extern void SetWordTaskArg(u8 taskId, u8 dataElem, u32 value); -extern void _call_via_r1(u32 a1, void *a2); - -extern void BlendPalette(u16, u16, u8, u16); - -EWRAM_DATA u16 gPlttBufferUnfaded[0x200] = {0}; -EWRAM_DATA u16 gPlttBufferFaded[0x200] = {0}; -EWRAM_DATA struct PaletteStruct sPaletteStructs[0x10] = {0}; -EWRAM_DATA struct PaletteFadeControl gPaletteFade = {0}; -EWRAM_DATA u32 gFiller_2037FE0 = 0; -EWRAM_DATA u32 sPlttBufferTransferPending = 0; -EWRAM_DATA u8 gPaletteDecompressionBuffer[0x400] = {0}; - -extern struct PaletteStructTemplate gDummyPaletteStructTemplate; -extern void *gUnknown_0852487C; -extern u8 gUnknown_0852489C[]; - -extern u16 gUnknown_03000F3C; -extern void *gUnknown_03000F44; - static void unused_sub_80A1CDC(struct PaletteStruct *, u32 *); static void unused_sub_80A1E40(struct PaletteStruct *, u32 *); static void unused_sub_80A1F00(struct PaletteStruct *); @@ -73,32 +51,29 @@ static u8 UpdateFastPaletteFade(void); static u8 UpdateHardwarePaletteFade(void); static void UpdateBlendRegisters(void); static bool8 IsSoftwarePaletteFadeFinishing(void); +static void sub_80A2D54(u8 taskId); -void sub_80A1818(u16 a1) -{ - void **v1 = &gUnknown_0852487C; - CpuSet(v1[a1 & 0x3], gPlttBufferUnfaded + 0x80, 0x10); - BlendPalette(0x80, 0x10, gPaletteFade.y, gPaletteFade.blendColor & 0x7FFF); - if ((u8)FindTaskIdByFunc(sub_8149DFC) != 0xFF ) - { - gUnknown_03000F44 = sub_80A1670; - gUnknown_03000F3C = 0x20; - } - return; -} +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[PLTT_DECOMP_BUFFER_SIZE] = {0}; -void sub_80A1884(u16 a1) -{ - void **v1 = &gUnknown_0852487C; - CpuSet(v1[a1 & 0x3], gPlttBufferUnfaded + 0x80, 0x10); - if ((u8)FindTaskIdByFunc(sub_8149DFC) == 0xFF ) - { - BlendPalette(0x80, 0x10, gPaletteFade.y, gPaletteFade.blendColor & 0x7FFF); - if (!--gUnknown_03000F3C) - gUnknown_03000F44 = 0; - } - return; -} +static const struct PaletteStructTemplate gDummyPaletteStructTemplate = { + .uid = 0xFFFF, + .pst_field_B_5 = 1 +}; +static const u8 gUnknown_0852489C[] = { + 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, + 11, 11, 11, 11, 11, + 16, 16, 16, 16, 16, + 21, 21, 21, 21, 21, + 27, 27, 27, 27, 27, + 31, 31 +}; void LoadCompressedPalette(const void *src, u16 offset, u16 size) { diff --git a/src/pokemon_1.c b/src/pokemon_1.c index fe7809826..f56ade967 100644 --- a/src/pokemon_1.c +++ b/src/pokemon_1.c @@ -33,7 +33,7 @@ void ZeroMonData(struct Pokemon *mon) SetMonData(mon, MON_DATA_MAX_HP, &arg); SetMonData(mon, MON_DATA_ATK, &arg); SetMonData(mon, MON_DATA_DEF, &arg); - SetMonData(mon, MON_DATA_SPD, &arg); + SetMonData(mon, MON_DATA_SPEED, &arg); SetMonData(mon, MON_DATA_SPATK, &arg); SetMonData(mon, MON_DATA_SPDEF, &arg); arg = 255; @@ -128,7 +128,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, SetBoxMonData(boxMon, MON_DATA_HP_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_ATK_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_DEF_IV, &fixedIV); - SetBoxMonData(boxMon, MON_DATA_SPD_IV, &fixedIV); + SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &fixedIV); } @@ -147,7 +147,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, value = Random(); iv = value & 0x1F; - SetBoxMonData(boxMon, MON_DATA_SPD_IV, &iv); + SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &iv); iv = (value & 0x3E0) >> 5; SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv); iv = (value & 0x7C00) >> 10; @@ -234,7 +234,7 @@ void CreateMonWithIVsOTID(struct Pokemon *mon, u16 species, u8 level, u8 *ivs, u SetMonData(mon, MON_DATA_HP_IV, &ivs[0]); SetMonData(mon, MON_DATA_ATK_IV, &ivs[1]); SetMonData(mon, MON_DATA_DEF_IV, &ivs[2]); - SetMonData(mon, MON_DATA_SPD_IV, &ivs[3]); + SetMonData(mon, MON_DATA_SPEED_IV, &ivs[3]); SetMonData(mon, MON_DATA_SPATK_IV, &ivs[4]); SetMonData(mon, MON_DATA_SPDEF_IV, &ivs[5]); CalculateMonStats(mon); @@ -305,7 +305,7 @@ void sub_806819C(struct Pokemon *mon, struct UnknownPokemonStruct *src) SetMonData(mon, MON_DATA_HP_EV, &src->hpEV); SetMonData(mon, MON_DATA_ATK_EV, &src->attackEV); SetMonData(mon, MON_DATA_DEF_EV, &src->defenseEV); - SetMonData(mon, MON_DATA_SPD_EV, &src->speedEV); + SetMonData(mon, MON_DATA_SPEED_EV, &src->speedEV); SetMonData(mon, MON_DATA_SPATK_EV, &src->spAttackEV); SetMonData(mon, MON_DATA_SPDEF_EV, &src->spDefenseEV); value = src->altAbility; @@ -317,7 +317,7 @@ void sub_806819C(struct Pokemon *mon, struct UnknownPokemonStruct *src) value = src->defenseIV; SetMonData(mon, MON_DATA_DEF_IV, &value); value = src->speedIV; - SetMonData(mon, MON_DATA_SPD_IV, &value); + SetMonData(mon, MON_DATA_SPEED_IV, &value); value = src->spAttackIV; SetMonData(mon, MON_DATA_SPATK_IV, &value); value = src->spDefenseIV; @@ -369,7 +369,7 @@ void sub_8068338(struct Pokemon *mon, struct UnknownPokemonStruct *src, bool8 lv SetMonData(mon, MON_DATA_HP_EV, &src->hpEV); SetMonData(mon, MON_DATA_ATK_EV, &src->attackEV); SetMonData(mon, MON_DATA_DEF_EV, &src->defenseEV); - SetMonData(mon, MON_DATA_SPD_EV, &src->speedEV); + SetMonData(mon, MON_DATA_SPEED_EV, &src->speedEV); SetMonData(mon, MON_DATA_SPATK_EV, &src->spAttackEV); SetMonData(mon, MON_DATA_SPDEF_EV, &src->spDefenseEV); value = src->altAbility; @@ -381,7 +381,7 @@ void sub_8068338(struct Pokemon *mon, struct UnknownPokemonStruct *src, bool8 lv value = src->defenseIV; SetMonData(mon, MON_DATA_DEF_IV, &value); value = src->speedIV; - SetMonData(mon, MON_DATA_SPD_IV, &value); + SetMonData(mon, MON_DATA_SPEED_IV, &value); value = src->spAttackIV; SetMonData(mon, MON_DATA_SPATK_IV, &value); value = src->spDefenseIV; diff --git a/src/pokemon_2.c b/src/pokemon_2.c index cf073570d..587773836 100644 --- a/src/pokemon_2.c +++ b/src/pokemon_2.c @@ -28,14 +28,14 @@ extern const u32 gBitTable[]; extern const struct SpriteTemplate gUnknown_08329D98[]; extern const struct SpriteTemplate gUnknown_08329DF8[]; extern const union AnimCmd* gUnknown_082FF70C[]; -extern const union AnimCmd* const * const gUnknown_08309AAC[]; +extern const union AnimCmd* const * const gMonAnimationsSpriteAnimsPtrTable[]; extern const union AnimCmd* const * const gUnknown_08305D0C[]; extern const union AnimCmd* const * const gUnknown_0830536C[]; extern const u8 gText_BadEgg[]; extern const u8 gText_EggNickname[]; extern u8 GetBankSide(u8 bank); -extern u8 GetBankByPlayerAI(u8 bank); +extern u8 GetBankByIdentity(u8 bank); extern u8 GetBankIdentity(u8 bank); u8 CountAliveMonsInBattle(u8 caseId) @@ -90,7 +90,7 @@ u8 sub_8069F34(u8 bank) status ^= 1; if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - return GetBankByPlayerAI(status); + return GetBankByIdentity(status); if (CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_ACTIVE) > 1) { u8 val; @@ -99,14 +99,14 @@ u8 sub_8069F34(u8 bank) val = status ^ 2; else val = status; - return GetBankByPlayerAI(val); + return GetBankByIdentity(val); } else { if ((gAbsentBankFlags & gBitTable[status])) - return GetBankByPlayerAI(status ^ 2); + return GetBankByIdentity(status ^ 2); else - return GetBankByPlayerAI(status); + return GetBankByIdentity(status); } } @@ -152,8 +152,8 @@ u8 GetGenderFromSpeciesAndPersonality(u16 species, u32 personality) void sub_806A068(u16 species, u8 bankIdentity) { - if (gBattleSpritesGfx != NULL) - gUnknown_0202499C = gBattleSpritesGfx->templates[bankIdentity]; + if (gMonSpritesGfxPtr != NULL) + gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity]; else if (gUnknown_020249B4[0]) gUnknown_0202499C = gUnknown_020249B4[0]->templates[bankIdentity]; else if (gUnknown_020249B4[1]) @@ -165,9 +165,9 @@ void sub_806A068(u16 species, u8 bankIdentity) if (bankIdentity == 0 || bankIdentity == 2) gUnknown_0202499C.anims = gUnknown_082FF70C; else if (species > 500) - gUnknown_0202499C.anims = gUnknown_08309AAC[species - 500]; + gUnknown_0202499C.anims = gMonAnimationsSpriteAnimsPtrTable[species - 500]; else - gUnknown_0202499C.anims = gUnknown_08309AAC[species]; + gUnknown_0202499C.anims = gMonAnimationsSpriteAnimsPtrTable[species]; } void sub_806A12C(u16 trainerSpriteId, u8 bankIdentity) @@ -180,8 +180,8 @@ void sub_806A12C(u16 trainerSpriteId, u8 bankIdentity) } else { - if (gBattleSpritesGfx != NULL) - gUnknown_0202499C = gBattleSpritesGfx->templates[bankIdentity]; + if (gMonSpritesGfxPtr != NULL) + gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity]; else gUnknown_0202499C = gUnknown_08329D98[bankIdentity]; gUnknown_0202499C.anims = gUnknown_0830536C[trainerSpriteId]; @@ -190,8 +190,8 @@ void sub_806A12C(u16 trainerSpriteId, u8 bankIdentity) void sub_806A1C0(u16 arg0, u8 bankIdentity) { - if (gBattleSpritesGfx != NULL) - gUnknown_0202499C = gBattleSpritesGfx->templates[bankIdentity]; + if (gMonSpritesGfxPtr != NULL) + gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity]; else gUnknown_0202499C = gUnknown_08329D98[bankIdentity]; gUnknown_0202499C.paletteTag = arg0; @@ -330,7 +330,7 @@ u32 GetMonData(struct Pokemon *mon, s32 field, u8* data) if (!ret) ret = mon->defense; break; - case MON_DATA_SPD: + case MON_DATA_SPEED: ret = GetDeoxysStat(mon, STAT_SPD); if (!ret) ret = mon->speed; @@ -351,7 +351,7 @@ u32 GetMonData(struct Pokemon *mon, s32 field, u8* data) case MON_DATA_DEF2: ret = mon->defense; break; - case MON_DATA_SPD2: + case MON_DATA_SPEED2: ret = mon->speed; break; case MON_DATA_SPATK2: @@ -512,7 +512,7 @@ u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data) case MON_DATA_DEF_EV: retVal = substruct2->defenseEV; break; - case MON_DATA_SPD_EV: + case MON_DATA_SPEED_EV: retVal = substruct2->speedEV; break; case MON_DATA_SPATK_EV: @@ -566,7 +566,7 @@ u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data) case MON_DATA_DEF_IV: retVal = substruct3->defenseIV; break; - case MON_DATA_SPD_IV: + case MON_DATA_SPEED_IV: retVal = substruct3->speedIV; break; case MON_DATA_SPATK_IV: @@ -747,7 +747,7 @@ void SetMonData(struct Pokemon *mon, s32 field, const void *dataArg) case MON_DATA_DEF: SET16(mon->defense); break; - case MON_DATA_SPD: + case MON_DATA_SPEED: SET16(mon->speed); break; case MON_DATA_SPATK: @@ -880,7 +880,7 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) case MON_DATA_DEF_EV: SET8(substruct2->defenseEV); break; - case MON_DATA_SPD_EV: + case MON_DATA_SPEED_EV: SET8(substruct2->speedEV); break; case MON_DATA_SPATK_EV: @@ -940,7 +940,7 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) case MON_DATA_DEF_IV: SET8(substruct3->defenseIV); break; - case MON_DATA_SPD_IV: + case MON_DATA_SPEED_IV: SET8(substruct3->speedIV); break; case MON_DATA_SPATK_IV: @@ -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; } @@ -1308,10 +1308,9 @@ void sub_805EF84(u8 bank, bool8); extern struct BattlePokemon gBattleMons[4]; -/* - void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex) { + u16* hpSwitchout; s32 i; u8 nickname[POKEMON_NAME_LENGTH * 2]; @@ -1330,7 +1329,7 @@ void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex) gBattleMons[bank].hpIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP_IV, NULL); gBattleMons[bank].attackIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_ATK_IV, NULL); gBattleMons[bank].defenseIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_DEF_IV, NULL); - gBattleMons[bank].speedIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPD_IV, NULL); + gBattleMons[bank].speedIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPEED_IV, NULL); gBattleMons[bank].spAttackIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPATK_IV, NULL); gBattleMons[bank].spDefenseIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPDEF_IV, NULL); gBattleMons[bank].personality = GetMonData(&gPlayerParty[partyIndex], MON_DATA_PERSONALITY, NULL); @@ -1340,7 +1339,7 @@ void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex) gBattleMons[bank].maxHP = GetMonData(&gPlayerParty[partyIndex], MON_DATA_MAX_HP, NULL); gBattleMons[bank].attack = GetMonData(&gPlayerParty[partyIndex], MON_DATA_ATK, NULL); gBattleMons[bank].defense = GetMonData(&gPlayerParty[partyIndex], MON_DATA_DEF, NULL); - gBattleMons[bank].speed = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPD, NULL); + gBattleMons[bank].speed = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPEED, NULL); gBattleMons[bank].spAttack = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPATK, NULL); gBattleMons[bank].spDefense = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPDEF, NULL); gBattleMons[bank].isEgg = GetMonData(&gPlayerParty[partyIndex], MON_DATA_IS_EGG, NULL); @@ -1352,15 +1351,9 @@ void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex) GetMonData(&gPlayerParty[partyIndex], MON_DATA_NICKNAME, nickname); StringCopy10(gBattleMons[bank].nickname, nickname); GetMonData(&gPlayerParty[partyIndex], MON_DATA_OT_NAME, gBattleMons[bank].otName); - // ewram memes from Ruby return - #ifdef NONMATCHING - gBattleStruct->hpOnSwitchout[GetBankSide(bank)] = gBattleMons[bank].hp; - #else - { - u32 side = GetBankSide(bank); - *(u16*)((void*)(gBattleStruct) + side) = gBattleMons[bank].hp; - } - #endif // NONMATCHING + + hpSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(bank)]; + *hpSwitchout = gBattleMons[bank].hp; for (i = 0; i < 8; i++) gBattleMons[bank].statStages[i] = 6; @@ -1369,4 +1362,3 @@ void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex) sub_803FA70(bank); sub_805EF84(bank, FALSE); } -*/ diff --git a/src/pokemon_3.c b/src/pokemon_3.c index 603732a34..5ff99aee2 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -216,7 +216,7 @@ void sub_806CF24(s32 stat) gBankTarget = gBankInMenu; StringCopy(gBattleTextBuff1, gStatNamesTable[gUnknown_08329EC8[stat]]); StringCopy(gBattleTextBuff2, gText_StatRose); - StrCpyDecodeToDisplayedStringBattle(gText_PkmnsStatChanged2); + BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnsStatChanged2); } u8 *sub_806CF78(u16 itemId) @@ -251,7 +251,7 @@ u8 *sub_806CF78(u16 itemId) else { gBankAttacker = gBankInMenu; - StrCpyDecodeToDisplayedStringBattle(gText_PkmnGettingPumped); + BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnGettingPumped); } } } @@ -259,7 +259,7 @@ u8 *sub_806CF78(u16 itemId) if (itemEffect[3] & 0x80) { gBankAttacker = gBankInMenu; - StrCpyDecodeToDisplayedStringBattle(gText_PkmnShroudedInMist); + BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnShroudedInMist); } return gDisplayedStringBattle; @@ -486,8 +486,8 @@ u16 SpeciesToCryId(u16 species) void sub_806D544(u16 species, u32 personality, u8 *dest) { if (species == SPECIES_SPINDA - && dest != gBattleSpritesGfx->sprites[0] - && dest != gBattleSpritesGfx->sprites[2]) + && dest != gMonSpritesGfxPtr->sprites[0] + && dest != gMonSpritesGfxPtr->sprites[2]) { int i; for (i = 0; i < 4; i++) @@ -601,9 +601,9 @@ bool8 sub_806D7EC(void) return retVal; } -bool8 sub_806D82C(u8 id) +bool16 sub_806D82C(u8 id) { - bool8 retVal = FALSE; + bool16 retVal = FALSE; switch (gLinkPlayers[id].lp_field_18) { case 0: @@ -1361,20 +1361,20 @@ void BoxMonRestorePP(struct BoxPokemon *boxMon) void sub_806E994(void) { gLastUsedAbility = gBattleStruct->field_B0; - gBattleTextBuff1[0] = 0xFD; - gBattleTextBuff1[1] = 4; + + gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = B_BUFF_MON_NICK_WITH_PREFIX; gBattleTextBuff1[2] = gBattleStruct->field_49; - gBattleTextBuff1[4] = EOS; + gBattleTextBuff1[4] = B_BUFF_EOS; + if (!GetBankSide(gBattleStruct->field_49)) gBattleTextBuff1[3] = pokemon_order_func(gBattlePartyID[gBattleStruct->field_49]); else gBattleTextBuff1[3] = gBattlePartyID[gBattleStruct->field_49]; - gBattleTextBuff2[0] = 0xFD; - gBattleTextBuff2[1] = 4; - gBattleTextBuff2[2] = gBankInMenu; - gBattleTextBuff2[3] = pokemon_order_func(gBattlePartyID[gBankInMenu]); - gBattleTextBuff2[4] = EOS; - StrCpyDecodeBattle(gText_PkmnsXPreventsSwitching, gStringVar4); + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff2, gBankInMenu, pokemon_order_func(gBattlePartyID[gBankInMenu])) + + BattleStringExpandPlaceholders(gText_PkmnsXPreventsSwitching, gStringVar4); } struct PokeItem @@ -1388,7 +1388,7 @@ extern const struct PokeItem gAlteringCaveWildMonHeldItems[9]; static s32 GetWildMonTableIdInAlteringCave(u16 species) { s32 i; - for (i = 0; i < 9; i++) + for (i = 0; i < (s32) ARRAY_COUNT(gAlteringCaveWildMonHeldItems); i++) if (gAlteringCaveWildMonHeldItems[i].species == species) return i; return 0; @@ -1519,8 +1519,6 @@ void BattleAnimateFrontSprite(struct Sprite* sprite, u16 species, bool8 noCry, u DoMonFrontSpriteAnimation(sprite, species, noCry, arg3); } -bool8 HasTwoFramesAnimation(u16 species); - extern void SpriteCallbackDummy_2(struct Sprite*); extern void sub_817F60C(struct Sprite*); diff --git a/src/pokemon_size_record.c b/src/pokemon_size_record.c index 12d98bfd8..1758fba32 100644 --- a/src/pokemon_size_record.c +++ b/src/pokemon_size_record.c @@ -57,7 +57,7 @@ static u32 GetMonSizeHash(struct Pokemon *pkmn) u16 hpIV = GetMonData(pkmn, MON_DATA_HP_IV) & 0xF; u16 attackIV = GetMonData(pkmn, MON_DATA_ATK_IV) & 0xF; u16 defenseIV = GetMonData(pkmn, MON_DATA_DEF_IV) & 0xF; - u16 speedIV = GetMonData(pkmn, MON_DATA_SPD_IV) & 0xF; + u16 speedIV = GetMonData(pkmn, MON_DATA_SPEED_IV) & 0xF; u16 spAtkIV = GetMonData(pkmn, MON_DATA_SPATK_IV) & 0xF; u16 spDefIV = GetMonData(pkmn, MON_DATA_SPDEF_IV) & 0xF; u32 hibyte = ((attackIV ^ defenseIV) * hpIV) ^ (personality & 0xFF); diff --git a/src/pokemon_storage_system.c b/src/pokemon_storage_system.c new file mode 100644 index 000000000..3e409244c --- /dev/null +++ b/src/pokemon_storage_system.c @@ -0,0 +1,15 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u8 gUnknown_03000F78[0x188]; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c new file mode 100755 index 000000000..838e91d90 --- /dev/null +++ b/src/pokemon_summary_screen.c @@ -0,0 +1,3679 @@ +#include "global.h" +#include "battle.h" +#include "bg.h" +#include "decompress.h" +#include "item.h" +#include "items.h" +#include "link.h" +#include "m4a.h" +#include "main.h" +#include "malloc.h" +#include "moves.h" +#include "palette.h" +#include "pokemon.h" +#include "songs.h" +#include "sound.h" +#include "species.h" +#include "sprite.h" +#include "string_util.h" +#include "task.h" +#include "text.h" +#include "window.h" + +struct ContestMove +{ + u8 effect; + u8 type; + u8 comboID; + u8 combo[4]; +}; + +struct ContestEffect +{ + u8 type; + u8 appeal; + u8 jam; +}; + + + +extern struct UnkSummaryStruct* gUnknown_0203CF1C; +extern struct BgTemplate gUnknown_0861CBB4; +extern u8 gUnknown_0203CF20; +extern struct MusicPlayerInfo gMPlay_BGM; +extern s8 gUnknown_0861CC1C[]; +extern u8 gUnknown_08329D22[]; +extern u8 gUnknown_0203CF21; +extern u16 gSpecialVar_0x8005; +extern struct UnkStruct_61CC04 gUnknown_0861CC04; +extern struct UnkStruct_61CC04 gUnknown_0861CC10; +extern struct UnkStruct_61CC04 gUnknown_0861CBEC; +extern struct UnkStruct_61CC04 gUnknown_0861CBF8; +extern u16 gUnknown_08DC3CD4[]; +extern struct ContestMove gContestMoves[]; +extern struct ContestEffect gContestEffects[]; +extern struct WindowTemplate gUnknown_0861CC24; +extern struct TextColor gUnknown_0861CD2C[]; +extern const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1]; +extern u8 gText_MaleSymbol[]; +extern u8 gText_FemaleSymbol[]; +extern u8 gUnknown_0861CDD3[]; +extern void (*const gUnknown_0861CE54[])(); +extern void (*const gUnknown_0861CE64[])(u8 taskId); +extern struct WindowTemplate gUnknown_0861CCCC; +extern u8 gUnknown_0861CE74[]; +extern u8 gUnknown_0861CE7B[]; +extern struct WindowTemplate gUnknown_0861CCEC; +extern struct WindowTemplate gUnknown_0861CD14; + +extern void sub_806F2AC(u8 a, u8 b); +void sub_81C488C(u8 a); +extern void do_scheduled_bg_tilemap_copies_to_vram(void); +extern u8 sub_81221EC(); +extern u8 sub_81221AC(); +extern void SetVBlankHBlankCallbacksToNull(); +extern void sub_8121DA0(); +extern void clear_scheduled_bg_copies_to_vram(); +extern void remove_some_task(); +extern void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); +extern void ShowBg(u8 a); +extern void SetGpuReg(u8 regOffset, u16 value); +extern void schedule_bg_copy_tilemap_to_vram(u8 a); +extern void SetBgTilemapBuffer(u8 bg, void *tilemap); +extern u8 gUnknown_08D9862C; +extern u8 gUnknown_08D98CC8; +extern u8 gUnknown_08D987FC; +extern u8 gUnknown_08D9898C; +extern u8 gUnknown_08D98B28; +extern u8 gUnknown_08D9853C; +extern u8 gUnknown_08D85620; +extern struct CompressedSpriteSheet gUnknown_0861CFBC; +extern struct CompressedSpriteSheet gUnknown_0861D074; +extern struct CompressedSpriteSheet gUnknown_0861D0F8; +extern struct CompressedSpritePalette gUnknown_0861D100; +extern struct CompressedSpritePalette gUnknown_0861D07C; +extern u8 gUnknown_08D97B84; +extern u8 gUnknown_08D97D0C; +extern void reset_temp_tile_data_buffers(); +extern void decompress_and_copy_tile_data_to_vram(u8 a, void* tiledata, u8 b, u8 c, u8 d); +extern u8 free_temp_tile_data_buffers_if_possible(); +extern void sub_8069004(struct BoxPokemon* a, void* b); +extern void sub_81C1E20(u8 taskId); +extern u8 *GetMonNickname(struct Pokemon *mon, u8 *dest); +extern u16 SpeciesToPokedexNum(u16 species); +extern u8 gText_UnkCtrlF908Clear01[]; +extern u8 gText_LevelSymbol[]; +extern u8 gText_PkmnInfo[]; +extern u8 gText_PkmnSkills[]; +extern u8 gText_BattleMoves[]; +extern u8 gText_ContestMoves[]; +extern u8 gText_Cancel2[]; +extern u8 gText_Info[]; +extern u8 gText_Switch[]; +extern u8 gText_RentalPkmn[]; +extern u8 gText_TypeSlash[]; +extern u8 gText_HP4[]; +extern u8 gText_Attack3[]; +extern u8 gText_Defense3[]; +extern u8 gText_SpAtk4[]; +extern u8 gText_SpDef4[]; +extern u8 gText_Speed2[]; +extern u8 gText_ExpPoints[]; +extern u8 gText_NextLv[]; +extern u8 gText_Status[]; +extern u8 gText_Power[]; +extern u8 gText_Accuracy2[]; +extern u8 gText_Appeal[]; +extern u8 gText_Jam[]; +extern u8 gText_OTSlash[]; +extern u8 gText_UnkCtrlF907F908[]; +extern u8 gAbilityNames[][13]; +extern u8 *gAbilityDescriptionPointers[]; +extern u8 gText_XNature[]; +extern u8 gText_XNatureHatchedAtYZ[]; +extern u8 gText_XNatureHatchedSomewhereAt[]; +extern u8 gText_XNatureMetAtYZ[]; +extern u8 gText_XNatureMetSomewhereAt[]; +extern u8 gText_XNatureFatefulEncounter[]; +extern u8 gText_XNatureProbablyMetAt[]; +extern u8 gText_XNatureObtainedInTrade[]; +extern u8 *gNatureNamePointers[]; +extern u8 gText_EmptyString5[]; +extern u32 gBattleTypeFlags; +extern u8 gText_FiveMarks[]; +extern u8 gText_EggWillTakeALongTime[]; +extern u8 gText_EggAboutToHatch[]; +extern u8 gText_EggWillHatchSoon[]; +extern u8 gText_EggWillTakeSomeTime[]; +extern u8 gText_PeculiarEggNicePlace[]; +extern u8 gText_PeculiarEggTrade[]; +extern u8 gText_EggFromTraveler[]; +extern u8 gText_EggFromHotSprings[]; +extern u8 gText_OddEggFoundByCouple[]; +extern u8 gText_None[]; +extern u8 gText_RibbonsVar1[]; +extern u8 gUnknown_0861CE82[]; +extern u8 gUnknown_0861CE8E[]; +extern u8 gText_OneDash[]; +extern u8 gText_TwoDashes[]; +extern u8 gText_ThreeDashes[]; +extern u8 gUnknown_0861CE97[]; +extern struct BattleMove gBattleMoves[]; + +extern u32 ChangeBgX(u8 bg, u32 value, u8 op); +extern void sub_8199C30(u8 a, u8 b, u8 c, u8 d, u8 e, u8 f); +extern void AddTextPrinterParametrized2(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, struct TextColor* colors, s8 speed, u8 *str); +extern s32 GetStringCenterAlignXOffset(u8 fontId, u8 *str, s32 totalWidth); +extern s32 GetStringRightAlignXOffset(u8 fontId, u8 *str, s32 totalWidth); +extern bool8 sub_81A6BF4(); +extern bool8 sub_81B9E94(); +extern void sub_81AFBF0(); +extern u8 sub_81AFC0C(u8 a, u8 *b); +extern void sub_81AFC28(u8 *a, u8 *b); +extern void sub_8124610(u8 *a, u8 b); +extern int GetPlayerIDAsU32(); +extern u8 GetCurrentPpToMaxPpState(u8 a, u8 b); + +void sub_81BFAE4(void); +void sub_81BFE24(); +u8 sub_81BFEB0(); +void sub_81C2554(); +void sub_81C1BA0(); +void sub_81C0098(struct Pokemon* a); +bool8 sub_81C00F0(struct Pokemon* a); +void sub_81C25E8(); +void sub_81C286C(); +void sub_81C2D9C(u8 a); +void sub_81C0348(); +void sub_81C2AFC(u8 a); +void sub_81C4190(); +void sub_81C42C8(); +u8 sub_81C45F4(void* a, u16* b); +void sub_81C4984(); +void sub_81C4A08(); +void sub_81C4A88(); +void sub_81C4280(); +void sub_81C0510(u8 taskId); +void sub_81C171C(u8 taskId); +void sub_8121E10(); +u8 sub_81B205C(struct Pokemon* a); +void sub_81C1DA4(u16 a, s16 b); +void sub_81C1EFC(u16 a, s16 b, u16 c); +void sub_81C240C(u16 a); +void sub_81C2194(u16 *a, u16 b, u8 c); +void sub_81C2074(u16 a, s16 b); +void sub_81C2524(); +void sub_81C2228(struct Pokemon* mon); +void sub_81C0484(u8 taskId); +void sub_81C4898(); +void sub_806F47C(u8 a); +u8 GetLRKeysState(); +void sub_81C0604(u8 taskId, s8 a); +void sub_81C0A8C(u8 taskId, s8 a); +void sub_81C48F0(); +void sub_81C0E48(u8 taskId); +void sub_81C0704(u8 taskId); +s8 sub_81C09B4(s8 a); +s8 sub_81C08F8(s8 a); +void sub_81C4204(u8 a, u8 b); +void sub_81C20F0(u8 taskId); +bool8 sub_81C0A50(struct Pokemon* mon); +void sub_81C49E0(); +void sub_81C0E24(); +void sub_81C2C38(u8 a); +void sub_81C0B8C(u8 taskId); +void sub_81C0CC4(u8 taskId); +void sub_81C2DE4(u8 a); +void sub_81C424C(); +void sub_81C0C68(u8 taskId); +void sub_81C0D44(u8 taskId); +void sub_81C22CC(struct Pokemon* mon); +void sub_81C0F44(u8 taskId); +void sub_81C3E9C(u16 a); +void sub_81C3F44(); +void sub_81C44F0(); +void sub_81C4AF8(u8 a); +void sub_81C1070(s16* a, s8 b, u8* c); +void sub_81C11F4(u8 a); +void sub_81C129C(u8 a); +bool8 sub_81C1040(); +void sub_81C4064(); +void sub_81C4C60(u8 a); +void sub_81C12E4(u8 taskId); +void sub_81C4C84(u8 a); +void sub_81C13B0(u8 a, u8 b); +void sub_81C14BC(struct Pokemon *mon, u8 a, u8 b); +void sub_81C15EC(struct BoxPokemon *mon, u8 a, u8 b); +void sub_81C40A0(u8 a, u8 b); +void sub_81C4568(u8 a, u8 b); +void sub_81C174C(u8 taskId); +bool8 sub_81C18A8(); +void sub_81C18F4(u8 a); +u8 sub_81B6D14(u16 a); +void sub_81C1940(u8 taskId); +void sub_81C4154(); +void sub_81C1F80(u8 taskId); +void sub_81C2628(); +void sub_81C2794(); +void sub_81C27DC(struct Pokemon *mon, u16 a); +void sub_81C2D68(u8 a); +void sub_81C335C(); +void sub_81C33CC(); +void sub_81C3428(); +void sub_81C349C(); +void sub_81C2EC4(); +void sub_81C2F5C(); +void sub_81C2FD8(); +void sub_81C302C(); +void sub_81C307C(); +void sub_81C3194(); +void sub_81C31C0(); +bool8 sub_81C3304(); +void sub_81C31F0(u8 *a); +u8 sub_81C3220(); +bool8 sub_81C32BC(); +void sub_81C35E4(); +void sub_81C3690(); +void sub_81C3710(); +void sub_81C37D8(); +void sub_81C3808(); +void sub_81C3890(); +void sub_81C38C0(); +void sub_81C3B08(u8 a); +void sub_81C3E2C(u8 a); +void sub_81C4D18(); + +void SetBgAttribute(u8 bg, u8 attributeId, u8 value); + +bool8 sub_81BFB10(); +u8 sub_81B1250(); + +union UnkUnion +{ + struct Pokemon mon[6]; + struct BoxPokemon boxMon[6]; +}; + + +u8 sub_80D214C(union UnkUnion* a, u8 b, u8 c, u8 d); + +struct PokeSummary +{ + u16 species; // 0x0 + u16 species2; // 0x2 + u8 isEgg; // 0x4 + u8 level; // 0x5 + u8 ribbons; // 0x6 + u8 unk7; // 0x7 + u8 altAbility; // 0x8 + u8 metLocation; // 0x9 + u8 metLevel; // 0xA + u8 metGame; // 0xB + u32 pid; // 0xC + u32 exp; // 0x10 + u16 moves[4]; // 0x14 + u8 pp[4]; // 0x1C + u16 currentHP; // 0x20 + u16 maxHP; // 0x22 + u16 atk; // 0x24 + u16 def; // 0x26 + u16 spatk; // 0x28 + u16 spdef; // 0x2A + u16 speed; // 0x2C + u16 item; // 0x2E + u16 friendship; // 0x30 + u8 OTGender; // 0x32 + u8 nature; // 0x33 + u8 ppBonuses; // 0x34 + u8 sanity; // 0x35 + u8 OTName[8]; // 0x36 + u8 unk3E[9]; // 0x3E + u32 OTID; // 0x48 +}; + +struct UnkSummaryStruct +{ + /*0x00*/ union UnkUnion *unk0; + /*0x04*/ void *unk4; + /*0x08*/ void *unk8; + /*0x0C*/ struct Pokemon currentMon; + /*0x70*/ struct PokeSummary summary; + u16 unkTilemap0[0x400]; + u16 unkTilemap0_1[0x400]; + u16 unkTilemap1[0x400]; + u16 unkTilemap1_1[0x400]; + u16 unkTilemap2[0x400]; + u16 unkTilemap2_1[0x400]; + u16 unkTilemap3[0x400]; + u16 unkTilemap3_1[0x400]; + u8 unk40BC; + u8 unk40BD; + u8 unk40BE; + u8 unk40BF; + u8 unk40C0; + u8 unk40C1; + u8 unk40C2; + u8 unk40C3; + u16 unk40C4; + u8 unk40C6; + u8 unk40C7; + u8 unk40C8; + u8 unk40C9; + u8 unk40CA; + u8 unk40CB[8]; + u8 unk40D3; + u8 unk40D4; + u8 unk40D5; + u8 unk_filler5[0x19]; + u8 unk40EF; + s16 unk40F0; + u8 unk_filler4[6]; +}; + +void sub_81BF8EC(u8 a, void *b, u8 c, u8 d, void *e) +{ + u8 byte; + gUnknown_0203CF1C = AllocZeroed(sizeof(struct UnkSummaryStruct)); + gUnknown_0203CF1C->unk40BC = a; + gUnknown_0203CF1C->unk0 = b; + gUnknown_0203CF1C->unk40BE = c; + gUnknown_0203CF1C->unk40BF = d; + gUnknown_0203CF1C->unk4 = e; + if (a == 2) + gUnknown_0203CF1C->unk40BD = 1; + else + gUnknown_0203CF1C->unk40BD = 0; + switch (a) + { + case 0: + case 2: + gUnknown_0203CF1C->unk40C1 = 0; + gUnknown_0203CF1C->unk40C2 = 3; + break; + case 1: + gUnknown_0203CF1C->unk40C1 = 0; + gUnknown_0203CF1C->unk40C2 = 3; + gUnknown_0203CF1C->unk40C8 = 1; + break; + case 3: + gUnknown_0203CF1C->unk40C1 = 2; + gUnknown_0203CF1C->unk40C2 = 3; + gUnknown_0203CF1C->unk40C3 = 1; + break; + } + byte = gUnknown_0203CF1C->unk40C1; + gUnknown_0203CF1C->unk40C0 = byte; + sub_81C488C(0xFF); + if (gMonSpritesGfxPtr == 0) + sub_806F2AC(0, 0); + SetMainCallback2(sub_81BFAE4); +} + +void sub_81BFA38(void *a, u8 b, u8 c, void *d, u16 e) +{ + sub_81BF8EC(3, a, b, c, d); + gUnknown_0203CF1C->unk40C4 = e; +} + +void sub_81BFA80(u8 a, void *b, u8 c, u8 d, void *e) +{ + sub_81BF8EC(a, b, c, d, e); + gUnknown_0203CF1C->unk40EF = 1; +} + +void sub_81BFAB4(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +void sub_81BFAD0(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +void sub_81BFAE4() +{ + while (1) + { + if (sub_81221EC() == 1 || sub_81BFB10() == TRUE || sub_81221AC() == 1) + break; + } +} + +bool8 sub_81BFB10(void) +{ + switch (gMain.state) + { + case 0: + SetVBlankHBlankCallbacksToNull(); + sub_8121DA0(); + clear_scheduled_bg_copies_to_vram(); + gMain.state++; + break; + case 1: + remove_some_task(); + gMain.state++; + break; + case 2: + ResetPaletteFade(); + gPaletteFade.bufferTransferDisabled = 1; + gMain.state++; + break; + case 3: + ResetSpriteData(); + gMain.state++; + break; + case 4: + FreeAllSpritePalettes(); + gMain.state++; + break; + case 5: + sub_81BFE24(); + gUnknown_0203CF1C->unk40F0 = 0; + gMain.state++; + break; + case 6: + if (sub_81BFEB0() != 0) + gMain.state++; + break; + case 7: + sub_81C2554(); + gMain.state++; + break; + case 8: + sub_81C1BA0(); + gMain.state++; + break; + case 9: + sub_81C0098(&gUnknown_0203CF1C->currentMon); + gUnknown_0203CF1C->unk40F0 = 0; + gMain.state++; + break; + case 10: + if (sub_81C00F0(&gUnknown_0203CF1C->currentMon) != 0) + gMain.state++; + break; + case 11: + sub_81C25E8(); + gMain.state++; + break; + case 12: + sub_81C286C(); + gMain.state++; + break; + case 13: + sub_81C2D9C(gUnknown_0203CF1C->unk40C0); + gMain.state++; + break; + case 14: + sub_81C0348(); + gMain.state++; + break; + case 15: + sub_81C2AFC(gUnknown_0203CF1C->unk40C0); + gMain.state++; + break; + case 16: + sub_81C4190(); + sub_81C42C8(); + gUnknown_0203CF1C->unk40F0 = 0; + gMain.state++; + break; + case 17: + gUnknown_0203CF1C->unk40D3 = sub_81C45F4(&gUnknown_0203CF1C->currentMon, &gUnknown_0203CF1C->unk40F0); + if (gUnknown_0203CF1C->unk40D3 != 0xFF) + { + gUnknown_0203CF1C->unk40F0 = 0; + gMain.state++; + } + break; + case 18: + sub_81C4984(&gUnknown_0203CF1C->currentMon); + gMain.state++; + break; + case 19: + sub_81C4A08(&gUnknown_0203CF1C->currentMon); + gMain.state++; + break; + case 20: + sub_81C4A88(); + gMain.state++; + break; + case 21: + sub_81C4280(); + gMain.state++; + break; + case 22: + if (gUnknown_0203CF1C->unk40BC != 3) + CreateTask(sub_81C0510, 0); + else + CreateTask(sub_81C171C, 0); + gMain.state++; + break; + case 23: + BlendPalettes(-1, 16, 0); + gMain.state++; + break; + case 24: + BeginNormalPaletteFade(-1, 0, 16, 0, 0); + gPaletteFade.bufferTransferDisabled = 0; + gMain.state++; + break; + default: + SetVBlankCallback(sub_81BFAD0); + SetMainCallback2(sub_81BFAB4); + return TRUE; + } + return FALSE; +} + +void sub_81BFE24() +{ + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, &gUnknown_0861CBB4, 4); + SetBgTilemapBuffer(1, &gUnknown_0203CF1C->unkTilemap2); + SetBgTilemapBuffer(2, &gUnknown_0203CF1C->unkTilemap1); + SetBgTilemapBuffer(3, &gUnknown_0203CF1C->unkTilemap0); + sub_8121E10(); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + schedule_bg_copy_tilemap_to_vram(3); + SetGpuReg(REG_OFFSET_DISPCNT, 0x1040); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); +} + +u8 sub_81BFEB0() +{ + switch (gUnknown_0203CF1C->unk40F0) + { + case 0: + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, &gUnknown_08D97D0C, 0, 0, 0); + gUnknown_0203CF1C->unk40F0++; + break; + case 1: + if (free_temp_tile_data_buffers_if_possible() != 1) + { + LZDecompressWram(&gUnknown_08D9862C, gUnknown_0203CF1C->unkTilemap0); + gUnknown_0203CF1C->unk40F0++; + } + break; + case 2: + LZDecompressWram(&gUnknown_08D98CC8, gUnknown_0203CF1C->unkTilemap0_1); + gUnknown_0203CF1C->unk40F0++; + break; + case 3: + LZDecompressWram(&gUnknown_08D987FC, gUnknown_0203CF1C->unkTilemap1_1); + gUnknown_0203CF1C->unk40F0++; + break; + case 4: + LZDecompressWram(&gUnknown_08D9898C, gUnknown_0203CF1C->unkTilemap2_1); + gUnknown_0203CF1C->unk40F0++; + break; + case 5: + LZDecompressWram(&gUnknown_08D98B28, gUnknown_0203CF1C->unkTilemap3_1); + gUnknown_0203CF1C->unk40F0++; + break; + case 6: + LoadCompressedPalette(&gUnknown_08D9853C, 0, 0x100); + LoadPalette(&gUnknown_08D85620, 0x81, 0x1E); + gUnknown_0203CF1C->unk40F0++; + break; + case 7: + LoadCompressedObjectPic(&gUnknown_0861CFBC); + gUnknown_0203CF1C->unk40F0++; + break; + case 8: + LoadCompressedObjectPic(&gUnknown_0861D074); + gUnknown_0203CF1C->unk40F0++; + break; + case 9: + LoadCompressedObjectPic(&gUnknown_0861D0F8); + gUnknown_0203CF1C->unk40F0++; + break; + case 10: + LoadCompressedObjectPalette(&gUnknown_0861D100); + gUnknown_0203CF1C->unk40F0++; + break; + case 11: + LoadCompressedObjectPalette(&gUnknown_0861D07C); + gUnknown_0203CF1C->unk40F0++; + break; + case 12: + LoadCompressedPalette(&gUnknown_08D97B84, 0x1D0, 0x60); + gUnknown_0203CF1C->unk40F0 = 0; + return 1; + } + return 0; +} + +void sub_81C0098(struct Pokemon *mon) +{ + if (gUnknown_0203CF1C->unk40BD == 0) + { + struct Pokemon *partyMon = gUnknown_0203CF1C->unk0->mon; + *mon = partyMon[gUnknown_0203CF1C->unk40BE]; + } + else + { + struct BoxPokemon *boxMon = gUnknown_0203CF1C->unk0->boxMon; + sub_8069004(&boxMon[gUnknown_0203CF1C->unk40BE], mon); + } +} + +bool8 sub_81C00F0(struct Pokemon *a) +{ + u32 i; + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + switch (gUnknown_0203CF1C->unk40F0) + { + case 0: + sum->species = GetMonData(a, MON_DATA_SPECIES); + sum->species2 = GetMonData(a, MON_DATA_SPECIES2); + sum->exp = GetMonData(a, MON_DATA_EXP); + sum->level = GetMonData(a, MON_DATA_LEVEL); + sum->altAbility = GetMonData(a, MON_DATA_ALT_ABILITY); + sum->item = GetMonData(a, MON_DATA_HELD_ITEM); + sum->pid = GetMonData(a, MON_DATA_PERSONALITY); + sum->sanity = GetMonData(a, MON_DATA_SANITY_BIT1); + if (sum->sanity != 0) + sum->isEgg = 1; + else + sum->isEgg = GetMonData(a, MON_DATA_IS_EGG); + break; + case 1: + for (i = 0; i < 4; i++) + { + sum->moves[i] = GetMonData(a, MON_DATA_MOVE1+i); + sum->pp[i] = GetMonData(a, MON_DATA_PP1+i); + } + sum->ppBonuses = GetMonData(a, MON_DATA_PP_BONUSES); + break; + case 2: + if ((struct Pokemon*)gUnknown_0203CF1C->unk0 == gPlayerParty || gUnknown_0203CF1C->unk40BC == 2 || gUnknown_0203CF1C->unk40EF == 1) + { + sum->nature = GetNature(a); + sum->currentHP = GetMonData(a, MON_DATA_HP); + sum->maxHP = GetMonData(a, MON_DATA_MAX_HP); + sum->atk = GetMonData(a, MON_DATA_ATK); + sum->def = GetMonData(a, MON_DATA_DEF); + sum->spatk = GetMonData(a, MON_DATA_SPATK); + sum->spdef = GetMonData(a, MON_DATA_SPDEF); + sum->speed = GetMonData(a, MON_DATA_SPEED); + } + else + { + sum->nature = GetNature(a); + sum->currentHP = GetMonData(a, MON_DATA_HP); + sum->maxHP = GetMonData(a, MON_DATA_MAX_HP); + sum->atk = GetMonData(a, MON_DATA_ATK2); + sum->def = GetMonData(a, MON_DATA_DEF2); + sum->spatk = GetMonData(a, MON_DATA_SPATK2); + sum->spdef = GetMonData(a, MON_DATA_SPDEF2); + sum->speed = GetMonData(a, MON_DATA_SPEED2); + } + break; + case 3: + GetMonData(a, MON_DATA_OT_NAME, &sum->OTName); + ConvertInternationalString((u8*)&sum->OTName, GetMonData(a, MON_DATA_LANGUAGE)); + sum->unk7 = sub_81B205C(a); + sum->OTGender = GetMonData(a, MON_DATA_OT_GENDER); + sum->OTID = GetMonData(a, MON_DATA_OT_ID); + sum->metLocation = GetMonData(a, MON_DATA_MET_LOCATION); + sum->metLevel = GetMonData(a, MON_DATA_MET_LEVEL); + sum->metGame = GetMonData(a, MON_DATA_MET_GAME); + sum->friendship = GetMonData(a, MON_DATA_FRIENDSHIP); + break; + default: + sum->ribbons = GetMonData(a, MON_DATA_RIBBON_COUNT); + return TRUE; + } + gUnknown_0203CF1C->unk40F0++; + return FALSE; +} + +void sub_81C0348(void) +{ + if (gUnknown_0203CF1C->unk40C0 != 2 && gUnknown_0203CF1C->unk40C0 != 3) + { + sub_81C1DA4(0, 255); + sub_81C1EFC(0, 255, 0); + } + else + { + sub_81C240C(gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]); + sub_81C2194(&gUnknown_0203CF1C->unkTilemap2[0], 3, 0); + sub_81C2194(&gUnknown_0203CF1C->unkTilemap3[0], 1, 0); + SetBgTilemapBuffer(1, &gUnknown_0203CF1C->unkTilemap3); + SetBgTilemapBuffer(2, &gUnknown_0203CF1C->unkTilemap2); + ChangeBgX(2, 0x10000, 1); + ClearWindowTilemap(0x13); + ClearWindowTilemap(0xD); + } + if (gUnknown_0203CF1C->summary.unk7 == 0) + { + sub_81C2074(0, 0xFF); + } + else + { + if (gUnknown_0203CF1C->unk40C0 != 2 && gUnknown_0203CF1C->unk40C0 != 3) + PutWindowTilemap(0xD); + } + sub_81C2524(); + sub_81C2228(&gUnknown_0203CF1C->currentMon); +} + +void sub_81C0434() +{ + FreeAllWindowBuffers(); + Free(gUnknown_0203CF1C); +} + +void sub_81C044C(u8 taskId) +{ + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gTasks[taskId].func = sub_81C0484; +} + +void sub_81C0484(u8 taskId) +{ + if (sub_81221EC() != 1 && !gPaletteFade.active) + { + SetMainCallback2(gUnknown_0203CF1C->unk4); + gUnknown_0203CF20 = gUnknown_0203CF1C->unk40BE; + sub_81C4898(); + ResetSpriteData(); + FreeAllSpritePalettes(); + StopCryAndClearCrySongs(); + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100); + if (gMonSpritesGfxPtr == 0) + sub_806F47C(0); + sub_81C0434(); + DestroyTask(taskId); + } +} + +void sub_81C0510(u8 taskId) +{ + if (sub_81221EC() != 1 && !gPaletteFade.active) + { + if (gMain.newKeys & DPAD_UP) + { + sub_81C0604(taskId, -1); + } + else if (gMain.newKeys & DPAD_DOWN) + { + sub_81C0604(taskId, 1); + } + else if ((gMain.newKeys & DPAD_LEFT) || GetLRKeysState() == 1) + { + sub_81C0A8C(taskId, -1); + } + else if ((gMain.newKeys & DPAD_RIGHT) || GetLRKeysState() == 2) + { + sub_81C0A8C(taskId, 1); + } + else if (gMain.newKeys & A_BUTTON) + { + if (gUnknown_0203CF1C->unk40C0 != 1) + { + if (gUnknown_0203CF1C->unk40C0 == 0) + { + sub_81C48F0(); + PlaySE(SE_SELECT); + sub_81C044C(taskId); + } + else + { + PlaySE(SE_SELECT); + sub_81C0E48(taskId); + } + } + } + else if (gMain.newKeys & B_BUTTON) + { + sub_81C48F0(); + PlaySE(SE_SELECT); + sub_81C044C(taskId); + } + } +} + +void sub_81C0604(u8 taskId, s8 a) +{ + s8 r4_2; + + if (gUnknown_0203CF1C->unk40C3 == 0) + { + if (gUnknown_0203CF1C->unk40BD == 1) + { + if (gUnknown_0203CF1C->unk40C0 != 0) + { + if (a == 1) + a = 0; + else + a = 2; + } + else + { + if (a == 1) + a = 1; + else + a = 3; + } + r4_2 = sub_80D214C(gUnknown_0203CF1C->unk0, gUnknown_0203CF1C->unk40BE, gUnknown_0203CF1C->unk40BF, a); + } + else if (sub_81B1250() == 1) + { + r4_2 = sub_81C09B4(a); + } + else + { + r4_2 = sub_81C08F8(a); + } + + if (r4_2 != -1) + { + PlaySE(SE_SELECT); + if (gUnknown_0203CF1C->summary.unk7 != 0) + { + sub_81C4204(2, 1); + ClearWindowTilemap(0xD); + schedule_bg_copy_tilemap_to_vram(0); + sub_81C2074(0, 2); + } + gUnknown_0203CF1C->unk40BE = r4_2; + gTasks[taskId].data[0] = 0; + gTasks[taskId].func = sub_81C0704; + } + } +} + +void sub_81C0704(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + switch (data[0]) + { + case 0: + StopCryAndClearCrySongs(); + break; + case 1: + sub_81C4898(); + DestroySpriteAndFreeResources(&gSprites[gUnknown_0203CF1C->unk40D3]); + break; + case 2: + DestroySpriteAndFreeResources(&gSprites[gUnknown_0203CF1C->unk40D4]); + break; + case 3: + sub_81C0098(&gUnknown_0203CF1C->currentMon); + gUnknown_0203CF1C->unk40F0 = 0; + break; + case 4: + if (sub_81C00F0(&gUnknown_0203CF1C->currentMon) == FALSE) + return; + break; + case 5: + sub_81C49E0(&gUnknown_0203CF1C->currentMon); + break; + case 6: + sub_81C4A08(&gUnknown_0203CF1C->currentMon); + break; + case 7: + if (gUnknown_0203CF1C->summary.unk7) + sub_81C2074(10, -2); + sub_81C2228(&gUnknown_0203CF1C->currentMon); + data[1] = 0; + break; + case 8: + gUnknown_0203CF1C->unk40D3 = sub_81C45F4(&gUnknown_0203CF1C->currentMon, &data[1]); + if (gUnknown_0203CF1C->unk40D3 == 0xFF) + return; + gSprites[gUnknown_0203CF1C->unk40D3].data2 = 1; + sub_81C0E24(); + data[1] = 0; + break; + case 9: + sub_81C4280(); + break; + case 10: + sub_81C25E8(); + break; + case 11: + sub_81C2D9C(gUnknown_0203CF1C->unk40C0); + sub_81C2524(); + break; + case 12: + gSprites[gUnknown_0203CF1C->unk40D3].data2 = 0; + break; + default: + if (sub_81221EC() == 0 && FuncIsActiveTask(sub_81C20F0) == 0) + { + data[0] = 0; + gTasks[taskId].func = sub_81C0510; + } + return; + } + data[0]++; +} + +s8 sub_81C08F8(s8 a) +{ + struct Pokemon *mon = gUnknown_0203CF1C->unk0->mon; + + if (gUnknown_0203CF1C->unk40C0 == 0) + { + if (a == -1 && gUnknown_0203CF1C->unk40BE == 0) + return -1; + if (a == 1 && gUnknown_0203CF1C->unk40BE >= gUnknown_0203CF1C->unk40BF) + return -1; + return gUnknown_0203CF1C->unk40BE + a; + } + else + { + s8 index = gUnknown_0203CF1C->unk40BE; + + do + { + index += a; + if (index < 0 || index > gUnknown_0203CF1C->unk40BF) + return -1; + } while (GetMonData(&mon[index], MON_DATA_IS_EGG) != 0); + return index; + } +} + +s8 sub_81C09B4(s8 a) +{ + struct Pokemon *mon = gUnknown_0203CF1C->unk0->mon; + s8 r5 = 0; + u8 i; + + for (i = 0; i < 6; i++) + { + if (gUnknown_0861CC1C[i] == gUnknown_0203CF1C->unk40BE) + { + r5 = i; + break; + } + } + + while (1) + { + int b; + s8* c = &gUnknown_0861CC1C[0]; + + r5 += a; + if (r5 < 0 || r5 >= 6) + return -1; + b = c[r5]; + if (sub_81C0A50(&mon[b]) == TRUE) + return b; + } +} + +bool8 sub_81C0A50(struct Pokemon* mon) +{ + if (GetMonData(mon, MON_DATA_SPECIES) == 0) + return FALSE; + else if (gUnknown_0203CF1C->unk40BE != 0 || GetMonData(mon, MON_DATA_IS_EGG) == 0) + return TRUE; + else + return FALSE; +} + +void sub_81C0A8C(u8 taskId, s8 b) +{ + struct PokeSummary *summary = &gUnknown_0203CF1C->summary; + s16 *data = gTasks[taskId].data; + + if (summary->isEgg) + return; + if (b == -1 && gUnknown_0203CF1C->unk40C0 == gUnknown_0203CF1C->unk40C1) + return; + if (b == 1 && gUnknown_0203CF1C->unk40C0 == gUnknown_0203CF1C->unk40C2) + return; + PlaySE(SE_SELECT); + sub_81C2C38(gUnknown_0203CF1C->unk40C0); + gUnknown_0203CF1C->unk40C0 += b; + data[0] = 0; + if (b == 1) + SetTaskFuncWithFollowupFunc(taskId, sub_81C0B8C, gTasks[taskId].func); + else + SetTaskFuncWithFollowupFunc(taskId, sub_81C0CC4, gTasks[taskId].func); + sub_81C2DE4(gUnknown_0203CF1C->unk40C0); + sub_81C424C(); +} + +void sub_81C0B8C(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (data[0] == 0) + { + if (gUnknown_0203CF1C->unk40C9 == 0) + { + data[1] = 1; + SetBgAttribute(1, 7, 1); + SetBgAttribute(2, 7, 2); + schedule_bg_copy_tilemap_to_vram(1); + } + else + { + data[1] = 2; + SetBgAttribute(2, 7, 1); + SetBgAttribute(1, 7, 2); + schedule_bg_copy_tilemap_to_vram(2); + } + ChangeBgX(data[1], 0, 0); + SetBgTilemapBuffer(data[1], (u8*)gUnknown_0203CF1C + ((gUnknown_0203CF1C->unk40C0 << 12) + 0xBC)); + ShowBg(1); + ShowBg(2); + } + ChangeBgX(data[1], 0x2000, 1); + data[0] += 32; + if (data[0] > 0xFF) + gTasks[taskId].func = sub_81C0C68; +} + +void sub_81C0C68(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + gUnknown_0203CF1C->unk40C9 ^= 1; + data[1] = 0; + data[0] = 0; + sub_81C1BA0(); + sub_81C2AFC(gUnknown_0203CF1C->unk40C0); + sub_81C4280(); + sub_81C0E24(); + SwitchTaskToFollowupFunc(taskId); +} + +void sub_81C0CC4(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (data[0] == 0) + { + if (gUnknown_0203CF1C->unk40C9 == 0) + data[1] = 2; + else + data[1] = 1; + ChangeBgX(data[1], 0x10000, 0); + } + ChangeBgX(data[1], 0x2000, 2); + data[0] += 32; + if (data[0] > 0xFF) + gTasks[taskId].func = sub_81C0D44; +} + +void sub_81C0D44(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (gUnknown_0203CF1C->unk40C9 == 0) + { + SetBgAttribute(1, 7, 1); + SetBgAttribute(2, 7, 2); + schedule_bg_copy_tilemap_to_vram(2); + } + else + { + SetBgAttribute(2, 7, 1); + SetBgAttribute(1, 7, 2); + schedule_bg_copy_tilemap_to_vram(1); + } + if (gUnknown_0203CF1C->unk40C0 > 1) + { + SetBgTilemapBuffer(data[1], (u8*)gUnknown_0203CF1C + ((gUnknown_0203CF1C->unk40C0 << 12) + 0xFFFFF0BC)); + ChangeBgX(data[1], 0x10000, 0); + } + ShowBg(1); + ShowBg(2); + gUnknown_0203CF1C->unk40C9 ^= 1; + data[1] = 0; + data[0] = 0; + sub_81C1BA0(); + sub_81C2AFC(gUnknown_0203CF1C->unk40C0); + sub_81C4280(); + sub_81C0E24(); + SwitchTaskToFollowupFunc(taskId); +} + +void sub_81C0E24() +{ + if (gUnknown_0203CF1C->unk40C0 == 1) + sub_81C22CC(&gUnknown_0203CF1C->currentMon); +} + +void sub_81C0E48(u8 taskId) +{ + u16 move; + gUnknown_0203CF1C->unk40C6 = 0; + move = gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]; + ClearWindowTilemap(0x13); + if (gSprites[gUnknown_0203CF1C->unk40D5].invisible == 0) + ClearWindowTilemap(0xD); + sub_81C1DA4(9, -3); + sub_81C1EFC(9, -3, move); + if (gUnknown_0203CF1C->unk40C8 == 0) + { + ClearWindowTilemap(5); + PutWindowTilemap(6); + } + sub_81C2194(&gUnknown_0203CF1C->unkTilemap2[0], 3, 0); + sub_81C2194(&gUnknown_0203CF1C->unkTilemap3[0], 1, 0); + sub_81C3E9C(move); + sub_81C3F44(); + sub_81C44F0(); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + sub_81C4AF8(8); + gTasks[taskId].func = sub_81C0F44; +} + +void sub_81C0F44(u8 taskId) +{ + u8 id = taskId; + s16 *data = gTasks[taskId].data; + + if (sub_81221EC() != 1) + { + if (gMain.newKeys & DPAD_UP) + { + data[0] = 4; + sub_81C1070(data, -1, &gUnknown_0203CF1C->unk40C6); + } + else if (gMain.newKeys & DPAD_DOWN) + { + data[0] = 4; + sub_81C1070(data, 1, &gUnknown_0203CF1C->unk40C6); + } + else if (gMain.newKeys & A_BUTTON) + { + if (gUnknown_0203CF1C->unk40C8 == 1 + || (gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + { + PlaySE(SE_SELECT); + sub_81C11F4(taskId); + } + else if (sub_81C1040() == TRUE) + { + PlaySE(SE_SELECT); + sub_81C129C(taskId); + } + else + { + PlaySE(SE_HAZURE); + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + sub_81C11F4(id); + } + } +} + +bool8 sub_81C1040(void) +{ + u8 i; + for (i = 1; i < 4; i++) + { + if (gUnknown_0203CF1C->summary.moves[i] != 0) + return TRUE; + } + return FALSE; +} + +void sub_81C1070(s16 *a, s8 b, u8 *c) +{ + s8 i; + s8 moveIndex; + u16 move; + + PlaySE(SE_SELECT); + moveIndex = *c; + for (i = 0; i < 4; i++) + { + moveIndex += b; + if (moveIndex > a[0]) + moveIndex = 0; + else if (moveIndex < 0) + moveIndex = a[0]; + if (moveIndex == 4) + { + move = gUnknown_0203CF1C->unk40C4; + break; + } + move = gUnknown_0203CF1C->summary.moves[moveIndex]; + if (move != 0) + break; + } + sub_81C240C(move); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + sub_81C3E9C(move); + if ((*c == 4 && gUnknown_0203CF1C->unk40C4 == 0) || a[1] == 1) + { + ClearWindowTilemap(19); + if (!gSprites[gUnknown_0203CF1C->unk40D5].invisible) + ClearWindowTilemap(13); + schedule_bg_copy_tilemap_to_vram(0); + sub_81C1DA4(9, -3); + sub_81C1EFC(9, -3, move); + } + if (*c != 4 && moveIndex == 4 && gUnknown_0203CF1C->unk40C4 == 0) + { + ClearWindowTilemap(14); + ClearWindowTilemap(15); + schedule_bg_copy_tilemap_to_vram(0); + sub_81C1DA4(0, 3); + sub_81C1EFC(0, 3, 0); + } + *c = moveIndex; + if (c == &gUnknown_0203CF1C->unk40C6) + sub_81C4D18(8); + else + sub_81C4D18(18); +} + +void sub_81C11F4(u8 taskId) +{ + sub_81C4C60(8); + ClearWindowTilemap(6); + PutWindowTilemap(5); + sub_81C3E9C(0); + sub_81C2194(&gUnknown_0203CF1C->unkTilemap2[0], 3, 1); + sub_81C2194(&gUnknown_0203CF1C->unkTilemap3[0], 1, 1); + sub_81C4064(); + if (gUnknown_0203CF1C->unk40C6 != 4) + { + ClearWindowTilemap(14); + ClearWindowTilemap(15); + sub_81C1DA4(0, 3); + sub_81C1EFC(0, 3, 0); + } + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + gTasks[taskId].func = sub_81C0510; +} + +void sub_81C129C(u8 taskId) +{ + gUnknown_0203CF1C->unk40C7 = gUnknown_0203CF1C->unk40C6; + sub_81C4C84(1); + sub_81C4AF8(18); + gTasks[taskId].func = sub_81C12E4; +} + +void sub_81C12E4(u8 taskId) +{ + u8 a = taskId; + s16* data = gTasks[taskId].data; + if (sub_81221EC() != 1) + { + if (gMain.newKeys & DPAD_UP) + { + data[0] = 3; + sub_81C1070(&data[0], -1, &gUnknown_0203CF1C->unk40C7); + } + else if (gMain.newKeys & DPAD_DOWN) + { + data[0] = 3; + sub_81C1070(&data[0], 1, &gUnknown_0203CF1C->unk40C7); + } + else if (gMain.newKeys & A_BUTTON) + { + if (gUnknown_0203CF1C->unk40C6 == gUnknown_0203CF1C->unk40C7) + { + sub_81C13B0(taskId, 0); + } + else + sub_81C13B0(taskId, 1); + } + else if (gMain.newKeys & B_BUTTON) + sub_81C13B0(a, 0); + } +} + +void sub_81C13B0(u8 taskId, u8 b) +{ + u16 move; + PlaySE(SE_SELECT); + sub_81C4C84(0); + sub_81C4C60(18); + if (b == 1) + { + if (gUnknown_0203CF1C->unk40BD == 0) + { + struct Pokemon *why = gUnknown_0203CF1C->unk0->mon; + sub_81C14BC(&why[gUnknown_0203CF1C->unk40BE], gUnknown_0203CF1C->unk40C6, gUnknown_0203CF1C->unk40C7); + } + else + { + struct BoxPokemon *why = gUnknown_0203CF1C->unk0->boxMon; + sub_81C15EC(&why[gUnknown_0203CF1C->unk40BE], gUnknown_0203CF1C->unk40C6, gUnknown_0203CF1C->unk40C7); + } + sub_81C0098(&gUnknown_0203CF1C->currentMon); + sub_81C40A0(gUnknown_0203CF1C->unk40C6, gUnknown_0203CF1C->unk40C7); + sub_81C4568(gUnknown_0203CF1C->unk40C6, gUnknown_0203CF1C->unk40C7); + gUnknown_0203CF1C->unk40C6 = gUnknown_0203CF1C->unk40C7; + } + move = gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]; + sub_81C3E9C(move); + sub_81C240C(move); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + gTasks[taskId].func = sub_81C0F44; +} + + +#ifdef NONMATCHING +void sub_81C14BC(struct Pokemon *mon, u8 swappingFromId, u8 swappingToId) +{ + u16 localMoveTo; + u16 localMoveFrom; + u8 localPpTo; + u8 localPpFrom; + u8 localPpBonuses; + u16* moveFromPtr; + u16* moveToPtr; + u8* ppFromPtr; + u8* ppToPtr; + u8* ppBonusesPtr; + + moveFromPtr = &gUnknown_0203CF1C->summary.moves[swappingFromId]; + localMoveFrom = *moveFromPtr; + + moveToPtr = &gUnknown_0203CF1C->summary.moves[swappingToId]; + localMoveTo = *moveToPtr; + + ppFromPtr = &gUnknown_0203CF1C->summary.pp[swappingFromId]; + localPpFrom = *ppFromPtr; + + ppToPtr = &gUnknown_0203CF1C->summary.pp[swappingToId]; + localPpTo = *ppToPtr; + + ppBonusesPtr = &gUnknown_0203CF1C->summary.ppBonuses; + localPpBonuses = *ppBonusesPtr; + +{ + u8 bitsFrom, bitsTo; + + bitsFrom = (localPpBonuses & gUnknown_08329D22[swappingFromId]) >> (swappingFromId << 1); + bitsTo = (localPpBonuses & gUnknown_08329D22[swappingToId]) >> (swappingToId << 1); + + + localPpBonuses &= ~(gUnknown_08329D22[swappingFromId]); + localPpBonuses &= ~(gUnknown_08329D22[swappingToId]); + + localPpBonuses |= ((bitsFrom << (swappingToId << 1)) + (bitsTo << (swappingToId << 1))); +} + + SetMonData(mon, swappingFromId + MON_DATA_MOVE1, &localMoveTo); + SetMonData(mon, swappingToId + MON_DATA_MOVE1, &localMoveFrom); + + SetMonData(mon, swappingFromId + MON_DATA_PP1, &localPpTo); + SetMonData(mon, swappingToId + MON_DATA_PP1, &localPpFrom); + + SetMonData(mon, MON_DATA_PP_BONUSES, &localPpBonuses); + + *moveFromPtr = localMoveTo; + *moveToPtr = localMoveFrom; + + *ppFromPtr = localPpTo; + *ppToPtr = localPpFrom; + + *ppBonusesPtr = localPpBonuses; +} +#else +__attribute__((naked)) +void sub_81C14BC(struct Pokemon *mon, u8 swappingFromId, u8 swappingToId) +{ + 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, 0x28\n\ + adds r7, r0, 0\n\ + adds r4, r1, 0\n\ + adds r6, r2, 0\n\ + lsls r4, 24\n\ + lsrs r4, 24\n\ + lsls r6, 24\n\ + lsrs r6, 24\n\ + ldr r0, =gUnknown_0203CF1C\n\ + ldr r2, [r0]\n\ + lsls r0, r4, 1\n\ + mov r10, r0\n\ + adds r1, r2, 0\n\ + adds r1, 0x84\n\ + adds r0, r1, r0\n\ + str r0, [sp, 0x8]\n\ + ldrh r0, [r0]\n\ + mov r3, sp\n\ + adds r3, 0x2\n\ + str r3, [sp, 0x1C]\n\ + strh r0, [r3]\n\ + lsls r0, r6, 1\n\ + mov r9, r0\n\ + add r1, r9\n\ + str r1, [sp, 0xC]\n\ + ldrh r1, [r1]\n\ + mov r0, sp\n\ + strh r1, [r0]\n\ + adds r1, r2, 0\n\ + adds r1, 0x8C\n\ + adds r3, r1, r4\n\ + str r3, [sp, 0x10]\n\ + ldrb r0, [r3]\n\ + mov r3, sp\n\ + adds r3, 0x5\n\ + str r3, [sp, 0x24]\n\ + strb r0, [r3]\n\ + adds r1, r6\n\ + str r1, [sp, 0x14]\n\ + ldrb r0, [r1]\n\ + mov r1, sp\n\ + adds r1, 0x4\n\ + str r1, [sp, 0x20]\n\ + strb r0, [r1]\n\ + adds r2, 0xA4\n\ + str r2, [sp, 0x18]\n\ + ldrb r0, [r2]\n\ + mov r5, sp\n\ + adds r5, 0x6\n\ + strb r0, [r5]\n\ + ldr r1, =gUnknown_08329D22\n\ + adds r0, r4, r1\n\ + ldrb r0, [r0]\n\ + mov r8, r0\n\ + ldrb r0, [r5]\n\ + adds r2, r0, 0\n\ + mov r3, r8\n\ + ands r2, r3\n\ + mov r3, r10\n\ + asrs r2, r3\n\ + lsls r2, 24\n\ + lsrs r2, 24\n\ + adds r1, r6, r1\n\ + ldrb r1, [r1]\n\ + mov r12, r1\n\ + adds r1, r0, 0\n\ + mov r3, r12\n\ + ands r1, r3\n\ + mov r3, r9\n\ + asrs r1, r3\n\ + lsls r1, 24\n\ + lsrs r1, 24\n\ + mov r3, r8\n\ + bics r0, r3\n\ + strb r0, [r5]\n\ + ldrb r0, [r5]\n\ + mov r3, r12\n\ + bics r0, r3\n\ + strb r0, [r5]\n\ + mov r0, r9\n\ + lsls r2, r0\n\ + mov r3, r10\n\ + lsls r1, r3\n\ + adds r2, r1\n\ + ldrb r0, [r5]\n\ + orrs r0, r2\n\ + strb r0, [r5]\n\ + adds r1, r4, 0\n\ + adds r1, 0xD\n\ + adds r0, r7, 0\n\ + mov r2, sp\n\ + bl SetMonData\n\ + adds r1, r6, 0\n\ + adds r1, 0xD\n\ + adds r0, r7, 0\n\ + ldr r2, [sp, 0x1C]\n\ + bl SetMonData\n\ + adds r4, 0x11\n\ + adds r0, r7, 0\n\ + adds r1, r4, 0\n\ + ldr r2, [sp, 0x20]\n\ + bl SetMonData\n\ + adds r6, 0x11\n\ + adds r0, r7, 0\n\ + adds r1, r6, 0\n\ + ldr r2, [sp, 0x24]\n\ + bl SetMonData\n\ + adds r0, r7, 0\n\ + movs r1, 0x15\n\ + adds r2, r5, 0\n\ + bl SetMonData\n\ + mov r0, sp\n\ + ldrh r0, [r0]\n\ + ldr r1, [sp, 0x8]\n\ + strh r0, [r1]\n\ + ldr r3, [sp, 0x1C]\n\ + ldrh r0, [r3]\n\ + ldr r1, [sp, 0xC]\n\ + strh r0, [r1]\n\ + ldr r3, [sp, 0x20]\n\ + ldrb r0, [r3]\n\ + ldr r1, [sp, 0x10]\n\ + strb r0, [r1]\n\ + ldr r3, [sp, 0x24]\n\ + ldrb r0, [r3]\n\ + ldr r1, [sp, 0x14]\n\ + strb r0, [r1]\n\ + ldrb r0, [r5]\n\ + ldr r3, [sp, 0x18]\n\ + strb r0, [r3]\n\ + add sp, 0x28\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\ + .pool\n\ + .syntax divided\n"); +} +#endif + +#ifdef NONMATCHING +void sub_81C15EC(struct BoxPokemon *mon, u8 swappingFromId, u8 swappingToId) +{ + u16 localMoveTo; + u16 localMoveFrom; + u8 localPpTo; + u8 localPpFrom; + u8 localPpBonuses; + u16* moveFromPtr; + u16* moveToPtr; + u8* ppFromPtr; + u8* ppToPtr; + u8* ppBonusesPtr; + + moveFromPtr = &gUnknown_0203CF1C->summary.moves[swappingFromId]; + localMoveFrom = *moveFromPtr; + + moveToPtr = &gUnknown_0203CF1C->summary.moves[swappingToId]; + localMoveTo = *moveToPtr; + + ppFromPtr = &gUnknown_0203CF1C->summary.pp[swappingFromId]; + localPpFrom = *ppFromPtr; + + ppToPtr = &gUnknown_0203CF1C->summary.pp[swappingToId]; + localPpTo = *ppToPtr; + + ppBonusesPtr = &gUnknown_0203CF1C->summary.ppBonuses; + localPpBonuses = *ppBonusesPtr; + +{ + u8 bitsFrom, bitsTo; + + bitsFrom = (localPpBonuses & gUnknown_08329D22[swappingFromId]) >> (swappingFromId << 1); + bitsTo = (localPpBonuses & gUnknown_08329D22[swappingToId]) >> (swappingToId << 1); + + + localPpBonuses &= ~(gUnknown_08329D22[swappingFromId]); + localPpBonuses &= ~(gUnknown_08329D22[swappingToId]); + + localPpBonuses |= ((bitsFrom << (swappingToId << 1)) + (bitsTo << (swappingToId << 1))); +} + + SetBoxMonData(mon, swappingFromId + MON_DATA_MOVE1, &localMoveTo); + SetBoxMonData(mon, swappingToId + MON_DATA_MOVE1, &localMoveFrom); + + SetBoxMonData(mon, swappingFromId + MON_DATA_PP1, &localPpTo); + SetBoxMonData(mon, swappingToId + MON_DATA_PP1, &localPpFrom); + + SetBoxMonData(mon, MON_DATA_PP_BONUSES, &localPpBonuses); + + *moveFromPtr = localMoveTo; + *moveToPtr = localMoveFrom; + + *ppFromPtr = localPpTo; + *ppToPtr = localPpFrom; + + *ppBonusesPtr = localPpBonuses; +} +#else +__attribute__((naked)) +void sub_81C15EC(struct BoxPokemon *mon, u8 swappingFromId, u8 swappingToId) +{ + 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, 0x28\n\ + adds r7, r0, 0\n\ + adds r4, r1, 0\n\ + adds r6, r2, 0\n\ + lsls r4, 24\n\ + lsrs r4, 24\n\ + lsls r6, 24\n\ + lsrs r6, 24\n\ + ldr r0, =gUnknown_0203CF1C\n\ + ldr r2, [r0]\n\ + lsls r0, r4, 1\n\ + mov r10, r0\n\ + adds r1, r2, 0\n\ + adds r1, 0x84\n\ + adds r0, r1, r0\n\ + str r0, [sp, 0x8]\n\ + ldrh r0, [r0]\n\ + mov r3, sp\n\ + adds r3, 0x2\n\ + str r3, [sp, 0x1C]\n\ + strh r0, [r3]\n\ + lsls r0, r6, 1\n\ + mov r9, r0\n\ + add r1, r9\n\ + str r1, [sp, 0xC]\n\ + ldrh r1, [r1]\n\ + mov r0, sp\n\ + strh r1, [r0]\n\ + adds r1, r2, 0\n\ + adds r1, 0x8C\n\ + adds r3, r1, r4\n\ + str r3, [sp, 0x10]\n\ + ldrb r0, [r3]\n\ + mov r3, sp\n\ + adds r3, 0x5\n\ + str r3, [sp, 0x24]\n\ + strb r0, [r3]\n\ + adds r1, r6\n\ + str r1, [sp, 0x14]\n\ + ldrb r0, [r1]\n\ + mov r1, sp\n\ + adds r1, 0x4\n\ + str r1, [sp, 0x20]\n\ + strb r0, [r1]\n\ + adds r2, 0xA4\n\ + str r2, [sp, 0x18]\n\ + ldrb r0, [r2]\n\ + mov r5, sp\n\ + adds r5, 0x6\n\ + strb r0, [r5]\n\ + ldr r1, =gUnknown_08329D22\n\ + adds r0, r4, r1\n\ + ldrb r0, [r0]\n\ + mov r8, r0\n\ + ldrb r0, [r5]\n\ + adds r2, r0, 0\n\ + mov r3, r8\n\ + ands r2, r3\n\ + mov r3, r10\n\ + asrs r2, r3\n\ + lsls r2, 24\n\ + lsrs r2, 24\n\ + adds r1, r6, r1\n\ + ldrb r1, [r1]\n\ + mov r12, r1\n\ + adds r1, r0, 0\n\ + mov r3, r12\n\ + ands r1, r3\n\ + mov r3, r9\n\ + asrs r1, r3\n\ + lsls r1, 24\n\ + lsrs r1, 24\n\ + mov r3, r8\n\ + bics r0, r3\n\ + strb r0, [r5]\n\ + ldrb r0, [r5]\n\ + mov r3, r12\n\ + bics r0, r3\n\ + strb r0, [r5]\n\ + mov r0, r9\n\ + lsls r2, r0\n\ + mov r3, r10\n\ + lsls r1, r3\n\ + adds r2, r1\n\ + ldrb r0, [r5]\n\ + orrs r0, r2\n\ + strb r0, [r5]\n\ + adds r1, r4, 0\n\ + adds r1, 0xD\n\ + adds r0, r7, 0\n\ + mov r2, sp\n\ + bl SetBoxMonData\n\ + adds r1, r6, 0\n\ + adds r1, 0xD\n\ + adds r0, r7, 0\n\ + ldr r2, [sp, 0x1C]\n\ + bl SetBoxMonData\n\ + adds r4, 0x11\n\ + adds r0, r7, 0\n\ + adds r1, r4, 0\n\ + ldr r2, [sp, 0x20]\n\ + bl SetBoxMonData\n\ + adds r6, 0x11\n\ + adds r0, r7, 0\n\ + adds r1, r6, 0\n\ + ldr r2, [sp, 0x24]\n\ + bl SetBoxMonData\n\ + adds r0, r7, 0\n\ + movs r1, 0x15\n\ + adds r2, r5, 0\n\ + bl SetBoxMonData\n\ + mov r0, sp\n\ + ldrh r0, [r0]\n\ + ldr r1, [sp, 0x8]\n\ + strh r0, [r1]\n\ + ldr r3, [sp, 0x1C]\n\ + ldrh r0, [r3]\n\ + ldr r1, [sp, 0xC]\n\ + strh r0, [r1]\n\ + ldr r3, [sp, 0x20]\n\ + ldrb r0, [r3]\n\ + ldr r1, [sp, 0x10]\n\ + strb r0, [r1]\n\ + ldr r3, [sp, 0x24]\n\ + ldrb r0, [r3]\n\ + ldr r1, [sp, 0x14]\n\ + strb r0, [r1]\n\ + ldrb r0, [r5]\n\ + ldr r3, [sp, 0x18]\n\ + strb r0, [r3]\n\ + add sp, 0x28\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\ + .pool\n\ + .syntax divided\n"); +} +#endif + +void sub_81C171C(u8 taskId) +{ + sub_81C44F0(); + sub_81C4AF8(8); + gTasks[taskId].func = sub_81C174C; +} + +void sub_81C174C(u8 taskId) +{ + s16* data = gTasks[taskId].data; + + if (sub_81221EC() != 1) + { + if (gPaletteFade.active != 1) + { + if (gMain.newKeys & DPAD_UP) + { + data[0] = 4; + sub_81C1070(data, -1, &gUnknown_0203CF1C->unk40C6); + } + else if (gMain.newKeys & DPAD_DOWN) + { + data[0] = 4; + sub_81C1070(data, 1, &gUnknown_0203CF1C->unk40C6); + } + else if (gMain.newKeys & DPAD_LEFT || GetLRKeysState() == 1) + { + sub_81C0A8C(taskId, -1); + } + else if (gMain.newKeys & DPAD_RIGHT || GetLRKeysState() == 2) + { + sub_81C0A8C(taskId, 1); + } + else if (gMain.newKeys & A_BUTTON) + { + if (sub_81C18A8() == TRUE) + { + sub_81C48F0(); + PlaySE(SE_SELECT); + gUnknown_0203CF21 = gUnknown_0203CF1C->unk40C6; + gSpecialVar_0x8005 = gUnknown_0203CF21; + sub_81C044C(taskId); + } + else + { + PlaySE(0x20); + sub_81C18F4(taskId); + } + } + else if (gMain.newKeys & B_BUTTON) + { + u32 var1; + sub_81C48F0(); + PlaySE(SE_SELECT); + gUnknown_0203CF21 = 4; + gSpecialVar_0x8005 = 4; + sub_81C044C(taskId); + } + } + } +} + +bool8 sub_81C18A8() +{ + if (gUnknown_0203CF1C->unk40C6 == 4 || gUnknown_0203CF1C->unk40C4 == 0 || sub_81B6D14(gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]) != 1) + return TRUE; + else + return FALSE; +} + +void sub_81C18F4(u8 taskId) +{ + ClearWindowTilemap(14); + ClearWindowTilemap(15); + schedule_bg_copy_tilemap_to_vram(0); + sub_81C1DA4(0, 3); + sub_81C1EFC(0, 3, 0); + sub_81C4154(); + gTasks[taskId].func = sub_81C1940; +} + +void sub_81C1940(u8 taskId) +{ + s16* data = gTasks[taskId].data; + u16 move; + if (FuncIsActiveTask(sub_81C1E20) != 1) + { + if (gMain.newKeys & DPAD_UP) + { + data[1] = 1; + data[0] = 4; + sub_81C1070(&data[0], -1, &gUnknown_0203CF1C->unk40C6); + data[1] = 0; + gTasks[taskId].func = sub_81C174C; + } + else if (gMain.newKeys & DPAD_DOWN) + { + data[1] = 1; + data[0] = 4; + sub_81C1070(&data[0], 1, &gUnknown_0203CF1C->unk40C6); + data[1] = 0; + gTasks[taskId].func = sub_81C174C; + } + else if (gMain.newKeys & DPAD_LEFT || GetLRKeysState() == 1) + { + if (gUnknown_0203CF1C->unk40C0 != 2) + { + + ClearWindowTilemap(19); + if (!gSprites[gUnknown_0203CF1C->unk40D5].invisible) + ClearWindowTilemap(13); + move = gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]; + gTasks[taskId].func = sub_81C174C; + sub_81C0A8C(taskId, -1); + sub_81C1DA4(9, -2); + sub_81C1EFC(9, -2, move); + } + } + else if (gMain.newKeys & DPAD_RIGHT || GetLRKeysState() == 2) + { + if (gUnknown_0203CF1C->unk40C0 != 3) + { + ClearWindowTilemap(19); + if (!gSprites[gUnknown_0203CF1C->unk40D5].invisible) + ClearWindowTilemap(13); + move = gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]; + gTasks[taskId].func = sub_81C174C; + sub_81C0A8C(taskId, 1); + sub_81C1DA4(9, -2); + sub_81C1EFC(9, -2, move); + } + } + else if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + ClearWindowTilemap(19); + if (!gSprites[gUnknown_0203CF1C->unk40D5].invisible) + ClearWindowTilemap(13); + move = gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]; + sub_81C3E9C(move); + schedule_bg_copy_tilemap_to_vram(0); + sub_81C1DA4(9, -3); + sub_81C1EFC(9, -3, move); + gTasks[taskId].func = sub_81C174C; + } + } +} + +u8 sub_81C1B94() +{ + return gUnknown_0203CF21; +} + +void sub_81C1BA0() +{ + u16 *alloced = Alloc(32); + u8 i; + for (i = 0; i < 4; i++) + { + u8 j = i << 1; + if (i < gUnknown_0203CF1C->unk40C1) + { + alloced[j+0] = 0x40; + alloced[j+1] = 0x40; + alloced[j+8] = 0x50; + alloced[j+9] = 0x50; + } + else if (i > gUnknown_0203CF1C->unk40C2) + { + alloced[j+0] = 0x4A; + alloced[j+1] = 0x4A; + alloced[j+8] = 0x5A; + alloced[j+9] = 0x5A; + } + else if (i < gUnknown_0203CF1C->unk40C0) + { + alloced[j+0] = 0x46; + alloced[j+1] = 0x47; + alloced[j+8] = 0x56; + alloced[j+9] = 0x57; + } + else if (i == gUnknown_0203CF1C->unk40C0) + { + if (i != gUnknown_0203CF1C->unk40C2) + { + alloced[j+0] = 0x41; + alloced[j+1] = 0x42; + alloced[j+8] = 0x51; + alloced[j+9] = 0x52; + } + else + { + alloced[j+0] = 0x4B; + alloced[j+1] = 0x4C; + alloced[j+8] = 0x5B; + alloced[j+9] = 0x5C; + } + } + else if (i != gUnknown_0203CF1C->unk40C2) + { + alloced[j+0] = 0x43; + alloced[j+1] = 0x44; + alloced[j+8] = 0x53; + alloced[j+9] = 0x54; + } + else + { + alloced[j+0] = 0x48; + alloced[j+1] = 0x49; + alloced[j+8] = 0x58; + alloced[j+9] = 0x59; + } + } + CopyToBgTilemapBufferRect_ChangePalette(3, alloced, 11, 0, 8, 2, 16); + schedule_bg_copy_tilemap_to_vram(3); + Free(alloced); +} + +struct UnkStruct_61CC04 +{ + u8 *ptr; + u8 field_4; + u8 field_5; + u8 field_6; + u8 field_7; + u8 field_8; + u8 field_9; +}; + +#ifdef NONMATCHING +void sub_81C1CB0(struct UnkStruct_61CC04 *a, u16 *b, u8 c, u8 d) +{ + u8 *alloced = Alloc(a->field_6 * (a->field_7 << 1)); + CpuFill16(a->field_4, alloced, a->field_7*a->field_6); + if (a->field_6 != c) + { + if (!d) + { + for (d;d < a->field_7; d++) + { + CpuCopy16(&a->ptr + ((c + a->field_6*d)), alloced + ((a->field_6*d) << 1), (a->field_6 - c) * 2); + } + } + else + { + for (d = 0;d < a->field_7; d++) + { + CpuCopy16(&a->ptr + (a->field_6*d), alloced + ((c + a->field_6*d) << 1), (a->field_6 - c) * 2); + } + } + } + d = 0; + while (d < a->field_7) + { + CpuCopy16(alloced + ((a->field_6*d) << 1), b + ((((a->field_9 + d) << 5) + a->field_8) << 1), a->field_6 * 2); + d++; + } + Free(alloced); +} +#else +__attribute__((naked)) +void sub_81C1CB0(struct UnkStruct_61CC04 *a, u16 *b, u8 c, u8 d) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + sub sp, 0x4\n\ + adds r4, r0, 0\n\ + mov r8, r1\n\ + lsls r2, 24\n\ + lsrs r6, r2, 24\n\ + lsls r3, 24\n\ + lsrs r5, r3, 24\n\ + ldrb r1, [r4, 0x6]\n\ + ldrb r0, [r4, 0x7]\n\ + lsls r0, 1\n\ + muls r0, r1\n\ + bl Alloc\n\ + adds r7, r0, 0\n\ + mov r1, sp\n\ + ldrh r0, [r4, 0x4]\n\ + strh r0, [r1]\n\ + ldrb r1, [r4, 0x7]\n\ + ldrb r0, [r4, 0x6]\n\ + adds r2, r1, 0\n\ + muls r2, r0\n\ + movs r0, 0x80\n\ + lsls r0, 17\n\ + orrs r2, r0\n\ + mov r0, sp\n\ + adds r1, r7, 0\n\ + bl CpuSet\n\ + ldrb r0, [r4, 0x6]\n\ + cmp r0, r6\n\ + beq _081C1D60\n\ + cmp r5, 0\n\ + bne _081C1D30\n\ + movs r5, 0\n\ + ldrb r0, [r4, 0x7]\n\ + cmp r5, r0\n\ + bcs _081C1D60\n\ +_081C1D00:\n\ + ldrb r2, [r4, 0x6]\n\ + adds r1, r2, 0\n\ + muls r1, r5\n\ + adds r3, r6, r1\n\ + lsls r3, 1\n\ + ldr r0, [r4]\n\ + adds r0, r3\n\ + lsls r1, 1\n\ + adds r1, r7, r1\n\ + subs r2, r6\n\ + ldr r3, =0x001fffff\n\ + ands r2, r3\n\ + bl CpuSet\n\ + adds r0, r5, 0x1\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ + ldrb r3, [r4, 0x7]\n\ + cmp r5, r3\n\ + bcc _081C1D00\n\ + b _081C1D60\n\ + .pool\n\ +_081C1D30:\n\ + movs r5, 0\n\ + ldrb r0, [r4, 0x7]\n\ + cmp r5, r0\n\ + bcs _081C1D60\n\ +_081C1D38:\n\ + ldrb r2, [r4, 0x6]\n\ + adds r1, r2, 0\n\ + muls r1, r5\n\ + lsls r3, r1, 1\n\ + ldr r0, [r4]\n\ + adds r0, r3\n\ + adds r1, r6, r1\n\ + lsls r1, 1\n\ + adds r1, r7, r1\n\ + subs r2, r6\n\ + ldr r3, =0x001fffff\n\ + ands r2, r3\n\ + bl CpuSet\n\ + adds r0, r5, 0x1\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ + ldrb r3, [r4, 0x7]\n\ + cmp r5, r3\n\ + bcc _081C1D38\n\ +_081C1D60:\n\ + movs r5, 0\n\ + b _081C1D8A\n\ + .pool\n\ +_081C1D68:\n\ + ldrb r2, [r4, 0x6]\n\ + adds r0, r2, 0\n\ + muls r0, r5\n\ + lsls r0, 1\n\ + adds r0, r7, r0\n\ + ldrb r1, [r4, 0x9]\n\ + adds r1, r5\n\ + lsls r1, 5\n\ + ldrb r3, [r4, 0x8]\n\ + adds r1, r3\n\ + lsls r1, 1\n\ + add r1, r8\n\ + bl CpuSet\n\ + adds r0, r5, 0x1\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ +_081C1D8A:\n\ + ldrb r0, [r4, 0x7]\n\ + cmp r5, r0\n\ + bcc _081C1D68\n\ + adds r0, r7, 0\n\ + bl Free\n\ + add sp, 0x4\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .syntax divided\n"); +} +#endif + +void sub_81C1DA4(u16 a, s16 b) +{ + if (b > gUnknown_0861CC04.field_6) + b = gUnknown_0861CC04.field_6; + if (b == 0 || b == gUnknown_0861CC04.field_6) + { + sub_81C1CB0(&gUnknown_0861CC04, &gUnknown_0203CF1C->unkTilemap2[0], b, 1); + } + else + { + u8 taskId = FindTaskIdByFunc(sub_81C1E20); + if (taskId == 0xFF) + { + taskId = CreateTask(sub_81C1E20, 8); + } + gTasks[taskId].data[0] = b; + gTasks[taskId].data[1] = a; + } +} + +void sub_81C1E20(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + data[1] += data[0]; + if (data[1] < 0) + { + data[1] = 0; + } + else if (data[1] > gUnknown_0861CC04.field_6) + { + data[1] = gUnknown_0861CC04.field_6; + } + sub_81C1CB0(&gUnknown_0861CC04, &gUnknown_0203CF1C->unkTilemap2[0], data[1], 1); + if (data[1] <= 0 || data[1] >= gUnknown_0861CC04.field_6) + { + if (data[0] < 0) + { + if (gUnknown_0203CF1C->unk40C0 == 2) + PutWindowTilemap(14); + + } + else + { + if (!gSprites[gUnknown_0203CF1C->unk40D5].invisible) + PutWindowTilemap(13); + PutWindowTilemap(19); + } + schedule_bg_copy_tilemap_to_vram(0); + DestroyTask(taskId); + } + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); +} + +void sub_81C1EFC(u16 a, s16 b, u16 move) +{ + if (b > gUnknown_0861CC10.field_6) + b = gUnknown_0861CC10.field_6; + if (b == 0 || b == gUnknown_0861CC10.field_6) + sub_81C1CB0(&gUnknown_0861CC10, &gUnknown_0203CF1C->unkTilemap3[0], b, 1); + else + { + u8 taskId = FindTaskIdByFunc(sub_81C1F80); + if (taskId == 0xFF) + taskId = CreateTask(sub_81C1F80, 8); + gTasks[taskId].data[0] = b; + gTasks[taskId].data[1] = a; + gTasks[taskId].data[2] = move; + } +} + +void sub_81C1F80(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + data[1] += data[0]; + if (data[1] < 0) + { + data[1] = 0; + } + else if (data[1] > gUnknown_0861CC10.field_6) + { + data[1] = gUnknown_0861CC10.field_6; + } + sub_81C1CB0(&gUnknown_0861CC10, &gUnknown_0203CF1C->unkTilemap3[0], data[1], 1); + if (data[1] <= 0 || data[1] >= gUnknown_0861CC10.field_6) + { + if (data[0] < 0) + { + if (gUnknown_0203CF1C->unk40C0 == 3 && FuncIsActiveTask(sub_81C0B8C) == 0) + PutWindowTilemap(15); + sub_81C240C(data[2]); + } + else + { + if (!gSprites[gUnknown_0203CF1C->unk40D5].invisible) + { + PutWindowTilemap(13); + } + PutWindowTilemap(19); + } + schedule_bg_copy_tilemap_to_vram(0); + DestroyTask(taskId); + } + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); +} + +void sub_81C2074(u16 a, s16 b) +{ + if (b > gUnknown_0861CBEC.field_6) + b = gUnknown_0861CBEC.field_6; + if (b == 0 || b == gUnknown_0861CBEC.field_6) + { + sub_81C1CB0(&gUnknown_0861CBEC, &gUnknown_0203CF1C->unkTilemap0[0], b, 0); + sub_81C1CB0(&gUnknown_0861CBF8, &gUnknown_0203CF1C->unkTilemap0[0], b, 0); + } + else + { + u8 taskId = CreateTask(sub_81C20F0, 8); + gTasks[taskId].data[0] = b; + gTasks[taskId].data[1] = a; + } +} + +void sub_81C20F0(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + data[1] += data[0]; + if (data[1] < 0) + data[1] = 0; + else if (data[1] > gUnknown_0861CBEC.field_6) + data[1] = gUnknown_0861CBEC.field_6; + sub_81C1CB0(&gUnknown_0861CBEC, &gUnknown_0203CF1C->unkTilemap0[0], data[1], 0); + sub_81C1CB0(&gUnknown_0861CBF8, &gUnknown_0203CF1C->unkTilemap0[0], data[1], 0); + schedule_bg_copy_tilemap_to_vram(3); + if (data[1] <= 0 || data[1] >= gUnknown_0861CBEC.field_6) + { + if (data[0] < 0) + { + sub_81C4A88(); + PutWindowTilemap(13); + schedule_bg_copy_tilemap_to_vram(0); + } + DestroyTask(taskId); + } +} + +// somebody send help this is a complete fucking mess +#ifdef NONMATCHING +void sub_81C2194(u16 *a, u16 b, u8 c) +{ + u16 i; + int var; + b *= 0x1000; + var = 0x56A; + + if (c == 0) + { + for (i = 0; i < 20; i++) + { + a[(i + var) << 1] = gUnknown_08DC3CD4[i] + b; + a[((i + var) << 1) + 0x40] = gUnknown_08DC3CD4[i] + b; + a[((i + var) << 1) + 0x80] = gUnknown_08DC3CD4[i + 20] + b; + } + } + else + { + for (i = 0; i < 20; i++) + { + a[(i + var)] = gUnknown_08DC3CD4[i + 20] + b; + a[((i + var)) + 0x40] = gUnknown_08DC3CD4[i + 40] + b; + a[((i + var)) + 0x80] = gUnknown_08DC3CD4[i + 40] + b; + } + } +} +#else +__attribute__((naked)) +void sub_81C2194(u16 *a, u16 b, u8 c) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + adds r6, r0, 0\n\ + lsls r2, 24\n\ + lsls r1, 28\n\ + lsrs r4, r1, 16\n\ + ldr r7, =0x0000056a\n\ + cmp r2, 0\n\ + bne _081C21E4\n\ + movs r3, 0\n\ + ldr r5, =gUnknown_08DC3CD4\n\ +_081C21A8:\n\ + adds r2, r7, r3\n\ + lsls r2, 1\n\ + adds r2, r6\n\ + lsls r0, r3, 1\n\ + adds r0, r5\n\ + ldrh r1, [r0]\n\ + adds r1, r4, r1\n\ + strh r1, [r2]\n\ + adds r0, r2, 0\n\ + adds r0, 0x40\n\ + strh r1, [r0]\n\ + adds r2, 0x80\n\ + adds r0, r3, 0\n\ + adds r0, 0x14\n\ + lsls r0, 1\n\ + adds r0, r5\n\ + ldrh r0, [r0]\n\ + adds r0, r4, r0\n\ + strh r0, [r2]\n\ + adds r0, r3, 0x1\n\ + lsls r0, 16\n\ + lsrs r3, r0, 16\n\ + cmp r3, 0x13\n\ + bls _081C21A8\n\ + b _081C221C\n\ + .pool\n\ +_081C21E4:\n\ + movs r3, 0\n\ + ldr r5, =gUnknown_08DC3CD4\n\ +_081C21E8:\n\ + adds r1, r7, r3\n\ + lsls r1, 1\n\ + adds r1, r6\n\ + adds r0, r3, 0\n\ + adds r0, 0x14\n\ + lsls r0, 1\n\ + adds r0, r5\n\ + ldrh r0, [r0]\n\ + adds r0, r4, r0\n\ + strh r0, [r1]\n\ + adds r2, r1, 0\n\ + adds r2, 0x40\n\ + adds r0, r3, 0\n\ + adds r0, 0x28\n\ + lsls r0, 1\n\ + adds r0, r5\n\ + ldrh r0, [r0]\n\ + adds r0, r4, r0\n\ + strh r0, [r2]\n\ + adds r1, 0x80\n\ + strh r0, [r1]\n\ + adds r0, r3, 0x1\n\ + lsls r0, 16\n\ + lsrs r3, r0, 16\n\ + cmp r3, 0x13\n\ + bls _081C21E8\n\ +_081C221C:\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided\n"); +} +#endif + +void sub_81C2228(struct Pokemon *mon) +{ + if (!CheckPartyPokerus(mon, 0) && CheckPartyHasHadPokerus(mon, 0)) + { + gUnknown_0203CF1C->unkTilemap0[0x223] = 0x2C; + gUnknown_0203CF1C->unkTilemap0_1[0x223] = 0x2C; + } + else + { + gUnknown_0203CF1C->unkTilemap0[0x223] = 0x81A; + gUnknown_0203CF1C->unkTilemap0_1[0x223] = 0x81A; + } + schedule_bg_copy_tilemap_to_vram(3); +} + +void sub_81C228C(u8 a) +{ + if (a == 0) + sub_8199C30(3, 1, 4, 8, 8, 0); + else + sub_8199C30(3, 1, 4, 8, 8, 5); + schedule_bg_copy_tilemap_to_vram(3); +} + +void sub_81C22CC(struct Pokemon *unused) +{ + s64 r6r7; + struct PokeSummary *summary = &gUnknown_0203CF1C->summary; + u16 *r9; + u8 i; + + if (summary->level < MAX_MON_LEVEL) + { + u32 r1 = gExperienceTables[gBaseStats[summary->species].growthRate][summary->level + 1] - gExperienceTables[gBaseStats[summary->species].growthRate][summary->level]; + u32 r4 = summary->exp - gExperienceTables[gBaseStats[summary->species].growthRate][summary->level]; + + r6r7 = r4 * 64 / r1; + if (r6r7 == 0 && r4 != 0) + r6r7 = 1; + } + else + { + r6r7 = 0; + } + + r9 = &gUnknown_0203CF1C->unkTilemap1_1[0x255]; + for (i = 0; i < 8; i++) + { + if (r6r7 > 7) + r9[i] = 0x206A; + else + r9[i] = 0x2062 + (r6r7 % 8); + r6r7 -= 8; + if (r6r7 < 0) + r6r7 = 0; + } + + if (GetBgTilemapBuffer(1) == gUnknown_0203CF1C->unkTilemap1) + schedule_bg_copy_tilemap_to_vram(1); + else + schedule_bg_copy_tilemap_to_vram(2); +} + +void sub_81C240C(u16 move) +{ + u16* r5 = &gUnknown_0203CF1C->unkTilemap3_1[0]; + u8 i; + u8 r4; + if (move != MOVE_NONE) + { + r4 = gContestEffects[gContestMoves[move].effect].appeal; + if (r4 != 0xFF) + r4 /= 10; + for (i = 0;i < 8; i++) + { + if (r4 != 0xFF && i < r4) + { + r5[((i>>2)*32)+(i&3)+0x1E6] = 0x103A; + } + else + r5[((i>>2)*32)+(i&3)+0x1E6] = 0x1039; + } + r4 = gContestEffects[gContestMoves[move].effect].jam; + if (r4 != 0xFF) + r4 /= 10; + for (i = 0;i < 8; i++) + { + if (r4 != 0xFF && i < r4) + { + r5[((i>>2)*32)+(i&3)+0x226] = 0x103C; + } + else + r5[((i>>2)*32)+(i&3)+0x226] = 0x103D; + } + } +} + +void sub_81C2524() +{ + if (gUnknown_0203CF1C->summary.isEgg != 0) + ChangeBgX(3, 0x10000, 0); + else + ChangeBgX(3, 0, 0); +} + +void sub_81C2554() +{ + u8 i; + InitWindows(&gUnknown_0861CC24); + DeactivateAllTextPrinters(); + for (i = 0; i < 20; i++) + FillWindowPixelBuffer(i, 0); + for (i = 0; i < 8; i++) + gUnknown_0203CF1C->unk40CB[i] |= 0xFF; +} + +void sub_81C25A4(u8 a, u8 *b, u8 c, u8 d, u8 e, u8 f) +{ + AddTextPrinterParametrized2(a, 1, c, d, 0, e, &gUnknown_0861CD2C[f], 0, b); +} + +void sub_81C25E8() +{ + FillWindowPixelBuffer(17, 0); + FillWindowPixelBuffer(18, 0); + FillWindowPixelBuffer(19, 0); + if (gUnknown_0203CF1C->summary.isEgg == 0) + sub_81C2628(); + else + sub_81C2794(); + schedule_bg_copy_tilemap_to_vram(0); +} + +void sub_81C2628() +{ + u8 strArray[16]; + struct Pokemon *mon = &gUnknown_0203CF1C->currentMon; + struct PokeSummary *summary = &gUnknown_0203CF1C->summary; + u16 r5 = SpeciesToPokedexNum(summary->species); + if (r5 != 0xFFFF) + { + StringCopy(gStringVar1, &gText_UnkCtrlF908Clear01[0]); + ConvertIntToDecimalStringN(gStringVar2, r5, 2, 3); + StringAppend(gStringVar1, gStringVar2); + if (IsMonShiny(mon) == 0) + { + sub_81C25A4(17, gStringVar1, 0, 1, 0, 1); + sub_81C228C(0); + } + else + { + sub_81C25A4(17, gStringVar1, 0, 1, 0, 7); + sub_81C228C(1); + } + PutWindowTilemap(17); + } + else + { + ClearWindowTilemap(17); + if (IsMonShiny(mon) == 0) + sub_81C228C(0); + else + sub_81C228C(1); + } + StringCopy(gStringVar1, &gText_LevelSymbol[0]); + ConvertIntToDecimalStringN(gStringVar2, summary->level, 0, 3); + StringAppend(gStringVar1, gStringVar2); + sub_81C25A4(19, gStringVar1, 0x18, 17, 0, 1); + GetMonNickname(mon, gStringVar1); + sub_81C25A4(18, gStringVar1, 0, 1, 0, 1); + strArray[0] = CHAR_SLASH; + StringCopy(&strArray[1], &gSpeciesNames[summary->species2][0]); + sub_81C25A4(19, &strArray[0], 0, 1, 0, 1); + sub_81C27DC(mon, summary->species2); + PutWindowTilemap(18); + PutWindowTilemap(19); +} + +void sub_81C2794() +{ + GetMonNickname(&gUnknown_0203CF1C->currentMon, gStringVar1); + sub_81C25A4(18, gStringVar1, 0, 1, 0, 1); + PutWindowTilemap(18); + ClearWindowTilemap(17); + ClearWindowTilemap(19); +} + +void sub_81C27DC(struct Pokemon *mon, u16 a) +{ + if (a != SPECIES_NIDORAN_M && a != SPECIES_NIDORAN_F) + { + u8 gender = GetMonGender(mon); + switch (gender) + { + case 0: + sub_81C25A4(0x13, &gText_MaleSymbol[0], 0x39, 17, 0, 3); + break; + case 0xFE: + sub_81C25A4(0x13, &gText_FemaleSymbol[0], 0x39, 17, 0, 4); + break; + } + } +} + +void sub_81C2838(u8 a, bool8 b, u32 c) +{ + BlitBitmapToWindow(a, (b) ? &gUnknown_0861CDD3[0] : &gUnknown_0861CDD3[0] - 0x80, c, 0, 16, 16); +} + +void sub_81C286C() +{ + int r4; + int r2; + int temp; + sub_81C25A4(0, gText_PkmnInfo, 2, 1, 0, 1); + sub_81C25A4(1, gText_PkmnSkills, 2, 1, 0, 1); + sub_81C25A4(2, gText_BattleMoves, 2, 1, 0, 1); + sub_81C25A4(3, gText_ContestMoves, 2, 1, 0, 1); + r4 = GetStringRightAlignXOffset(1, gText_Cancel2, 0x3E); + r2 = r4 - 16; + if (r2 < 0) + r2 = 0; + sub_81C2838(4, 0, r2); + sub_81C25A4(4, gText_Cancel2, r4, 1, 0, 0); + r4 = GetStringRightAlignXOffset(1, gText_Info, 0x3E); + r2 = r4 - 16; + if (r2 < 0) + r2 = 0; + sub_81C2838(5, 0, r2); + sub_81C25A4(5, gText_Info, r4, 1, 0, 0); + r4 = GetStringRightAlignXOffset(1, gText_Switch, 0x3E); + r2 = r4 - 16; + if (r2 < 0) + r2 = 0; + sub_81C2838(6, 0, r2); + sub_81C25A4(6, gText_Switch, r4, 1, 0, 0); + sub_81C25A4(8, gText_RentalPkmn, 0, 1, 0, 1); + sub_81C25A4(9, gText_TypeSlash, 0, 1, 0, 0); + temp = 6; + temp += GetStringCenterAlignXOffset(1, gText_HP4, 42); + sub_81C25A4(10, gText_HP4, temp, 1, 0, 1); + temp = 6; + temp += GetStringCenterAlignXOffset(1, gText_Attack3, 42); + sub_81C25A4(10, gText_Attack3, temp, 17, 0, 1); + temp = 6; + temp += GetStringCenterAlignXOffset(1, gText_Defense3, 42); + sub_81C25A4(10, gText_Defense3, temp, 33, 0, 1); + temp = 2; + temp += GetStringCenterAlignXOffset(1, gText_SpAtk4, 36); + sub_81C25A4(11, gText_SpAtk4, temp, 1, 0, 1); + temp = 2; + temp += GetStringCenterAlignXOffset(1, gText_SpDef4, 36); + sub_81C25A4(11, gText_SpDef4, temp, 17, 0, 1); + temp = 2; + temp += GetStringCenterAlignXOffset(1, gText_Speed2, 36); + sub_81C25A4(11, gText_Speed2, temp, 33, 0, 1); + sub_81C25A4(12, gText_ExpPoints, 6, 1, 0, 1); + sub_81C25A4(12, gText_NextLv, 6, 17, 0, 1); + sub_81C25A4(13, gText_Status, 2, 1, 0, 1); + sub_81C25A4(14, gText_Power, 0, 1, 0, 1); + sub_81C25A4(14, gText_Accuracy2, 0, 17, 0, 1); + sub_81C25A4(15, gText_Appeal, 0, 1, 0, 1); + sub_81C25A4(15, gText_Jam, 0, 17, 0, 1); +} + +void sub_81C2AFC(u8 a) +{ + u8 i; + ClearWindowTilemap(0); + ClearWindowTilemap(1); + ClearWindowTilemap(2); + ClearWindowTilemap(3); + switch (a) + { + case 0: + PutWindowTilemap(0); + PutWindowTilemap(4); + if (sub_81A6BF4() == TRUE || sub_81B9E94() == TRUE) + PutWindowTilemap(8); + PutWindowTilemap(9); + break; + case 1: + PutWindowTilemap(1); + PutWindowTilemap(10); + PutWindowTilemap(11); + PutWindowTilemap(12); + break; + case 2: + PutWindowTilemap(2); + if (gUnknown_0203CF1C->unk40BC == 3) + { + if(!(gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + PutWindowTilemap(14); + } + else + PutWindowTilemap(5); + break; + case 3: + PutWindowTilemap(3); + if (gUnknown_0203CF1C->unk40BC == 3) + { + if(!(gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + PutWindowTilemap(15); + } + else + PutWindowTilemap(5); + break; + } + for (i = 0; i < 8; i++) + { + PutWindowTilemap(gUnknown_0203CF1C->unk40CB[i]); + } + schedule_bg_copy_tilemap_to_vram(0); +} + +void sub_81C2C38(u8 a) +{ + u8 i; + switch (a) + { + case 0: + ClearWindowTilemap(4); + if (sub_81A6BF4() == TRUE || sub_81B9E94() == TRUE) + ClearWindowTilemap(8); + ClearWindowTilemap(9); + break; + case 1: + ClearWindowTilemap(10); + ClearWindowTilemap(11); + ClearWindowTilemap(12); + break; + case 2: + if (gUnknown_0203CF1C->unk40BC == 3) + { + if(!(gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + ClearWindowTilemap(14); + } + else + ClearWindowTilemap(5); + break; + case 3: + if (gUnknown_0203CF1C->unk40BC == 3) + { + if(!(gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + ClearWindowTilemap(15); + } + else + ClearWindowTilemap(5); + break; + } + for (i = 0; i < 8; i++) + sub_81C2D68(i); + schedule_bg_copy_tilemap_to_vram(0); +} + + + +#ifdef NONMATCHING +u8 sub_81C2D2C(struct WindowTemplate *template, u8 a) +{ + u8 *r4 = gUnknown_0203CF1C->unk40CB; + if (r4[a] == 0xFF) + { + r4[a] = AddWindow(&template[a]); + FillWindowPixelBuffer(r4[a], 0); + } + return r4[a]; +} +#else +__attribute__((naked)) +u8 sub_81C2D2C(struct WindowTemplate *template, u8 a) +{ + asm(".syntax unified\n\ + push {r4,lr}\n\ + adds r3, r0, 0\n\ + lsls r1, 24\n\ + lsrs r2, r1, 24\n\ + ldr r0, =gUnknown_0203CF1C\n\ + ldr r4, =0x000040cb\n\ + adds r1, r2, r4\n\ + ldr r0, [r0]\n\ + adds r4, r0, r1\n\ + ldrb r0, [r4]\n\ + cmp r0, 0xFF\n\ + bne _081C2D56\n\ + lsls r0, r2, 3\n\ + adds r0, r3, r0\n\ + bl AddWindow\n\ + strb r0, [r4]\n\ + ldrb r0, [r4]\n\ + movs r1, 0\n\ + bl FillWindowPixelBuffer\n\ +_081C2D56:\n\ + ldrb r0, [r4]\n\ + pop {r4}\n\ + pop {r1}\n\ + bx r1\n\ + .pool\n\ + .syntax divided\n"); +} +#endif + +#ifdef NONMATCHING +void sub_81C2D68(u8 a) +{ + u8 *r4 = gUnknown_0203CF1C->unk40CB; + if (r4[a] != 0xFF) + { + ClearWindowTilemap(r4[a]); + RemoveWindow(r4[a]); + r4[a] = 0xFF; + } +} +#else +__attribute__((naked)) +void sub_81C2D68(u8 a) +{ + asm(".syntax unified\n\ + push {r4,lr}\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + ldr r1, =gUnknown_0203CF1C\n\ + ldr r2, =0x000040cb\n\ + adds r0, r2\n\ + ldr r1, [r1]\n\ + adds r4, r1, r0\n\ + ldrb r0, [r4]\n\ + cmp r0, 0xFF\n\ + beq _081C2D8C\n\ + bl ClearWindowTilemap\n\ + ldrb r0, [r4]\n\ + bl RemoveWindow\n\ + movs r0, 0xFF\n\ + strb r0, [r4]\n\ +_081C2D8C:\n\ + pop {r4}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided\n"); +} +#endif + +void sub_81C2D9C(u8 a) +{ + u16 i; + for (i = 0; i < 8; i++) + { + if (gUnknown_0203CF1C->unk40CB[i] != 0xFF) + FillWindowPixelBuffer(gUnknown_0203CF1C->unk40CB[i], 0); + } + gUnknown_0861CE54[a](); +} + +void sub_81C2DE4(u8 a) +{ + CreateTask(gUnknown_0861CE64[a], 16); +} + +void sub_81C2E00() +{ + if (gUnknown_0203CF1C->summary.isEgg) + { + sub_81C335C(); + sub_81C33CC(); + sub_81C3428(); + sub_81C349C(); + } + else + { + sub_81C2EC4(); + sub_81C2F5C(); + sub_81C2FD8(); + sub_81C302C(); + sub_81C307C(); + sub_81C3194(); + } +} + +void sub_81C2E40(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 dataa = data[0] - 1; + switch (dataa) + { + case 0: + sub_81C2EC4(); + break; + case 1: + sub_81C2F5C(); + break; + case 2: + sub_81C2FD8(); + break; + case 3: + sub_81C302C(); + break; + case 4: + sub_81C307C(); + break; + case 5: + sub_81C3194(); + break; + case 6: + DestroyTask(taskId); + return; + } + data[0]++; +} + +void sub_81C2EC4() +{ + u8 r5; + int r2; + if (sub_81A6BF4() != 1 && sub_81B9E94() != 1) + { + r5 = sub_81C2D2C(&gUnknown_0861CCCC, 0); + sub_81C25A4(r5, gText_OTSlash, 0, 1, 0, 1); + r2 = GetStringWidth(1, gText_OTSlash, 0); + if (gUnknown_0203CF1C->summary.OTGender == 0) + sub_81C25A4(r5, gUnknown_0203CF1C->summary.OTName, r2, 1, 0, 5); + else + sub_81C25A4(r5, gUnknown_0203CF1C->summary.OTName, r2, 1, 0, 6); + } +} + +void sub_81C2F5C() +{ + int r4; + if (sub_81A6BF4() != TRUE && sub_81B9E94() != TRUE) + { + ConvertIntToDecimalStringN(StringCopy(gStringVar1, gText_UnkCtrlF907F908), (u16)gUnknown_0203CF1C->summary.OTID, 2, 5); + r4 = GetStringRightAlignXOffset(1, gStringVar1, 0x38); + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 1), gStringVar1, r4, 1, 0, 1); + } +} + +void sub_81C2FD8() +{ + u8 ability = GetAbilityBySpecies(gUnknown_0203CF1C->summary.species, gUnknown_0203CF1C->summary.altAbility); + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 2), gAbilityNames[ability], 0, 1, 0, 1); +} + +void sub_81C302C() +{ + u8 ability = GetAbilityBySpecies(gUnknown_0203CF1C->summary.species, gUnknown_0203CF1C->summary.altAbility); + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 2), gAbilityDescriptionPointers[ability], 0, 17, 0, 0); +} + +void sub_81C307C() +{ + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + u8 *text; + sub_81AFBF0(); + sub_81AFC0C(0, gUnknown_0861CE74); + sub_81AFC0C(1, gUnknown_0861CE7B); + sub_81C31C0(); + if (sub_81A6BF4() == TRUE || sub_81B9E94() == TRUE || sub_81C3304() == TRUE) + sub_81AFC28(gStringVar4, gText_XNature); + else + { + u8 *alloced1 = Alloc(32); + u8 *alloced2 = Alloc(32); + sub_81C31F0(alloced1); + if (sum->metLocation <= 0xD4) + { + sub_8124610(alloced2, sum->metLocation); + sub_81AFC0C(4, alloced2); + } + if (sub_81C3220() == 1) + { + if (sum->metLevel == 0) + text = (sum->metLocation > 0xD4) ? gText_XNatureHatchedSomewhereAt : gText_XNatureHatchedAtYZ; + else + text = (sum->metLocation > 0xD4) ? gText_XNatureMetSomewhereAt : gText_XNatureMetAtYZ; + } + else if (sum->metLocation == 0xFF) + text = gText_XNatureFatefulEncounter; + else if (sum->metLocation != 0xFE && sub_81C32BC()) + text = (sum->metLocation > 0xD4) ? gText_XNatureObtainedInTrade : gText_XNatureProbablyMetAt; + else + text = gText_XNatureObtainedInTrade; + sub_81AFC28(gStringVar4, text); + Free(alloced1); + Free(alloced2); + } +} + +void sub_81C3194() +{ + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 3), gStringVar4, 0, 1, 0, 0); +} + +void sub_81C31C0() +{ + struct UnkSummaryStruct *sumStruct = gUnknown_0203CF1C; + sub_81AFC0C(2, gNatureNamePointers[sumStruct->summary.nature]); + sub_81AFC0C(5, gText_EmptyString5); +} + +void sub_81C31F0(u8 *a) +{ + u8 level = gUnknown_0203CF1C->summary.metLevel; + if (level == 0) + level = 5; + ConvertIntToDecimalStringN(a, level, 0, 3); + sub_81AFC0C(3, a); +} + +u8 sub_81C3220() +{ + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + u32 r4; + u8 r5; + if (gUnknown_0203CF1C->unk0 == (union UnkUnion *)&gEnemyParty) + { + u8 multiID = GetMultiplayerId()^1; + r4 = (u16)gLinkPlayers[multiID].trainerId; + r5 = gLinkPlayers[multiID].gender; + StringCopy(gStringVar1, gLinkPlayers[multiID].name); + } + else + { + r4 = GetPlayerIDAsU32() & 0xFFFF; + r5 = gSaveBlock2Ptr->playerGender; + StringCopy(gStringVar1, gSaveBlock2Ptr->playerName); + } + if (r5 != sum->OTGender || r4 != (sum->OTID & 0xFFFF) || StringCompareWithoutExtCtrlCodes(gStringVar1, sum->OTName)) + { + return 0; + } + return 1; +} + +bool8 sub_81C32BC() +{ + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + u8 r0 = sum->metGame - 1; + if (r0 <= 4) + return TRUE; + return FALSE; +} + +bool8 sub_81C32E0() +{ + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + u8 r0 = sum->metGame - 1; + if (r0 <= 2) + return TRUE; + return FALSE; +} + +bool8 sub_81C3304() +{ + if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) && gMain.inBattle) + { + if (gUnknown_0203CF1C->unk40BE == 1 || gUnknown_0203CF1C->unk40BE == 4 || gUnknown_0203CF1C->unk40BE == 5) + return TRUE; + } + return FALSE; +} + +#ifdef NONMATCHING +void sub_81C335C() +{ + u8 r4 = sub_81C2D2C(&gUnknown_0861CCCC, 0); + u32 r5 = GetStringWidth(1, gText_OTSlash, 0); + sub_81C25A4(r4, gText_OTSlash, 0, 1, 0, 1); + sub_81C25A4(r4, gText_FiveMarks, r5, 1, 0, 1); +} +#else +__attribute__((naked)) +void sub_81C335C() +{ + asm(".syntax unified\n\ + push {r4-r6,lr}\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5,r6}\n\ + sub sp, 0x8\n\ + ldr r0, =gUnknown_0861CCCC\n\ + movs r1, 0\n\ + bl sub_81C2D2C\n\ + adds r4, r0, 0\n\ + lsls r4, 24\n\ + lsrs r4, 24\n\ + ldr r0, =gText_OTSlash\n\ + mov r8, r0\n\ + movs r0, 0x1\n\ + mov r1, r8\n\ + movs r2, 0\n\ + bl GetStringWidth\n\ + adds r5, r0, 0\n\ + movs r0, 0\n\ + mov r9, r0\n\ + str r0, [sp]\n\ + movs r6, 0x1\n\ + str r6, [sp, 0x4]\n\ + adds r0, r4, 0\n\ + mov r1, r8\n\ + movs r2, 0\n\ + movs r3, 0x1\n\ + bl sub_81C25A4\n\ + ldr r1, =gText_FiveMarks\n\ + lsls r5, 24\n\ + lsrs r5, 24\n\ + mov r0, r9\n\ + str r0, [sp]\n\ + str r6, [sp, 0x4]\n\ + adds r0, r4, 0\n\ + adds r2, r5, 0\n\ + movs r3, 0x1\n\ + bl sub_81C25A4\n\ + add sp, 0x8\n\ + pop {r3,r4}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + pop {r4-r6}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided\n"); +} +#endif + +void sub_81C33CC() +{ + int r4; + StringCopy(gStringVar1, gText_UnkCtrlF907F908); + StringAppend(gStringVar1, gText_FiveMarks); + r4 = GetStringRightAlignXOffset(1, gStringVar1, 0x38); + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 1), gStringVar1, r4, 1, 0, 1); +} + +void sub_81C3428() +{ + u8 *text; + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + if (gUnknown_0203CF1C->summary.sanity == 1) + text = gText_EggWillTakeALongTime; + else if (sum->friendship <= 5) + text = gText_EggAboutToHatch; + else if (sum->friendship <= 10) + text = gText_EggWillHatchSoon; + else if (sum->friendship <= 40) + text = gText_EggWillTakeSomeTime; + else + text = gText_EggWillTakeALongTime; + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 2), text, 0, 1, 0, 0); +} + +void sub_81C349C() +{ + u8 *text; + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + if (gUnknown_0203CF1C->summary.sanity != 1) + { + if (sum->metLocation == 0xFF) + text = gText_PeculiarEggNicePlace; + else if (sub_81C32BC() == 0 || sub_81C3220() == 0) + text = gText_PeculiarEggTrade; + else if (sum->metLocation == 0xFD) + text = (sub_81C32E0() == TRUE) ? gText_EggFromHotSprings : gText_EggFromTraveler; + else + text = gText_OddEggFoundByCouple; + } + else + text = gText_OddEggFoundByCouple; + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCCC, 3), text, 0, 1, 0, 0); +} + +void sub_81C3530() +{ + sub_81C35E4(); + sub_81C3690(); + sub_81C3710(); + sub_81C37D8(); + sub_81C3808(); + sub_81C3890(); + sub_81C38C0(); +} + +void sub_81C3554(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 dataa = data[0] - 1; + switch (dataa) + { + case 0: + sub_81C35E4(); + break; + case 1: + sub_81C3690(); + break; + case 2: + sub_81C3710(); + break; + case 3: + sub_81C37D8(); + break; + case 4: + sub_81C3808(); + break; + case 5: + sub_81C3890(); + break; + case 6: + sub_81C38C0(); + break; + case 7: + DestroyTask(taskId); + return; + } + data[0]++; +} + +void sub_81C35E4() +{ + u8 *text; + int offset; + if (gUnknown_0203CF1C->summary.item == ITEM_ENIGMA_BERRY && sub_81B1250() == 1 && (gUnknown_0203CF1C->unk40BE == 1 || gUnknown_0203CF1C->unk40BE == 4 || gUnknown_0203CF1C->unk40BE == 5)) + { + text = (u8*)ItemId_GetItem(ITEM_ENIGMA_BERRY); + } + else if (gUnknown_0203CF1C->summary.item == ITEM_NONE) + text = gText_None; + else + { + CopyItemName(gUnknown_0203CF1C->summary.item, gStringVar1); + text = gStringVar1; + } + offset = GetStringCenterAlignXOffset(1, text, 0x48) + 6; + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCEC, 0), text, offset, 1, 0, 0); +} + +void sub_81C3690() +{ + u8 *text; + int offset; + if (gUnknown_0203CF1C->summary.ribbons == 0) + text = gText_None; + else + { + ConvertIntToDecimalStringN(gStringVar1, gUnknown_0203CF1C->summary.ribbons, 1, 2); + StringExpandPlaceholders(gStringVar4, gText_RibbonsVar1); + text = gStringVar4; + } + offset = GetStringCenterAlignXOffset(1, text, 0x46) + 6; + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCEC, 1), text, offset, 1, 0, 0); +} + +void sub_81C3710() +{ + u8 *alloced1 = Alloc(8); + u8 *alloced2 = Alloc(8); + u8 *alloced3 = Alloc(8); + u8 *alloced4 = Alloc(8); + ConvertIntToDecimalStringN(alloced1, gUnknown_0203CF1C->summary.currentHP, 1, 3); + ConvertIntToDecimalStringN(alloced2, gUnknown_0203CF1C->summary.maxHP, 1, 3); + ConvertIntToDecimalStringN(alloced3, gUnknown_0203CF1C->summary.atk, 1, 7); + ConvertIntToDecimalStringN(alloced4, gUnknown_0203CF1C->summary.def, 1, 7); + sub_81AFBF0(); + sub_81AFC0C(0, alloced1); + sub_81AFC0C(1, alloced2); + sub_81AFC0C(2, alloced3); + sub_81AFC0C(3, alloced4); + sub_81AFC28(gStringVar4, gUnknown_0861CE82); + Free(alloced1); + Free(alloced2); + Free(alloced3); + Free(alloced4); +} + +void sub_81C37D8() +{ + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCEC, 2), gStringVar4, 4, 1, 0, 0); +} + +void sub_81C3808() +{ + ConvertIntToDecimalStringN(gStringVar1, gUnknown_0203CF1C->summary.spatk, 1, 3); + ConvertIntToDecimalStringN(gStringVar2, gUnknown_0203CF1C->summary.spdef, 1, 3); + ConvertIntToDecimalStringN(gStringVar3, gUnknown_0203CF1C->summary.speed, 1, 3); + sub_81AFBF0(); + sub_81AFC0C(0, gStringVar1); + sub_81AFC0C(1, gStringVar2); + sub_81AFC0C(2, gStringVar3); + sub_81AFC28(gStringVar4, gUnknown_0861CE8E); +} + +void sub_81C3890() +{ + sub_81C25A4(sub_81C2D2C(&gUnknown_0861CCEC, 3), gStringVar4, 2, 1, 0, 0); +} + +void sub_81C38C0() +{ + struct PokeSummary *sum = &gUnknown_0203CF1C->summary; + u8 r6 = sub_81C2D2C(&gUnknown_0861CCEC, 4); + int offset; + u32 expToNextLevel; + ConvertIntToDecimalStringN(gStringVar1, sum->exp, 1, 7); + offset = GetStringRightAlignXOffset(1, gStringVar1, 0x2A) + 2; + sub_81C25A4(r6, gStringVar1, offset, 1, 0, 0); + if (sum->level < MAX_MON_LEVEL) + expToNextLevel = gExperienceTables[gBaseStats[sum->species].growthRate][sum->level + 1] - sum->exp; + else + expToNextLevel = 0; + ConvertIntToDecimalStringN(gStringVar1, expToNextLevel, 1, 6); + offset = GetStringRightAlignXOffset(1, gStringVar1, 0x2A) + 2; + sub_81C25A4(r6, gStringVar1, offset, 17, 0, 0); +} + +void sub_81C3984() +{ + sub_81C3B08(0); + sub_81C3B08(1); + sub_81C3B08(2); + sub_81C3B08(3); + if (gUnknown_0203CF1C->unk40BC == 3) + { + sub_81C3F44(); + if (gUnknown_0203CF1C->unk40C6 == 4) + { + if (gUnknown_0203CF1C->unk40C4 != 0) + sub_81C3E9C(gUnknown_0203CF1C->unk40C4); + } + else + sub_81C3E9C(gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]); + } +} + +void sub_81C39F0(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 dataa = data[0] - 1; + + switch (dataa) + { + case 0: + sub_81C3B08(0); + break; + case 1: + sub_81C3B08(1); + break; + case 2: + sub_81C3B08(2); + break; + case 3: + sub_81C3B08(3); + break; + case 4: + if (gUnknown_0203CF1C->unk40BC == 3) + sub_81C3F44(); + break; + case 5: + if (gUnknown_0203CF1C->unk40BC == 3) + { + if (gUnknown_0203CF1C->unk40C6 == 4) + data[1] = gUnknown_0203CF1C->unk40C4; + else + data[1] = gUnknown_0203CF1C->summary.moves[gUnknown_0203CF1C->unk40C6]; + } + break; + case 6: + if (gUnknown_0203CF1C->unk40BC == 3) + { + if (!(gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + sub_81C3E9C(data[1]); + } + break; + case 7: + DestroyTask(taskId); + return; + } + data[0]++; +} + +#ifdef NONMATCHING +void sub_81C3B08(u8 a) +{ + struct UnkSummaryStruct *r10 = gUnknown_0203CF1C; + u8 r8 = sub_81C2D2C(&gUnknown_0861CD14, 0); + u8 sp = sub_81C2D2C(&gUnknown_0861CD14, 1); + u8 r6; + u8 r5; + u8 *text; + int offset; + u16 move; + if (r10->summary.moves[a] != 0) + { + move = r10->summary.moves[a]; + r6 = CalculatePPWithBonus(move, r10->summary.ppBonuses, a); + sub_81C25A4(r8, gMoveNames[move], 0, (a<<4) + 1, 0, 1); + ConvertIntToDecimalStringN(gStringVar1, r10->summary.pp[a], 1, 2); + ConvertIntToDecimalStringN(gStringVar2, r6, 1, 2); + sub_81AFBF0(); + sub_81AFC0C(0, gStringVar1); + sub_81AFC0C(1, gStringVar2); + sub_81AFC28(gStringVar4, gUnknown_0861CE97); + text = gStringVar4; + r5 = GetCurrentPpToMaxPpState(r10->summary.pp[a], r6) + 9; + offset = GetStringRightAlignXOffset(1, text, 0x2C); + } + else + { + sub_81C25A4(r8, gText_OneDash, 0, (a<<4) + 1, 0, 1); + text = gText_TwoDashes; + r5 = 12; + offset = GetStringCenterAlignXOffset(1, text, 0x2C); + } + sub_81C25A4(sp, text, offset, (a<<4), 0, r5); +} +#else +__attribute__((naked)) +void sub_81C3B08(u8 a) +{ + 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, 0xC\n\ + lsls r0, 24\n\ + lsrs r7, r0, 24\n\ + ldr r0, =gUnknown_0203CF1C\n\ + ldr r0, [r0]\n\ + mov r10, r0\n\ + ldr r4, =gUnknown_0861CD14\n\ + adds r0, r4, 0\n\ + movs r1, 0\n\ + bl sub_81C2D2C\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + mov r8, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0x1\n\ + bl sub_81C2D2C\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + str r0, [sp, 0x8]\n\ + lsls r1, r7, 1\n\ + mov r0, r10\n\ + adds r0, 0x84\n\ + adds r0, r1\n\ + ldrh r5, [r0]\n\ + cmp r5, 0\n\ + beq _081C3C00\n\ + mov r0, r10\n\ + adds r0, 0xA4\n\ + ldrb r1, [r0]\n\ + adds r0, r5, 0\n\ + adds r2, r7, 0\n\ + bl CalculatePPWithBonus\n\ + adds r6, r0, 0\n\ + lsls r6, 24\n\ + lsrs r6, 24\n\ + movs r0, 0xD\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gMoveNames\n\ + adds r1, r0\n\ + lsls r0, r7, 4\n\ + mov r9, r0\n\ + mov r3, r9\n\ + adds r3, 0x1\n\ + lsls r3, 24\n\ + lsrs r3, 24\n\ + movs r0, 0\n\ + str r0, [sp]\n\ + movs r0, 0x1\n\ + str r0, [sp, 0x4]\n\ + mov r0, r8\n\ + movs r2, 0\n\ + bl sub_81C25A4\n\ + ldr r0, =gStringVar1\n\ + mov r8, r0\n\ + mov r5, r10\n\ + adds r5, 0x8C\n\ + adds r5, r7\n\ + ldrb r1, [r5]\n\ + movs r2, 0x1\n\ + movs r3, 0x2\n\ + bl ConvertIntToDecimalStringN\n\ + ldr r4, =gStringVar2\n\ + adds r0, r4, 0\n\ + adds r1, r6, 0\n\ + movs r2, 0x1\n\ + movs r3, 0x2\n\ + bl ConvertIntToDecimalStringN\n\ + bl sub_81AFBF0\n\ + movs r0, 0\n\ + mov r1, r8\n\ + bl sub_81AFC0C\n\ + movs r0, 0x1\n\ + adds r1, r4, 0\n\ + bl sub_81AFC0C\n\ + ldr r4, =gStringVar4\n\ + ldr r1, =gUnknown_0861CE97\n\ + adds r0, r4, 0\n\ + bl sub_81AFC28\n\ + adds r7, r4, 0\n\ + ldrb r0, [r5]\n\ + adds r1, r6, 0\n\ + bl GetCurrentPpToMaxPpState\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + adds r5, r0, 0\n\ + adds r5, 0x9\n\ + movs r0, 0x1\n\ + adds r1, r7, 0\n\ + movs r2, 0x2C\n\ + bl GetStringRightAlignXOffset\n\ + mov r4, r9\n\ + b _081C3C26\n\ + .pool\n\ +_081C3C00:\n\ + ldr r1, =gText_OneDash\n\ + lsls r4, r7, 4\n\ + adds r3, r4, 0x1\n\ + lsls r3, 24\n\ + lsrs r3, 24\n\ + str r5, [sp]\n\ + movs r0, 0x1\n\ + str r0, [sp, 0x4]\n\ + mov r0, r8\n\ + movs r2, 0\n\ + bl sub_81C25A4\n\ + ldr r7, =gText_TwoDashes\n\ + movs r5, 0xC\n\ + movs r0, 0x1\n\ + adds r1, r7, 0\n\ + movs r2, 0x2C\n\ + bl GetStringCenterAlignXOffset\n\ +_081C3C26:\n\ + lsls r2, r0, 24\n\ + lsrs r2, 24\n\ + adds r3, r4, 0x1\n\ + lsls r3, 24\n\ + lsrs r3, 24\n\ + movs r0, 0\n\ + str r0, [sp]\n\ + lsls r0, r5, 24\n\ + lsrs r0, 24\n\ + str r0, [sp, 0x4]\n\ + ldr r0, [sp, 0x8]\n\ + adds r1, r7, 0\n\ + bl sub_81C25A4\n\ + add sp, 0xC\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\ + .pool\n\ + .syntax divided\n"); +} +#endif + +void sub_81C3C5C(u16 move) +{ + u8 *text; + if (move != 0) + { + FillWindowPixelRect(14, 0, 0x35, 0, 0x13, 0x20); + if (gBattleMoves[move].power <= 1) + text = gText_ThreeDashes; + else + { + ConvertIntToDecimalStringN(gStringVar1, gBattleMoves[move].power, 1, 3); + text = gStringVar1; + } + sub_81C25A4(14, text, 0x35, 1, 0, 0); + if (gBattleMoves[move].accuracy == 0) + text = gText_ThreeDashes; + else + { + ConvertIntToDecimalStringN(gStringVar1, gBattleMoves[move].accuracy, 1, 3); + text = gStringVar1; + } + sub_81C25A4(14, text, 0x35, 17, 0, 0); + } +} + +void sub_81C3D08() +{ + sub_81C3B08(0); + sub_81C3B08(1); + sub_81C3B08(2); + sub_81C3B08(3); + if (gUnknown_0203CF1C->unk40BC == 3) + { + sub_81C3F44(); + sub_81C3E2C(gUnknown_0203CF1C->unk40C6); + } +} + +void sub_81C3D54(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + s16 dataa = data[0] - 1; + + switch (dataa) + { + case 0: + sub_81C3B08(0); + break; + case 1: + sub_81C3B08(1); + break; + case 2: + sub_81C3B08(2); + break; + case 3: + sub_81C3B08(3); + break; + case 4: + if (gUnknown_0203CF1C->unk40BC == 3) + sub_81C3F44(); + break; + case 5: + if (gUnknown_0203CF1C->unk40BC == 3) + { + if (!(gUnknown_0203CF1C->unk40C4 == 0 && gUnknown_0203CF1C->unk40C6 == 4)) + sub_81C3E2C(gUnknown_0203CF1C->unk40C6); + } + break; + case 6: + DestroyTask(taskId); + return; + } + data[0]++; +}
\ No newline at end of file diff --git a/src/record_mixing.c b/src/record_mixing.c new file mode 100644 index 000000000..151835e5e --- /dev/null +++ b/src/record_mixing.c @@ -0,0 +1,28 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA bool8 gUnknown_03001130; +IWRAM_DATA struct SecretBaseRecord *gUnknown_03001134; +IWRAM_DATA TVShow *gUnknown_03001138; +IWRAM_DATA struct UnknownSaveStruct2ABC *gUnknown_0300113C; +IWRAM_DATA OldMan *gUnknown_03001140; +IWRAM_DATA struct EasyChatPair *gUnknown_03001144; +IWRAM_DATA struct DaycareData *gUnknown_03001148; +IWRAM_DATA void *gUnknown_0300114C; // gSaveBlock2Ptr->field_64C +IWRAM_DATA LilycoveLady *gUnknown_03001150; +IWRAM_DATA void *gUnknown_03001154; // gSaveBlock2Ptr->field_0DC; +IWRAM_DATA void *gUnknown_03001158; // gSaveBlock2Ptr->field_64C +IWRAM_DATA u32 gUnknown_0300115C; +IWRAM_DATA u8 gUnknown_03001160[8]; +IWRAM_DATA u32 gUnknown_03001168[3]; + +// Static ROM declarations + +// .rodata + +// .text 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 new file mode 100644 index 000000000..343ddb9c0 --- /dev/null +++ b/src/reshow_battle_screen.c @@ -0,0 +1,354 @@ +#include "global.h" +#include "reshow_battle_screen.h" +#include "battle.h" +#include "palette.h" +#include "main.h" +#include "unknown_task.h" +#include "text.h" +#include "gpu_regs.h" +#include "bg.h" +#include "battle_controllers.h" +#include "link.h" +#include "sprite.h" +#include "species.h" +#include "battle_interface.h" + +extern u16 gBattle_BG0_X; +extern u16 gBattle_BG0_Y; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattle_BG3_X; +extern u16 gBattle_BG3_Y; +extern u8 gReservedSpritePaletteCount; +extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT]; +extern u8 gBankInMenu; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gNoOfAllBanks; +extern u32 gBattleTypeFlags; +extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT]; +extern u8 gBattleMonForms[BATTLE_BANKS_COUNT]; +extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT]; +extern struct SpriteTemplate gUnknown_0202499C; + +extern const union AnimCmd * const * const gMonAnimationsSpriteAnimsPtrTable[]; + +extern void dp12_8087EA4(void); +extern void trs_config(void); +extern bool8 IsDoubleBattle(void); +extern u8 sub_80A614C(u8 bank); +extern u8 sub_80A6138(u8 bank); +extern u8 sub_80A82E4(u8 bank); +extern void sub_806A068(u16 species, u8 bankIdentity); +extern void sub_806A12C(u16 backPicId, u8 bankIdentity); +extern u8 sub_80A5C6C(u8 bank, u8 caseId); + +// this file's functions +static void CB2_ReshowBattleScreenAfterMenu(void); +static bool8 LoadBankSpriteGfx(u8 bank); +static void CreateBankSprite(u8 bank); +static void CreateHealthboxSprite(u8 bank); +static void sub_80A95F4(void); + +void nullsub_35(void) +{ + +} + +void ReshowBattleScreenAfterMenu(void) +{ + gPaletteFade.bufferTransferDisabled = 1; + SetHBlankCallback(NULL); + SetVBlankCallback(NULL); + SetGpuReg(REG_OFFSET_MOSAIC, 0); + gBattleScripting.reshowMainState = 0; + gBattleScripting.reshowHelperState = 0; + SetMainCallback2(CB2_ReshowBattleScreenAfterMenu); +} + +static void CB2_ReshowBattleScreenAfterMenu(void) +{ + switch (gBattleScripting.reshowMainState) + { + case 0: + dp12_8087EA4(); + trs_config(); + SetBgAttribute(1, BG_CTRL_ATTR_VISIBLE, 0); + SetBgAttribute(2, BG_CTRL_ATTR_VISIBLE, 0); + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + ResetPaletteFade(); + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0; + gBattle_BG2_X = 0; + gBattle_BG2_Y = 0; + gBattle_BG3_X = 0; + gBattle_BG3_Y = 0; + break; + case 1: + CpuFastFill(0, (void*)(VRAM), VRAM_SIZE); + break; + case 2: + LoadBattleTextboxAndBackground(); + break; + case 3: + ResetSpriteData(); + break; + case 4: + FreeAllSpritePalettes(); + gReservedSpritePaletteCount = 4; + break; + case 5: + sub_805E350(); + break; + case 6: + if (BattleLoadAllHealthBoxesGfx(gBattleScripting.reshowHelperState)) + { + gBattleScripting.reshowHelperState = 0; + } + else + { + gBattleScripting.reshowHelperState++; + gBattleScripting.reshowMainState--; + } + break; + case 7: + if (!LoadBankSpriteGfx(0)) + gBattleScripting.reshowMainState--; + break; + case 8: + if (!LoadBankSpriteGfx(1)) + gBattleScripting.reshowMainState--; + break; + case 9: + if (!LoadBankSpriteGfx(2)) + gBattleScripting.reshowMainState--; + break; + case 10: + if (!LoadBankSpriteGfx(3)) + gBattleScripting.reshowMainState--; + break; + case 11: + CreateBankSprite(0); + break; + case 12: + CreateBankSprite(1); + break; + case 13: + CreateBankSprite(2); + break; + case 14: + CreateBankSprite(3); + break; + case 15: + CreateHealthboxSprite(0); + break; + case 16: + CreateHealthboxSprite(1); + break; + case 17: + CreateHealthboxSprite(2); + break; + case 18: + CreateHealthboxSprite(3); + break; + case 19: + { + u8 opponentBank; + u16 species; + + LoadAndCreateEnemyShadowSprites(); + + opponentBank = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + species = GetMonData(&gEnemyParty[gBattlePartyID[opponentBank]], MON_DATA_SPECIES); + SetBankEnemyShadowSpriteCallback(opponentBank, species); + + if (IsDoubleBattle()) + { + opponentBank = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + species = GetMonData(&gEnemyParty[gBattlePartyID[opponentBank]], MON_DATA_SPECIES); + SetBankEnemyShadowSpriteCallback(opponentBank, species); + } + + ActionSelectionCreateCursorAt(gActionSelectionCursor[gBankInMenu], 0); + + if (gLinkVSyncDisabled != 0 && gReceivedRemoteLinkPlayers != 0) + { + sub_800E0E8(); + sub_800DFB4(0, 0); + } + } + break; + default: + SetVBlankCallback(VBlankCB_Battle); + sub_80A95F4(); + BeginHardwarePaletteFade(0xFF, 0, 0x10, 0, 1); + gPaletteFade.bufferTransferDisabled = 0; + SetMainCallback2(BattleMainCB2); + sub_805EF14(); + break; + } + + gBattleScripting.reshowMainState++; +} + +static void sub_80A95F4(void) +{ + struct BGCntrlBitfield *regBgcnt1, *regBgcnt2; + + regBgcnt1 = (struct BGCntrlBitfield *)(®_BG1CNT); + regBgcnt1->charBaseBlock = 0; + + regBgcnt2 = (struct BGCntrlBitfield *)(®_BG2CNT); + regBgcnt2->charBaseBlock = 0; +} + +static bool8 LoadBankSpriteGfx(u8 bank) +{ + if (bank < gNoOfAllBanks) + { + if (GetBankSide(bank) != SIDE_PLAYER) + { + if (!gBattleSpritesDataPtr->bankData[bank].behindSubstitute) + BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlePartyID[bank]], bank); + else + BattleLoadSubstituteSpriteGfx(bank, FALSE); + } + else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && bank == 0) + LoadBackTrainerBankSpriteGfx(gSaveBlock2Ptr->playerGender, bank); + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL && bank == 0) + LoadBackTrainerBankSpriteGfx(BACK_PIC_WALLY, bank); + else if (!gBattleSpritesDataPtr->bankData[bank].behindSubstitute) + BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlePartyID[bank]], bank); + else + BattleLoadSubstituteSpriteGfx(bank, FALSE); + + gBattleScripting.reshowHelperState = 0; + } + return TRUE; +} + +// todo: get rid of it once the struct is declared in a header +struct MonCoords +{ + // This would use a bitfield, but sub_8079F44 + // uses it as a u8 and casting won't match. + u8 coords; // u8 x:4, y:4; + u8 y_offset; +}; +extern const struct MonCoords gTrainerBackPicCoords[]; + +static void CreateBankSprite(u8 bank) +{ + if (bank < gNoOfAllBanks) + { + u8 posY; + + if (gBattleSpritesDataPtr->bankData[bank].behindSubstitute) + posY = sub_80A614C(bank); + else + posY = sub_80A6138(bank); + + if (GetBankSide(bank) != SIDE_PLAYER) + { + if (GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_HP) == 0) + return; + + sub_806A068(GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_SPECIES), GetBankIdentity(bank)); + gBankSpriteIds[bank] = CreateSprite(&gUnknown_0202499C, sub_80A5C6C(bank, 2), posY, sub_80A82E4(bank)); + gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank; + gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy; + gSprites[gBankSpriteIds[bank]].data0 = bank; + gSprites[gBankSpriteIds[bank]].data2 = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_SPECIES); + + StartSpriteAnim(&gSprites[gBankSpriteIds[bank]], gBattleMonForms[bank]); + if (gBattleSpritesDataPtr->bankData[bank].transformSpecies == SPECIES_CASTFORM) + gSprites[gBankSpriteIds[bank]].anims = gMonAnimationsSpriteAnimsPtrTable[SPECIES_CASTFORM]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && bank == 0) + { + sub_806A12C(gSaveBlock2Ptr->playerGender, GetBankIdentity(IDENTITY_PLAYER_MON1)); + gBankSpriteIds[bank] = CreateSprite(&gUnknown_0202499C, 0x50, + (8 - gTrainerBackPicCoords[gSaveBlock2Ptr->playerGender].coords) * 4 + 80, + sub_80A82E4(0)); + gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank; + gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy; + gSprites[gBankSpriteIds[bank]].data0 = bank; + } + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL && bank == 0) + { + sub_806A12C(BACK_PIC_WALLY, GetBankIdentity(0)); + gBankSpriteIds[bank] = CreateSprite(&gUnknown_0202499C, 0x50, + (8 - gTrainerBackPicCoords[BACK_PIC_WALLY].coords) * 4 + 80, + sub_80A82E4(0)); + gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank; + gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy; + gSprites[gBankSpriteIds[bank]].data0 = bank; + } + else + { + if (GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_HP) == 0) + return; + + sub_806A068(GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES), GetBankIdentity(bank)); + gBankSpriteIds[bank] = CreateSprite(&gUnknown_0202499C, sub_80A5C6C(bank, 2), posY, sub_80A82E4(bank)); + gSprites[gBankSpriteIds[bank]].oam.paletteNum = bank; + gSprites[gBankSpriteIds[bank]].callback = SpriteCallbackDummy; + gSprites[gBankSpriteIds[bank]].data0 = bank; + gSprites[gBankSpriteIds[bank]].data2 = GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES); + + StartSpriteAnim(&gSprites[gBankSpriteIds[bank]], gBattleMonForms[bank]); + if (gBattleSpritesDataPtr->bankData[bank].transformSpecies == SPECIES_CASTFORM) + gSprites[gBankSpriteIds[bank]].anims = gMonAnimationsSpriteAnimsPtrTable[SPECIES_CASTFORM]; + } + + gSprites[gBankSpriteIds[bank]].invisible = gBattleSpritesDataPtr->bankData[bank].invisible; + } +} + +static void CreateHealthboxSprite(u8 bank) +{ + if (bank < gNoOfAllBanks) + { + u8 healthboxSpriteId; + + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && bank == 0) + healthboxSpriteId = CreateSafariPlayerHealthboxSprites(); + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL && bank == 0) + return; + else + healthboxSpriteId = CreateBankHealthboxSprites(bank); + + gHealthBoxesIds[bank] = healthboxSpriteId; + SetBankHealthboxSpritePos(bank); + SetHealthboxSpriteVisible(healthboxSpriteId); + + if (GetBankSide(bank) != SIDE_PLAYER) + UpdateHealthboxAttribute(gHealthBoxesIds[bank], &gEnemyParty[gBattlePartyID[bank]], HEALTHBOX_ALL); + else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + UpdateHealthboxAttribute(gHealthBoxesIds[bank], &gPlayerParty[gBattlePartyID[bank]], HEALTHBOX_SAFARI_ALL_TEXT); + else + UpdateHealthboxAttribute(gHealthBoxesIds[bank], &gPlayerParty[gBattlePartyID[bank]], HEALTHBOX_ALL); + + if (GetBankIdentity(bank) == IDENTITY_OPPONENT_MON2 || GetBankIdentity(bank) == IDENTITY_PLAYER_MON2) + DummyBattleInterfaceFunc(gHealthBoxesIds[bank], TRUE); + else + DummyBattleInterfaceFunc(gHealthBoxesIds[bank], FALSE); + + if (GetBankSide(bank) != SIDE_PLAYER) + { + if (GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_HP) == 0) + SetHealthboxSpriteInvisible(healthboxSpriteId); + } + else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) + { + if (GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_HP) == 0) + SetHealthboxSpriteInvisible(healthboxSpriteId); + } + } +} diff --git a/src/roamer.c b/src/roamer.c new file mode 100644 index 000000000..cbe1b6312 --- /dev/null +++ b/src/roamer.c @@ -0,0 +1,218 @@ +#include "global.h" +#include "roamer.h" +#include "pokemon.h" +#include "rng.h" +#include "species.h" +#include "event_data.h" + +enum +{ + MAP_GRP = 0, // map group + MAP_NUM = 1, // map number +}; + +EWRAM_DATA static u8 sLocationHistory[3][2] = {0}; +EWRAM_DATA static u8 sRoamerLocation[2] = {0}; + +static const u8 sRoamerLocations[][6] = +{ + { 0x19, 0x1A, 0x20, 0x21, 0x31, 0xFF }, + { 0x1A, 0x19, 0x20, 0x21, 0xFF, 0xFF }, + { 0x20, 0x1A, 0x19, 0x21, 0xFF, 0xFF }, + { 0x21, 0x20, 0x19, 0x1A, 0x22, 0x26 }, + { 0x22, 0x21, 0x23, 0xFF, 0xFF, 0xFF }, + { 0x23, 0x22, 0x24, 0xFF, 0xFF, 0xFF }, + { 0x24, 0x23, 0x25, 0x26, 0xFF, 0xFF }, + { 0x25, 0x24, 0x26, 0xFF, 0xFF, 0xFF }, + { 0x26, 0x25, 0x21, 0xFF, 0xFF, 0xFF }, + { 0x27, 0x24, 0x28, 0x29, 0xFF, 0xFF }, + { 0x28, 0x27, 0x2A, 0xFF, 0xFF, 0xFF }, + { 0x29, 0x27, 0x2A, 0xFF, 0xFF, 0xFF }, + { 0x2A, 0x28, 0x29, 0x2B, 0xFF, 0xFF }, + { 0x2B, 0x2A, 0x2C, 0xFF, 0xFF, 0xFF }, + { 0x2C, 0x2B, 0x2D, 0xFF, 0xFF, 0xFF }, + { 0x2D, 0x2C, 0x2E, 0xFF, 0xFF, 0xFF }, + { 0x2E, 0x2D, 0x2F, 0xFF, 0xFF, 0xFF }, + { 0x2F, 0x2E, 0x30, 0xFF, 0xFF, 0xFF }, + { 0x30, 0x2F, 0x31, 0xFF, 0xFF, 0xFF }, + { 0x31, 0x30, 0x19, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, +}; + +void ClearRoamerData(void) +{ + memset(&gSaveBlock1Ptr->roamer, 0, sizeof(struct Roamer)); + (&gSaveBlock1Ptr->roamer)->species = SPECIES_LATIAS; +} + +void ClearRoamerLocationData(void) +{ + u8 i; + + for (i = 0; i < 3; i++) + { + sLocationHistory[i][MAP_GRP] = 0; + sLocationHistory[i][MAP_NUM] = 0; + } + + sRoamerLocation[MAP_GRP] = 0; + sRoamerLocation[MAP_NUM] = 0; +} + +static void CreateInitialRoamerMon(bool16 createLatios) +{ + if (!createLatios) + (&gSaveBlock1Ptr->roamer)->species = SPECIES_LATIAS; + else + (&gSaveBlock1Ptr->roamer)->species = SPECIES_LATIOS; + + CreateMon(&gEnemyParty[0], (&gSaveBlock1Ptr->roamer)->species, 40, 0x20, 0, 0, 0, 0); + (&gSaveBlock1Ptr->roamer)->level = 40; + (&gSaveBlock1Ptr->roamer)->status = 0; + (&gSaveBlock1Ptr->roamer)->active = TRUE; + (&gSaveBlock1Ptr->roamer)->ivs = GetMonData(&gEnemyParty[0], MON_DATA_IVS); + (&gSaveBlock1Ptr->roamer)->personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY); + (&gSaveBlock1Ptr->roamer)->hp = GetMonData(&gEnemyParty[0], MON_DATA_MAX_HP); + (&gSaveBlock1Ptr->roamer)->cool = GetMonData(&gEnemyParty[0], MON_DATA_COOL); + (&gSaveBlock1Ptr->roamer)->beauty = GetMonData(&gEnemyParty[0], MON_DATA_BEAUTY); + (&gSaveBlock1Ptr->roamer)->cute = GetMonData(&gEnemyParty[0], MON_DATA_CUTE); + (&gSaveBlock1Ptr->roamer)->smart = GetMonData(&gEnemyParty[0], MON_DATA_SMART); + (&gSaveBlock1Ptr->roamer)->tough = GetMonData(&gEnemyParty[0], MON_DATA_TOUGH); + sRoamerLocation[MAP_GRP] = 0; + sRoamerLocation[MAP_NUM] = sRoamerLocations[Random() % 20][0]; +} + +void InitRoamer(void) +{ + ClearRoamerData(); + ClearRoamerLocationData(); + CreateInitialRoamerMon(gSpecialVar_0x8004); +} + +void UpdateLocationHistoryForRoamer(void) +{ + sLocationHistory[2][MAP_GRP] = sLocationHistory[1][MAP_GRP]; + sLocationHistory[2][MAP_NUM] = sLocationHistory[1][MAP_NUM]; + + sLocationHistory[1][MAP_GRP] = sLocationHistory[0][MAP_GRP]; + sLocationHistory[1][MAP_NUM] = sLocationHistory[0][MAP_NUM]; + + sLocationHistory[0][MAP_GRP] = gSaveBlock1Ptr->location.mapGroup; + sLocationHistory[0][MAP_NUM] = gSaveBlock1Ptr->location.mapNum; +} + +void RoamerMoveToOtherLocationSet(void) +{ + u8 val = 0; + struct Roamer *roamer = &gSaveBlock1Ptr->roamer; + + if (!roamer->active) + return; + + sRoamerLocation[MAP_GRP] = val; + + while (1) + { + val = sRoamerLocations[Random() % 20][0]; + if (sRoamerLocation[MAP_NUM] != val) + { + sRoamerLocation[MAP_NUM] = val; + return; + } + } +} + +void RoamerMove(void) +{ + u8 locSet = 0; + + if ((Random() % 16) == 0) + { + RoamerMoveToOtherLocationSet(); + } + else + { + struct Roamer *roamer = &gSaveBlock1Ptr->roamer; + + if (!roamer->active) + return; + + while (locSet < 20) + { + if (sRoamerLocation[MAP_NUM] == sRoamerLocations[locSet][0]) + { + u8 mapNum; + while (1) + { + mapNum = sRoamerLocations[locSet][(Random() % 5) + 1]; + if (!(sLocationHistory[2][MAP_GRP] == 0 && sLocationHistory[2][MAP_NUM] == mapNum) && mapNum != 0xFF) + break; + } + sRoamerLocation[MAP_NUM] = mapNum; + return; + } + locSet++; + } + } +} + +bool8 IsRoamerAt(u8 mapGroup, u8 mapNum) +{ + struct Roamer *roamer = &gSaveBlock1Ptr->roamer; + + if (roamer->active && mapGroup == sRoamerLocation[MAP_GRP] && mapNum == sRoamerLocation[MAP_NUM]) + return TRUE; + else + return FALSE; +} + +void CreateRoamerMonInstance(void) +{ + struct Pokemon *mon; + struct Roamer *roamer; + + mon = &gEnemyParty[0]; + ZeroEnemyPartyMons(); + roamer = &gSaveBlock1Ptr->roamer; + CreateMonWithIVsPersonality(mon, roamer->species, roamer->level, roamer->ivs, roamer->personality); + SetMonData(mon, MON_DATA_STATUS, &gSaveBlock1Ptr->roamer.status); + SetMonData(mon, MON_DATA_HP, &gSaveBlock1Ptr->roamer.hp); + SetMonData(mon, MON_DATA_COOL, &gSaveBlock1Ptr->roamer.cool); + SetMonData(mon, MON_DATA_BEAUTY, &gSaveBlock1Ptr->roamer.beauty); + SetMonData(mon, MON_DATA_CUTE, &gSaveBlock1Ptr->roamer.cute); + SetMonData(mon, MON_DATA_SMART, &gSaveBlock1Ptr->roamer.smart); + SetMonData(mon, MON_DATA_TOUGH, &gSaveBlock1Ptr->roamer.tough); +} + +bool8 TryStartRoamerEncounter(void) +{ + if (IsRoamerAt(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum) == TRUE && (Random() % 4) == 0) + { + CreateRoamerMonInstance(); + return TRUE; + } + else + { + return FALSE; + } +} + +void UpdateRoamerHPStatus(struct Pokemon *mon) +{ + (&gSaveBlock1Ptr->roamer)->hp = GetMonData(mon, MON_DATA_HP); + (&gSaveBlock1Ptr->roamer)->status = GetMonData(mon, MON_DATA_STATUS); + + RoamerMoveToOtherLocationSet(); +} + +void SetRoamerInactive(void) +{ + struct Roamer *roamer = &gSaveBlock1Ptr->roamer; + roamer->active = FALSE; +} + +void GetRoamerLocation(u8 *mapGroup, u8 *mapNum) +{ + *mapGroup = sRoamerLocation[MAP_GRP]; + *mapNum = sRoamerLocation[MAP_NUM]; +} diff --git a/src/rom4.c b/src/rom4.c new file mode 100644 index 000000000..c538595f2 --- /dev/null +++ b/src/rom4.c @@ -0,0 +1,19 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations +IWRAM_DATA void *gUnknown_03000E0C; +IWRAM_DATA u8 gUnknown_03000E10[4]; +IWRAM_DATA u8 (*gUnknown_03000E14)(u32); +IWRAM_DATA u8 gUnknown_03000E18; +IWRAM_DATA u8 gUnknown_03000E19; +IWRAM_DATA void *rom4_c_unused_03000e1c; + +// Static ROM declarations + +// .rodata + +// .text diff --git a/src/safari_zone.c b/src/safari_zone.c index 3e25468bf..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) @@ -114,7 +114,7 @@ void sub_80FC190(void) { SetMainCallback2(c2_exit_to_overworld_2_switch); } - else if (gBattleOutcome == 8) + else if (gBattleOutcome == BATTLE_SAFARI_OUT_OF_BALLS) { ScriptContext2_RunNewScript(gUnknown_082A4B4C); warp_in(); @@ -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/save.c b/src/save.c index 5ca855247..2c1b26ca9 100644 --- a/src/save.c +++ b/src/save.c @@ -2,17 +2,19 @@ #include "gba/flash_internal.h" #include "save.h" #include "game_stat.h" +#include "task.h" -extern struct SaveSectionOffsets gSaveSectionOffsets[0xE]; extern struct SaveSectionLocation gRamSaveSectionLocations[0xE]; extern u8 gDecompressionBuffer[]; extern u32 gFlashMemoryPresent; extern u16 gUnknown_03006294; +extern bool8 gSoftResetDisabled; + +extern const struct SaveSectionOffsets gSaveSectionOffsets[0xE]; extern void DoSaveFailedScreen(u8); // save_failed_screen extern void LoadSerializedGame(void); // load_save extern bool32 ProgramFlashSectorAndVerify(u8 sector, u8 *data); -extern void ReadFlash(u8 sector, u32 arg1, void* data, u32 size); // iwram common u16 gLastWrittenSector; @@ -576,84 +578,27 @@ u16 CalculateChecksum(void *data, u16 size) return ((checksum >> 16) + checksum); } -#ifdef NONMATCHING -// the initial allocation of the pointer and toAdd variable doesnt match up with the original function. however, forcing it is impossible since gRamSaveSectionLocations is loaded first. void UpdateSaveAddresses(void) { int i = 0; - gRamSaveSectionLocations[i].data = gSaveBlock2Ptr + gSaveSectionOffsets[0].toAdd; - gRamSaveSectionLocations[i].size = gSaveSectionOffsets[0].size; - for(i = 1; i < 5; i++) + gRamSaveSectionLocations[i].data = (void*)(gSaveBlock2Ptr) + gSaveSectionOffsets[i].toAdd; + gRamSaveSectionLocations[i].size = gSaveSectionOffsets[i].size; + + for (i = 1; i < 5; i++) { - gRamSaveSectionLocations[i].data = gSaveBlock1Ptr + gSaveSectionOffsets[i].toAdd; + gRamSaveSectionLocations[i].data = (void*)(gSaveBlock1Ptr) + gSaveSectionOffsets[i].toAdd; gRamSaveSectionLocations[i].size = gSaveSectionOffsets[i].size; } - for(i = 5; i < 14; i++) + for (i = 5; i < 14; i++) { - gRamSaveSectionLocations[i].data = gPokemonStoragePtr + gSaveSectionOffsets[i].toAdd; + gRamSaveSectionLocations[i].data = (void*)(gPokemonStoragePtr) + gSaveSectionOffsets[i].toAdd; gRamSaveSectionLocations[i].size = gSaveSectionOffsets[i].size; + + i++;i--; // needed to match } } -#else -__attribute__((naked)) -void UpdateSaveAddresses(void) -{ - asm(".syntax unified\n\ - push {r4,r5,lr}\n\ - ldr r3, =gRamSaveSectionLocations\n\ - ldr r0, =gSaveBlock2Ptr\n\ - ldr r2, =gSaveSectionOffsets\n\ - ldrh r1, [r2]\n\ - ldr r0, [r0]\n\ - adds r0, r1\n\ - str r0, [r3]\n\ - ldrh r0, [r2, 0x2]\n\ - strh r0, [r3, 0x4]\n\ - ldr r5, =gSaveBlock1Ptr\n\ - adds r3, 0x8\n\ - adds r2, 0x4\n\ - movs r4, 0x3\n\ -_081531AC:\n\ - ldrh r0, [r2]\n\ - ldr r1, [r5]\n\ - adds r1, r0\n\ - str r1, [r3]\n\ - ldrh r0, [r2, 0x2]\n\ - strh r0, [r3, 0x4]\n\ - adds r3, 0x8\n\ - adds r2, 0x4\n\ - subs r4, 0x1\n\ - cmp r4, 0\n\ - bge _081531AC\n\ - movs r4, 0x5\n\ - ldr r1, =gRamSaveSectionLocations\n\ - ldr r5, =gPokemonStoragePtr\n\ - ldr r0, =gSaveSectionOffsets\n\ - adds r3, r1, 0\n\ - adds r3, 0x28\n\ - adds r2, r0, 0\n\ - adds r2, 0x14\n\ -_081531D2:\n\ - ldrh r0, [r2]\n\ - ldr r1, [r5]\n\ - adds r1, r0\n\ - str r1, [r3]\n\ - ldrh r0, [r2, 0x2]\n\ - strh r0, [r3, 0x4]\n\ - adds r3, 0x8\n\ - adds r2, 0x4\n\ - adds r4, 0x1\n\ - cmp r4, 0xD\n\ - ble _081531D2\n\ - pop {r4,r5}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} -#endif extern u32 GetGameStat(u8 index); // rom4 extern void IncrementGameStat(u8 index); // rom4 @@ -860,7 +805,7 @@ u32 sub_81535DC(u8 sector, u8* dst) if (sector != 30 && sector != 31) return 0xFF; - ReadFlash(sector, 0, &gSaveDataBuffer, sizeof(struct SaveSection)); + ReadFlash(sector, 0, (u8 *)&gSaveDataBuffer, sizeof(struct SaveSection)); if (*(u32*)(&gSaveDataBuffer.data[0]) != 0xB39D) return 0xFF; // copies whole save section except u32 counter @@ -894,3 +839,85 @@ u32 sub_8153634(u8 sector, u8* src) return 0xFF; return 1; } + +extern void save_serialize_map(void); +extern void sub_8076D5C(void); +extern void sav2_gender2_inplace_and_xFE(void); +extern void sub_800ADF8(void); +extern bool8 sub_800A520(void); + +void sub_8153688(u8 taskId) +{ + s16* taskData = gTasks[taskId].data; + + switch (taskData[0]) + { + case 0: + gSoftResetDisabled = TRUE; + taskData[0] = 1; + break; + case 1: + sub_800ADF8(); + taskData[0] = 2; + break; + case 2: + if (sub_800A520()) + { + if (taskData[2] == 0) + save_serialize_map(); + taskData[0] = 3; + } + break; + case 3: + if (taskData[2] == 0) + sub_8076D5C(); + sub_8153380(); + taskData[0] = 4; + break; + case 4: + if (++taskData[1] == 5) + { + taskData[1] = 0; + taskData[0] = 5; + } + break; + case 5: + if (sub_81533AC()) + taskData[0] = 6; + else + taskData[0] = 4; + break; + case 6: + sub_81533E0(); + taskData[0] = 7; + break; + case 7: + if (taskData[2] == 0) + sav2_gender2_inplace_and_xFE(); + sub_800ADF8(); + taskData[0] = 8; + break; + case 8: + if (sub_800A520()) + { + sub_8153408(); + taskData[0] = 9; + } + break; + case 9: + sub_800ADF8(); + taskData[0] = 10; + break; + case 10: + if (sub_800A520()) + taskData[0]++; + break; + case 11: + if (++taskData[1] > 5) + { + gSoftResetDisabled = FALSE; + DestroyTask(taskId); + } + break; + } +} diff --git a/src/save_failed_screen.c b/src/save_failed_screen.c new file mode 100755 index 000000000..3f49b89e6 --- /dev/null +++ b/src/save_failed_screen.c @@ -0,0 +1,426 @@ +#include "global.h" +#include "text.h" +#include "main.h" +#include "palette.h" +#include "gpu_regs.h" +#include "bg.h" +#include "task.h" +#include "window.h" +#include "menu.h" +#include "save.h" +#include "gba/flash_internal.h" + +#define MSG_WIN_TOP 12 +#define CLOCK_WIN_TOP (MSG_WIN_TOP - 4) + +extern void AddTextPrinterParametrized2(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, struct TextColor *color, s8 speed, u8 *str); + +extern void (*gGameContinueCallback)(void); + +extern u32 gDamagedSaveSectors; + +extern const u8 gBirchHelpGfx[]; +extern const u8 gBirchBagTilemap[]; +extern const u8 gBirchGrassTilemap[]; +extern const u16 gBirchBagGrassPal[]; +extern const u16 gUnknown_0850FEFC[]; +extern const u16 gUnknown_0860F074[]; +extern const u32 gUnknown_0850E87C[]; +extern struct SaveSection gSaveDataBuffer; + +extern u8 gText_SaveFailedCheckingBackup[]; +extern u8 gText_BackupMemoryDamaged[]; +extern u8 gText_CheckCompleted[]; +extern u8 gText_SaveCompleteGameCannotContinue[]; +extern u8 gText_SaveCompletePressA[]; +extern u8 gText_GamePlayCannotBeContinued[]; + +extern u8 gDecompressionBuffer[]; + +// gSaveFailedClockInfo enum +enum +{ + CLOCK_RUNNING, + DEBUG_TIMER +}; + +// gSaveFailedWindowIds enum +enum +{ + TEXT_WIN_ID, + CLOCK_WIN_ID +}; + +EWRAM_DATA u16 gSaveFailedType = {0}; +EWRAM_DATA u16 gSaveFailedClockInfo[2] = {0}; +EWRAM_DATA u8 gSaveFailedUnused1[12] = {0}; +EWRAM_DATA u8 gSaveFailedWindowIds[2] = {0}; +EWRAM_DATA u8 gSaveFailedUnused2[4] = {0}; + +static const struct OamData sClockOamData = +{ + 160, // Y + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0 +}; + +static const struct BgTemplate gUnknown_085EFD88[3] = +{ + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0, + }, + { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 14, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0, + }, + { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 15, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0, + }, +}; + +static const struct WindowTemplate gUnknown_085EFD94[] = +{ + { + .priority = 255, + .tilemapLeft = 0, + .tilemapTop = 0, + .width = 0, + .height = 0, + .paletteNum = 0, + .baseBlock = 0, + } +}; + +static const struct WindowTemplate gUnknown_085EFD9C[] = +{ + { + .priority = 0, + .tilemapLeft = 1, + .tilemapTop = 13, + .width = 28, + .height = 6, + .paletteNum = 15, + .baseBlock = 1, + } +}; + +static const struct WindowTemplate gUnknown_085EFDA4[] = +{ + { + .priority = 0, + .tilemapLeft = 14, + .tilemapTop = 9, + .width = 2, + .height = 2, + .paletteNum = 15, + .baseBlock = 169, + } +}; + +static const u8 sClockFrames[8][3] = +{ + { 1, 0, 0 }, + { 5, 0, 0 }, + { 9, 0, 0 }, + { 5, 0, 1 }, + { 1, 0, 1 }, + { 5, 1, 1 }, + { 9, 1, 0 }, + { 5, 1, 0 }, +}; + +static const u8 gSaveFailedClockPal[] = INCBIN_U8("graphics/misc/clock_small.gbapal"); +static const u8 gSaveFailedClockGfx[] = INCBIN_U8("graphics/misc/clock_small.4bpp.lz"); + +static void CB2_SaveFailedScreen(void); +static void CB2_WipeSave(void); +static void CB2_GameplayCannotBeContinued(void); +static void CB2_FadeAndReturnToTitleScreen(void); +static void CB2_ReturnToTitleScreen(void); +static void VBlankCB_UpdateClockGraphics(void); +static bool8 VerifySectorWipe(u16 sector); +static bool8 WipeSectors(u32); + +// although this is a general text printer, it's only used in this file. +static void SaveFailedScreenTextPrint(u8 *text, u8 var1, u8 var2) +{ + struct TextColor color; + + color.fgColor = 0; + color.bgColor = 15; + color.shadowColor = 3; + AddTextPrinterParametrized2(gSaveFailedWindowIds[TEXT_WIN_ID], 1, var1 * 8, var2 * 8 + 1, 0, 0, &color, 0, text); +} + +void DoSaveFailedScreen(u8 saveType) +{ + SetMainCallback2(CB2_SaveFailedScreen); + gSaveFailedType = saveType; + gSaveFailedClockInfo[CLOCK_RUNNING] = FALSE; + gSaveFailedClockInfo[DEBUG_TIMER] = 0; + gSaveFailedWindowIds[TEXT_WIN_ID] = 0; + gSaveFailedWindowIds[CLOCK_WIN_ID] = 0; +} + +static void VBlankCB(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void CB2_SaveFailedScreen(void) +{ + switch (gMain.state) + { + case 0: + default: + SetVBlankCallback(NULL); + SetGpuReg(REG_OFFSET_DISPCNT, 0); + SetGpuReg(REG_OFFSET_BG3CNT, 0); + SetGpuReg(REG_OFFSET_BG2CNT, 0); + SetGpuReg(REG_OFFSET_BG1CNT, 0); + SetGpuReg(REG_OFFSET_BG0CNT, 0); + SetGpuReg(REG_OFFSET_BG3HOFS, 0); + SetGpuReg(REG_OFFSET_BG3VOFS, 0); + SetGpuReg(REG_OFFSET_BG2HOFS, 0); + SetGpuReg(REG_OFFSET_BG2VOFS, 0); + SetGpuReg(REG_OFFSET_BG1HOFS, 0); + SetGpuReg(REG_OFFSET_BG1VOFS, 0); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + // how come this doesnt use the Dma manager? + DmaFill16(3, 0, VRAM, VRAM_SIZE); + DmaFill32(3, 0, OAM, OAM_SIZE); + DmaFill16(3, 0, PLTT, PLTT_SIZE); + LZ77UnCompVram(gBirchHelpGfx, (void *)VRAM); + LZ77UnCompVram(gBirchBagTilemap, (void *)(VRAM + 0x7000)); + LZ77UnCompVram(gBirchGrassTilemap, (void *)(VRAM + 0x7800)); + LZ77UnCompVram(gSaveFailedClockGfx, (void *)(VRAM + 0x10020)); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_085EFD88, 3); + SetBgTilemapBuffer(0, (void *)&gDecompressionBuffer[0x2000]); + CpuFill32(0, &gDecompressionBuffer[0x2000], 0x800); + LoadBgTiles(0, gUnknown_0850E87C, 0x120, 0x214); + InitWindows(gUnknown_085EFD94); + // AddWindowWithoutTileMap returns a u16/integer, but the info is clobbered into a u8 here resulting in lost info. Bug? + gSaveFailedWindowIds[TEXT_WIN_ID] = AddWindowWithoutTileMap(gUnknown_085EFD9C); + SetWindowAttribute(gSaveFailedWindowIds[TEXT_WIN_ID], 7, (u32)&gDecompressionBuffer[0x2800]); + gSaveFailedWindowIds[CLOCK_WIN_ID] = AddWindowWithoutTileMap(gUnknown_085EFDA4); + SetWindowAttribute(gSaveFailedWindowIds[CLOCK_WIN_ID], 7, (u32)&gDecompressionBuffer[0x3D00]); + DeactivateAllTextPrinters(); + ResetSpriteData(); + ResetTasks(); + ResetPaletteFade(); + LoadPalette(gBirchBagGrassPal, 0, 0x40); + LoadPalette(gSaveFailedClockPal, 0x100, 0x20); + LoadPalette(gUnknown_0850FEFC, 0xE0, 0x20); + LoadPalette(gUnknown_0860F074, 0xF0, 0x20); + SetWindowBorderStyle(gSaveFailedWindowIds[TEXT_WIN_ID], FALSE, 0x214, 0xE); + SetWindowBorderStyle(gSaveFailedWindowIds[CLOCK_WIN_ID], FALSE, 0x214, 0xE); + FillWindowPixelBuffer(gSaveFailedWindowIds[CLOCK_WIN_ID], 0x11); // backwards? + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + CopyWindowToVram(gSaveFailedWindowIds[CLOCK_WIN_ID], 2); // again? + CopyWindowToVram(gSaveFailedWindowIds[TEXT_WIN_ID], 1); + SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, 0); + EnableInterrupts(1); + SetVBlankCallback(VBlankCB); + SetGpuReg(0, 0x1040); + ShowBg(0); + ShowBg(2); + ShowBg(3); + gMain.state++; + break; + case 1: + if (!UpdatePaletteFade()) + { + SetMainCallback2(CB2_WipeSave); + SetVBlankCallback(VBlankCB_UpdateClockGraphics); + } + break; + } +} + +static void CB2_WipeSave(void) +{ + u8 wipeTries = 0; + + gSaveFailedClockInfo[CLOCK_RUNNING] = TRUE; + + while (gDamagedSaveSectors != 0 && wipeTries < 3) + { + if (WipeSectors(gDamagedSaveSectors) != FALSE) + { + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0); + SetMainCallback2(CB2_GameplayCannotBeContinued); + return; + } + + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + SaveFailedScreenTextPrint(gText_CheckCompleted, 1, 0); + HandleSavingData(gSaveFailedType); + + if (gDamagedSaveSectors != 0) + { + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0); + } + + wipeTries++; + } + + if (wipeTries == 3) + { + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0); + } + else + { + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + + if (gGameContinueCallback == NULL) + SaveFailedScreenTextPrint(gText_SaveCompleteGameCannotContinue, 1, 0); + else + SaveFailedScreenTextPrint(gText_SaveCompletePressA, 1, 0); + } + + SetMainCallback2(CB2_FadeAndReturnToTitleScreen); +} + +static void CB2_GameplayCannotBeContinued(void) +{ + gSaveFailedClockInfo[CLOCK_RUNNING] = FALSE; + + if (gMain.newKeys & A_BUTTON) + { + FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11); + SaveFailedScreenTextPrint(gText_GamePlayCannotBeContinued, 1, 0); + SetVBlankCallback(VBlankCB); + SetMainCallback2(CB2_FadeAndReturnToTitleScreen); + } +} + +static void CB2_FadeAndReturnToTitleScreen(void) +{ + gSaveFailedClockInfo[CLOCK_RUNNING] = FALSE; + + if (gMain.newKeys & A_BUTTON) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0); + SetVBlankCallback(VBlankCB); + SetMainCallback2(CB2_ReturnToTitleScreen); + } +} + +static void CB2_ReturnToTitleScreen(void) +{ + if (!UpdatePaletteFade()) + { + if (gGameContinueCallback == NULL) // no callback exists, so do a soft reset. + { + DoSoftReset(); + } + else + { + SetMainCallback2((MainCallback)gGameContinueCallback); + gGameContinueCallback = NULL; + } + } +} + +static void VBlankCB_UpdateClockGraphics(void) +{ + unsigned int n = (gMain.vblankCounter2 >> 3) & 7; + + gMain.oamBuffer[0] = sClockOamData; + gMain.oamBuffer[0].x = 112; + gMain.oamBuffer[0].y = (CLOCK_WIN_TOP + 1) * 8;; + + if (gSaveFailedClockInfo[CLOCK_RUNNING] != FALSE) + { + gMain.oamBuffer[0].tileNum = sClockFrames[n][0]; + gMain.oamBuffer[0].matrixNum = (sClockFrames[n][2] << 4) | (sClockFrames[n][1] << 3); + } + else + { + gMain.oamBuffer[0].tileNum = 1; + } + + CpuFastCopy(gMain.oamBuffer, (void *)OAM, 4); + + if (gSaveFailedClockInfo[DEBUG_TIMER]) + gSaveFailedClockInfo[DEBUG_TIMER]--; +} + +static bool8 VerifySectorWipe(u16 sector) +{ + u32 *ptr = (u32 *)&gSaveDataBuffer; + u16 i; + + ReadFlash(sector, 0, (u8 *)ptr, 4096); + + for (i = 0; i < 0x400; i++, ptr++) + if (*ptr) + return TRUE; + + return FALSE; +} + +static bool8 WipeSector(u16 sector) +{ + u16 i, j; + bool8 failed = TRUE; + + for (i = 0; failed && i < 130; i++) + { + for (j = 0; j < 0x1000; j++) + ProgramFlashByte(sector, j, 0); + + failed = VerifySectorWipe(sector); + } + + return failed; +} + +static bool8 WipeSectors(u32 sectorBits) +{ + u16 i; + + for (i = 0; i < 0x20; i++) + if ((sectorBits & (1 << i)) && !WipeSector(i)) + sectorBits &= ~(1 << i); + + if (sectorBits == 0) + return FALSE; + else + return TRUE; +} diff --git a/src/save_location.c b/src/save_location.c new file mode 100755 index 000000000..61a5fd30d --- /dev/null +++ b/src/save_location.c @@ -0,0 +1,146 @@ +#include "global.h" +#include "save_location.h" +#include "map_constants.h" + +// used to make the list defines a little less ugly. +#define MAP(name) ((MAP_GROUP_##name << 8) + (MAP_ID_##name)) + +// specialSaveWarp flags +#define POKECENTER_SAVEWARP (1 << 1) +#define LOBBY_SAVEWARP (1 << 2) +#define UNK_SPECIAL_SAVE_WARP_FLAG_3 (1 << 3) + +static bool32 IsCurMapInLocationList(const u16 *list) +{ + u16 locSum = (gSaveBlock1Ptr->location.mapGroup << 8) + (gSaveBlock1Ptr->location.mapNum); + + // im sure it was written a different way, but for the love of christ I cant figure out how to write it different where it still matches. + if (*list != 0xFFFF) + { + u16 termValue = 0xFFFF; + const u16 *localList; + for (localList = list; *localList != termValue; localList++) + if (*localList == locSum) + return TRUE; + } + return FALSE; +} + +// TODO: Not require a packed u16 array for these lists +static const u16 sSaveLocationPokeCenterList[] = +{ + MAP(OLDALE_TOWN_POKEMON_CENTER_1F), + MAP(OLDALE_TOWN_POKEMON_CENTER_2F), + MAP(DEWFORD_TOWN_POKEMON_CENTER_1F), + MAP(DEWFORD_TOWN_POKEMON_CENTER_2F), + MAP(LAVARIDGE_TOWN_POKEMON_CENTER_1F), + MAP(LAVARIDGE_TOWN_POKEMON_CENTER_2F), + MAP(FALLARBOR_TOWN_POKEMON_CENTER_1F), + MAP(FALLARBOR_TOWN_POKEMON_CENTER_2F), + MAP(VERDANTURF_TOWN_POKEMON_CENTER_1F), + MAP(VERDANTURF_TOWN_POKEMON_CENTER_2F), + MAP(PACIFIDLOG_TOWN_POKEMON_CENTER_1F), + MAP(PACIFIDLOG_TOWN_POKEMON_CENTER_2F), + MAP(PETALBURG_CITY_POKEMON_CENTER_1F), + MAP(PETALBURG_CITY_POKEMON_CENTER_2F), + MAP(SLATEPORT_CITY_POKEMON_CENTER_1F), + MAP(SLATEPORT_CITY_POKEMON_CENTER_2F), + MAP(MAUVILLE_CITY_POKEMON_CENTER_1F), + MAP(MAUVILLE_CITY_POKEMON_CENTER_2F), + MAP(RUSTBORO_CITY_POKEMON_CENTER_1F), + MAP(RUSTBORO_CITY_POKEMON_CENTER_2F), + MAP(FORTREE_CITY_POKEMON_CENTER_1F), + MAP(FORTREE_CITY_POKEMON_CENTER_2F), + MAP(LILYCOVE_CITY_POKEMON_CENTER_1F), + MAP(LILYCOVE_CITY_POKEMON_CENTER_2F), + MAP(MOSSDEEP_CITY_POKEMON_CENTER_1F), + MAP(MOSSDEEP_CITY_POKEMON_CENTER_2F), + MAP(SOOTOPOLIS_CITY_POKEMON_CENTER_1F), + MAP(SOOTOPOLIS_CITY_POKEMON_CENTER_2F), + MAP(EVER_GRANDE_CITY_POKEMON_CENTER_1F), + MAP(EVER_GRANDE_CITY_POKEMON_CENTER_2F), + MAP(EVER_GRANDE_CITY_POKEMON_LEAGUE_1F), + MAP(EVER_GRANDE_CITY_POKEMON_LEAGUE_2F), + MAP(BATTLE_FRONTIER_POKEMON_CENTER_1F), + MAP(BATTLE_FRONTIER_POKEMON_CENTER_2F), + MAP(SINGLE_BATTLE_COLOSSEUM), + MAP(TRADE_CENTER), + MAP(RECORD_CORNER), + MAP(DOUBLE_BATTLE_COLOSSEUM), + 0xFFFF, +}; + +static bool32 IsCurMapPokeCenter(void) +{ + return IsCurMapInLocationList(sSaveLocationPokeCenterList); +} + +static const u16 sSaveLocationReloadLocList[] = // there's only 1 location, and it's presumed its for the save reload feature for battle tower +{ + MAP(BATTLE_TOWER_LOBBY), + 0xFFFF, +}; + +static bool32 IsCurMapReloadLocation(void) +{ + return IsCurMapInLocationList(sSaveLocationReloadLocList); +} + +// nulled out list. unknown what this would have been +static const u16 sUnknown_0861440E[] = +{ + 0xFFFF, +}; + +bool32 sub_81AFCEC(void) +{ + return IsCurMapInLocationList(sUnknown_0861440E); +} + +static void TrySetPokeCenterWarpStatus(void) +{ + if (IsCurMapPokeCenter() == FALSE) + gSaveBlock2Ptr->specialSaveWarp &= ~(POKECENTER_SAVEWARP); + else + gSaveBlock2Ptr->specialSaveWarp |= POKECENTER_SAVEWARP; +} + +static void TrySetReloadWarpStatus(void) +{ + if (!IsCurMapReloadLocation()) + gSaveBlock2Ptr->specialSaveWarp &= ~(LOBBY_SAVEWARP); + else + gSaveBlock2Ptr->specialSaveWarp |= LOBBY_SAVEWARP; +} + +// this function definitely sets a warp status, but because the list is empty, it's unknown what this does yet. +static void sub_81AFD5C(void) +{ + if (!sub_81AFCEC()) + gSaveBlock2Ptr->specialSaveWarp &= ~(UNK_SPECIAL_SAVE_WARP_FLAG_3); + else + gSaveBlock2Ptr->specialSaveWarp |= UNK_SPECIAL_SAVE_WARP_FLAG_3; +} + +void TrySetMapSaveWarpStatus(void) +{ + TrySetPokeCenterWarpStatus(); + TrySetReloadWarpStatus(); + sub_81AFD5C(); +} + +void sub_81AFDA0(void) +{ + gSaveBlock2Ptr->field_A8 |= 0x8000; + gSaveBlock2Ptr->field_A8 |= 0x1; + gSaveBlock2Ptr->field_A8 |= 0x2; + gSaveBlock2Ptr->field_A8 |= 0x4; + gSaveBlock2Ptr->field_A8 |= 0x10; + gSaveBlock2Ptr->field_A8 |= 0x20; + gSaveBlock2Ptr->field_A8 |= 0x8; +} + +void sub_81AFDD0(void) +{ + gSaveBlock2Ptr->specialSaveWarp |= 0x80; +} diff --git a/src/scrcmd.c b/src/scrcmd.c new file mode 100644 index 000000000..af314609c --- /dev/null +++ b/src/scrcmd.c @@ -0,0 +1,2452 @@ +#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; + +extern u16 gSpecialVar_0x8000; +extern u16 gSpecialVar_0x8001; +extern u16 gSpecialVar_0x8002; +extern u16 gSpecialVar_0x8004; + +extern u16 gScriptResult; + +extern u16 gScriptContestCategory; + +IWRAM_DATA u8 gUnknown_03000F30; + +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; +} + +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)); + + 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/script_menu.c b/src/script_menu.c new file mode 100644 index 000000000..04f1e82b7 --- /dev/null +++ b/src/script_menu.c @@ -0,0 +1,16 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u8 gUnknown_03001124[6]; +IWRAM_DATA u32 filler_0300112c; + +// Static ROM declarations + +// .rodata + +// .text 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/start_menu.c b/src/start_menu.c index ac393ce2e..37331a922 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -170,13 +170,13 @@ extern const u8 gText_BattlePyramidFloor[]; void DisplayPyramidFloorWindow(void) { // TODO: fix location - if (*(u16*)(&gSaveBlock2Ptr->field_CAA[8]) == 7) + if (gSaveBlock2Ptr->field_CAA[4] == 7) sBattlePyramidFloorWindowId = AddWindow(&gPyramidFloorWindowTemplate_1); else sBattlePyramidFloorWindowId = AddWindow(&gPyramidFloorWindowTemplate_2); PutWindowTilemap(sBattlePyramidFloorWindowId); sub_81973FC(sBattlePyramidFloorWindowId, 0); - StringCopy(gStringVar1, gUnknown_08510510[*(u16*)(&gSaveBlock2Ptr->field_CAA[8])]); + StringCopy(gStringVar1, gUnknown_08510510[gSaveBlock2Ptr->field_CAA[4]]); StringExpandPlaceholders(gStringVar4, gText_BattlePyramidFloor); PrintTextOnWindow(sBattlePyramidFloorWindowId, 1, gStringVar4, 0, 1, 0xFF, NULL); CopyWindowToVram(sBattlePyramidFloorWindowId, 2); @@ -207,7 +207,7 @@ static bool32 PrintStartMenuItemsMultistep(s16 *index, u32 n) do { - if (sStartMenuItems[sCurrentStartMenuActions[_index]].func == StartMenu_PlayerName) + if (sStartMenuItems[sCurrentStartMenuActions[_index]].func.u8_void == StartMenu_PlayerName) { } diff --git a/src/string_util.c b/src/string_util.c index 92e9f19e8..ea50ba5a5 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -625,7 +625,7 @@ u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color) return dest; } -bool32 sub_8009228(u8 *str) +bool32 IsStringJapanese(u8 *str) { while (*str != EOS) { diff --git a/src/text.c b/src/text.c index 0081a8244..8108a6867 100644 --- a/src/text.c +++ b/src/text.c @@ -1,9 +1,9 @@ #include "global.h" -#include "text.h" #include "main.h" #include "palette.h" #include "string_util.h" #include "window.h" +#include "text.h" extern void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); extern void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); @@ -32,11 +32,7 @@ u8 gUnknown_03002FB0[0x20]; u8 gUnknown_03002FD0[0x20]; u8 gUnknown_03002FF0[0x20]; u8 gGlyphDimensions[0x2]; -struct { - u8 flag_0:1; - u8 flag_1:1; - u8 flag_2:1; -} gTextFlags; +TextFlags gTextFlags; const u8 gFontHalfRowOffsets[] = { 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, @@ -149,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; @@ -1972,7 +1968,7 @@ bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) } } -bool8 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) +bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) { bool8 result = FALSE; if (gTextFlags.flag_2 != 0) @@ -1991,9 +1987,9 @@ bool8 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) return result; } -bool8 TextPrinterWait(struct TextPrinter *textPrinter) +bool16 TextPrinterWait(struct TextPrinter *textPrinter) { - bool8 result = FALSE; + bool16 result = FALSE; if (gTextFlags.flag_2 != 0) { result = TextPrinterWaitAutoMode(textPrinter); diff --git a/src/tileset_anims.c b/src/tileset_anims.c new file mode 100644 index 000000000..4ad787e1c --- /dev/null +++ b/src/tileset_anims.c @@ -0,0 +1,1411 @@ + +// Includes +#include "global.h" +#include "palette.h" +#include "blend_palette.h" +#include "battle_transition.h" +#include "task.h" + +// Static type declarations + +// Static RAM declarations + +static EWRAM_DATA struct { + const u16 *src; + u16 *dest; + u16 size; +} sTilesetDMA3TransferBuffer[20] = {0}; + +static u8 sTilesetDMA3TransferBufferSize; +static u16 sPrimaryTilesetCBCounter; +static u16 sPrimaryTilesetCBBufferSize; +static u16 sSecondaryTilesetCBCounter; +static u16 sSecondaryTilesetCBBufferSize; +static void (*sPrimaryTilesetCB)(u16); +static void (*sSecondaryTilesetCB)(u16); + +// Static ROM declarations + +static void cur_mapheader_run_tileset1_func(void); +static void cur_mapheader_run_tileset2_func(void); + +// .rodata + + +const u16 gUnknown_085105C4[] = INCBIN_U16("data/tilesets/primary/general/anim/0/1.4bpp"); + +const u16 gUnknown_08510644[] = INCBIN_U16("data/tilesets/primary/general/anim/0/0.4bpp"); + +const u16 gUnknown_085106C4[] = INCBIN_U16("data/tilesets/primary/general/anim/0/2.4bpp"); + +const u16 tileset_anims_space_0[16] = {}; + +const u16 *const gTilesetAnims_General0[] = { + gUnknown_08510644, + gUnknown_085105C4, + gUnknown_08510644, + gUnknown_085106C4 +}; + +const u16 gUnknown_08510774[] = INCBIN_U16("data/tilesets/primary/general/anim/1/0.4bpp"); + +const u16 gUnknown_08510B34[] = INCBIN_U16("data/tilesets/primary/general/anim/1/1.4bpp"); + +const u16 gUnknown_08510EF4[] = INCBIN_U16("data/tilesets/primary/general/anim/1/2.4bpp"); + +const u16 gUnknown_085112B4[] = INCBIN_U16("data/tilesets/primary/general/anim/1/3.4bpp"); + +const u16 gUnknown_08511674[] = INCBIN_U16("data/tilesets/primary/general/anim/1/4.4bpp"); + +const u16 gUnknown_08511A34[] = INCBIN_U16("data/tilesets/primary/general/anim/1/5.4bpp"); + +const u16 gUnknown_08511DF4[] = INCBIN_U16("data/tilesets/primary/general/anim/1/6.4bpp"); + +const u16 gUnknown_085121B4[] = INCBIN_U16("data/tilesets/primary/general/anim/1/7.4bpp"); + +const u16 *const gTilesetAnims_General1[] = { + gUnknown_08510774, + gUnknown_08510B34, + gUnknown_08510EF4, + gUnknown_085112B4, + gUnknown_08511674, + gUnknown_08511A34, + gUnknown_08511DF4, + gUnknown_085121B4 +}; + +const u16 gUnknown_08512594[] = INCBIN_U16("data/tilesets/primary/general/anim/2/0.4bpp"); + +const u16 gUnknown_085126D4[] = INCBIN_U16("data/tilesets/primary/general/anim/2/1.4bpp"); + +const u16 gUnknown_08512814[] = INCBIN_U16("data/tilesets/primary/general/anim/2/2.4bpp"); + +const u16 gUnknown_08512954[] = INCBIN_U16("data/tilesets/primary/general/anim/2/3.4bpp"); + +const u16 gUnknown_08512A94[] = INCBIN_U16("data/tilesets/primary/general/anim/2/4.4bpp"); + +const u16 gUnknown_08512BD4[] = INCBIN_U16("data/tilesets/primary/general/anim/2/5.4bpp"); + +const u16 gUnknown_08512D14[] = INCBIN_U16("data/tilesets/primary/general/anim/2/6.4bpp"); + +const u16 *const gTilesetAnims_General2[] = { + gUnknown_08512594, + gUnknown_085126D4, + gUnknown_08512814, + gUnknown_08512954, + gUnknown_08512A94, + gUnknown_08512BD4, + gUnknown_08512D14, + gUnknown_08512594 +}; + +const u16 gUnknown_08512E74[] = INCBIN_U16("data/tilesets/primary/general/anim/3/0.4bpp"); + +const u16 gUnknown_08512F34[] = INCBIN_U16("data/tilesets/primary/general/anim/3/1.4bpp"); + +const u16 gUnknown_08512FF4[] = INCBIN_U16("data/tilesets/primary/general/anim/3/2.4bpp"); + +const u16 gUnknown_085130B4[] = INCBIN_U16("data/tilesets/primary/general/anim/3/3.4bpp"); + +const u16 *const gTilesetAnims_General3[] = { + gUnknown_08512E74, + gUnknown_08512F34, + gUnknown_08512FF4, + gUnknown_085130B4 +}; + +const u16 gUnknown_08513184[] = INCBIN_U16("data/tilesets/primary/general/anim/4/0.4bpp"); + +const u16 gUnknown_085132C4[] = INCBIN_U16("data/tilesets/primary/general/anim/4/1.4bpp"); + +const u16 gUnknown_08513404[] = INCBIN_U16("data/tilesets/primary/general/anim/4/2.4bpp"); + +const u16 gUnknown_08513544[] = INCBIN_U16("data/tilesets/primary/general/anim/4/3.4bpp"); + +const u16 *const gTilesetAnims_General4[] = { + gUnknown_08513184, + gUnknown_085132C4, + gUnknown_08513404, + gUnknown_08513544 +}; + +const u16 gUnknown_08513694[] = INCBIN_U16("data/tilesets/secondary/lavaridge/anim/0.4bpp"); + +const u16 gUnknown_08513714[] = INCBIN_U16("data/tilesets/secondary/lavaridge/anim/1.4bpp"); + +const u16 gUnknown_08513794[] = INCBIN_U16("data/tilesets/secondary/lavaridge/anim/2.4bpp"); + +const u16 gUnknown_08513814[] = INCBIN_U16("data/tilesets/secondary/lavaridge/anim/3.4bpp"); + +const u16 *const gTilesetAnims_Lavaridge0[] = { + gUnknown_08513694, + gUnknown_08513714, + gUnknown_08513794, + gUnknown_08513814 +}; + +const u16 gUnknown_085138A4[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/0/0.4bpp"); + +const u16 gUnknown_08513C64[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/0/1.4bpp"); + +const u16 gUnknown_08514024[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/0/2.4bpp"); + +const u16 *const gTilesetAnims_Pacifidlog0[] = { + gUnknown_085138A4, + gUnknown_08513C64, + gUnknown_08514024, + gUnknown_08513C64 +}; + +const u16 gUnknown_085143F4[] = INCBIN_U16("data/tilesets/secondary/underwater/anim/0.4bpp"); + +const u16 gUnknown_08514474[] = INCBIN_U16("data/tilesets/secondary/underwater/anim/1.4bpp"); + +const u16 gUnknown_085144F4[] = INCBIN_U16("data/tilesets/secondary/underwater/anim/2.4bpp"); + +const u16 gUnknown_08514574[] = INCBIN_U16("data/tilesets/secondary/underwater/anim/3.4bpp"); + +const u16 *const gTilesetAnims_Underwater0[] = { + gUnknown_085143F4, + gUnknown_08514474, + gUnknown_085144F4, + gUnknown_08514574 +}; + +const u16 gUnknown_08514604[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/0.4bpp"); + +const u16 gUnknown_08514704[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/1.4bpp"); + +const u16 gUnknown_08514804[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/2.4bpp"); + +const u16 gUnknown_08514904[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/3.4bpp"); + +const u16 gUnknown_08514A04[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/4.4bpp"); + +const u16 gUnknown_08514B04[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/5.4bpp"); + +const u16 gUnknown_08514C04[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/6.4bpp"); + +const u16 gUnknown_08514D04[] = INCBIN_U16("data/tilesets/secondary/pacifidlog/anim/1/7.4bpp"); + +const u16 *const gTilesetAnims_Pacifidlog1[] = { + gUnknown_08514604, + gUnknown_08514704, + gUnknown_08514804, + gUnknown_08514904, + gUnknown_08514A04, + gUnknown_08514B04, + gUnknown_08514C04, + gUnknown_08514D04 +}; + +const u16 gUnknown_08514E24[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/a/0.4bpp"); + +const u16 gUnknown_08514EA4[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/a/1.4bpp"); + +const u16 gUnknown_08514F24[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/a/2.4bpp"); + +const u16 gUnknown_08514FA4[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/a/3.4bpp"); + +const u16 gUnknown_08515024[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/1/a/1.4bpp"); + +const u16 gUnknown_085150A4[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/b/0.4bpp"); + +const u16 gUnknown_08515124[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/b/1.4bpp"); + +const u16 gUnknown_085151A4[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/b/2.4bpp"); + +const u16 gUnknown_08515224[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/0/b/3.4bpp"); + +const u16 gUnknown_085152A4[] = INCBIN_U16("data/tilesets/secondary/mauville/anim/1/b/1.4bpp"); + +const u16 tileset_anims_space_1[16] = {}; + +u16 *const gTilesetAnims_MauvilleVDests0[] = { + (u16 *)(BG_VRAM + 0x4c00), + (u16 *)(BG_VRAM + 0x4c80), + (u16 *)(BG_VRAM + 0x4d00), + (u16 *)(BG_VRAM + 0x4d80), + (u16 *)(BG_VRAM + 0x4e00), + (u16 *)(BG_VRAM + 0x4e80), + (u16 *)(BG_VRAM + 0x4f00), + (u16 *)(BG_VRAM + 0x4f80) +}; + +u16 *const gTilesetAnims_MauvilleVDests1[] = { + (u16 *)(BG_VRAM + 0x5000), + (u16 *)(BG_VRAM + 0x5080), + (u16 *)(BG_VRAM + 0x5100), + (u16 *)(BG_VRAM + 0x5180), + (u16 *)(BG_VRAM + 0x5200), + (u16 *)(BG_VRAM + 0x5280), + (u16 *)(BG_VRAM + 0x5300), + (u16 *)(BG_VRAM + 0x5380) +}; + +const u16 *const gTilesetAnims_Mauville0a[] = { + gUnknown_08514E24, + gUnknown_08514E24, + gUnknown_08514EA4, + gUnknown_08514F24, + gUnknown_08514FA4, + gUnknown_08514FA4, + gUnknown_08514FA4, + gUnknown_08514FA4, + gUnknown_08514FA4, + gUnknown_08514FA4, + gUnknown_08514F24, + gUnknown_08514EA4 +}; + +const u16 *const gTilesetAnims_Mauville0b[] = { + gUnknown_085150A4, + gUnknown_085150A4, + gUnknown_08515124, + gUnknown_085151A4, + gUnknown_08515224, + gUnknown_08515224, + gUnknown_08515224, + gUnknown_08515224, + gUnknown_08515224, + gUnknown_08515224, + gUnknown_085151A4, + gUnknown_08515124 +}; + +const u16 *const gTilesetAnims_Mauville1a[] = { + gUnknown_08514E24, + gUnknown_08514E24, + gUnknown_08515024, + gUnknown_08515024 +}; + +const u16 *const gTilesetAnims_Mauville1b[] = { + gUnknown_085150A4, + gUnknown_085150A4, + gUnknown_085152A4, + gUnknown_085152A4 +}; + +const u16 gUnknown_08515404[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/0.4bpp"); + +const u16 gUnknown_08515484[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/1.4bpp"); + +const u16 gUnknown_08515504[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/2.4bpp"); + +const u16 gUnknown_08515584[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/3.4bpp"); + +const u16 gUnknown_08515604[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/4.4bpp"); + +const u16 gUnknown_08515684[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/5.4bpp"); + +const u16 gUnknown_08515704[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/6.4bpp"); + +const u16 gUnknown_08515784[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/0/7.4bpp"); + +u16 *const gTilesetAnims_RustboroVDests0[] = { + (u16 *)(BG_VRAM + 0x5000), + (u16 *)(BG_VRAM + 0x5080), + (u16 *)(BG_VRAM + 0x5100), + (u16 *)(BG_VRAM + 0x5180), + (u16 *)(BG_VRAM + 0x5200), + (u16 *)(BG_VRAM + 0x5280), + (u16 *)(BG_VRAM + 0x5300), + (u16 *)(BG_VRAM + 0x5380) +}; + +const u16 *const gTilesetAnims_Rustboro0[] = { + gUnknown_08515404, + gUnknown_08515484, + gUnknown_08515504, + gUnknown_08515584, + gUnknown_08515604, + gUnknown_08515684, + gUnknown_08515704, + gUnknown_08515784 +}; + +const u16 gUnknown_08515844[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/1/0.4bpp"); + +const u16 gUnknown_085158C4[] = INCBIN_U16("data/tilesets/secondary/rustboro/anim/1/1.4bpp"); + +const u16 tileset_anims_space_2[16] = {}; + +const u16 *const gTilesetAnims_Rustboro1[] = { + gUnknown_08515844, + gUnknown_085158C4 +}; + +const u16 gUnknown_0851596C[] = INCBIN_U16("data/tilesets/secondary/cave/anim/0.4bpp"); + +const u16 gUnknown_085159EC[] = INCBIN_U16("data/tilesets/secondary/cave/anim/1.4bpp"); + +const u16 gUnknown_08515A6C[] = INCBIN_U16("data/tilesets/secondary/cave/anim/2.4bpp"); + +const u16 gUnknown_08515AEC[] = INCBIN_U16("data/tilesets/secondary/cave/anim/3.4bpp"); + +const u16 gUnknown_08515B6C[] = INCBIN_U16("data/tilesets/secondary/cave/anim/unused/0.4bpp"); + +const u16 gUnknown_08515BEC[] = INCBIN_U16("data/tilesets/secondary/cave/anim/unused/1.4bpp"); + +const u16 gUnknown_08515C6C[] = INCBIN_U16("data/tilesets/secondary/cave/anim/unused/2.4bpp"); + +const u16 gUnknown_08515CEC[] = INCBIN_U16("data/tilesets/secondary/cave/anim/unused/3.4bpp"); + +const u16 tileset_anims_space_3[16] = {}; + +const u16 *const gTilesetAnims_Lavaridge1_Cave0[] = { + gUnknown_0851596C, + gUnknown_085159EC, + gUnknown_08515A6C, + gUnknown_08515AEC +}; + +const u16 gUnknown_08515D9C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/0.4bpp"); + +const u16 gUnknown_08515E1C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/1.4bpp"); + +const u16 gUnknown_08515E9C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/2.4bpp"); + +const u16 gUnknown_08515F1C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/3.4bpp"); + +const u16 gUnknown_08515F9C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/4.4bpp"); + +const u16 gUnknown_0851601C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/5.4bpp"); + +const u16 gUnknown_0851609C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/6.4bpp"); + +const u16 gUnknown_0851611C[] = INCBIN_U16("data/tilesets/secondary/ever_grande/anim/7.4bpp"); + +const u16 tileset_anims_space_4[16] = {}; + +u16 *const gTilesetAnims_EverGrandeVDests0[] = { + (u16 *)(BG_VRAM + 0x5c00), + (u16 *)(BG_VRAM + 0x5c80), + (u16 *)(BG_VRAM + 0x5d00), + (u16 *)(BG_VRAM + 0x5d80), + (u16 *)(BG_VRAM + 0x5e00), + (u16 *)(BG_VRAM + 0x5e80), + (u16 *)(BG_VRAM + 0x5f00), + (u16 *)(BG_VRAM + 0x5f80) +}; + +const u16 *const gTilesetAnims_EverGrande0[] = { + gUnknown_08515D9C, + gUnknown_08515E1C, + gUnknown_08515E9C, + gUnknown_08515F1C, + gUnknown_08515F9C, + gUnknown_0851601C, + gUnknown_0851609C, + gUnknown_0851611C +}; + +const u16 gUnknown_085161FC[] = INCBIN_U16("data/tilesets/secondary/dewford/anim/0.4bpp"); + +const u16 gUnknown_085162BC[] = INCBIN_U16("data/tilesets/secondary/dewford/anim/1.4bpp"); + +const u16 gUnknown_0851637C[] = INCBIN_U16("data/tilesets/secondary/dewford/anim/2.4bpp"); + +const u16 gUnknown_0851643C[] = INCBIN_U16("data/tilesets/secondary/dewford/anim/3.4bpp"); + +const u16 *const gTilesetAnims_Dewford0[] = { + gUnknown_085161FC, + gUnknown_085162BC, + gUnknown_0851637C, + gUnknown_0851643C +}; + +const u16 gUnknown_0851650C[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_west/anim/0.4bpp"); + +const u16 gUnknown_085165CC[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_west/anim/1.4bpp"); + +const u16 gUnknown_0851668C[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_west/anim/2.4bpp"); + +const u16 gUnknown_0851674C[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_west/anim/3.4bpp"); + +const u16 *const gTilesetAnims_BattleFrontierOutsideWest0[] = { + gUnknown_0851650C, + gUnknown_085165CC, + gUnknown_0851668C, + gUnknown_0851674C +}; + +const u16 gUnknown_0851681C[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_east/anim/0.4bpp"); + +const u16 gUnknown_085168DC[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_east/anim/1.4bpp"); + +const u16 gUnknown_0851699C[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_east/anim/2.4bpp"); + +const u16 gUnknown_08516A5C[] = INCBIN_U16("data/tilesets/secondary/battle_frontier_outside_east/anim/3.4bpp"); + +const u16 *const gTilesetAnims_BattleFrontierOutsideEast0[] = { + gUnknown_0851681C, + gUnknown_085168DC, + gUnknown_0851699C, + gUnknown_08516A5C +}; + +const u16 gUnknown_08516B2C[] = INCBIN_U16("data/tilesets/secondary/slateport/anim/0.4bpp"); + +const u16 gUnknown_08516BAC[] = INCBIN_U16("data/tilesets/secondary/slateport/anim/1.4bpp"); + +const u16 gUnknown_08516C2C[] = INCBIN_U16("data/tilesets/secondary/slateport/anim/2.4bpp"); + +const u16 gUnknown_08516CAC[] = INCBIN_U16("data/tilesets/secondary/slateport/anim/3.4bpp"); + +const u16 *const gTilesetAnims_Slateport0[] = { + gUnknown_08516B2C, + gUnknown_08516BAC, + gUnknown_08516C2C, + gUnknown_08516CAC +}; + +const u16 gUnknown_08516D3C[] = INCBIN_U16("data/tilesets/primary/building/anim/0.4bpp"); + +const u16 gUnknown_08516DBC[] = INCBIN_U16("data/tilesets/primary/building/anim/1.4bpp"); + +const u16 *const gTilesetAnims_InsideBuilding0[] = { + gUnknown_08516D3C, + gUnknown_08516DBC +}; + +const u16 gUnknown_08516E44[] = INCBIN_U16("data/tilesets/secondary/sootopolis_gym/anim/0/0.4bpp"); + +const u16 gUnknown_08516FC4[] = INCBIN_U16("data/tilesets/secondary/sootopolis_gym/anim/0/1.4bpp"); + +const u16 gUnknown_08517144[] = INCBIN_U16("data/tilesets/secondary/sootopolis_gym/anim/0/2.4bpp"); + +const u16 gUnknown_085172C4[] = INCBIN_U16("data/tilesets/secondary/sootopolis_gym/anim/1/0.4bpp"); + +const u16 gUnknown_08517544[] = INCBIN_U16("data/tilesets/secondary/sootopolis_gym/anim/1/1.4bpp"); + +const u16 gUnknown_085177C4[] = INCBIN_U16("data/tilesets/secondary/sootopolis_gym/anim/1/2.4bpp"); + +const u16 *const gTilesetAnims_SootopolisGym0[] = { + gUnknown_08516E44, + gUnknown_08516FC4, + gUnknown_08517144 +}; + +const u16 *const gTilesetAnims_SootopolisGym1[] = { + gUnknown_085172C4, + gUnknown_08517544, + gUnknown_085177C4 +}; + +const u16 gUnknown_08517A5C[] = INCBIN_U16("data/tilesets/secondary/elite_four/anim/1/0.4bpp"); + +const u16 gUnknown_08517ADC[] = INCBIN_U16("data/tilesets/secondary/elite_four/anim/1/1.4bpp"); + +const u16 gUnknown_08517B5C[] = INCBIN_U16("data/tilesets/secondary/elite_four/anim/0/0.4bpp"); + +const u16 gUnknown_08517B7C[] = INCBIN_U16("data/tilesets/secondary/elite_four/anim/0/1.4bpp"); + +const u16 gUnknown_08517B9C[] = INCBIN_U16("data/tilesets/secondary/elite_four/anim/0/2.4bpp"); + +const u16 gUnknown_08517BBC[] = INCBIN_U16("data/tilesets/secondary/elite_four/anim/0/3.4bpp"); + +const u16 tileset_anims_space_5[16] = {}; + +const u16 *const gTilesetAnims_EliteFour1[] = { + gUnknown_08517B5C, + gUnknown_08517B7C, + gUnknown_08517B9C, + gUnknown_08517BBC +}; + +const u16 *const gTilesetAnims_EliteFour0[] = { + gUnknown_08517A5C, + gUnknown_08517ADC +}; + +const u16 gUnknown_08517C14[] = INCBIN_U16("data/tilesets/secondary/mauville_gym/anim/0.4bpp"); + +const u16 gUnknown_08517E14[] = INCBIN_U16("data/tilesets/secondary/mauville_gym/anim/1.4bpp"); + +const u16 tileset_anims_space_6[16] = {}; + +const u16 *const gTilesetAnims_MauvilleGym0[] = { + gUnknown_08517C14, + gUnknown_08517E14 +}; + +const u16 gUnknown_0851803C[] = INCBIN_U16("data/tilesets/secondary/bike_shop/anim/0.4bpp"); + +const u16 gUnknown_0851815C[] = INCBIN_U16("data/tilesets/secondary/bike_shop/anim/1.4bpp"); + +const u16 tileset_anims_space_7[16] = {}; + +const u16 *const gTilesetAnims_BikeShop0[] = { + gUnknown_0851803C, + gUnknown_0851815C +}; + +const u16 gUnknown_085182A4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/0.4bpp"); + +const u16 gUnknown_08518EA4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/1.4bpp"); + +const u16 gUnknown_08519AA4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/2.4bpp"); + +const u16 gUnknown_0851A6A4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/3.4bpp"); + +const u16 gUnknown_0851B2A4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/4.4bpp"); + +const u16 gUnknown_0851BEA4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/5.4bpp"); + +const u16 gUnknown_0851CAA4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/6.4bpp"); + +const u16 gUnknown_0851D6A4[] = INCBIN_U16("data/tilesets/secondary/sootopolis/anim/7.4bpp"); + +const u16 tileset_anims_space_8[16] = {}; + +const u16 gUnknown_0851E2C4[] = INCBIN_U16("data/tilesets/secondary/unused_1/0.4bpp"); + +const u16 gUnknown_0851EAC4[] = INCBIN_U16("data/tilesets/secondary/unused_1/1.4bpp"); + +const u16 gUnknown_0851F2C4[] = INCBIN_U16("data/tilesets/secondary/unused_1/2.4bpp"); + +const u16 gUnknown_0851FAC4[] = INCBIN_U16("data/tilesets/secondary/unused_1/3.4bpp"); + +const u16 *const gTilesetAnims_Sootopolis0[] = { + gUnknown_085182A4, + gUnknown_08518EA4, + gUnknown_08519AA4, + gUnknown_0851A6A4, + gUnknown_0851B2A4, + gUnknown_0851BEA4, + gUnknown_0851CAA4, + gUnknown_0851D6A4 +}; + +const u16 gUnknown_085202E4[] = INCBIN_U16("data/tilesets/secondary/battle_pyramid/anim/0/0.4bpp"); + +const u16 gUnknown_085203E4[] = INCBIN_U16("data/tilesets/secondary/battle_pyramid/anim/0/1.4bpp"); + +const u16 gUnknown_085204E4[] = INCBIN_U16("data/tilesets/secondary/battle_pyramid/anim/0/2.4bpp"); + +const u16 tileset_anims_space_9[16] = {}; + +const u16 gUnknown_08520604[] = INCBIN_U16("data/tilesets/secondary/battle_pyramid/anim/1/0.4bpp"); + +const u16 gUnknown_08520704[] = INCBIN_U16("data/tilesets/secondary/battle_pyramid/anim/1/1.4bpp"); + +const u16 gUnknown_08520804[] = INCBIN_U16("data/tilesets/secondary/battle_pyramid/anim/1/2.4bpp"); + +const u16 tileset_anims_space_10[7808] = {}; + +const u16 gUnknown_08524604[] = INCBIN_U16("data/tilesets/secondary/unused_2/0.4bpp"); + +const u16 tileset_anims_space_11[224] = {}; + +const u16 gUnknown_08524804[] = INCBIN_U16("data/tilesets/secondary/unused_2/1.4bpp"); + +const u16 *const gTilesetAnims_BattlePyramid0[] = { + gUnknown_085202E4, + gUnknown_085203E4, + gUnknown_085204E4 +}; + +const u16 *const gTilesetAnims_BattlePyramid1[] = { + gUnknown_08520604, + gUnknown_08520704, + gUnknown_08520804 +}; + +extern const u16 gUnknown_08D85640[]; +extern const u16 gUnknown_08D85660[]; +extern const u16 gUnknown_08D85680[]; +extern const u16 gUnknown_08D856A0[]; + +static const u16 *const gTilesetAnims_BattleDomePals0[] = { + gUnknown_08D85640, + gUnknown_08D85660, + gUnknown_08D85680, + gUnknown_08D856A0, +}; + +// .text + +static void ResetTilesetAnimBuffer(void) +{ + sTilesetDMA3TransferBufferSize = 0; + CpuFill32(0, sTilesetDMA3TransferBuffer, sizeof sTilesetDMA3TransferBuffer); +} + +static void AppendTilesetAnimToBuffer(const u16 *src, u16 *dest, u16 size) +{ + if (sTilesetDMA3TransferBufferSize < 20) + { + sTilesetDMA3TransferBuffer[sTilesetDMA3TransferBufferSize].src = src; + sTilesetDMA3TransferBuffer[sTilesetDMA3TransferBufferSize].dest = dest; + sTilesetDMA3TransferBuffer[sTilesetDMA3TransferBufferSize].size = size; + sTilesetDMA3TransferBufferSize ++; + } +} + +void TransferTilesetAnimsBuffer(void) +{ + int i; + + for (i = 0; i < sTilesetDMA3TransferBufferSize; i ++) + { + DmaCopy16(3, sTilesetDMA3TransferBuffer[i].src, sTilesetDMA3TransferBuffer[i].dest, sTilesetDMA3TransferBuffer[i].size); + } + sTilesetDMA3TransferBufferSize = 0; +} + +void cur_mapheader_run_tileset_funcs_after_some_cpuset(void) +{ + ResetTilesetAnimBuffer(); + cur_mapheader_run_tileset1_func(); + cur_mapheader_run_tileset2_func(); +} + +void sub_80A0A2C(void) +{ + cur_mapheader_run_tileset2_func(); +} + +void sub_80A0A38(void) +{ + ResetTilesetAnimBuffer(); + if (++sPrimaryTilesetCBCounter >= sPrimaryTilesetCBBufferSize) + sPrimaryTilesetCBCounter = 0; + if (++sSecondaryTilesetCBCounter >= sSecondaryTilesetCBBufferSize) + sSecondaryTilesetCBCounter = 0; + if (sPrimaryTilesetCB) + sPrimaryTilesetCB(sPrimaryTilesetCBCounter); + if (sSecondaryTilesetCB) + sSecondaryTilesetCB(sSecondaryTilesetCBCounter); +} + +static void cur_mapheader_run_tileset1_func(void) +{ + sPrimaryTilesetCBCounter = 0; + sPrimaryTilesetCBBufferSize = 0; + sPrimaryTilesetCB = NULL; + if (gMapHeader.mapData->primaryTileset && gMapHeader.mapData->primaryTileset->callback) + gMapHeader.mapData->primaryTileset->callback(); +} + +static void cur_mapheader_run_tileset2_func(void) +{ + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = 0; + sSecondaryTilesetCB = NULL; + if (gMapHeader.mapData->secondaryTileset && gMapHeader.mapData->secondaryTileset->callback) + gMapHeader.mapData->secondaryTileset->callback(); +} + +void TilesetCb_General(void) +{ + static void sub_80A0B70(u16); + + sPrimaryTilesetCBCounter = 0; + sPrimaryTilesetCBBufferSize = 0x100; + sPrimaryTilesetCB = sub_80A0B70; +} + +void TilesetCb_InsideBuilding(void) +{ + static void sub_80A0BB4(u16); + + sPrimaryTilesetCBCounter = 0; + sPrimaryTilesetCBBufferSize = 0x100; + sPrimaryTilesetCB = sub_80A0BB4; +} + +static void sub_80A0B70(u16 timer) +{ + static void sub_80A0BCC(u16); + static void sub_80A0BF4(u16); + static void sub_80A0C1C(u16); + static void sub_80A0C44(u16); + static void sub_80A12AC(u16); + + if ((timer & 0x0F) == 0) + sub_80A0BCC(timer >> 4); + if ((timer & 0x0F) == 1) + sub_80A0BF4(timer >> 4); + if ((timer & 0x0F) == 2) + sub_80A0C1C(timer >> 4); + if ((timer & 0x0F) == 3) + sub_80A0C44(timer >> 4); + if ((timer & 0x0F) == 4) + sub_80A12AC(timer >> 4); +} + +static void sub_80A0BB4(u16 timer) +{ + static void sub_80A1688(u16); + + if ((timer & 0x7) == 0) + sub_80A1688(timer >> 3); +} + +static void sub_80A0BCC(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_General0[idx], (u16 *)(BG_VRAM + 0x3F80), 0x80); +} + +static void sub_80A0BF4(u16 timer) +{ + u8 idx; + + idx = timer % 8; + AppendTilesetAnimToBuffer(gTilesetAnims_General1[idx], (u16 *)(BG_VRAM + 0x3600), 0x3C0); +} + +static void sub_80A0C1C(u16 timer) +{ + u16 idx; + + idx = timer % 8; + AppendTilesetAnimToBuffer(gTilesetAnims_General2[idx], (u16 *)(BG_VRAM + 0x3a00), 0x140); +} + +static void sub_80A0C44(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_General3[idx], (u16 *)(BG_VRAM + 0x3e00), 0xc0); +} + +void TilesetCb_Petalburg(void) +{ + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = NULL; +} + +void TilesetCb_Rustboro(void) +{ + static void sub_80A103C(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A103C; +} + +void TilesetCb_Dewford(void) +{ + static void sub_80A10B8(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A10B8; +} + +void TilesetCb_Slateport(void) +{ + static void sub_80A10D0(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A10D0; +} + +void TilesetCb_Mauville(void) +{ + static void sub_80A10E8(u16); + + sSecondaryTilesetCBCounter = sPrimaryTilesetCBCounter; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A10E8; +} + +void TilesetCb_Lavaridge(void) +{ + static void sub_80A115C(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A115C; +} + +void TilesetCb_Fallarbor(void) +{ + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = NULL; +} + +void TilesetCb_Fortree(void) +{ + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = NULL; +} + +void TilesetCb_Lilycove(void) +{ + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = NULL; +} + +void TilesetCb_Mossdeep(void) +{ + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = NULL; +} + +void TilesetCb_EverGrande(void) +{ + static void sub_80A1188(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A1188; +} + +void TilesetCb_Pacifidlog(void) +{ + static void sub_80A11FC(u16); + + sSecondaryTilesetCBCounter = sPrimaryTilesetCBCounter; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A11FC; +} + +void TilesetCb_Sootopolis(void) +{ + static void sub_80A122C(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A122C; +} + +void TilesetCb_BattleFrontierOutsideWest(void) +{ + static void sub_80A127C(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A127C; +} + +void TilesetCb_BattleFrontierOutsideEast(void) +{ + static void sub_80A1294(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A1294; +} + +void TilesetCb_Underwater(void) +{ + static void sub_80A1244(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = 128; + sSecondaryTilesetCB = sub_80A1244; +} + +void TilesetCb_SootopolisGym(void) +{ + static void sub_80A15D8(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = 240; + sSecondaryTilesetCB = sub_80A15D8; +} + +void TilesetCb_Cave(void) +{ + static void sub_80A1260(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A1260; +} + +void TilesetCb_EliteFour(void) +{ + static void sub_80A15F0(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = 128; + sSecondaryTilesetCB = sub_80A15F0; +} + +void TilesetCb_MauvilleGym(void) +{ + static void sub_80A15C0(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A15C0; +} + +void TilesetCb_BikeShop(void) +{ + static void sub_80A161C(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A161C; +} + +void TilesetCb_BattlePyramid(void) +{ + static void sub_80A1634(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A1634; +} + +void TilesetCb_BattleDome(void) +{ + static void sub_80A1658(u16); + + sSecondaryTilesetCBCounter = 0; + sSecondaryTilesetCBBufferSize = sPrimaryTilesetCBBufferSize; + sSecondaryTilesetCB = sub_80A1658; +} + +static void sub_80A103C(u16 timer) +{ + static void sub_80A1434(u16, u8); + static void sub_80A1470(u16); + + if ((timer & 0x07) == 0) + { + sub_80A1434(timer >> 3, 0); + sub_80A1470(timer >> 3); + } + if ((timer & 0x07) == 1) + sub_80A1434(timer >> 3, 1); + if ((timer & 0x07) == 2) + sub_80A1434(timer >> 3, 2); + if ((timer & 0x07) == 3) + sub_80A1434(timer >> 3, 3); + if ((timer & 0x07) == 4) + sub_80A1434(timer >> 3, 4); + if ((timer & 0x07) == 5) + sub_80A1434(timer >> 3, 5); + if ((timer & 0x07) == 6) + sub_80A1434(timer >> 3, 6); + if ((timer & 0x07) == 7) + sub_80A1434(timer >> 3, 7); +} + +static void sub_80A10B8(u16 timer) +{ + static void sub_80A1520(u16); + + if ((timer & 7) == 0) + sub_80A1520(timer >> 3); +} + +static void sub_80A10D0(u16 timer) +{ + static void sub_80A1598(u16); + + if ((timer & 15) == 0) + sub_80A1598(timer >> 4); +} + +static void sub_80A10E8(u16 timer) +{ + static void sub_80A1394(u16, u8); + + if ((timer & 0x07) == 0) + sub_80A1394(timer >> 3, 0); + if ((timer & 0x07) == 1) + sub_80A1394(timer >> 3, 1); + if ((timer & 0x07) == 2) + sub_80A1394(timer >> 3, 2); + if ((timer & 0x07) == 3) + sub_80A1394(timer >> 3, 3); + if ((timer & 0x07) == 4) + sub_80A1394(timer >> 3, 4); + if ((timer & 0x07) == 5) + sub_80A1394(timer >> 3, 5); + if ((timer & 0x07) == 6) + sub_80A1394(timer >> 3, 6); + if ((timer & 0x07) == 7) + sub_80A1394(timer >> 3, 7); +} + +static void sub_80A115C(u16 timer) +{ + static void sub_80A12D4(u8); + static void sub_80A1498(u16); + + if ((timer & 0x0F) == 0) + sub_80A12D4(timer >> 4); + if ((timer & 0x0F) == 1) + sub_80A1498(timer >> 4); +} + +static void sub_80A1188(u16 timer) +{ + static void sub_80A14C0(u16, u8); + + if ((timer & 0x07) == 0) + sub_80A14C0(timer >> 3, 0); + if ((timer & 0x07) == 1) + sub_80A14C0(timer >> 3, 1); + if ((timer & 0x07) == 2) + sub_80A14C0(timer >> 3, 2); + if ((timer & 0x07) == 3) + sub_80A14C0(timer >> 3, 3); + if ((timer & 0x07) == 4) + sub_80A14C0(timer >> 3, 4); + if ((timer & 0x07) == 5) + sub_80A14C0(timer >> 3, 5); + if ((timer & 0x07) == 6) + sub_80A14C0(timer >> 3, 6); + if ((timer & 0x07) == 7) + sub_80A14C0(timer >> 3, 7); +} + +static void sub_80A11FC(u16 timer) +{ + static void sub_80A131C(u8); + static void sub_80A136C(u8); + + if ((timer & 0x0F) == 0) + sub_80A131C(timer >> 4); + if ((timer & 0x0F) == 1) + sub_80A136C(timer >> 4); +} + +static void sub_80A122C(u16 timer) +{ + static void sub_80A1798(u16); + + if ((timer & 0x0F) == 0) + sub_80A1798(timer >> 4); +} + +static void sub_80A1244(u16 timer) +{ + static void sub_80A1344(u8); + + if ((timer & 0x0F) == 0) + sub_80A1344(timer >> 4); +} + +static void sub_80A1260(u16 timer) +{ + static void sub_80A14F8(u16); + + if ((timer & 0x0F) == 1) + sub_80A14F8(timer >> 4); +} + +static void sub_80A127C(u16 timer) +{ + static void sub_80A1548(u16); + + if ((timer & 0x07) == 0) + sub_80A1548(timer >> 3); +} + +static void sub_80A1294(u16 timer) +{ + static void sub_80A1570(u16); + + if ((timer & 0x07) == 0) + sub_80A1570(timer >> 3); +} + +static void sub_80A12AC(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_General4[idx], (u16 *)(BG_VRAM + 0x3c00), 0x140); +} + +static void sub_80A12D4(u8 timer) +{ + u8 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Lavaridge0[idx], (u16 *)(BG_VRAM + 0x6400), 0x80); + + idx = (timer + 2) % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Lavaridge0[idx], (u16 *)(BG_VRAM + 0x6480), 0x80); +} + +static void sub_80A131C(u8 timer) +{ + u8 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Pacifidlog0[idx], (u16 *)(BG_VRAM + 0x7a00), 0x3C0); +} + +static void sub_80A1344(u8 timer) +{ + u8 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Underwater0[idx], (u16 *)(BG_VRAM + 0x7e00), 0x80); +} + +static void sub_80A136C(u8 timer) +{ + u8 idx; + + idx = timer % 8; + AppendTilesetAnimToBuffer(gTilesetAnims_Pacifidlog1[idx], (u16 *)(BG_VRAM + 0x7e00), 0x100); +} + +static void sub_80A1394(u16 timer_div, u8 timer_mod) +{ + timer_div -= timer_mod; + if (timer_div < 12) // almost certainly a typo + { + timer_div %= 12; + AppendTilesetAnimToBuffer(gTilesetAnims_Mauville0a[timer_div], gTilesetAnims_MauvilleVDests0[timer_mod], 0x80); + AppendTilesetAnimToBuffer(gTilesetAnims_Mauville0b[timer_div], gTilesetAnims_MauvilleVDests1[timer_mod], 0x80); + } + else + { + timer_div %= 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Mauville1a[timer_div], gTilesetAnims_MauvilleVDests0[timer_mod], 0x80); + AppendTilesetAnimToBuffer(gTilesetAnims_Mauville1b[timer_div], gTilesetAnims_MauvilleVDests1[timer_mod], 0x80); + } +} + +static void sub_80A1434(u16 timer_div, u8 timer_mod) +{ + timer_div -= timer_mod; + timer_div %= 8; + if (gTilesetAnims_Rustboro0[timer_div]) + AppendTilesetAnimToBuffer(gTilesetAnims_Rustboro0[timer_div], gTilesetAnims_RustboroVDests0[timer_mod], 0x80); +} + +static void sub_80A1470(u16 timer) +{ + u16 idx; + + idx = timer % 2; + AppendTilesetAnimToBuffer(gTilesetAnims_Rustboro1[idx], (u16 *)(BG_VRAM + 0x7800), 0x80); +} + +static void sub_80A1498(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Lavaridge1_Cave0[idx], (u16 *)(BG_VRAM + 0x5400), 0x80); +} + +static void sub_80A14C0(u16 timer_div, u8 timer_mod) +{ + timer_div -= timer_mod; + timer_div %= 8; + + AppendTilesetAnimToBuffer(gTilesetAnims_EverGrande0[timer_div], gTilesetAnims_EverGrandeVDests0[timer_mod], 0x80); +} + +static void sub_80A14F8(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Lavaridge1_Cave0[idx], (u16 *)(BG_VRAM + 0x7400), 0x80); +} + +static void sub_80A1520(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Dewford0[idx], (u16 *)(BG_VRAM + 0x5540), 0xC0); +} + +static void sub_80A1548(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_BattleFrontierOutsideWest0[idx], (u16 *)(BG_VRAM + 0x5b40), 0xC0); +} + +static void sub_80A1570(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_BattleFrontierOutsideEast0[idx], (u16 *)(BG_VRAM + 0x5b40), 0xC0); +} + +static void sub_80A1598(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_Slateport0[idx], (u16 *)(BG_VRAM + 0x5c00), 0x80); +} + +static void sub_80A15C0(u16 timer) +{ + static void sub_80A1748(u16); + + if ((timer & 1) == 0) + sub_80A1748(timer >> 1); +} + +static void sub_80A15D8(u16 timer) +{ + static void sub_80A16B0(u16); + + if ((timer & 7) == 0) + sub_80A16B0(timer >> 3); +} + +static void sub_80A15F0(u16 timer) +{ + static void sub_80A1720(u16); + static void sub_80A16F8(u16); + + if ((timer & 0x3f) == 1) + sub_80A1720(timer >> 6); + if ((timer & 0x07) == 1) + sub_80A16F8(timer >> 3); +} +static void sub_80A161C(u16 timer) +{ + static void sub_80A1770(u16); + + if ((timer & 3) == 0) + sub_80A1770(timer >> 2); +} + +static void sub_80A1634(u16 timer) +{ + static void sub_80A17C0(u16); + static void sub_80A17EC(u16); + + if ((timer & 7) == 0) + { + sub_80A17C0(timer >> 3); + sub_80A17EC(timer >> 3); + } +} + +static void sub_80A1658(u16 timer) +{ + static void sub_80A1818(u16); + + if ((timer & 3) == 0) + sub_80A1818(timer >> 2); +} + +static void sub_80A1670(u16 timer) +{ + static void sub_80A1884(u16); + + if ((timer & 3) == 0) + sub_80A1884(timer >> 2); +} + +static void sub_80A1688(u16 timer) +{ + u16 idx; + + idx = timer % 2; + AppendTilesetAnimToBuffer(gTilesetAnims_InsideBuilding0[idx], (u16 *)(BG_VRAM + 0x3e00), 0x80); +} + +static void sub_80A16B0(u16 timer) +{ + u16 idx; + + idx = timer % 3; + AppendTilesetAnimToBuffer(gTilesetAnims_SootopolisGym0[idx], (u16 *)(BG_VRAM + 0x7e00), 0x180); + AppendTilesetAnimToBuffer(gTilesetAnims_SootopolisGym1[idx], (u16 *)(BG_VRAM + 0x7a00), 0x280); +} + +static void sub_80A16F8(u16 timer) +{ + u16 idx; + + idx = timer % 4; + AppendTilesetAnimToBuffer(gTilesetAnims_EliteFour1[idx], (u16 *)(BG_VRAM + 0x7f00), 0x20); +} + +static void sub_80A1720(u16 timer) +{ + u16 idx; + + idx = timer % 2; + AppendTilesetAnimToBuffer(gTilesetAnims_EliteFour0[idx], (u16 *)(BG_VRAM + 0x7c00), 0x80); +} + +static void sub_80A1748(u16 timer) +{ + u16 idx; + + idx = timer % 2; + AppendTilesetAnimToBuffer(gTilesetAnims_MauvilleGym0[idx], (u16 *)(BG_VRAM + 0x5200), 0x200); +} + +static void sub_80A1770(u16 timer) +{ + u16 idx; + + idx = timer % 2; + AppendTilesetAnimToBuffer(gTilesetAnims_BikeShop0[idx], (u16 *)(BG_VRAM + 0x7e00), 0x120); +} + +static void sub_80A1798(u16 timer) +{ + u16 idx; + + idx = timer % 8; + AppendTilesetAnimToBuffer(gTilesetAnims_Sootopolis0[idx], (u16 *)(BG_VRAM + 0x5e00), 0xc00); +} + +static void sub_80A17C0(u16 timer) +{ + u16 idx; + + idx = timer % 3; + AppendTilesetAnimToBuffer(gTilesetAnims_BattlePyramid0[idx], (u16 *)(BG_VRAM + 0x52e0), 0x100); +} + +static void sub_80A17EC(u16 timer) +{ + u16 idx; + + idx = timer % 3; + AppendTilesetAnimToBuffer(gTilesetAnims_BattlePyramid1[idx], (u16 *)(BG_VRAM + 0x50e0), 0x100); +} + +static void sub_80A1818(u16 a1) +{ + CpuCopy16(gTilesetAnims_BattleDomePals0[a1 & 0x3], gPlttBufferUnfaded + 0x80, 32); + BlendPalette(0x80, 0x10, gPaletteFade.y, gPaletteFade.blendColor & 0x7FFF); + if ((u8)FindTaskIdByFunc(sub_8149DFC) != 0xFF ) + { + sSecondaryTilesetCB = sub_80A1670; + sSecondaryTilesetCBBufferSize = 0x20; + } +} + +static void sub_80A1884(u16 a1) +{ + CpuCopy16(gTilesetAnims_BattleDomePals0[a1 & 0x3], gPlttBufferUnfaded + 0x80, 32); + if ((u8)FindTaskIdByFunc(sub_8149DFC) == 0xFF ) + { + BlendPalette(0x80, 0x10, gPaletteFade.y, gPaletteFade.blendColor & 0x7FFF); + if (!--sSecondaryTilesetCBBufferSize) + sSecondaryTilesetCB = NULL; + } +} diff --git a/src/tv.c b/src/tv.c new file mode 100644 index 000000000..3c822b394 --- /dev/null +++ b/src/tv.c @@ -0,0 +1,7927 @@ + +// Includes +#include "global.h" +#include "rtc.h" +#include "overworld.h" +#include "map_constants.h" +#include "rng.h" +#include "event_data.h" +#include "fieldmap.h" +#include "field_camera.h" +#include "strings.h" +#include "string_util.h" +#include "international_string_util.h" +#include "pokemon_storage_system.h" +#include "field_message_box.h" +#include "easy_chat.h" +#include "species.h" +#include "moves.h" +#include "battle.h" +#include "battle_tower.h" +#include "contest.h" +#include "items.h" +#include "item.h" +#include "link.h" +#include "main.h" +#include "event_scripts.h" +#include "shop.h" +#include "lilycove_lady.h" +#include "rom6.h" +#include "pokedex.h" +#include "field_map_obj.h" +#include "text.h" +#include "script_menu.h" +#include "naming_screen.h" +#include "malloc.h" +#include "region_map.h" +#include "decoration.h" +#include "secret_base.h" +#include "tv.h" + +// Static type declarations + +#define rbernoulli(num, den) TV_BernoulliTrial(0xFFFF * (num) / (den)) + +// Static RAM declarations + +s8 sCurTVShowSlot; +u16 sTV_SecretBaseVisitMovesTemp[8]; +u8 sTV_DecorationsBuffer[16]; +struct { + u8 level; + u16 species; + u16 move; +} sTV_SecretBaseVisitMonsTemp[10]; + +IWRAM_DATA u8 sTVShowMixingNumPlayers; +IWRAM_DATA u8 sTVShowNewsMixingNumPlayers; +IWRAM_DATA s8 sTVShowMixingCurSlot; + +EWRAM_DATA u16 sPokemonAnglerSpecies = 0; +EWRAM_DATA u16 sPokemonAnglerAttemptCounters = 0; +EWRAM_DATA u16 sFindThatGamerCoinsSpent = 0; +EWRAM_DATA bool8 sFindThatGamerWhichGame = FALSE; +EWRAM_DATA ALIGNED(4) u8 sRecordMixingPartnersWithoutShowsToShare = 0; +EWRAM_DATA ALIGNED(4) u8 sTVShowState = 0; +EWRAM_DATA u8 sTVSecretBaseSecretsRandomValues[3] = {}; + +// Static ROM declarations + +extern const u8 *const sTVBravoTrainerTextGroup[]; +extern const u8 *const sTVBravoTrainerBattleTowerTextGroup[]; + +void ClearPokemonNews(void); +u8 GetTVChannelByShowType(u8 kind); +u8 FindFirstActiveTVShowThatIsNotAMassOutbreak(void); +u8 CheckForBigMovieOrEmergencyNewsOnTV(void); +void SetTVMetatilesOnMap(int width, int height, u16 tileId); +u8 FindAnyTVNewsOnTheAir(void); +bool8 IsTVShowInSearchOfTrainersAiring(void); +void TakeTVShowInSearchOfTrainersOffTheAir(void); +bool8 TV_BernoulliTrial(u16 ratio); +s8 FindEmptyTVSlotBeyondFirstFiveShowsOfArray(TVShow *shows); +bool8 HasMixableShowAlreadyBeenSpawnedWithPlayerID(u8 kind, bool8 flag); +void tv_store_id_3x(TVShow *show); +void DeleteTVShowInArrayByIdx(TVShow *shows, u8 idx); +s8 FindEmptyTVSlotWithinFirstFiveShowsOfArray(TVShow *shows); +void FindActiveBroadcastByShowType_SetScriptResult(u8 kind); +void InterviewBefore_BravoTrainerPkmnProfile(void); +void InterviewBefore_NameRater(void); +u16 TV_GetSomeOtherSpeciesAlreadySeenByPlayer(u16 passedSpecies); +void sub_80EFA88(void); +void sub_80EF93C(TVShow *shows); +s8 sub_80EEE30(PokeNews *pokeNews); +bool8 sub_80EF0E4(u8 newsKind); +void ClearPokemonNewsI(u8 i); +void sub_80F1254(TVShow *shows); +void sub_80F12A4(TVShow *shows); +void sub_80F0358(TVShow *player1, TVShow *player2, TVShow *player3, TVShow *player4); +void sub_80F0C04(void); +void sub_80F0708(void); +void sub_80F0B64(void); +s8 sub_80F06D0(TVShow *tvShows); +bool8 sub_80F049C(TVShow *dest[], TVShow *src[], u8 idx); +bool8 sub_80F0580(TVShow *tv1, TVShow *tv2, u8 idx); +bool8 sub_80F05E8(TVShow *tv1, TVShow *tv2, u8 idx); +bool8 sub_80F0668(TVShow *tv1, TVShow *tv2, u8 idx); +void sub_80F0B00(u8 showIdx); +void sub_80F0B24(u16 species, u8 showIdx); +void sub_80F0D60(PokeNews *player1, PokeNews *player2, PokeNews *player3, PokeNews *player4); +void sub_80F0EEC(void); +void sub_80F0F24(void); +s8 sub_80F0ECC(PokeNews *pokeNews, u8 idx); +void sub_80F0E58(PokeNews *dest[], PokeNews *src[]); +bool8 sub_80F0E84(PokeNews *dest, PokeNews *src, s8 slot); +void TVShowDone(void); +void InterviewAfter_FanClubLetter(void); +void InterviewAfter_RecentHappenings(void); +void InterviewAfter_PkmnFanClubOpinions(void); +void InterviewAfter_DummyShow4(void); +void InterviewAfter_BravoTrainerPokemonProfile(void); +void InterviewAfter_BravoTrainerBattleTowerProfile(void); +void InterviewAfter_ContestLiveUpdates(void); +void UpdateWorldOfMastersAndPutItOnTheAir(void); +void PutPokemonTodayFailedOnTheAir(void); +void sub_80ED718(void); +void sub_80EED88(void); +void TV_SortPurchasesByQuantity(void); +void sub_80ED8B4(u16 days); +void UpdateMassOutbreakTimeLeft(u16 days); +void sub_80EF120(u16 days); +void sub_80EDA48(u16 days); +void sub_80EEB98(u16 days); +void PutFishingAdviceShowOnTheAir(void); +void sub_80EDA80(void); +u8 TV_MonDataIdxToRibbon(u8 monDataIdx); +void sub_80EEBF4(u8 actionIdx); +bool8 IsPriceDiscounted(u8 newsKind); +void InterviewBefore_FanClubLetter(void); +void InterviewBefore_RecentHappenings(void); +void InterviewBefore_PkmnFanClubOpinions(void); +void InterviewBefore_Dummy(void); +void InterviewBefore_BravoTrainerBTProfile(void); +void InterviewBefore_ContestLiveUpdates(void); +void InterviewBefore_3CheersForPokeblocks(void); +void InterviewBefore_FanClubSpecial(void); +void ChangeBoxPokemonNickname_CB(void); +void DoTVShowPokemonFanClubLetter(void); +void DoTVShowRecentHappenings(void); +void DoTVShowPokemonFanClubOpinions(void); +void DoTVShowDummiedOut(void); +void DoTVShowPokemonNewsMassOutbreak(void); +void DoTVShowBravoTrainerPokemonProfile(void); +void DoTVShowBravoTrainerBattleTower(void); +void DoTVShowPokemonTodaySuccessfulCapture(void); +void DoTVShowTodaysSmartShopper(void); +void DoTVShowTheNameRaterShow(void); +void DoTVShowPokemonContestLiveUpdates(void); +void DoTVShowPokemonBattleUpdate(void); +void DoTVShow3CheersForPokeblocks(void); +void DoTVShowPokemonTodayFailedCapture(void); +void DoTVShowPokemonAngler(void); +void DoTVShowTheWorldOfMasters(void); +void DoTVShowTodaysRivalTrainer(void); +void DoTVShowDewfordTrendWatcherNetwork(void); +void DoTVShowHoennTreasureInvestigators(void); +void DoTVShowFindThatGamer(void); +void DoTVShowBreakingNewsTV(void); +void DoTVShowSecretBaseVisit(void); +void DoTVShowPokemonLotteryWinnerFlashReport(void); +void DoTVShowThePokemonBattleSeminar(void); +void DoTVShowTrainerFanClubSpecial(void); +void DoTVShowTrainerFanClub(void); +void DoTVShowSpotTheCuties(void); +void DoTVShowPokemonNewsBattleFrontier(void); +void DoTVShowWhatsNo1InHoennToday(void); +void DoTVShowSecretBaseSecrets(void); +void DoTVShowSafariFanClub(void); +void DoTVShowPokemonContestLiveUpdates2(void); + +// .rodata + +const struct { + u16 species; + u16 moves[4]; + u8 level; + u8 location; +} sPokeOutbreakSpeciesList[] = { + { + SPECIES_SEEDOT, + {MOVE_BIDE, MOVE_HARDEN, MOVE_LEECH_SEED}, + 3, 0x11 // Route 102 + }, + { + SPECIES_NUZLEAF, + {MOVE_HARDEN, MOVE_GROWTH, MOVE_NATURE_POWER, MOVE_LEECH_SEED}, + 15, 0x1D // Route 114 + }, + { + SPECIES_SEEDOT, + {MOVE_HARDEN, MOVE_GROWTH, MOVE_NATURE_POWER, MOVE_LEECH_SEED}, + 13, 0x20 // Route 117 + }, + { + SPECIES_SEEDOT, + {MOVE_GIGA_DRAIN, MOVE_FRUSTRATION, MOVE_SOLAR_BEAM, MOVE_LEECH_SEED}, + 25, 0x23 // Route 110 + }, + { + SPECIES_SKITTY, + {MOVE_GROWL, MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_ATTRACT}, + 8, 0x1F // Route 116 + } +}; + +// TODO: Figure out what these are, and define constants in include/flags.h +const u16 sGoldSymbolFlags[] = { + SYS_TOWER_GOLD, + SYS_DOME_GOLD, + SYS_PALACE_GOLD, + SYS_ARENA_GOLD, + SYS_FACTORY_GOLD, + SYS_PIKE_GOLD, + SYS_PYRAMID_GOLD +}; + +const u16 sSilverSymbolFlags[] = { + SYS_TOWER_SILVER, + SYS_DOME_SILVER, + SYS_PALACE_SILVER, + SYS_ARENA_SILVER, + SYS_FACTORY_SILVER, + SYS_PIKE_SILVER, + SYS_PYRAMID_SILVER +}; + +// TODO: Figure out what these are, and define constants in include/vars.h +const u16 sNumberOneVarsAndThresholds[][2] = { + {VAR_DAILY_SLOTS, 100}, + {VAR_DAILY_ROULETTE, 50}, + {VAR_DAILY_WILDS, 100}, + {VAR_DAILY_BLENDER, 20}, + {VAR_DAILY_PLANTED_BERRIES, 20}, + {VAR_DAILY_PICKED_BERRIES, 20}, + {VAR_DAILY_BP, 30} +}; + +const u8 *const sPokeNewsTextGroup_Upcoming[] = { + NULL, + gPokeNewsTextSlateport_Upcoming, + gPokeNewsTextGameCorner_Upcoming, + gPokeNewsTextLilycove_Upcoming, + gPokeNewsTextBlendMaster_Upcoming +}; + +const u8 *const sPokeNewsTextGroup_Ongoing[] = { + NULL, + gPokeNewsTextSlateport_Ongoing, + gPokeNewsTextGameCorner_Ongoing, + gPokeNewsTextLilycove_Ongoing, + gPokeNewsTextBlendMaster_Ongoing +}; + +const u8 *const sPokeNewsTextGroup_Ending[] = { + NULL, + gPokeNewsTextSlateport_Ending, + gPokeNewsTextGameCorner_Ending, + gPokeNewsTextLilycove_Ending, + gPokeNewsTextBlendMaster_Ending +}; + +u8 *const gTVStringVarPtrs[] = { + gStringVar1, + gStringVar2, + gStringVar3 +}; + +const u8 *const sTVFanClubTextGroup[] = { + gTVFanClubText00, + gTVFanClubText01, + gTVFanClubText02, + gTVFanClubText03, + gTVFanClubText04, + gTVFanClubText05, + gTVFanClubText06, + gTVFanClubText07 +}; + +const u8 *const sTVRecentHappeninssTextGroup[] = { + gTVRecentHappeningsText00, + gTVRecentHappeningsText01, + gTVRecentHappeningsText02, + gTVRecentHappeningsText03, + gTVRecentHappeningsText04, + gTVRecentHappeningsText05 +}; + +const u8 *const sTVFanClubOpinionsTextGroup[] = { + gTVFanClubOpinionsText00, + gTVFanClubOpinionsText01, + gTVFanClubOpinionsText02, + gTVFanClubOpinionsText03, + gTVFanClubOpinionsText04 +}; + +const u8 *const sTVMassOutbreakTextGroup[] = { + gTVMassOutbreakText00 +}; + +const u8 *const sTVPokemonTodaySuccessfulTextGroup[] = { + gTVPokemonTodaySuccessfulText00, + gTVPokemonTodaySuccessfulText01, + gTVPokemonTodaySuccessfulText02, + gTVPokemonTodaySuccessfulText03, + gTVPokemonTodaySuccessfulText04, + gTVPokemonTodaySuccessfulText05, + gTVPokemonTodaySuccessfulText06, + gTVPokemonTodaySuccessfulText07, + gTVPokemonTodaySuccessfulText08, + gTVPokemonTodaySuccessfulText09, + gTVPokemonTodaySuccessfulText10, + gTVPokemonTodaySuccessfulText11 +}; + +const u8 *const sTVTodaysSmartShopperTextGroup[] = { + gTVTodaysSmartShopperText00, + gTVTodaysSmartShopperText01, + gTVTodaysSmartShopperText02, + gTVTodaysSmartShopperText03, + gTVTodaysSmartShopperText04, + gTVTodaysSmartShopperText05, + gTVTodaysSmartShopperText06, + gTVTodaysSmartShopperText07, + gTVTodaysSmartShopperText08, + gTVTodaysSmartShopperText09, + gTVTodaysSmartShopperText10, + gTVTodaysSmartShopperText11, + gTVTodaysSmartShopperText12 +}; + +const u8 *const sTVBravoTrainerTextGroup[] = { + gTVBravoTrainerText00, + gTVBravoTrainerText01, + gTVBravoTrainerText02, + gTVBravoTrainerText03, + gTVBravoTrainerText04, + gTVBravoTrainerText05, + gTVBravoTrainerText06, + gTVBravoTrainerText07, + gTVBravoTrainerText08 +}; + +const u8 *const sTV3CheersForPokeblocksTextGroup[] = { + gTV3CheersForPokeblocksText00, + gTV3CheersForPokeblocksText01, + gTV3CheersForPokeblocksText02, + gTV3CheersForPokeblocksText03, + gTV3CheersForPokeblocksText04, + gTV3CheersForPokeblocksText05 +}; + +const u8 *const sTVBravoTrainerBattleTowerTextGroup[] = { + gTVBravoTrainerBattleTowerText00, + gTVBravoTrainerBattleTowerText01, + gTVBravoTrainerBattleTowerText02, + gTVBravoTrainerBattleTowerText03, + gTVBravoTrainerBattleTowerText04, + gTVBravoTrainerBattleTowerText05, + gTVBravoTrainerBattleTowerText06, + gTVBravoTrainerBattleTowerText07, + gTVBravoTrainerBattleTowerText08, + gTVBravoTrainerBattleTowerText09, + gTVBravoTrainerBattleTowerText10, + gTVBravoTrainerBattleTowerText11, + gTVBravoTrainerBattleTowerText12, + gTVBravoTrainerBattleTowerText13, + gTVBravoTrainerBattleTowerText14 +}; + +const u8 *const sTVContestLiveUpdatesTextGroup[] = { + gTVContestLiveUpdatesText00, + gTVContestLiveUpdatesText01, + gTVContestLiveUpdatesText02, + gTVContestLiveUpdatesText03, + gTVContestLiveUpdatesText04, + gTVContestLiveUpdatesText05, + gTVContestLiveUpdatesText06, + gTVContestLiveUpdatesText07, + gTVContestLiveUpdatesText08, + gTVContestLiveUpdatesText09, + gTVContestLiveUpdatesText10, + gTVContestLiveUpdatesText11, + gTVContestLiveUpdatesText12, + gTVContestLiveUpdatesText13, + gTVContestLiveUpdatesText14, + gTVContestLiveUpdatesText15, + gTVContestLiveUpdatesText16, + gTVContestLiveUpdatesText17, + gTVContestLiveUpdatesText18, + gTVContestLiveUpdatesText19, + gTVContestLiveUpdatesText20, + gTVContestLiveUpdatesText21, + gTVContestLiveUpdatesText22, + gTVContestLiveUpdatesText23, + gTVContestLiveUpdatesText24, + gTVContestLiveUpdatesText25, + gTVContestLiveUpdatesText26, + gTVContestLiveUpdatesText27, + gTVContestLiveUpdatesText28, + gTVContestLiveUpdatesText29, + gTVContestLiveUpdatesText30, + gTVContestLiveUpdatesText31, + gTVContestLiveUpdatesText32 +}; + +const u8 *const sTVPokemonBattleUpdateTextGroup[] = { + gTVPokemonBattleUpdateText00, + gTVPokemonBattleUpdateText01, + gTVPokemonBattleUpdateText02, + gTVPokemonBattleUpdateText03, + gTVPokemonBattleUpdateText04, + gTVPokemonBattleUpdateText05, + gTVPokemonBattleUpdateText06, + gTVPokemonBattleUpdateText07 +}; + +const u8 *const sTVTrainerFanClubSpecialTextGroup[] = { + gTVTrainerFanClubSpecialText00, + gTVTrainerFanClubSpecialText01, + gTVTrainerFanClubSpecialText02, + gTVTrainerFanClubSpecialText03, + gTVTrainerFanClubSpecialText04, + gTVTrainerFanClubSpecialText05 +}; + +const u8 *const sTVNameRaterTextGroup[] = { + gTVNameRaterText00, + gTVNameRaterText01, + gTVNameRaterText02, + gTVNameRaterText03, + gTVNameRaterText04, + gTVNameRaterText05, + gTVNameRaterText06, + gTVNameRaterText07, + gTVNameRaterText08, + gTVNameRaterText09, + gTVNameRaterText10, + gTVNameRaterText11, + gTVNameRaterText12, + gTVNameRaterText13, + gTVNameRaterText14, + gTVNameRaterText15, + gTVNameRaterText16, + gTVNameRaterText17, + gTVNameRaterText18 +}; + +const u8 *const sTVPokemonContestLiveUpdates2TextGroup[] = { + gTVPokemonContestLiveUpdates2Text00, + gTVPokemonContestLiveUpdates2Text01, + gTVPokemonContestLiveUpdates2Text02, + gTVPokemonContestLiveUpdates2Text03 +}; + +const u8 *const sTVPokemonTodayFailedTextGroup[] = { + gTVPokemonTodayFailedText00, + gTVPokemonTodayFailedText01, + gTVPokemonTodayFailedText02, + gTVPokemonTodayFailedText03, + gTVPokemonTodayFailedText04, + gTVPokemonTodayFailedText05, + gTVPokemonTodayFailedText06 +}; + +const u8 *const sTVPokemonAnslerTextGroup[] = { + gTVPokemonAnglerText00, + gTVPokemonAnglerText01 +}; + +const u8 *const sTVWorldOfMastersTextGroup[] = { + gTVWorldOfMastersText00, + gTVWorldOfMastersText01, + gTVWorldOfMastersText02 +}; + +const u8 *const sTVTodaysRivalTrainerTextGroup[] = { + gTVTodaysRivalTrainerText00, + gTVTodaysRivalTrainerText01, + gTVTodaysRivalTrainerText02, + gTVTodaysRivalTrainerText03, + gTVTodaysRivalTrainerText04, + gTVTodaysRivalTrainerText05, + gTVTodaysRivalTrainerText06, + gTVTodaysRivalTrainerText07, + gTVTodaysRivalTrainerText08, + gTVTodaysRivalTrainerText09, + gTVTodaysRivalTrainerText10 +}; + +const u8 *const sTVDewfordTrendWatcherNetworkTextGroup[] = { + gTVDewfordTrendWatcherNetworkText00, + gTVDewfordTrendWatcherNetworkText01, + gTVDewfordTrendWatcherNetworkText02, + gTVDewfordTrendWatcherNetworkText03, + gTVDewfordTrendWatcherNetworkText04, + gTVDewfordTrendWatcherNetworkText05, + gTVDewfordTrendWatcherNetworkText06 +}; + +const u8 *const sTVHoennTreasureInvestisatorsTextGroup[] = { + gTVHoennTreasureInvestigatorsText00, + gTVHoennTreasureInvestigatorsText01, + gTVHoennTreasureInvestigatorsText02 +}; + +const u8 *const sTVFindThatGamerTextGroup[] = { + gTVFindThatGamerText00, + gTVFindThatGamerText01, + gTVFindThatGamerText02, + gTVFindThatGamerText03 +}; + +const u8 *const sTVBreakinsNewsTextGroup[] = { + gTVBreakingNewsText00, + gTVBreakingNewsText01, + gTVBreakingNewsText02, + gTVBreakingNewsText03, + gTVBreakingNewsText04, + gTVBreakingNewsText05, + gTVBreakingNewsText06, + gTVBreakingNewsText07, + gTVBreakingNewsText08, + gTVBreakingNewsText09, + gTVBreakingNewsText10, + gTVBreakingNewsText11, + gTVBreakingNewsText12 +}; + +const u8 *const sTVSecretBaseVisitTextGroup[] = { + gTVSecretBaseVisitText00, + gTVSecretBaseVisitText01, + gTVSecretBaseVisitText02, + gTVSecretBaseVisitText03, + gTVSecretBaseVisitText04, + gTVSecretBaseVisitText05, + gTVSecretBaseVisitText06, + gTVSecretBaseVisitText07, + gTVSecretBaseVisitText08, + gTVSecretBaseVisitText09, + gTVSecretBaseVisitText10, + gTVSecretBaseVisitText11, + gTVSecretBaseVisitText12, + gTVSecretBaseVisitText13 +}; + +const u8 *const sTVPokemonLotteryWinnerFlashReportTextGroup[] = { + gTVPokemonLotteryWinnerFlashReportText00 +}; + +const u8 *const sTVThePokemonBattleSeminarTextGroup[] = { + gTVThePokemonBattleSeminarText00, + gTVThePokemonBattleSeminarText01, + gTVThePokemonBattleSeminarText02, + gTVThePokemonBattleSeminarText03, + gTVThePokemonBattleSeminarText04, + gTVThePokemonBattleSeminarText05, + gTVThePokemonBattleSeminarText06 +}; + +const u8 *const sTVTrainerFanClubTextGroup[] = { + gTVTrainerFanClubText00, + gTVTrainerFanClubText01, + gTVTrainerFanClubText02, + gTVTrainerFanClubText03, + gTVTrainerFanClubText04, + gTVTrainerFanClubText05, + gTVTrainerFanClubText06, + gTVTrainerFanClubText07, + gTVTrainerFanClubText08, + gTVTrainerFanClubText09, + gTVTrainerFanClubText10, + gTVTrainerFanClubText11 +}; + +const u8 *const sTVCutiesTextGroup[] = { + gTVCutiesText00, + gTVCutiesText01, + gTVCutiesText02, + gTVCutiesText03, + gTVCutiesText04, + gTVCutiesText05, + gTVCutiesText06, + gTVCutiesText07, + gTVCutiesText08, + gTVCutiesText09, + gTVCutiesText10, + gTVCutiesText11, + gTVCutiesText12, + gTVCutiesText13, + gTVCutiesText14, + gTVCutiesText15 +}; + +const u8 *const sTVPokemonNewsBattleFrontierTextGroup[] = { + gTVPokemonNewsBattleFrontierText00, + gTVPokemonNewsBattleFrontierText01, + gTVPokemonNewsBattleFrontierText02, + gTVPokemonNewsBattleFrontierText03, + gTVPokemonNewsBattleFrontierText04, + gTVPokemonNewsBattleFrontierText05, + gTVPokemonNewsBattleFrontierText06, + gTVPokemonNewsBattleFrontierText07, + gTVPokemonNewsBattleFrontierText08, + gTVPokemonNewsBattleFrontierText09, + gTVPokemonNewsBattleFrontierText10, + gTVPokemonNewsBattleFrontierText11, + gTVPokemonNewsBattleFrontierText12, + gTVPokemonNewsBattleFrontierText13, + gTVPokemonNewsBattleFrontierText14, + gTVPokemonNewsBattleFrontierText15, + gTVPokemonNewsBattleFrontierText16, + gTVPokemonNewsBattleFrontierText17, + gTVPokemonNewsBattleFrontierText18 +}; + +const u8 *const sTVWhatsNo1InHoennTodayTextGroup[] = { + gTVWhatsNo1InHoennTodayText00, + gTVWhatsNo1InHoennTodayText01, + gTVWhatsNo1InHoennTodayText02, + gTVWhatsNo1InHoennTodayText03, + gTVWhatsNo1InHoennTodayText04, + gTVWhatsNo1InHoennTodayText05, + gTVWhatsNo1InHoennTodayText06, + gTVWhatsNo1InHoennTodayText07, + gTVWhatsNo1InHoennTodayText08 +}; + +const u8 *const sTVSecretBaseSecretsTextGroup[] = { + gTVSecretBaseSecretsText00, + gTVSecretBaseSecretsText01, + gTVSecretBaseSecretsText02, + gTVSecretBaseSecretsText03, + gTVSecretBaseSecretsText04, + gTVSecretBaseSecretsText05, + gTVSecretBaseSecretsText06, + gTVSecretBaseSecretsText07, + gTVSecretBaseSecretsText08, + gTVSecretBaseSecretsText09, + gTVSecretBaseSecretsText10, + gTVSecretBaseSecretsText11, + gTVSecretBaseSecretsText12, + gTVSecretBaseSecretsText13, + gTVSecretBaseSecretsText14, + gTVSecretBaseSecretsText15, + gTVSecretBaseSecretsText16, + gTVSecretBaseSecretsText17, + gTVSecretBaseSecretsText18, + gTVSecretBaseSecretsText19, + gTVSecretBaseSecretsText20, + gTVSecretBaseSecretsText21, + gTVSecretBaseSecretsText22, + gTVSecretBaseSecretsText23, + gTVSecretBaseSecretsText24, + gTVSecretBaseSecretsText25, + gTVSecretBaseSecretsText26, + gTVSecretBaseSecretsText27, + gTVSecretBaseSecretsText28, + gTVSecretBaseSecretsText29, + gTVSecretBaseSecretsText30, + gTVSecretBaseSecretsText31, + gTVSecretBaseSecretsText32, + gTVSecretBaseSecretsText33, + gTVSecretBaseSecretsText34, + gTVSecretBaseSecretsText35, + gTVSecretBaseSecretsText36, + gTVSecretBaseSecretsText37, + gTVSecretBaseSecretsText38, + gTVSecretBaseSecretsText39, + gTVSecretBaseSecretsText40, + gTVSecretBaseSecretsText41, + gTVSecretBaseSecretsText42 +}; + +const u8 *const sTVSafariFanClubTextGroup[] = { + gTVSafariFanClubText00, + gTVSafariFanClubText01, + gTVSafariFanClubText02, + gTVSafariFanClubText03, + gTVSafariFanClubText04, + gTVSafariFanClubText05, + gTVSafariFanClubText06, + gTVSafariFanClubText07, + gTVSafariFanClubText08, + gTVSafariFanClubText09, + gTVSafariFanClubText10 +}; + +const u8 *const sTVInSearchOfTrainersTextGroup[] = { + gTVInSearchOfTrainersText00, + gTVInSearchOfTrainersText01, + gTVInSearchOfTrainersText02, + gTVInSearchOfTrainersText03, + gTVInSearchOfTrainersText04, + gTVInSearchOfTrainersText05, + gTVInSearchOfTrainersText06, + gTVInSearchOfTrainersText07, + gTVInSearchOfTrainersText08 +}; + +const u8 sTVSecretBaseSecretsStateLookup[] = { + 0x0a, + 0x0b, + 0x0c, + 0x0d, + 0x0e, + 0x0f, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x17, + 0x18, + 0x19, + 0x1a, + 0x1b, + 0x1c, + 0x1d, + 0x1e, + 0x1f, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2a, + 0x2b +}; + +// .text + +void ClearTVShowData(void) +{ + u8 i; + u8 j; + + for (i = 0; i < ARRAY_COUNT(gSaveBlock1Ptr->tvShows); i ++) + { + gSaveBlock1Ptr->tvShows[i].common.kind = 0; + gSaveBlock1Ptr->tvShows[i].common.active = 0; + for (j = 0; j < sizeof(TVShow) - 2; j ++) + { + gSaveBlock1Ptr->tvShows[i].common.pad02[j] = 0; + } + } + ClearPokemonNews(); +} + +u8 special_0x44(void) +{ + u8 i; + u8 j; + u8 selIdx; + TVShow *show; + + for (i = 5; i < ARRAY_COUNT(gSaveBlock1Ptr->tvShows) - 1; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind == 0) + { + break; + } + } + j = Random() % i; + selIdx = j; + do + { + if (GetTVChannelByShowType(gSaveBlock1Ptr->tvShows[j].common.kind) != 4) + { + if (gSaveBlock1Ptr->tvShows[j].common.active == TRUE) + { + return j; + } + } + else + { + show = &gSaveBlock1Ptr->tvShows[j]; + if (show->massOutbreak.daysLeft == 0 && show->massOutbreak.active == TRUE) + { + return j; + } + } + if (j == 0) + { + j = ARRAY_COUNT(gSaveBlock1Ptr->tvShows) - 2; + } + else + { + j --; + } + } while (j != selIdx); + return 0xFF; +} + +u8 FindAnyTVShowOnTheAir(void) +{ + u8 response; + + response = special_0x44(); + if (response == 0xFF) + { + return 0xFF; + } + if (gSaveBlock1Ptr->outbreakPokemonSpecies != SPECIES_NONE && gSaveBlock1Ptr->tvShows[response].common.kind == TVSHOW_MASS_OUTBREAK) + { + return FindFirstActiveTVShowThatIsNotAMassOutbreak(); + } + return response; +} + +void UpdateTVScreensOnMap(int width, int height) +{ + FlagSet(SYS_TV_WATCH); + switch (CheckForBigMovieOrEmergencyNewsOnTV()) + { + case 1: + SetTVMetatilesOnMap(width, height, 0x3); + break; + case 2: + break; + default: + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_LILYCOVE_CITY_COVE_LILY_MOTEL_1F && gSaveBlock1Ptr->location.mapNum == MAP_ID_LILYCOVE_CITY_COVE_LILY_MOTEL_1F) + { + SetTVMetatilesOnMap(width, height, 0x3); + } + else if (FlagGet(SYS_TV_START) && (FindAnyTVShowOnTheAir() != 0xff || FindAnyTVNewsOnTheAir() != 0xff || IsTVShowInSearchOfTrainersAiring())) + { + FlagClear(SYS_TV_WATCH); + SetTVMetatilesOnMap(width, height, 0x3); + } + break; + } +} + +void SetTVMetatilesOnMap(int width, int height, u16 tileId) +{ + int x; + int y; + + for (y = 0; y < height; y ++) + { + for (x = 0; x < width; x ++) + { + if (MapGridGetMetatileBehaviorAt(x, y) == 0x86) // is this tile a TV? + { + MapGridSetMetatileIdAt(x, y, tileId | 0xc00); + } + } + } +} + +void TurnOffTVScreen(void) +{ + SetTVMetatilesOnMap(gUnknown_03005DC0.width, gUnknown_03005DC0.height, 0x0002); + DrawWholeMapView(); +} + +void TurnOnTVScreen(void) +{ + SetTVMetatilesOnMap(gUnknown_03005DC0.width, gUnknown_03005DC0.height, 0x0003); + DrawWholeMapView(); +} + +u8 special_0x45(void) +{ + return gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004].common.kind; +} + +u8 FindFirstActiveTVShowThatIsNotAMassOutbreak(void) +{ + u8 i; + + for (i = 0; i < ARRAY_COUNT(gSaveBlock1Ptr->tvShows) - 1; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind != 0 && gSaveBlock1Ptr->tvShows[i].common.kind != TVSHOW_MASS_OUTBREAK && gSaveBlock1Ptr->tvShows[i].common.active == TRUE) + { + return i; + } + } + return 0xFF; +} + +u8 special_0x4a(void) +{ + TVShow *tvShow; + + tvShow = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + if (tvShow->common.kind == TVSHOW_MASS_OUTBREAK && gSaveBlock1Ptr->outbreakPokemonSpecies != SPECIES_NONE) + { + return FindFirstActiveTVShowThatIsNotAMassOutbreak(); + } + return gSpecialVar_0x8004; +} + +// IN SEARCH OF TRAINERS + +void ResetGabbyAndTy(void) +{ + gSaveBlock1Ptr->gabbyAndTyData.mon1 = SPECIES_NONE; + gSaveBlock1Ptr->gabbyAndTyData.mon2 = SPECIES_NONE; + gSaveBlock1Ptr->gabbyAndTyData.lastMove = MOVE_NONE; + gSaveBlock1Ptr->gabbyAndTyData.quote[0] = -1; + gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.onAir = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.valA_5 = 0; + gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn2 = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon2 = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem2 = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall2 = FALSE; + gSaveBlock1Ptr->gabbyAndTyData.valB_4 = 0; + gSaveBlock1Ptr->gabbyAndTyData.mapnum = 0; + gSaveBlock1Ptr->gabbyAndTyData.battleNum = 0; +} + +void GabbyAndTyBeforeInterview(void) +{ + u8 i; + + gSaveBlock1Ptr->gabbyAndTyData.mon1 = gBattleResults.playerMon1Species; + gSaveBlock1Ptr->gabbyAndTyData.mon2 = gBattleResults.playerMon2Species; + gSaveBlock1Ptr->gabbyAndTyData.lastMove = gBattleResults.lastUsedMovePlayer; + if (gSaveBlock1Ptr->gabbyAndTyData.battleNum != 0xFF) + { + gSaveBlock1Ptr->gabbyAndTyData.battleNum ++; + } + gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn = gBattleResults.unk5_0; + if (gBattleResults.playerFaintCounter != 0) + { + gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon = TRUE; + } + else + { + gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon = FALSE; + } + if (gBattleResults.unk3 != 0) + { + gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem = TRUE; + } + else + { + gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem = FALSE; + } + if (!gBattleResults.usedMasterBall) + { + for (i = 0; i < 11; i ++) + { + if (gBattleResults.catchAttempts[i]) + { + gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall = TRUE; + break; + } + } + } + else + { + gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall = TRUE; + } + TakeTVShowInSearchOfTrainersOffTheAir(); + if (gSaveBlock1Ptr->gabbyAndTyData.lastMove == MOVE_NONE) + { + FlagSet(0x0001); + } +} + +void GabbyAndTyAfterInterview(void) +{ + gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn2 = gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn; + gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon2 = gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon; + gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem2 = gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem; + gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall2 = gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall; + gSaveBlock1Ptr->gabbyAndTyData.onAir = TRUE; + gSaveBlock1Ptr->gabbyAndTyData.mapnum = gMapHeader.regionMapSectionId; + IncrementGameStat(GAME_STAT_GOT_INTERVIEWED); +} + +void TakeTVShowInSearchOfTrainersOffTheAir(void) +{ + gSaveBlock1Ptr->gabbyAndTyData.onAir = FALSE; +} + +u8 GabbyAndTyGetBattleNum(void) +{ + if (gSaveBlock1Ptr->gabbyAndTyData.battleNum > 5) + { + return (gSaveBlock1Ptr->gabbyAndTyData.battleNum % 3) + 6; + } + return gSaveBlock1Ptr->gabbyAndTyData.battleNum; +} + +bool8 IsTVShowInSearchOfTrainersAiring(void) +{ + return gSaveBlock1Ptr->gabbyAndTyData.onAir; +} + +bool8 GabbyAndTyGetLastQuote(void) +{ + if (gSaveBlock1Ptr->gabbyAndTyData.quote[0] == 0xFFFF) + { + return FALSE; + } + CopyEasyChatWord(gStringVar1, gSaveBlock1Ptr->gabbyAndTyData.quote[0]); + gSaveBlock1Ptr->gabbyAndTyData.quote[0] = -1; + return TRUE; +} + +u8 GabbyAndTyGetLastBattleTrivia(void) +{ + if (!gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn2) + { + return 1; + } + if (gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall2) + { + return 2; + } + if (gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem2) + { + return 3; + } + if (gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon2) + { + return 4; + } + return 0; +} + +void GabbyAndTySetScriptVarsToFieldObjectLocalIds(void) +{ + switch (GabbyAndTyGetBattleNum()) + { + case 1: + gSpecialVar_0x8004 = 14; + gSpecialVar_0x8005 = 13; + break; + case 2: + gSpecialVar_0x8004 = 5; + gSpecialVar_0x8005 = 6; + break; + case 3: + gSpecialVar_0x8004 = 18; + gSpecialVar_0x8005 = 17; + break; + case 4: + gSpecialVar_0x8004 = 21; + gSpecialVar_0x8005 = 22; + break; + case 5: + gSpecialVar_0x8004 = 8; + gSpecialVar_0x8005 = 9; + break; + case 6: + gSpecialVar_0x8004 = 19; + gSpecialVar_0x8005 = 20; + break; + case 7: + gSpecialVar_0x8004 = 23; + gSpecialVar_0x8005 = 24; + break; + case 8: + gSpecialVar_0x8004 = 10; + gSpecialVar_0x8005 = 11; + break; + } +} + +void InterviewAfter(void) +{ + switch (gSpecialVar_0x8005) + { + case TVSHOW_FAN_CLUB_LETTER: + InterviewAfter_FanClubLetter(); + break; + case TVSHOW_RECENT_HAPPENINGS: + InterviewAfter_RecentHappenings(); + break; + case TVSHOW_PKMN_FAN_CLUB_OPINIONS: + InterviewAfter_PkmnFanClubOpinions(); + break; + case TVSHOW_UNKN_SHOWTYPE_04: + InterviewAfter_DummyShow4(); + break; + case TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE: + InterviewAfter_BravoTrainerPokemonProfile(); + break; + case TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE: + InterviewAfter_BravoTrainerBattleTowerProfile(); + break; + case TVSHOW_CONTEST_LIVE_UPDATES: + InterviewAfter_ContestLiveUpdates(); + break; + } +} + +void PutPokemonTodayCaughtOnAir(void) +{ + u8 i; + u16 ct; + TVShow *show; + u32 language2; + u16 itemLastUsed; + + ct = 0; + sub_80EED88(); + sub_80ED718(); + if (gBattleResults.caughtMonSpecies == SPECIES_NONE) + { + PutPokemonTodayFailedOnTheAir(); + } + else + { + UpdateWorldOfMastersAndPutItOnTheAir(); + if (!rbernoulli(1, 1) && StringCompare(gSpeciesNames[gBattleResults.caughtMonSpecies], gBattleResults.caughtMonNick)) + { + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_POKEMON_TODAY_CAUGHT, FALSE) != TRUE) + { + for (i = 0; i < 11; i ++) + { + ct += gBattleResults.catchAttempts[i]; + } + if (ct != 0 || gBattleResults.usedMasterBall) + { + ct = 0; + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->pokemonToday.kind = TVSHOW_POKEMON_TODAY_CAUGHT; + show->pokemonToday.active = FALSE; + if (gBattleResults.usedMasterBall) + { + ct = 1; + itemLastUsed = ITEM_MASTER_BALL; + } + else + { + for (i = 0; i < 11; i ++) + { + ct += gBattleResults.catchAttempts[i]; + } + if (ct > 0xFF) + { + ct = 0xFF; + } + itemLastUsed = gLastUsedItem; + } + show->pokemonToday.nBallsUsed = ct; + show->pokemonToday.ball = itemLastUsed; + StringCopy(show->pokemonToday.playerName, gSaveBlock2Ptr->playerName); + StringCopy(show->pokemonToday.nickname, gBattleResults.caughtMonNick); + language2 = sub_81DB604(show->pokemonToday.nickname); + StripExtCtrlCodes(show->pokemonToday.nickname); + show->pokemonToday.species = gBattleResults.caughtMonSpecies; + tv_store_id_3x(show); + show->pokemonToday.language = gGameLanguage; + show->pokemonToday.language2 = language2; + } + } + } + } +} + +void UpdateWorldOfMastersAndPutItOnTheAir(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + if (show->worldOfMasters.kind != TVSHOW_WORLD_OF_MASTERS) + { + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + show->worldOfMasters.steps = GetGameStat(GAME_STAT_STEPS); + show->worldOfMasters.kind = TVSHOW_WORLD_OF_MASTERS; + } + show->worldOfMasters.numPokeCaught ++; + show->worldOfMasters.caughtPoke = gBattleResults.caughtMonSpecies; + show->worldOfMasters.species = gBattleResults.playerMon1Species; + show->worldOfMasters.location = gMapHeader.regionMapSectionId; +} + +void PutPokemonTodayFailedOnTheAir(void) +{ + u16 ct; + u8 i; + TVShow *show; + + if (!rbernoulli(1, 1)) + { + for (i = 0, ct = 0; i < 11; i ++) + { + ct += gBattleResults.catchAttempts[i]; + } + if (ct > 0xFF) + { + ct = 0xFF; + } + if (ct > 2 && (gBattleOutcome == BATTLE_POKE_FLED || gBattleOutcome == BATTLE_WON)) + { + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_POKEMON_TODAY_FAILED, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->pokemonTodayFailed.kind = TVSHOW_POKEMON_TODAY_FAILED; + show->pokemonTodayFailed.active = FALSE; + show->pokemonTodayFailed.species = gBattleResults.playerMon1Species; + show->pokemonTodayFailed.species2 = gBattleResults.lastOpponentSpecies; + show->pokemonTodayFailed.nBallsUsed = ct; + show->pokemonTodayFailed.outcome = gBattleOutcome; + show->pokemonTodayFailed.location = gMapHeader.regionMapSectionId; + StringCopy(show->pokemonTodayFailed.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->pokemonTodayFailed.language = gGameLanguage; + } + } + } +} + +void tv_store_id_3x(TVShow *show) +{ + u32 id; + + id = GetPlayerIDAsU32(); + show->common.srcTrainerId2Lo = id; + show->common.srcTrainerId2Hi = id >> 8; + show->common.srcTrainerIdLo = id; + show->common.srcTrainerIdHi = id >> 8; + show->common.trainerIdLo = id; + show->common.trainerIdHi = id >> 8; +} + +void tv_store_id_2x(TVShow *show) +{ + u32 id; + + id = GetPlayerIDAsU32(); + show->common.srcTrainerIdLo = id; + show->common.srcTrainerIdHi = id >> 8; + show->common.trainerIdLo = id; + show->common.trainerIdHi = id >> 8; +} + +void InterviewAfter_ContestLiveUpdates(void) +{ + TVShow *show; + TVShow *show2; + + show = &gSaveBlock1Ptr->tvShows[24]; + if (show->contestLiveUpdates.kind == TVSHOW_CONTEST_LIVE_UPDATES) + { + show2 = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show2->contestLiveUpdates.kind = TVSHOW_CONTEST_LIVE_UPDATES; + show2->contestLiveUpdates.active = TRUE; + StringCopy(show2->contestLiveUpdates.playerName, gSaveBlock2Ptr->playerName); + 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; + show2->contestLiveUpdates.round1Rank = show->contestLiveUpdates.round1Rank; + show2->contestLiveUpdates.round2Rank = show->contestLiveUpdates.round2Rank; + show2->contestLiveUpdates.move = show->contestLiveUpdates.move; + show2->contestLiveUpdates.appealFlags1 = show->contestLiveUpdates.appealFlags1; + StringCopy(show2->contestLiveUpdates.winningTrainerName, show->contestLiveUpdates.winningTrainerName); + tv_store_id_2x(show2); + show2->contestLiveUpdates.language = gGameLanguage; + show2->contestLiveUpdates.winningTrainerLanguage = show->contestLiveUpdates.winningTrainerLanguage; + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + } +} + +void PutBattleUpdateOnTheAir(u8 a0, u16 a1, u16 a2, u16 a3) +{ + TVShow *show; + u8 name[32]; + + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_BATTLE_UPDATE); + if (gScriptResult != 1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->battleUpdate.kind = TVSHOW_BATTLE_UPDATE; + show->battleUpdate.active = TRUE; + StringCopy(show->battleUpdate.playerName, gSaveBlock2Ptr->playerName); + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + show->battleUpdate.battleType = 2; + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + show->battleUpdate.battleType = 1; + } + else + { + show->battleUpdate.battleType = 0; + } + show->battleUpdate.move = a1; + show->battleUpdate.species2 = a2; + show->battleUpdate.species = a3; + StringCopy(name, gLinkPlayers[a0].name); + StripExtCtrlCodes(name); + StringCopy(show->battleUpdate.linkOpponentName, name); + tv_store_id_2x(show); + show->battleUpdate.language = gGameLanguage; + if (show->battleUpdate.language == LANGUAGE_JAPANESE || gLinkPlayers[a0].language == LANGUAGE_JAPANESE) + { + show->battleUpdate.linkOpponentLanguage = LANGUAGE_JAPANESE; + } + else + { + show->battleUpdate.linkOpponentLanguage = gLinkPlayers[a0].language; + } + } + } +} + +bool8 Put3CheersForPokeblocksOnTheAir(const u8 *partnersName, u8 flavor, u8 unused, u8 sheen, u8 language) +{ + TVShow *show; + u8 name[32]; + + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot == -1) + { + return FALSE; + } + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_3_CHEERS_FOR_POKEBLOCKS); + if (gScriptResult == 1) + { + return FALSE; + } + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->threeCheers.kind = TVSHOW_3_CHEERS_FOR_POKEBLOCKS; + show->threeCheers.active = TRUE; + StringCopy(show->threeCheers.playerName, gSaveBlock2Ptr->playerName); + StringCopy(name, partnersName); + StripExtCtrlCodes(name); + StringCopy(show->threeCheers.worstBlenderName, name); + show->threeCheers.flavor = flavor; + show->threeCheers.unk_03_3 = unused; + show->threeCheers.sheen = sheen; + tv_store_id_2x(show); + show->threeCheers.language = gGameLanguage; + if (show->threeCheers.language == LANGUAGE_JAPANESE || language == LANGUAGE_JAPANESE) + { + show->threeCheers.worstBlenderLanguage = LANGUAGE_JAPANESE; + } + else + { + show->threeCheers.worstBlenderLanguage = language; + } + return TRUE; +} + +void PutFanClubSpecialOnTheAir(void) +{ + TVShow *show; + u8 name[32]; + u32 id; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8006]; + show->fanClubSpecial.score = gSpecialVar_0x8005 * 10; + StringCopy(show->fanClubSpecial.playerName, gSaveBlock2Ptr->playerName); + show->fanClubSpecial.kind = TVSHOW_FAN_CLUB_SPECIAL; + show->fanClubSpecial.active = TRUE; + id = GetPlayerIDAsU32(); + show->fanClubSpecial.idLo = id; + show->fanClubSpecial.idHi = id >> 8; + StringCopy(name, gStringVar1); + StripExtCtrlCodes(name); + StringCopy(show->fanClubSpecial.idolName, name); + tv_store_id_2x(show); + show->fanClubSpecial.language = gGameLanguage; + if (show->fanClubSpecial.language == LANGUAGE_JAPANESE || gSaveBlock1Ptr->unk_31A0 == LANGUAGE_JAPANESE) + { + show->fanClubSpecial.idolNameLanguage = LANGUAGE_JAPANESE; + } + else + { + show->fanClubSpecial.idolNameLanguage = gSaveBlock1Ptr->unk_31A0; + } +} + +void ContestLiveUpdates_BeforeInterview_1(u8 a0) +{ + TVShow *show; + + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show = &gSaveBlock1Ptr->tvShows[24]; + show->contestLiveUpdates.round1Rank = a0; + show->contestLiveUpdates.kind = TVSHOW_CONTEST_LIVE_UPDATES; + } +} + +void ContestLiveUpdates_BeforeInterview_2(u8 a0) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show->contestLiveUpdates.round2Rank = a0; + } +} + +void ContestLiveUpdates_BeforeInterview_3(u8 a0) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show->contestLiveUpdates.appealFlags1 = a0; + } +} + +void ContestLiveUpdates_BeforeInterview_4(u16 a0) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show->contestLiveUpdates.move = a0; + } +} + +void ContestLiveUpdates_BeforeInterview_5(u8 a0, u8 a1) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show->contestLiveUpdates.winningSpecies = gUnknown_02039E00[a1].unk_00; + StringCopy(show->contestLiveUpdates.winningTrainerName, gUnknown_02039E00[a1].unk_0d); + StripExtCtrlCodes(show->contestLiveUpdates.winningTrainerName); + show->contestLiveUpdates.appealFlags2 = a0; + if (a1 + 1 > gUnknown_02039F30) + { + show->contestLiveUpdates.winningTrainerLanguage = gLinkPlayers[0].language; + } + else if (gGameLanguage == LANGUAGE_JAPANESE || gLinkPlayers[a1].language == LANGUAGE_JAPANESE) + { + show->contestLiveUpdates.winningTrainerLanguage = LANGUAGE_JAPANESE; + } + else + { + show->contestLiveUpdates.winningTrainerLanguage = gLinkPlayers[a1].language; + } + } +} + +void InterviewAfter_BravoTrainerPokemonProfile(void) +{ + TVShow *show; + TVShow *show2; + + show = &gSaveBlock1Ptr->tvShows[24]; + if (show->bravoTrainer.kind == TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE) + { + show2 = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show2->bravoTrainer.kind = TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE; + show2->bravoTrainer.active = TRUE; + show2->bravoTrainer.species = show->bravoTrainer.species; + StringCopy(show2->bravoTrainer.playerName, gSaveBlock2Ptr->playerName); + StringCopy(show2->bravoTrainer.pokemonNickname, show->bravoTrainer.pokemonNickname); + show2->bravoTrainer.contestCategory = show->bravoTrainer.contestCategory; + show2->bravoTrainer.contestRank = show->bravoTrainer.contestRank; + show2->bravoTrainer.move = show->bravoTrainer.move; + show2->bravoTrainer.contestResult = show->bravoTrainer.contestResult; + show2->bravoTrainer.contestCategory = show->bravoTrainer.contestCategory; + tv_store_id_2x(show2); + show2->bravoTrainer.language = gGameLanguage; + if (show2->bravoTrainer.language == LANGUAGE_JAPANESE || show->bravoTrainer.pokemonNameLanguage == LANGUAGE_JAPANESE) + { + show2->bravoTrainer.pokemonNameLanguage = LANGUAGE_JAPANESE; + } + else + { + show2->bravoTrainer.pokemonNameLanguage = show->bravoTrainer.pokemonNameLanguage; + } + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + } +} + +void BravoTrainerPokemonProfile_BeforeInterview1(u16 a0) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + InterviewBefore_BravoTrainerPkmnProfile(); + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + show->bravoTrainer.move = a0; + show->bravoTrainer.kind = TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE; + } +} + +void BravoTrainerPokemonProfile_BeforeInterview2(u8 a0) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show->bravoTrainer.contestResult = a0; + 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); + StripExtCtrlCodes(show->bravoTrainer.pokemonNickname); + show->bravoTrainer.pokemonNameLanguage = GetMonData(&gPlayerParty[gUnknown_02039F24], MON_DATA_LANGUAGE); + } +} + +void InterviewAfter_BravoTrainerBattleTowerProfile(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->bravoTrainerTower.kind = TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE; + show->bravoTrainerTower.active = TRUE; + StringCopy(show->bravoTrainerTower.trainerName, gSaveBlock2Ptr->playerName); + StringCopy(show->bravoTrainerTower.pokemonName, gSaveBlock2Ptr->field_BD8); + show->bravoTrainerTower.species = gSaveBlock2Ptr->field_BD4; + show->bravoTrainerTower.defeatedSpecies = gSaveBlock2Ptr->field_BD6; + show->bravoTrainerTower.numFights = sub_8164FCC(gSaveBlock2Ptr->field_D07, 0); + show->bravoTrainerTower.wonTheChallenge = gSaveBlock2Ptr->field_D06; + if (gSaveBlock2Ptr->field_D07 == 0) + { + show->bravoTrainerTower.btLevel = 50; + } + else + { + show->bravoTrainerTower.btLevel = 100; + } + show->bravoTrainerTower.interviewResponse = gSpecialVar_0x8004; + tv_store_id_2x(show); + show->bravoTrainerTower.language = gGameLanguage; + if (show->bravoTrainerTower.language == LANGUAGE_JAPANESE || gSaveBlock2Ptr->field_BEB == LANGUAGE_JAPANESE) + { + show->bravoTrainerTower.pokemonNameLanguage = LANGUAGE_JAPANESE; + } + else + { + show->bravoTrainerTower.pokemonNameLanguage = gSaveBlock2Ptr->field_BEB; + } +} + +void SaveRecordedItemPurchasesForTVShow(void) +{ + TVShow *show; + u8 i; + + if (!(gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_TRAINER_HILL_LOBBY && gSaveBlock1Ptr->location.mapNum == MAP_ID_TRAINER_HILL_LOBBY) && !(gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_BATTLE_FRONTIER_MART && gSaveBlock1Ptr->location.mapNum == MAP_ID_BATTLE_FRONTIER_MART) && !rbernoulli(1, 3)) + { + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_SMART_SHOPPER, FALSE) != TRUE) + { + TV_SortPurchasesByQuantity(); + if (gUnknown_02039F80[0].quantity >= 20) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->smartshopperShow.kind = TVSHOW_SMART_SHOPPER; + show->smartshopperShow.active = FALSE; + show->smartshopperShow.shopLocation = gMapHeader.regionMapSectionId; + for (i = 0; i < 3; i ++) + { + show->smartshopperShow.itemIds[i] = gUnknown_02039F80[i].itemId; + show->smartshopperShow.itemAmounts[i] = gUnknown_02039F80[i].quantity; + } + show->smartshopperShow.priceReduced = GetPriceReduction(1); + StringCopy(show->smartshopperShow.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->smartshopperShow.language = gGameLanguage; + } + } + } +} + +void PutNameRaterShowOnTheAir(void) +{ + TVShow *show; + + InterviewBefore_NameRater(); + if (gScriptResult != 1) + { + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar1); + if (StringLength(gSaveBlock2Ptr->playerName) > 1 && StringLength(gStringVar1) > 1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->nameRaterShow.kind = TVSHOW_NAME_RATER_SHOW; + show->nameRaterShow.active = TRUE; + show->nameRaterShow.species = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPECIES, NULL); + show->nameRaterShow.random = Random() % 3; + show->nameRaterShow.random2 = Random() % 2; + show->nameRaterShow.randomSpecies = TV_GetSomeOtherSpeciesAlreadySeenByPlayer(show->nameRaterShow.species); + StringCopy(show->nameRaterShow.trainerName, gSaveBlock2Ptr->playerName); + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, show->nameRaterShow.pokemonName); + StripExtCtrlCodes(show->nameRaterShow.pokemonName); + tv_store_id_2x(show); + show->nameRaterShow.language = gGameLanguage; + show->nameRaterShow.pokemonNameLanguage = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_LANGUAGE); + } + } +} + +void StartMassOutbreak(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gSaveBlock1Ptr->outbreakPokemonSpecies = show->massOutbreak.species; + gSaveBlock1Ptr->outbreakLocationMapNum = show->massOutbreak.locationMapNum; + gSaveBlock1Ptr->outbreakLocationMapGroup = show->massOutbreak.locationMapGroup; + gSaveBlock1Ptr->outbreakPokemonLevel = show->massOutbreak.level; + gSaveBlock1Ptr->outbreakUnk1 = show->massOutbreak.var02; + gSaveBlock1Ptr->outbreakUnk2 = show->massOutbreak.var0E; + gSaveBlock1Ptr->outbreakPokemonMoves[0] = show->massOutbreak.moves[0]; + gSaveBlock1Ptr->outbreakPokemonMoves[1] = show->massOutbreak.moves[1]; + gSaveBlock1Ptr->outbreakPokemonMoves[2] = show->massOutbreak.moves[2]; + gSaveBlock1Ptr->outbreakPokemonMoves[3] = show->massOutbreak.moves[3]; + gSaveBlock1Ptr->outbreakUnk4 = show->massOutbreak.var03; + gSaveBlock1Ptr->outbreakPokemonProbability = show->massOutbreak.probability; + gSaveBlock1Ptr->outbreakDaysLeft = 2; +} + +void PutLilycoveContestLadyShowOnTheAir(void) +{ + TVShow *show; + + sub_80EFA88(); + if (gScriptResult != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + sub_818E848(&show->contestLiveUpdates2.language); + show->contestLiveUpdates2.pokemonNameLanguage = LANGUAGE_ENGLISH; + show->contestLiveUpdates2.kind = TVSHOW_CONTEST_LIVE_UPDATES_2; + show->contestLiveUpdates2.active = TRUE; + sub_818E81C(show->contestLiveUpdates2.playerName); + sub_818E7E0(&show->contestLiveUpdates2.contestCategory, show->contestLiveUpdates2.nickname); + show->contestLiveUpdates2.pokeblockState = sub_818E880(); + tv_store_id_2x(show); + } +} + +void InterviewAfter_FanClubLetter(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->fanclubLetter.kind = TVSHOW_FAN_CLUB_LETTER; + show->fanclubLetter.active = TRUE; + StringCopy(show->fanclubLetter.playerName, gSaveBlock2Ptr->playerName); + show->fanclubLetter.species = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL); + tv_store_id_2x(show); + show->fanclubLetter.language = gGameLanguage; +} + +void InterviewAfter_RecentHappenings(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->recentHappenings.kind = TVSHOW_RECENT_HAPPENINGS; + show->recentHappenings.active = TRUE; + StringCopy(show->recentHappenings.playerName, gSaveBlock2Ptr->playerName); + show->recentHappenings.var02 = 0; + tv_store_id_2x(show); + show->recentHappenings.language = gGameLanguage; +} + +void InterviewAfter_PkmnFanClubOpinions(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->fanclubOpinions.kind = TVSHOW_PKMN_FAN_CLUB_OPINIONS; + show->fanclubOpinions.active = TRUE; + show->fanclubOpinions.friendshipHighNybble = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_FRIENDSHIP, NULL) >> 4; + show->fanclubOpinions.questionAsked = gSpecialVar_0x8007; + StringCopy(show->fanclubOpinions.playerName, gSaveBlock2Ptr->playerName); + GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_NICKNAME, show->fanclubOpinions.nickname); + StripExtCtrlCodes(show->fanclubOpinions.nickname); + 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[GetLeadMonIndex()], MON_DATA_LANGUAGE) == LANGUAGE_JAPANESE) + { + show->fanclubOpinions.pokemonNameLanguage = LANGUAGE_JAPANESE; + } + else + { + show->fanclubOpinions.pokemonNameLanguage = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_LANGUAGE); + } +} + +void InterviewAfter_DummyShow4() +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; +} + +void sub_80ED718(void) +{ + u8 i; + u16 outbreakIdx; + TVShow *show; + + if (FlagGet(SYS_GAME_CLEAR)) + { + for (i = 0; i < 24; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind == TVSHOW_MASS_OUTBREAK) + { + return; + } + } + if (!rbernoulli(1, 200)) + { + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + outbreakIdx = Random() % ARRAY_COUNT(sPokeOutbreakSpeciesList); + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->massOutbreak.kind = TVSHOW_MASS_OUTBREAK; + show->massOutbreak.active = TRUE; + show->massOutbreak.level = sPokeOutbreakSpeciesList[outbreakIdx].level; + show->massOutbreak.var02 = 0; + show->massOutbreak.var03 = 0; + show->massOutbreak.species = sPokeOutbreakSpeciesList[outbreakIdx].species; + show->massOutbreak.var0E = 0; + show->massOutbreak.moves[0] = sPokeOutbreakSpeciesList[outbreakIdx].moves[0]; + show->massOutbreak.moves[1] = sPokeOutbreakSpeciesList[outbreakIdx].moves[1]; + show->massOutbreak.moves[2] = sPokeOutbreakSpeciesList[outbreakIdx].moves[2]; + show->massOutbreak.moves[3] = sPokeOutbreakSpeciesList[outbreakIdx].moves[3]; + show->massOutbreak.locationMapNum = sPokeOutbreakSpeciesList[outbreakIdx].location; + show->massOutbreak.locationMapGroup = 0; + show->massOutbreak.var12 = 0; + show->massOutbreak.probability = 50; + show->massOutbreak.var15 = 0; + show->massOutbreak.daysLeft = 1; + tv_store_id_2x(show); + show->massOutbreak.language = gGameLanguage; + } + } + } +} + +void EndMassOutbreak(void) +{ + gSaveBlock1Ptr->outbreakPokemonSpecies = SPECIES_NONE; + gSaveBlock1Ptr->outbreakLocationMapNum = 0; + gSaveBlock1Ptr->outbreakLocationMapGroup = 0; + gSaveBlock1Ptr->outbreakPokemonLevel = 0; + gSaveBlock1Ptr->outbreakUnk1 = 0; + gSaveBlock1Ptr->outbreakUnk2 = 0; + gSaveBlock1Ptr->outbreakPokemonMoves[0] = MOVE_NONE; + gSaveBlock1Ptr->outbreakPokemonMoves[1] = MOVE_NONE; + gSaveBlock1Ptr->outbreakPokemonMoves[2] = MOVE_NONE; + gSaveBlock1Ptr->outbreakPokemonMoves[3] = MOVE_NONE; + gSaveBlock1Ptr->outbreakUnk4 = 0; + gSaveBlock1Ptr->outbreakPokemonProbability = 0; + gSaveBlock1Ptr->outbreakDaysLeft = 0; +} + +void sub_80ED888(u16 days) +{ + + sub_80ED8B4(days); + UpdateMassOutbreakTimeLeft(days); + sub_80EF120(days); + sub_80EDA48(days); + sub_80EEB98(days); +} + +void sub_80ED8B4(u16 days) +{ + u8 i; + TVShow *show; + + if (gSaveBlock1Ptr->outbreakPokemonSpecies == SPECIES_NONE) + { + for (i = 0; i < 24; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].massOutbreak.kind == TVSHOW_MASS_OUTBREAK && gSaveBlock1Ptr->tvShows[i].massOutbreak.active == TRUE) + { + show = &gSaveBlock1Ptr->tvShows[i]; + if (show->massOutbreak.daysLeft < days) + { + show->massOutbreak.daysLeft = 0; + } + else + { + show->massOutbreak.daysLeft -= days; + } + break; + } + } + } +} + +void UpdateMassOutbreakTimeLeft(u16 days) +{ + if (gSaveBlock1Ptr->outbreakDaysLeft <= days) + { + EndMassOutbreak(); + } + else + { + gSaveBlock1Ptr->outbreakDaysLeft -= days; + } +} + +void sub_80ED950(bool8 flag) +{ + if (flag) + { + if (sPokemonAnglerAttemptCounters >> 8 > 4) + { + PutFishingAdviceShowOnTheAir(); + } + sPokemonAnglerAttemptCounters &= 0xFF; + if (sPokemonAnglerAttemptCounters != 0xFF) + { + sPokemonAnglerAttemptCounters += 0x01; + } + } + else + { + if ((u8)sPokemonAnglerAttemptCounters > 4) + { + PutFishingAdviceShowOnTheAir(); + } + sPokemonAnglerAttemptCounters &= 0xFF00; + if (sPokemonAnglerAttemptCounters >> 8 != 0xFF) + { + sPokemonAnglerAttemptCounters += 0x0100; + } + } +} + +void PutFishingAdviceShowOnTheAir(void) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_FISHING_ADVICE, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->pokemonAngler.kind = TVSHOW_FISHING_ADVICE; + show->pokemonAngler.active = FALSE; + show->pokemonAngler.nBites = sPokemonAnglerAttemptCounters; + show->pokemonAngler.nFails = sPokemonAnglerAttemptCounters >> 8; + show->pokemonAngler.species = sPokemonAnglerSpecies; + StringCopy(show->pokemonAngler.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->pokemonAngler.language = gGameLanguage; + } +} + +void sub_80EDA3C(u16 species) +{ + sPokemonAnglerSpecies = species; +} + +void sub_80EDA48(u16 days) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[24]; + if (show->worldOfMasters.kind == TVSHOW_WORLD_OF_MASTERS) + { + if (show->worldOfMasters.numPokeCaught >= 20) + { + sub_80EDA80(); + } + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + } +} + +void sub_80EDA80(void) +{ + TVShow *show; + TVShow *show2; + + show = &gSaveBlock1Ptr->tvShows[24]; + if (!rbernoulli(1, 1)) + { + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_WORLD_OF_MASTERS, FALSE) != TRUE) + { + show2 = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show2->worldOfMasters.kind = TVSHOW_WORLD_OF_MASTERS; + show2->worldOfMasters.active = FALSE; + show2->worldOfMasters.numPokeCaught = show->worldOfMasters.numPokeCaught; + show2->worldOfMasters.steps = GetGameStat(GAME_STAT_STEPS) - show->worldOfMasters.steps; + show2->worldOfMasters.caughtPoke = show->worldOfMasters.caughtPoke; + show2->worldOfMasters.species = show->worldOfMasters.species; + show2->worldOfMasters.location = show->worldOfMasters.location; + StringCopy(show2->worldOfMasters.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show2); + show2->worldOfMasters.language = gGameLanguage; + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, 24); + } + } +} + +void sub_80EDB44(void) +{ + TVShow *show; + u32 i; + u8 nBadges; + + HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_TODAYS_RIVAL_TRAINER, TRUE); + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->rivalTrainer.kind = TVSHOW_TODAYS_RIVAL_TRAINER; + show->rivalTrainer.active = FALSE; + for (i = BADGE01_GET, nBadges = 0; i < BADGE01_GET + 8; i ++) + { + if (FlagGet(i)) + { + nBadges ++; + } + } + show->rivalTrainer.badgeCount = nBadges; + if (IsNationalPokedexEnabled()) + { + show->rivalTrainer.dexCount = pokedex_count(0x01); + } + else + { + show->rivalTrainer.dexCount = sub_80C0844(0x01); + } + show->rivalTrainer.location = gMapHeader.regionMapSectionId; + show->rivalTrainer.mapDataId = gMapHeader.mapDataId; + show->rivalTrainer.nSilverSymbols = 0; + show->rivalTrainer.nGoldSymbols = 0; + for (i = 0; i < 7; i ++) + { + if (FlagGet(sSilverSymbolFlags[i]) == TRUE) + { + show->rivalTrainer.nSilverSymbols ++; + } + if (FlagGet(sGoldSymbolFlags[i]) == TRUE) + { + show->rivalTrainer.nGoldSymbols ++; + } + } + show->rivalTrainer.battlePoints = gSaveBlock2Ptr->frontierBattlePoints; + StringCopy(show->rivalTrainer.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->rivalTrainer.language = gGameLanguage; + } +} + +void sub_80EDC60(const u16 *words) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_TREND_WATCHER, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->trendWatcher.kind = TVSHOW_TREND_WATCHER; + show->trendWatcher.active = FALSE; + show->trendWatcher.gender = gSaveBlock2Ptr->playerGender; + show->trendWatcher.words[0] = words[0]; + show->trendWatcher.words[1] = words[1]; + StringCopy(show->trendWatcher.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->trendWatcher.language = gGameLanguage; + } +} + +void sub_80EDCE8(void) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_TREASURE_INVESTIGATORS, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->treasureInvestigators.kind = TVSHOW_TREASURE_INVESTIGATORS; + show->treasureInvestigators.active = FALSE; + show->treasureInvestigators.item = gSpecialVar_0x8005; + show->treasureInvestigators.location = gMapHeader.regionMapSectionId; + show->treasureInvestigators.mapDataId = gMapHeader.mapDataId; + StringCopy(show->treasureInvestigators.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->treasureInvestigators.language = gGameLanguage; + } +} + +void sub_80EDD78(u16 nCoinsPaidOut) +{ + TVShow *show; + bool8 flag; + u16 nCoinsWon; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_FIND_THAT_GAMER, FALSE) != TRUE) + { + flag = FALSE; + switch (sFindThatGamerWhichGame) + { + case FALSE: + if (nCoinsPaidOut >= sFindThatGamerCoinsSpent + 200) + { + flag = TRUE; + nCoinsWon = nCoinsPaidOut - sFindThatGamerCoinsSpent; + break; + } + if (sFindThatGamerCoinsSpent >= 100 && nCoinsPaidOut <= sFindThatGamerCoinsSpent - 100) + { + nCoinsWon = sFindThatGamerCoinsSpent - nCoinsPaidOut; + break; + } + return; + case TRUE: + if (nCoinsPaidOut >= sFindThatGamerCoinsSpent + 50) + { + flag = TRUE; + nCoinsWon = nCoinsPaidOut - sFindThatGamerCoinsSpent; + break; + } + if (sFindThatGamerCoinsSpent >= 50 && nCoinsPaidOut <= sFindThatGamerCoinsSpent - 50) + { + nCoinsWon = sFindThatGamerCoinsSpent - nCoinsPaidOut; + break; + } + return; + default: + return; + } + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->findThatGamer.kind = TVSHOW_FIND_THAT_GAMER; + show->findThatGamer.active = FALSE; + show->findThatGamer.nCoins = nCoinsWon; + show->findThatGamer.whichGame = sFindThatGamerWhichGame; + show->findThatGamer.won = flag; + StringCopy(show->findThatGamer.playerName, gSaveBlock2Ptr->playerName); + tv_store_id_3x(show); + show->findThatGamer.language = gGameLanguage; + } +} + +void sub_80EDE70(u16 nCoinsSpent) +{ + sFindThatGamerWhichGame = FALSE; + sFindThatGamerCoinsSpent = nCoinsSpent; +} + +void sub_80EDE84(u16 nCoinsSpent) +{ + sFindThatGamerWhichGame = TRUE; + sFindThatGamerCoinsSpent = nCoinsSpent; +} + +#ifdef NONMATCHING // FIXME: Register allocation shenanigans +void sub_80EDE98(TVShow *show) +{ + u8 i; + u8 j; + u16 k; + u8 n; + u8 deco; + u8 x; + + for (i = 0; i < 16; i ++) + { + sTV_DecorationsBuffer[i] = 0; + } + for (i = 0, n = 0; i < 16; i ++) + { + deco = gSaveBlock1Ptr->secretBases[0].decorations[i]; + if (deco) + { + for (j = 0; j < 16; j ++) + { + if (sTV_DecorationsBuffer[j] == 0) + { + sTV_DecorationsBuffer[j] = deco; + n ++; + break; + } + if (sTV_DecorationsBuffer[j] == deco) + { + break; + } + } + } + } + if (n > 4) + { + show->secretBaseVisit.nDecorations = 4; + } + else + { + show->secretBaseVisit.nDecorations = n; + } + switch (show->secretBaseVisit.nDecorations) + { + case 0: + break; + case 1: + show->secretBaseVisit.decorations[0] = sTV_DecorationsBuffer[0]; + break; + default: + for (k = 0; k < n * n; k ++) + { + i = Random() % n; + j = Random() % n; + x = sTV_DecorationsBuffer[i]; + sTV_DecorationsBuffer[i] = sTV_DecorationsBuffer[j]; + sTV_DecorationsBuffer[j] = x; + } + for (i = 0; i < show->secretBaseVisit.nDecorations; i ++) + { + show->secretBaseVisit.decorations[i] = sTV_DecorationsBuffer[i]; + } + break; + } +} +#else +__attribute__((naked)) +void sub_80EDE98(TVShow *show) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmov r7, r9\n" + "\tmov r6, r8\n" + "\tpush {r6,r7}\n" + "\tmov r8, r0\n" + "\tmovs r3, 0\n" + "\tldr r6, =sTV_DecorationsBuffer\n" + "\tldr r7, =gSaveBlock1Ptr\n" + "\tadds r2, r6, 0\n" + "\tmovs r1, 0\n" + "_080EDEAC:\n" + "\tadds r0, r3, r2\n" + "\tstrb r1, [r0]\n" + "\tadds r0, r3, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r3, r0, 24\n" + "\tcmp r3, 0xF\n" + "\tbls _080EDEAC\n" + "\tmovs r3, 0\n" + "\tmovs r5, 0\n" + "_080EDEBE:\n" + "\tldr r0, [r7]\n" + "\tldr r1, =0x00001aae\n" + "\tadds r0, r1\n" + "\tadds r0, r3\n" + "\tldrb r4, [r0]\n" + "\tadds r3, 0x1\n" + "\tcmp r4, 0\n" + "\tbeq _080EDF0A\n" + "\tmovs r1, 0\n" + "\tldrb r0, [r6]\n" + "\tcmp r0, 0\n" + "\tbne _080EDEE8\n" + "\tstrb r4, [r6]\n" + "\tb _080EDF04\n" + "\t.pool\n" + "_080EDEE8:\n" + "\tadds r0, r1, r6\n" + "\tldrb r0, [r0]\n" + "\tcmp r0, r4\n" + "\tbeq _080EDF0A\n" + "\tadds r0, r1, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r1, r0, 24\n" + "\tcmp r1, 0xF\n" + "\tbhi _080EDF0A\n" + "\tadds r2, r1, r6\n" + "\tldrb r0, [r2]\n" + "\tcmp r0, 0\n" + "\tbne _080EDEE8\n" + "\tstrb r4, [r2]\n" + "_080EDF04:\n" + "\tadds r0, r5, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r5, r0, 24\n" + "_080EDF0A:\n" + "\tlsls r0, r3, 24\n" + "\tlsrs r3, r0, 24\n" + "\tcmp r3, 0xF\n" + "\tbls _080EDEBE\n" + "\tcmp r5, 0x4\n" + "\tbls _080EDF1E\n" + "\tmovs r0, 0x4\n" + "\tmov r1, r8\n" + "\tstrb r0, [r1, 0x3]\n" + "\tb _080EDF22\n" + "_080EDF1E:\n" + "\tmov r0, r8\n" + "\tstrb r5, [r0, 0x3]\n" + "_080EDF22:\n" + "\tmov r1, r8\n" + "\tldrb r0, [r1, 0x3]\n" + "\tcmp r0, 0\n" + "\tbeq _080EDFA4\n" + "\tcmp r0, 0x1\n" + "\tbne _080EDF34\n" + "\tldrb r0, [r6]\n" + "\tstrb r0, [r1, 0x4]\n" + "\tb _080EDFA4\n" + "_080EDF34:\n" + "\tmovs r6, 0\n" + "\tadds r7, r5, 0\n" + "\tmuls r7, r5\n" + "\tcmp r6, r7\n" + "\tbge _080EDF7E\n" + "\tldr r0, =sTV_DecorationsBuffer\n" + "\tmov r9, r0\n" + "_080EDF42:\n" + "\tbl Random\n" + "\tlsls r0, 16\n" + "\tlsrs r0, 16\n" + "\tadds r1, r5, 0\n" + "\tbl __modsi3\n" + "\tlsls r0, 24\n" + "\tlsrs r4, r0, 24\n" + "\tbl Random\n" + "\tlsls r0, 16\n" + "\tlsrs r0, 16\n" + "\tadds r1, r5, 0\n" + "\tbl __modsi3\n" + "\tlsls r0, 24\n" + "\tlsrs r1, r0, 24\n" + "\tmov r0, r9\n" + "\tadds r2, r4, r0\n" + "\tldrb r3, [r2]\n" + "\tadd r1, r9\n" + "\tldrb r0, [r1]\n" + "\tstrb r0, [r2]\n" + "\tstrb r3, [r1]\n" + "\tadds r0, r6, 0x1\n" + "\tlsls r0, 16\n" + "\tlsrs r6, r0, 16\n" + "\tcmp r6, r7\n" + "\tblt _080EDF42\n" + "_080EDF7E:\n" + "\tmovs r3, 0\n" + "\tmov r1, r8\n" + "\tldrb r1, [r1, 0x3]\n" + "\tcmp r3, r1\n" + "\tbcs _080EDFA4\n" + "\tmov r2, r8\n" + "\tadds r2, 0x4\n" + "\tldr r4, =sTV_DecorationsBuffer\n" + "_080EDF8E:\n" + "\tadds r1, r2, r3\n" + "\tadds r0, r3, r4\n" + "\tldrb r0, [r0]\n" + "\tstrb r0, [r1]\n" + "\tadds r0, r3, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r3, r0, 24\n" + "\tmov r0, r8\n" + "\tldrb r0, [r0, 0x3]\n" + "\tcmp r3, r0\n" + "\tbcc _080EDF8E\n" + "_080EDFA4:\n" + "\tpop {r3,r4}\n" + "\tmov r8, r3\n" + "\tmov r9, r4\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0\n" + "\t.pool"); +} +#endif + +void sub_80EDFB4(TVShow *show) +{ + u8 i; + u16 move; + u16 j; + u8 nMoves; + u8 nPokemon; + u16 sum; + + for (i = 0, nPokemon = 0; i < PARTY_SIZE; i ++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) != SPECIES_NONE && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + { + sTV_SecretBaseVisitMonsTemp[nPokemon].level = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); + sTV_SecretBaseVisitMonsTemp[nPokemon].species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES); + nMoves = 0; + move = GetMonData(&gPlayerParty[i], MON_DATA_MOVE1); + if (move != MOVE_NONE) + { + sTV_SecretBaseVisitMovesTemp[nMoves] = move; + nMoves ++; + } + move = GetMonData(&gPlayerParty[i], MON_DATA_MOVE2); + if (move != MOVE_NONE) + { + sTV_SecretBaseVisitMovesTemp[nMoves] = move; + nMoves ++; + } + move = GetMonData(&gPlayerParty[i], MON_DATA_MOVE3); + if (move != MOVE_NONE) + { + sTV_SecretBaseVisitMovesTemp[nMoves] = move; + nMoves ++; + } + move = GetMonData(&gPlayerParty[i], MON_DATA_MOVE4); + if (move != MOVE_NONE) + { + sTV_SecretBaseVisitMovesTemp[nMoves] = move; + nMoves ++; + } + sTV_SecretBaseVisitMonsTemp[nPokemon].move = sTV_SecretBaseVisitMovesTemp[Random() % nMoves]; + nPokemon ++; + } + } + for (i = 0, sum = 0; i < nPokemon; i ++) + { + sum += sTV_SecretBaseVisitMonsTemp[i].level; + } + show->secretBaseVisit.avgLevel = sum / nPokemon; + j = Random() % nPokemon; + show->secretBaseVisit.species = sTV_SecretBaseVisitMonsTemp[j].species; + show->secretBaseVisit.move = sTV_SecretBaseVisitMonsTemp[j].move; +} + +void TV_PutSecretBaseVisitOnTheAir(void) +{ + TVShow *show; + + HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_SECRET_BASE_VISIT, TRUE); + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->secretBaseVisit.kind = TVSHOW_SECRET_BASE_VISIT; + show->secretBaseVisit.active = FALSE; + StringCopy(show->secretBaseVisit.playerName, gSaveBlock2Ptr->playerName); + sub_80EDE98(show); + sub_80EDFB4(show); + tv_store_id_3x(show); + show->secretBaseVisit.language = gGameLanguage; + } +} + +void sub_80EE184(void) +{ + TVShow *show; + u8 i; + u16 balls; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_BREAKING_NEWS, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->breakingNews.kind = TVSHOW_BREAKING_NEWS; + show->breakingNews.active = FALSE; + balls = 0; + for (i = 0; i < 11; i ++) + { + balls += gBattleResults.catchAttempts[i]; + } + if (gBattleResults.usedMasterBall) + { + balls ++; + } + show->breakingNews.location = gMapHeader.regionMapSectionId; + StringCopy(show->breakingNews.playerName, gSaveBlock2Ptr->playerName); + show->breakingNews.poke1Species = gBattleResults.playerMon1Species; + switch (gBattleOutcome) + { + case BATTLE_LOST: + case BATTLE_DREW: + show->breakingNews.kind = TVSHOW_OFF_AIR; + return; + case BATTLE_CAUGHT: + show->breakingNews.outcome = 0; + break; + case BATTLE_WON: + show->breakingNews.outcome = 1; + break; + case BATTLE_RAN: + case BATTLE_PLAYER_TELEPORTED: + case BATTLE_SAFARI_OUT_OF_BALLS: + show->breakingNews.outcome = 2; + break; + case BATTLE_POKE_FLED: + case BATTLE_OPPONENT_TELEPORTED: + show->breakingNews.outcome = 3; + break; + } + show->breakingNews.lastOpponentSpecies = gBattleResults.lastOpponentSpecies; + switch (show->breakingNews.outcome) + { + case 0: + if (gBattleResults.usedMasterBall) + { + show->breakingNews.caughtMonBall = ITEM_MASTER_BALL; + } + else + { + show->breakingNews.caughtMonBall = gBattleResults.caughtMonBall; + } + show->breakingNews.balls = balls; + break; + case 1: + show->breakingNews.lastUsedMove = gBattleResults.lastUsedMovePlayer; + break; + case 2: + break; + case 3: + break; + } + tv_store_id_3x(show); + show->breakingNews.language = gGameLanguage; + } +} + +void sub_80EE2CC(void) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_LOTTO_WINNER, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->lottoWinner.kind = TVSHOW_LOTTO_WINNER; + show->lottoWinner.active = FALSE; + StringCopy(show->lottoWinner.playerName, gSaveBlock2Ptr->playerName); + show->lottoWinner.whichPrize = 4 - gSpecialVar_0x8004; + show->lottoWinner.item = gSpecialVar_0x8005; + tv_store_id_3x(show); + show->lottoWinner.language = gGameLanguage; + } +} + +void sub_80EE35C(u16 foeSpecies, u16 species, u8 moveIdx, const u16 *movePtr, u16 betterMove) +{ + TVShow *show; + u8 i; + u8 j; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_BATTLE_SEMINAR, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->battleSeminar.kind = TVSHOW_BATTLE_SEMINAR; + show->battleSeminar.active = FALSE; + StringCopy(show->battleSeminar.playerName, gSaveBlock2Ptr->playerName); + show->battleSeminar.foeSpecies = foeSpecies; + show->battleSeminar.species = species; + show->battleSeminar.move = movePtr[moveIdx]; + for (i = 0, j = 0; i < 4; i ++) + { + if (i != moveIdx && movePtr[i]) + { + show->battleSeminar.otherMoves[j] = movePtr[i]; + j ++; + } + } + show->battleSeminar.nOtherMoves = j; + show->battleSeminar.betterMove = betterMove; + tv_store_id_3x(show); + show->battleSeminar.language = gGameLanguage; + } +} + +void sub_80EE44C(u8 nMonsCaught, u8 nPkblkUsed) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_SAFARI_FAN_CLUB, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->safariFanClub.kind = TVSHOW_SAFARI_FAN_CLUB; + show->safariFanClub.active = FALSE; + StringCopy(show->safariFanClub.playerName, gSaveBlock2Ptr->playerName); + show->safariFanClub.nMonsCaught = nMonsCaught; + show->safariFanClub.nPkblkUsed = nPkblkUsed; + tv_store_id_3x(show); + show->safariFanClub.language = gGameLanguage; + } +} + +void sub_80EE4DC(struct Pokemon *pokemon, u8 ribbonMonDataIdx) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_CUTIES, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->cuties.kind = TVSHOW_CUTIES; + show->cuties.active = FALSE; + StringCopy(show->cuties.playerName, gSaveBlock2Ptr->playerName); + GetMonData(pokemon, MON_DATA_NICKNAME, show->cuties.nickname); + StripExtCtrlCodes(show->cuties.nickname); + show->cuties.nRibbons = GetRibbonCount(pokemon); + show->cuties.selectedRibbon = TV_MonDataIdxToRibbon(ribbonMonDataIdx); + tv_store_id_3x(show); + show->cuties.language = gGameLanguage; + if (show->cuties.language == LANGUAGE_JAPANESE || GetMonData(pokemon, MON_DATA_LANGUAGE) == LANGUAGE_JAPANESE) + { + show->cuties.pokemonNameLanguage = LANGUAGE_JAPANESE; + } + else + { + show->cuties.pokemonNameLanguage = GetMonData(pokemon, MON_DATA_LANGUAGE); + } + } +} + +u8 GetRibbonCount(struct Pokemon *pokemon) +{ + u8 nRibbons; + + nRibbons = 0; + nRibbons += GetMonData(pokemon, MON_DATA_COOL_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_BEAUTY_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_CUTE_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_SMART_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_TOUGH_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_CHAMPION_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_WINNING_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_VICTORY_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_ARTIST_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_EFFORT_RIBBON); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_1); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_2); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_3); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_4); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_5); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_6); + nRibbons += GetMonData(pokemon, MON_DATA_GIFT_RIBBON_7); + return nRibbons; +} + +u8 TV_MonDataIdxToRibbon(u8 monDataIdx) +{ + if (monDataIdx == MON_DATA_CHAMPION_RIBBON) return 0; + if (monDataIdx == MON_DATA_COOL_RIBBON) return 1; + if (monDataIdx == MON_DATA_BEAUTY_RIBBON) return 5; + if (monDataIdx == MON_DATA_CUTE_RIBBON) return 9; + if (monDataIdx == MON_DATA_SMART_RIBBON) return 13; + if (monDataIdx == MON_DATA_TOUGH_RIBBON) return 17; + if (monDataIdx == MON_DATA_WINNING_RIBBON) return 21; + if (monDataIdx == MON_DATA_VICTORY_RIBBON) return 22; + if (monDataIdx == MON_DATA_ARTIST_RIBBON) return 23; + if (monDataIdx == MON_DATA_EFFORT_RIBBON) return 24; + if (monDataIdx == MON_DATA_GIFT_RIBBON_1) return 25; + if (monDataIdx == MON_DATA_GIFT_RIBBON_2) return 26; + if (monDataIdx == MON_DATA_GIFT_RIBBON_3) return 27; + if (monDataIdx == MON_DATA_GIFT_RIBBON_4) return 28; + if (monDataIdx == MON_DATA_GIFT_RIBBON_5) return 29; + if (monDataIdx == MON_DATA_GIFT_RIBBON_6) return 30; + if (monDataIdx == MON_DATA_GIFT_RIBBON_7) return 31; + return 0; +} + +void sub_80EE72C(void) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1 && HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_TRAINER_FAN_CLUB, FALSE) != TRUE) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->trainerFanClub.kind = TVSHOW_TRAINER_FAN_CLUB; + show->trainerFanClub.active = FALSE; + StringCopy(show->trainerFanClub.playerName, gSaveBlock2Ptr->playerName); + show->trainerFanClub.words[0] = gSaveBlock1Ptr->unk2BB0[0]; + show->trainerFanClub.words[1] = gSaveBlock1Ptr->unk2BB0[1]; + tv_store_id_3x(show); + show->trainerFanClub.language = gGameLanguage; + } +} + +bool8 sub_80EE7C0(void) +{ + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot == -1) + { + return TRUE; + } + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_FAN_CLUB_SPECIAL); + if (gScriptResult == TRUE) + { + return TRUE; + } + if (gSaveBlock1Ptr->linkBattleRecords[0].name[0] == EOS) + { + return TRUE; + } + return FALSE; +} + +bool8 sub_80EE818(void) +{ + u32 playerId; + u8 showIdx; + TVShow *shows; + + if (HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_FRONTIER, FALSE) == TRUE) + { + shows = gSaveBlock1Ptr->tvShows; + playerId = GetPlayerIDAsU32(); + for (showIdx = 5; showIdx < 24; showIdx ++) + { + if (shows[showIdx].common.kind == TVSHOW_FRONTIER && (playerId & 0xFF) == shows[showIdx].common.trainerIdLo && ((playerId >> 8) & 0xFF) == shows[showIdx].common.trainerIdHi) + { + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, showIdx); + sub_80EF93C(gSaveBlock1Ptr->tvShows); + return TRUE; + } + } + } + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot == -1) + { + return FALSE; + } + return TRUE; +} + +void sub_80EE8C8(u16 winStreak, u8 facility) +{ + TVShow *show; + + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->frontier.kind = TVSHOW_FRONTIER; + show->frontier.active = FALSE; + StringCopy(show->frontier.playerName, gSaveBlock2Ptr->playerName); + show->frontier.winStreak = winStreak; + show->frontier.facility = facility; + switch (facility) + { + case 1: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + show->frontier.species1 = GetMonData(&gPlayerParty[0], MON_DATA_SPECIES, NULL); + show->frontier.species2 = GetMonData(&gPlayerParty[1], MON_DATA_SPECIES, NULL); + show->frontier.species3 = GetMonData(&gPlayerParty[2], MON_DATA_SPECIES, NULL); + break; + case 2: + show->frontier.species1 = GetMonData(&gPlayerParty[0], MON_DATA_SPECIES, NULL); + show->frontier.species2 = GetMonData(&gPlayerParty[1], MON_DATA_SPECIES, NULL); + show->frontier.species3 = GetMonData(&gPlayerParty[2], MON_DATA_SPECIES, NULL); + show->frontier.species4 = GetMonData(&gPlayerParty[3], MON_DATA_SPECIES, NULL); + break; + case 3: + show->frontier.species1 = GetMonData(&gPlayerParty[0], MON_DATA_SPECIES, NULL); + show->frontier.species2 = GetMonData(&gPlayerParty[1], MON_DATA_SPECIES, NULL); + break; + case 4: + show->frontier.species1 = GetMonData(&gSaveBlock1Ptr->playerParty[gSaveBlock2Ptr->field_CAA[0] - 1], MON_DATA_SPECIES, NULL); + show->frontier.species2 = GetMonData(&gSaveBlock1Ptr->playerParty[gSaveBlock2Ptr->field_CAA[1] - 1], MON_DATA_SPECIES, NULL); + break; + } + tv_store_id_3x(show); + show->frontier.language = gGameLanguage; + } +} + +void sub_80EEA70(void) +{ + TVShow *show; + u8 strbuf[32]; + + if (HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_SECRET_BASE_SECRETS, FALSE) != TRUE) + { + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->secretBaseSecrets.kind = TVSHOW_SECRET_BASE_SECRETS; + show->secretBaseSecrets.active = FALSE; + StringCopy(show->secretBaseSecrets.playerName, gSaveBlock2Ptr->playerName); + show->secretBaseSecrets.stepsInBase = VarGet(0x40ec); + sub_80E980C(); + StringCopy(strbuf, gStringVar1); + StripExtCtrlCodes(strbuf); + StringCopy(show->secretBaseSecrets.baseOwnersName, strbuf); + show->secretBaseSecrets.item = VarGet(0x40ed); + show->secretBaseSecrets.flags = VarGet(0x40ee) + (VarGet(0x40ef) << 16); + tv_store_id_3x(show); + show->secretBaseSecrets.language = gGameLanguage; + if (show->secretBaseSecrets.language == LANGUAGE_JAPANESE || gSaveBlock1Ptr->secretBases[VarGet(VAR_0x4054)].language == LANGUAGE_JAPANESE) + { + show->secretBaseSecrets.baseOwnersNameLanguage = LANGUAGE_JAPANESE; + } + else + { + show->secretBaseSecrets.baseOwnersNameLanguage = gSaveBlock1Ptr->secretBases[VarGet(VAR_0x4054)].language; + } + } + } +} + +void sub_80EEB98(u16 days) +{ + u8 i; + + for (i = 0; i < ARRAY_COUNT(sNumberOneVarsAndThresholds); i ++) + { + if (VarGet(sNumberOneVarsAndThresholds[i][0]) >= sNumberOneVarsAndThresholds[i][1]) + { + sub_80EEBF4(i); + break; + } + } + for (i = 0; i < ARRAY_COUNT(sNumberOneVarsAndThresholds); i ++) + { + VarSet(sNumberOneVarsAndThresholds[i][0], 0); + } +} + +void sub_80EEBF4(u8 actionIdx) +{ + TVShow *show; + + HasMixableShowAlreadyBeenSpawnedWithPlayerID(TVSHOW_NUMBER_ONE, TRUE); + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + if (sCurTVShowSlot != -1) + { + show = &gSaveBlock1Ptr->tvShows[sCurTVShowSlot]; + show->numberOne.kind = TVSHOW_NUMBER_ONE; + show->numberOne.active = FALSE; + StringCopy(show->numberOne.playerName, gSaveBlock2Ptr->playerName); + show->numberOne.actionIdx = actionIdx; + show->numberOne.count = VarGet(sNumberOneVarsAndThresholds[actionIdx][0]); + tv_store_id_3x(show); + show->numberOne.language = gGameLanguage; + } +} + +void sub_80EEC80(void) +{ + VarSet(VAR_DAILY_SLOTS, VarGet(VAR_DAILY_SLOTS) + 1); +} + +void sub_80EECA4(void) +{ + VarSet(VAR_DAILY_ROULETTE, VarGet(VAR_DAILY_ROULETTE) + 1); +} + +void sub_80EECC8(void) +{ + VarSet(VAR_DAILY_WILDS, VarGet(VAR_DAILY_WILDS) + 1); +} + +void sub_80EECEC(void) +{ + VarSet(VAR_DAILY_BLENDER, VarGet(VAR_DAILY_BLENDER) + 1); +} + +void sub_80EED10(void) +{ + VarSet(VAR_DAILY_PLANTED_BERRIES, VarGet(VAR_DAILY_PLANTED_BERRIES) + 1); +} + +void sub_80EED34(void) +{ + VarSet(VAR_DAILY_PICKED_BERRIES, VarGet(VAR_DAILY_PICKED_BERRIES) + gSpecialVar_0x8006); +} + +void sub_80EED60(u16 delta) +{ + VarSet(VAR_DAILY_BP, VarGet(VAR_DAILY_BP) + delta); +} + +// PokeNews + +void sub_80EED88(void) +{ + u8 newsKind; + + if (FlagGet(SYS_GAME_CLEAR)) + { + sCurTVShowSlot = sub_80EEE30(gSaveBlock1Ptr->pokeNews); + if (sCurTVShowSlot != -1 && rbernoulli(1, 100) != TRUE) + { + newsKind = (Random() % 4) + POKENEWS_SLATEPORT; + if (sub_80EF0E4(newsKind) != TRUE) + { + gSaveBlock1Ptr->pokeNews[sCurTVShowSlot].kind = newsKind; + gSaveBlock1Ptr->pokeNews[sCurTVShowSlot].days = 4; + gSaveBlock1Ptr->pokeNews[sCurTVShowSlot].state = TRUE; + } + } + } +} + +s8 sub_80EEE30(PokeNews *pokeNews) +{ + s8 i; + + for (i = 0; i < 16; i ++) + { + if (pokeNews[i].kind == 0) + { + return i; + } + } + return -1; +} + +void ClearPokemonNews(void) +{ + u8 i; + + for (i = 0; i < 16; i ++) + { + ClearPokemonNewsI(i); + } +} + +void ClearPokemonNewsI(u8 i) +{ + gSaveBlock1Ptr->pokeNews[i].kind = POKENEWS_NONE; + gSaveBlock1Ptr->pokeNews[i].state = FALSE; + gSaveBlock1Ptr->pokeNews[i].days = 0; +} + +void sub_80EEEB8(void) +{ + u8 i; + u8 j; + + for (i = 0; i < 15; i ++) + { + if (gSaveBlock1Ptr->pokeNews[i].kind == POKENEWS_NONE) + { + for (j = i + 1; j < 16; j ++) + { + if (gSaveBlock1Ptr->pokeNews[j].kind != POKENEWS_NONE) + { + gSaveBlock1Ptr->pokeNews[i] = gSaveBlock1Ptr->pokeNews[j]; + ClearPokemonNewsI(j); + break; + } + } + } + } +} + +u8 FindAnyTVNewsOnTheAir(void) +{ + u8 i; + + for (i = 0; i < 16; i ++) + { + if (gSaveBlock1Ptr->pokeNews[i].kind != POKENEWS_NONE && gSaveBlock1Ptr->pokeNews[i].state == TRUE && gSaveBlock1Ptr->pokeNews[i].days < 3) + { + return i; + } + } + return -1; +} + +void DoPokeNews(void) +{ + u8 i; + u16 n; + + i = FindAnyTVNewsOnTheAir(); + if (i == 0xFF) + { + gScriptResult = FALSE; + } + else + { + if (gSaveBlock1Ptr->pokeNews[i].days == 0) + { + gSaveBlock1Ptr->pokeNews[i].state = 2; + if (gLocalTime.hours < 20) + { + ShowFieldMessage(sPokeNewsTextGroup_Ongoing[gSaveBlock1Ptr->pokeNews[i].kind]); + } + else + { + ShowFieldMessage(sPokeNewsTextGroup_Ending[gSaveBlock1Ptr->pokeNews[i].kind]); + } + } + else + { + n = gSaveBlock1Ptr->pokeNews[i].days; + ConvertIntToDecimalStringN(gStringVar1, n, STR_CONV_MODE_LEFT_ALIGN, 1); + gSaveBlock1Ptr->pokeNews[i].state = 0; + ShowFieldMessage(sPokeNewsTextGroup_Upcoming[gSaveBlock1Ptr->pokeNews[i].kind]); + } + gScriptResult = TRUE; + } +} + +bool8 GetPriceReduction(u8 newsKind) +{ + u8 i; + + if (newsKind == 0) + { + return FALSE; + } + for (i = 0; i < 16; i ++) + { + if (gSaveBlock1Ptr->pokeNews[i].kind == newsKind) + { + if (gSaveBlock1Ptr->pokeNews[i].state == 2 && IsPriceDiscounted(newsKind)) + { + return TRUE; + } + return FALSE; + } + } + return FALSE; +} + +bool8 IsPriceDiscounted(u8 newsKind) +{ + switch (newsKind) + { + case POKENEWS_SLATEPORT: + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_SLATEPORT_CITY && gSaveBlock1Ptr->location.mapNum == MAP_ID_SLATEPORT_CITY && gScriptLastTalked == 25) + { + return TRUE; + } + return FALSE; + case POKENEWS_LILYCOVE: + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_LILYCOVE_CITY_DEPARTMENT_STORE_ROOFTOP && gSaveBlock1Ptr->location.mapNum == MAP_ID_LILYCOVE_CITY_DEPARTMENT_STORE_ROOFTOP) + { + return TRUE; + } + return FALSE; + } + return TRUE; +} + +bool8 sub_80EF0E4(u8 newsKind) +{ + u8 i; + if (newsKind == POKENEWS_NONE) + { + return TRUE; + } + for (i = 0; i < 16; i ++) + { + if (gSaveBlock1Ptr->pokeNews[i].kind == newsKind) + { + return TRUE; + } + } + return FALSE; +} + +void sub_80EF120(u16 days) +{ + u8 i; + + for (i = 0; i < 16; i ++) + { + if (gSaveBlock1Ptr->pokeNews[i].kind != POKENEWS_NONE) + { + if (gSaveBlock1Ptr->pokeNews[i].days < days) + { + ClearPokemonNewsI(i); + } + else + { + if (gSaveBlock1Ptr->pokeNews[i].state == 0 && FlagGet(SYS_GAME_CLEAR) == TRUE) + { + gSaveBlock1Ptr->pokeNews[i].state = 1; + } + gSaveBlock1Ptr->pokeNews[i].days -= days; + } + } + } + sub_80EEEB8(); +} + +void CopyContestRankToStringVar(u8 varIdx, u8 rank) +{ + switch (rank) + { + case 0: // NORMAL + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[5]); + break; + case 1: // SUPER + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[6]); + break; + case 2: // HYPER + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[7]); + break; + case 3: // MASTER + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[8]); + break; + } +} + +void CopyContestCategoryToStringVar(u8 varIdx, u8 category) +{ + switch (category) + { + case 0: // COOL + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[0]); + break; + case 1: // BEAUTY + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[1]); + break; + case 2: // CUTE + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[2]); + break; + case 3: // SMART + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[3]); + break; + case 4: // TOUGH + StringCopy(gTVStringVarPtrs[varIdx], gUnknown_0858BAF0[4]); + break; + } +} + +void SetContestCategoryStringVarForInterview(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + CopyContestCategoryToStringVar(1, show->bravoTrainer.contestCategory); +} + +void TV_PrintIntToStringVar(u8 varIdx, int value) +{ + int nDigits; + + nDigits = sub_80EF370(value); + ConvertIntToDecimalStringN(gTVStringVarPtrs[varIdx], value, STR_CONV_MODE_LEFT_ALIGN, nDigits); +} + +size_t sub_80EF370(int value) +{ + if (value / 10 == 0) + { + return 1; + } + if (value / 100 == 0) + { + return 2; + } + if (value / 1000 == 0) + { + return 3; + } + if (value / 10000 == 0) + { + return 4; + } + if (value / 100000 == 0) + { + return 5; + } + if (value / 1000000 == 0) + { + return 6; + } + if (value / 10000000 == 0) + { + return 7; + } + if (value / 100000000 == 0) + { + return 8; + } + return 1; +} + +void sub_80EF40C(u8 varIdx, TVShow *show) +{ + u8 i; + int price; + + price = 0; + for (i = 0; i < 3; i ++) + { + if (show->smartshopperShow.itemIds[i] != ITEM_NONE) + { + price += itemid_get_market_price(show->smartshopperShow.itemIds[i]) * show->smartshopperShow.itemAmounts[i]; + } + } + if (show->smartshopperShow.priceReduced == TRUE) + { + TV_PrintIntToStringVar(varIdx, price >> 1); + } + else + { + TV_PrintIntToStringVar(varIdx, price); + } +} + +bool8 HasMixableShowAlreadyBeenSpawnedWithPlayerID(u8 kind, bool8 flag) +{ + u32 playerId; + TVShow *shows; + u8 i; + + shows = gSaveBlock1Ptr->tvShows; + playerId = GetPlayerIDAsU32(); + for (i = 5; i < 24; i ++) + { + if (shows[i].common.kind == kind && (playerId & 0xFF) == shows[i].common.trainerIdLo && ((playerId >> 8) & 0xFF) == shows[i].common.trainerIdHi) + { + if (flag == TRUE) + { + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, i); + sub_80EF93C(gSaveBlock1Ptr->tvShows); + } + return TRUE; + } + } + return FALSE; +} + +void TV_SortPurchasesByQuantity(void) +{ + u8 i; + u8 j; + u16 tmpId; + u16 tmpQn; + + for (i = 0; i < 2; i ++) + { + for (j = i + 1; j < 3; j ++) + { + if (gUnknown_02039F80[i].quantity < gUnknown_02039F80[j].quantity) + { + tmpId = gUnknown_02039F80[i].itemId; + tmpQn = gUnknown_02039F80[i].quantity; + gUnknown_02039F80[i].itemId = gUnknown_02039F80[j].itemId; + gUnknown_02039F80[i].quantity = gUnknown_02039F80[j].quantity; + gUnknown_02039F80[j].itemId = tmpId; + gUnknown_02039F80[j].quantity = tmpQn; + } + } + } +} + +void FindActiveBroadcastByShowType_SetScriptResult(u8 kind) +{ + u8 i; + for (i = 0; i < 5; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind == kind) + { + if (gSaveBlock1Ptr->tvShows[i].common.active == TRUE) + { + gScriptResult = TRUE; + } + else + { + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, i); + sub_80EF93C(gSaveBlock1Ptr->tvShows); + sub_80EFA88(); + } + return; + } + } + sub_80EFA88(); +} + +void InterviewBefore(void) +{ + gScriptResult = FALSE; + switch (gSpecialVar_0x8005) + { + case TVSHOW_FAN_CLUB_LETTER: + InterviewBefore_FanClubLetter(); + break; + case TVSHOW_RECENT_HAPPENINGS: + InterviewBefore_RecentHappenings(); + break; + case TVSHOW_PKMN_FAN_CLUB_OPINIONS: + InterviewBefore_PkmnFanClubOpinions(); + break; + case TVSHOW_UNKN_SHOWTYPE_04: + InterviewBefore_Dummy(); + break; + case TVSHOW_NAME_RATER_SHOW: + InterviewBefore_NameRater(); + break; + case TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE: + InterviewBefore_BravoTrainerPkmnProfile(); + break; + case TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE: + InterviewBefore_BravoTrainerBTProfile(); + break; + case TVSHOW_CONTEST_LIVE_UPDATES: + InterviewBefore_ContestLiveUpdates(); + break; + case TVSHOW_3_CHEERS_FOR_POKEBLOCKS: + InterviewBefore_3CheersForPokeblocks(); + break; + case TVSHOW_FAN_CLUB_SPECIAL: + InterviewBefore_FanClubSpecial(); + break; + } +} + +void InterviewBefore_FanClubLetter(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_FAN_CLUB_LETTER); + if (!gScriptResult) + { + StringCopy(gStringVar1, gSpeciesNames[GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL)]); + InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].fanclubLetter.words, 6); + } +} + +void InterviewBefore_RecentHappenings(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_RECENT_HAPPENINGS); + if (!gScriptResult) + { + InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].recentHappenings.words, 6); + } +} + +void InterviewBefore_PkmnFanClubOpinions(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_PKMN_FAN_CLUB_OPINIONS); + if (!gScriptResult) + { + 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); + } +} + +void InterviewBefore_Dummy(void) +{ + gScriptResult = TRUE; +} + +void InterviewBefore_NameRater(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_NAME_RATER_SHOW); +} + +void InterviewBefore_BravoTrainerPkmnProfile(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE); + if (!gScriptResult) + { + InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].bravoTrainer.words, 2); + } +} + +void InterviewBefore_ContestLiveUpdates(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_CONTEST_LIVE_UPDATES); +} + +void InterviewBefore_3CheersForPokeblocks(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_3_CHEERS_FOR_POKEBLOCKS); +} + +void InterviewBefore_BravoTrainerBTProfile(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE); + if (!gScriptResult) + { + InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].bravoTrainerTower.words, 1); + } +} + +void InterviewBefore_FanClubSpecial(void) +{ + FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_FAN_CLUB_SPECIAL); + if (!gScriptResult) + { + InitializeEasyChatWordArray(gSaveBlock1Ptr->tvShows[sCurTVShowSlot].fanClubSpecial.words, 1); + } +} + +bool8 sub_80EF88C(u8 monIdx) +{ + struct Pokemon *pokemon; + u8 language; + + pokemon = &gPlayerParty[monIdx]; + GetMonData(pokemon, MON_DATA_NICKNAME, gStringVar1); + language = GetMonData(pokemon, MON_DATA_LANGUAGE, &language); + if (language == LANGUAGE_ENGLISH && !StringCompare(gSpeciesNames[GetMonData(pokemon, MON_DATA_SPECIES, NULL)], gStringVar1)) + { + return FALSE; + } + return TRUE; +} + +bool8 sub_80EF8F8(void) +{ + return sub_80EF88C(GetLeadMonIndex()); +} + +void DeleteTVShowInArrayByIdx(TVShow *shows, u8 idx) +{ + u8 i; + + shows[idx].common.kind = TVSHOW_OFF_AIR; + shows[idx].common.active = FALSE; + for (i = 0; i < 34; i ++) + { + shows[idx].common.pad02[i] = 0; + } +} + +void sub_80EF93C(TVShow *shows) +{ + u8 i; + u8 j; + + for (i = 0; i < 4; i ++) + { + if (shows[i].common.kind == TVSHOW_OFF_AIR) + { + for (j = i + 1; j < 5; j ++) + { + if (shows[j].common.kind != TVSHOW_OFF_AIR) + { + shows[i] = shows[j]; + DeleteTVShowInArrayByIdx(shows, j); + break; + } + } + } + } + for (i = 5; i < 24; i ++) + { + if (shows[i].common.kind == TVSHOW_OFF_AIR) + { + for (j = i + 1; j < 24; j ++) + { + if (shows[j].common.kind != TVSHOW_OFF_AIR) + { + shows[i] = shows[j]; + DeleteTVShowInArrayByIdx(shows, j); + break; + } + } + } + } +} + +u16 TV_GetSomeOtherSpeciesAlreadySeenByPlayer_AndPrintName(u8 varIdx, u16 passedSpecies) +{ + u16 species; + + species = TV_GetSomeOtherSpeciesAlreadySeenByPlayer(passedSpecies); + StringCopy(gTVStringVarPtrs[varIdx], gSpeciesNames[species]); + return species; +} + +u16 TV_GetSomeOtherSpeciesAlreadySeenByPlayer(u16 passedSpecies) +{ + u16 species; + u16 initSpecies; + + species = (Random() % (NUM_SPECIES - 1)) + 1; + initSpecies = species; + while (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), 0) != 1 || species == passedSpecies) + { + if (species == 1) + { + species = NUM_SPECIES - 1; + } + else + { + species --; + } + if (species == initSpecies) + { + species = passedSpecies; + return species; + } + }; + return species; +} + +void sub_80EFA88(void) +{ + sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows); + gSpecialVar_0x8006 = sCurTVShowSlot; + if (sCurTVShowSlot == -1) + { + gScriptResult = TRUE; + } + else + { + gScriptResult = FALSE; + } +} + +s8 FindEmptyTVSlotWithinFirstFiveShowsOfArray(TVShow *shows) +{ + u8 i; + + for (i = 0; i < 5; i ++) + { + if (shows[i].common.kind == TVSHOW_OFF_AIR) + { + return i; + } + } + return -1; +} + +s8 FindEmptyTVSlotBeyondFirstFiveShowsOfArray(TVShow *shows) +{ + s8 i; + + for (i = 5; i < 24; i ++) + { + if (shows[i].common.kind == TVSHOW_OFF_AIR) + { + return i; + } + } + return -1; +} + +bool8 TV_BernoulliTrial(u16 ratio) +{ + if (Random() <= ratio) + { + return FALSE; + } + return TRUE; +} + +void TV_FanClubLetter_RandomWordToStringVar3(TVShow *show) +{ + u8 i; + + i = Random() % 6; + while (TRUE) + { + if (i == 6) + { + i = 0; + } + if (show->fanclubLetter.words[i] != 0xFFFF) + { + break; + } + i ++; + } + CopyEasyChatWord(gStringVar3, show->fanclubLetter.words[i]); +} + +u8 TV_GetNicknameSumMod8(TVShow *show) +{ + u8 i; + u16 ct; + + ct = 0; + for (i = 0; i < 11; i ++) + { + if (show->nameRaterShow.pokemonName[i] == EOS) + { + break; + } + ct += show->nameRaterShow.pokemonName[i]; + } + return ct & 7; +} + +void TV_GetNicknameSubstring(u8 varIdx, u8 whichPosition, u8 charParam, u16 whichString, u16 species, TVShow *show) +{ + u8 buff[16]; + u8 i; + u16 strlen; + + for (i = 0; i < 3; i ++) + { + buff[i] = EOS; + } + if (whichString == 0) + { + strlen = StringLength(show->nameRaterShow.trainerName); + if (charParam == 0) + { + buff[0] = show->nameRaterShow.trainerName[whichPosition]; + } + else if (charParam == 1) + { + buff[0] = show->nameRaterShow.trainerName[strlen - whichPosition]; + } + else if (charParam == 2) + { + buff[0] = show->nameRaterShow.trainerName[whichPosition]; + buff[1] = show->nameRaterShow.trainerName[whichPosition + 1]; + } + else + { + buff[0] = show->nameRaterShow.trainerName[strlen - (whichPosition + 2)]; + buff[1] = show->nameRaterShow.trainerName[strlen - (whichPosition + 1)]; + } + ConvertInternationalString(buff, show->nameRaterShow.language); + } + else if (whichString == 1) + { + strlen = StringLength(show->nameRaterShow.pokemonName); + if (charParam == 0) + { + buff[0] = show->nameRaterShow.pokemonName[whichPosition]; + } + else if (charParam == 1) + { + buff[0] = show->nameRaterShow.pokemonName[strlen - whichPosition]; + } + else if (charParam == 2) + { + buff[0] = show->nameRaterShow.pokemonName[whichPosition]; + buff[1] = show->nameRaterShow.pokemonName[whichPosition + 1]; + } + else + { + buff[0] = show->nameRaterShow.pokemonName[strlen - (whichPosition + 2)]; + buff[1] = show->nameRaterShow.pokemonName[strlen - (whichPosition + 1)]; + } + ConvertInternationalString(buff, show->nameRaterShow.pokemonNameLanguage); + } + else + { + strlen = StringLength(gSpeciesNames[species]); + if (charParam == 0) + { + buff[0] = gSpeciesNames[species][whichPosition]; + } + else if (charParam == 1) + { + buff[0] = gSpeciesNames[species][strlen - whichPosition]; + } + else if (charParam == 2) + { + buff[0] = gSpeciesNames[species][whichPosition]; + buff[1] = gSpeciesNames[species][whichPosition + 1]; + } + else + { + buff[0] = gSpeciesNames[species][strlen - (whichPosition + 2)]; + buff[1] = gSpeciesNames[species][strlen - (whichPosition + 1)]; + } + } + StringCopy(gTVStringVarPtrs[varIdx], buff); +} + +bool8 TV_IsScriptShowKindAlreadyInQueue(void) +{ + u8 i; + + for (i = 0; i < 5; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind == gSpecialVar_0x8004) + { + return TRUE; + } + } + return FALSE; +} + +bool8 TV_PutNameRaterShowOnTheAirIfNicnkameChanged(void) +{ + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar1); + if (!StringCompare(gStringVar3, gStringVar1)) + { + return FALSE; + } + PutNameRaterShowOnTheAir(); + return TRUE; +} + +void ChangePokemonNickname(void) +{ + void ChangePokemonNickname_CB(void); + + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar3); + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar2); + DoNamingScreen(3, gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPECIES, NULL), GetMonGender(&gPlayerParty[gSpecialVar_0x8004]), GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_PERSONALITY, NULL), ChangePokemonNickname_CB); +} + +void ChangePokemonNickname_CB(void) +{ + SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar2); + c2_exit_to_overworld_1_continue_scripts_restart_music(); +} + +void ChangeBoxPokemonNickname(void) +{ + struct BoxPokemon *boxMon; + + boxMon = GetBoxedMonPtr(gSpecialVar_0x8012, gSpecialVar_0x8013); + GetBoxMonData(boxMon, MON_DATA_NICKNAME, gStringVar3); + GetBoxMonData(boxMon, MON_DATA_NICKNAME, gStringVar2); + DoNamingScreen(3, gStringVar2, GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL), GetBoxMonGender(boxMon), GetBoxMonData(boxMon, MON_DATA_PERSONALITY, NULL), ChangeBoxPokemonNickname_CB); +} + +void ChangeBoxPokemonNickname_CB(void) +{ + SetBoxMonNickFromAnyBox(gSpecialVar_0x8012, gSpecialVar_0x8013, gStringVar2); + c2_exit_to_overworld_1_continue_scripts_restart_music(); +} + +void TV_CopyNicknameToStringVar1AndEnsureTerminated(void) +{ + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar1); + StringGetEnd10(gStringVar1); +} + +void TV_CheckMonOTIDEqualsPlayerID(void) +{ + if (GetPlayerIDAsU32() == GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_OT_ID, NULL)) + { + gScriptResult = FALSE; + } + else + { + gScriptResult = TRUE; + } +} + +u8 GetTVChannelByShowType(u8 kind) +{ + if (kind == TVSHOW_OFF_AIR) + { + return 0; + } + if (kind >= TVSHOW_FAN_CLUB_LETTER && kind < TVSHOW_POKEMON_TODAY_CAUGHT) + { + return 2; + } + if (kind >= TVSHOW_POKEMON_TODAY_CAUGHT && kind < TVSHOW_MASS_OUTBREAK) + { + return 3; + } + if (kind >= TVSHOW_MASS_OUTBREAK && kind < 61) + { + return 4; + } + return 0; +} + +u32 GetPlayerIDAsU32(void) +{ + return (gSaveBlock2Ptr->playerTrainerId[3] << 24) | (gSaveBlock2Ptr->playerTrainerId[2] << 16) | (gSaveBlock2Ptr->playerTrainerId[1] << 8) | gSaveBlock2Ptr->playerTrainerId[0]; +} + +u8 CheckForBigMovieOrEmergencyNewsOnTV(void) +{ + if (gSaveBlock1Ptr->location.mapGroup != MAP_GROUP_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F) + { + return 0; + } + if (gSaveBlock2Ptr->playerGender == MALE) + { + if (gSaveBlock1Ptr->location.mapNum != MAP_ID_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F) + { + return 0; + } + } + else + { + if (gSaveBlock1Ptr->location.mapNum != MAP_ID_LITTLEROOT_TOWN_MAYS_HOUSE_1F) + { + return 0; + } + } + if (FlagGet(SYS_TV_LATI) == TRUE) + { + return 1; + } + if (FlagGet(SYS_TV_HOME) == TRUE) + { + return 2; + } + return 1; +} + +void GetMomOrDadStringForTVMessage(void) +{ + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F) + { + if (gSaveBlock2Ptr->playerGender == MALE) + { + if (gSaveBlock1Ptr->location.mapNum == MAP_ID_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F) + { + StringCopy(gStringVar1, gText_Mom); + VarSet(VAR_0x4003, 1); + } + } + else + { + if (gSaveBlock1Ptr->location.mapNum == MAP_ID_LITTLEROOT_TOWN_MAYS_HOUSE_1F) + { + StringCopy(gStringVar1, gText_Mom); + VarSet(VAR_0x4003, 1); + } + } + } + if (VarGet(VAR_0x4003) == 1) + { + StringCopy(gStringVar1, gText_Mom); + } + else if (VarGet(VAR_0x4003) == 2) + { + StringCopy(gStringVar1, gText_Dad); + } + else if (VarGet(VAR_0x4003) > 2) + { + if (VarGet(VAR_0x4003) % 2 == 0) + StringCopy(gStringVar1, gText_Mom); + else + StringCopy(gStringVar1, gText_Dad); + } + else + { + if (Random() % 2 != 0) + { + StringCopy(gStringVar1, gText_Mom); + VarSet(VAR_0x4003, 1); + } + else + { + StringCopy(gStringVar1, gText_Dad); + VarSet(VAR_0x4003, 2); + } + } +} + +void sub_80F01B8(void) +{ + VarSet(VAR_0x40BC, 0); + RemoveFieldObjectByLocalIdAndMap(5, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + FlagSet(0x396); +} + +void sub_80F01E8(void *src, u32 size, u8 masterIdx) +{ + u8 i; + u16 version; + TVShow (*rmBuffer2)[4][25]; + TVShow (*rmBuffer)[4][25]; + + rmBuffer2 = malloc(4 * 25 * sizeof(TVShow)); + if (rmBuffer2 != NULL) + { + for (i = 0; i < 4; i ++) + { + memcpy((*rmBuffer2)[i], src + i * size, sizeof((*rmBuffer2)[i])); + } + rmBuffer = rmBuffer2; + for (i = 0; i < GetLinkPlayerCount(); i ++) + { + version = (u8)gLinkPlayers[i].version; + if (version == VERSION_RUBY || version == VERSION_SAPPHIRE) + { + sub_80F1254((*rmBuffer)[i]); + } + else if (version == VERSION_EMERALD && gLinkPlayers[i].language == LANGUAGE_JAPANESE) + { + sub_80F12A4((*rmBuffer)[i]); + } + } + switch (masterIdx) + { + case 0: + sub_80F0358(gSaveBlock1Ptr->tvShows, (*rmBuffer)[1], (*rmBuffer)[2], (*rmBuffer)[3]); + break; + case 1: + sub_80F0358((*rmBuffer)[0], gSaveBlock1Ptr->tvShows, (*rmBuffer)[2], (*rmBuffer)[3]); + break; + case 2: + sub_80F0358((*rmBuffer)[0], (*rmBuffer)[1], gSaveBlock1Ptr->tvShows, (*rmBuffer)[3]); + break; + case 3: + sub_80F0358((*rmBuffer)[0], (*rmBuffer)[1], (*rmBuffer)[2], gSaveBlock1Ptr->tvShows); + break; + } + sub_80EF93C(gSaveBlock1Ptr->tvShows); + sub_80F0C04(); + sub_80EF93C(gSaveBlock1Ptr->tvShows); + sub_80F0708(); + sub_80F0B64(); + free(rmBuffer2); + } +} + +void sub_80F0358(TVShow player1[25], TVShow player2[25], TVShow player3[25], TVShow player4[25]) +{ + u8 i; + u8 j; + TVShow **argslist[4]; + + argslist[0] = &player1; + argslist[1] = &player2; + argslist[2] = &player3; + argslist[3] = &player4; + sTVShowMixingNumPlayers = GetLinkPlayerCount(); + while (1) + { + for (i = 0; i < sTVShowMixingNumPlayers; i ++) + { + if (i == 0) + { + sRecordMixingPartnersWithoutShowsToShare = i; + } + sTVShowMixingCurSlot = sub_80F06D0(argslist[i][0]); + if (sTVShowMixingCurSlot == -1) + { + sRecordMixingPartnersWithoutShowsToShare ++; + if (sRecordMixingPartnersWithoutShowsToShare == sTVShowMixingNumPlayers) + { + return; + } + } + else + { + for (j = 0; j < sTVShowMixingNumPlayers - 1; j ++) + { + sCurTVShowSlot = FindEmptyTVSlotBeyondFirstFiveShowsOfArray(argslist[(i + j + 1) % sTVShowMixingNumPlayers][0]); + if (sCurTVShowSlot != -1 + && sub_80F049C(&argslist[(i + j + 1) % sTVShowMixingNumPlayers][0], &argslist[i][0], (i + j + 1) % sTVShowMixingNumPlayers) == 1) + { + break; + } + } + if (j == sTVShowMixingNumPlayers - 1) + { + DeleteTVShowInArrayByIdx(argslist[i][0], sTVShowMixingCurSlot); + } + } + } + } +} + +bool8 sub_80F049C(TVShow *dest[25], TVShow *src[25], u8 idx) +{ + u8 value; + u8 switchval; + TVShow *tv1; + TVShow *tv2; + + tv1 = *dest; + tv2 = *src; + value = FALSE; + switchval = GetTVChannelByShowType(tv2[sTVShowMixingCurSlot].common.kind); + switch (switchval) + { + case 2: + value = sub_80F0580(&tv1[sCurTVShowSlot], &tv2[sTVShowMixingCurSlot], idx); + break; + case 3: + value = sub_80F05E8(&tv1[sCurTVShowSlot], &tv2[sTVShowMixingCurSlot], idx); + break; + case 4: + value = sub_80F0668(&tv1[sCurTVShowSlot], &tv2[sTVShowMixingCurSlot], idx); + break; + } + if (value == TRUE) + { + DeleteTVShowInArrayByIdx(tv2, sTVShowMixingCurSlot); + return TRUE; + } + return FALSE; +} + +u8 sub_80F0580(TVShow *tv1, TVShow *tv2, u8 idx) +{ + u32 linkTrainerId = GetLinkPlayerTrainerId(idx); + + if ((linkTrainerId & 0xFF) == tv2->common.trainerIdLo && ((linkTrainerId >> 8) & 0xFF) == tv2->common.trainerIdHi) + { + return FALSE; + } + tv2->common.trainerIdLo = tv2->common.srcTrainerIdLo; + tv2->common.trainerIdHi = tv2->common.srcTrainerIdHi; + tv2->common.srcTrainerIdLo = linkTrainerId & 0xFF; + tv2->common.srcTrainerIdHi = linkTrainerId >> 8; + *tv1 = *tv2; + tv1->common.active = TRUE; + return TRUE; +} + +u8 sub_80F05E8(TVShow *tv1, TVShow *tv2, u8 idx) +{ + u32 linkTrainerId = GetLinkPlayerTrainerId(idx); + if ((linkTrainerId & 0xFF) == tv2->common.srcTrainerIdLo && ((linkTrainerId >> 8) & 0xFF) == tv2->common.srcTrainerIdHi) + { + return FALSE; + } + if ((linkTrainerId & 0xFF) == tv2->common.trainerIdLo && ((linkTrainerId >> 8) & 0xFF) == tv2->common.trainerIdHi) + { + return FALSE; + } + tv2->common.srcTrainerIdLo = tv2->common.srcTrainerId2Lo; + tv2->common.srcTrainerIdHi = tv2->common.srcTrainerId2Hi; + tv2->common.srcTrainerId2Lo = linkTrainerId & 0xFF; + tv2->common.srcTrainerId2Hi = linkTrainerId >> 8; + *tv1 = *tv2; + tv1->common.active = TRUE; + return TRUE; +} + +u8 sub_80F0668(TVShow *tv1, TVShow *tv2, u8 idx) +{ + u32 linkTrainerId = GetLinkPlayerTrainerId(idx); + if ((linkTrainerId & 0xFF) == tv2->common.trainerIdLo && ((linkTrainerId >> 8) & 0xFF) == tv2->common.trainerIdHi) + { + return FALSE; + } + tv2->common.trainerIdLo = tv2->common.srcTrainerIdLo; + tv2->common.trainerIdHi = tv2->common.srcTrainerIdHi; + tv2->common.srcTrainerIdLo = linkTrainerId & 0xFF; + tv2->common.srcTrainerIdHi = linkTrainerId >> 8; + *tv1 = *tv2; + tv1->common.active = TRUE; + tv1->massOutbreak.daysLeft = 1; + return TRUE; +} + +s8 sub_80F06D0(TVShow *tvShows) +{ + u8 i; + + for (i = 0; i < 24; i ++) + { + if (tvShows[i].common.active == FALSE && (u8)(tvShows[i].common.kind - 1) < 60) + { + return i; + } + } + return -1; +} + +#ifdef NONMATCHING +void sub_80F0708(void) // FIXME: register allocation shenanigans +{ + u16 i; + TVShow *show; + + for (i = 0; i < 24; i ++) + { + switch (gSaveBlock1Ptr->tvShows[i].common.kind) + { + case TVSHOW_CONTEST_LIVE_UPDATES: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->contestLiveUpdates.species, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->contestLiveUpdates.winningSpecies, i); + break; + case TVSHOW_3_CHEERS_FOR_POKEBLOCKS: + break; + case TVSHOW_BATTLE_UPDATE: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->battleUpdate.species2, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->battleUpdate.species, i); + break; + case TVSHOW_FAN_CLUB_SPECIAL: + break; + case TVSHOW_CONTEST_LIVE_UPDATES_2: + break; + + case TVSHOW_OFF_AIR: + break; + case TVSHOW_FAN_CLUB_LETTER: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->fanclubLetter.species, i); + break; + case TVSHOW_RECENT_HAPPENINGS: + break; + case TVSHOW_PKMN_FAN_CLUB_OPINIONS: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->fanclubOpinions.species, i); + break; + case TVSHOW_UNKN_SHOWTYPE_04: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->unkShow04.var06, i); + break; + case TVSHOW_NAME_RATER_SHOW: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->nameRaterShow.species, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->nameRaterShow.randomSpecies, i); + break; + case TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->bravoTrainer.species, i); + break; + case TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->bravoTrainerTower.species, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->bravoTrainerTower.defeatedSpecies, i); + break; + + case TVSHOW_POKEMON_TODAY_CAUGHT: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->pokemonToday.species, i); + break; + case TVSHOW_SMART_SHOPPER: + break; + case TVSHOW_POKEMON_TODAY_FAILED: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->pokemonTodayFailed.species, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->pokemonTodayFailed.species2, i); + break; + case TVSHOW_FISHING_ADVICE: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->pokemonAngler.species, i); + break; + case TVSHOW_WORLD_OF_MASTERS: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->worldOfMasters.species, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->worldOfMasters.caughtPoke, i); + break; + + case TVSHOW_TODAYS_RIVAL_TRAINER: + break; + case TVSHOW_TREND_WATCHER: + break; + case TVSHOW_TREASURE_INVESTIGATORS: + break; + case TVSHOW_FIND_THAT_GAMER: + break; + case TVSHOW_BREAKING_NEWS: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->breakingNews.lastOpponentSpecies, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->breakingNews.poke1Species, i); + break; + case TVSHOW_SECRET_BASE_VISIT: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->secretBaseVisit.species, i); + break; + case TVSHOW_LOTTO_WINNER: + break; + case TVSHOW_BATTLE_SEMINAR: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->battleSeminar.species, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->battleSeminar.foeSpecies, i); + break; + case TVSHOW_TRAINER_FAN_CLUB: + break; + case TVSHOW_CUTIES: + break; + case TVSHOW_FRONTIER: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->frontier.species1, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->frontier.species2, i); + switch ((&gSaveBlock1Ptr->tvShows[i])->frontier.facility) + { + case 3: + case 4: + break; + case 1: + case 5 ... 13: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->frontier.species3, i); + break; + case 2: + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->frontier.species3, i); + sub_80F0B24((&gSaveBlock1Ptr->tvShows[i])->frontier.species4, i); + break; + } + break; + case TVSHOW_NUMBER_ONE: + break; + case TVSHOW_SECRET_BASE_SECRETS: + break; + case TVSHOW_SAFARI_FAN_CLUB: + break; + + case TVSHOW_MASS_OUTBREAK: + break; + + default: + sub_80F0B00(i); + break; + } + } +} +#else +__attribute__((naked)) void sub_80F0708(void) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmov r7, r9\n" + "\tmov r6, r8\n" + "\tpush {r6,r7}\n" + "\tsub sp, 0x8\n" + "\tmovs r0, 0\n" + "\tmov r9, r0\n" + "_080F0716:\n" + "\tldr r3, =gSaveBlock1Ptr\n" + "\tldr r1, [r3]\n" + "\tmov r4, r9\n" + "\tlsls r2, r4, 3\n" + "\tadds r0, r2, r4\n" + "\tlsls r0, 2\n" + "\tadds r1, r0\n" + "\tldr r0, =0x000027cc\n" + "\tadds r1, r0\n" + "\tldrb r0, [r1]\n" + "\tadds r7, r2, 0\n" + "\tcmp r0, 0x29\n" + "\tbls _080F0732\n" + "\tb _080F0AD8\n" + "_080F0732:\n" + "\tlsls r0, 2\n" + "\tldr r1, =_080F0748\n" + "\tadds r0, r1\n" + "\tldr r0, [r0]\n" + "\tmov pc, r0\n" + "\t.pool\n" + "\t.align 2, 0\n" + "_080F0748:\n" + "\t.4byte _080F0AE2_break @ TVSHOW_OFF_AIR\n" + "\t.4byte _080F0848 @ TVSHOW_FAN_CLUB_LETTER\n" + "\t.4byte _080F0AE2_break @ TVSHOW_RECENT_HAPPENINGS\n" + "\t.4byte _080F0860 @ TVSHOW_PKMN_FAN_CLUB_OPINIONS\n" + "\t.4byte _080F0878 @ TVSHOW_UNKN_SHOWTYPE_04\n" + "\t.4byte _080F0890 @ TVSHOW_NAME_RATER_SHOW\n" + "\t.4byte _080F08BC @ TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE\n" + "\t.4byte _080F08D4 @ TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE\n" + "\t.4byte _080F07F0 @ TVSHOW_CONTEST_LIVE_UPDATES\n" + "\t.4byte _080F0AE2_break @ TVSHOW_3_CHEERS_FOR_POKEBLOCKS\n" + "\t.4byte _080F081C @ TVSHOW_BATTLE_UPDATE\n" + "\t.4byte _080F0AE2_break @ TVSHOW_FAN_CLUB_SPECIAL\n" + "\t.4byte _080F0AE2_break @ TVSHOW_CONTEST_LIVE_UPDATES_2\n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0900 @ TVSHOW_POKEMON_TODAY_CAUGHT\n" + "\t.4byte _080F0AE2_break @ TVSHOW_SMART_SHOPPER\n" + "\t.4byte _080F0918 @ TVSHOW_POKEMON_TODAY_FAILED\n" + "\t.4byte _080F0944 @ TVSHOW_FISHING_ADVICE\n" + "\t.4byte _080F095C @ TVSHOW_WORLD_OF_MASTERS\n" + "\t.4byte _080F0AE2_break @ TVSHOW_TODAYS_RIVAL_TRAINER\n" + "\t.4byte _080F0AE2_break @ TVSHOW_TREND_WATCHER\n" + "\t.4byte _080F0AE2_break @ TVSHOW_TREASURE_INVESTIGATORS\n" + "\t.4byte _080F0AE2_break @ TVSHOW_FIND_THAT_GAMER\n" + "\t.4byte _080F0974 @ TVSHOW_BREAKING_NEWS\n" + "\t.4byte _080F09A0 @ TVSHOW_SECRET_BASE_VISIT\n" + "\t.4byte _080F0AE2_break @ TVSHOW_LOTTO_WINNER\n" + "\t.4byte _080F09C0 @ TVSHOW_BATTLE_SEMINAR\n" + "\t.4byte _080F0AE2_break @ TVSHOW_TRAINER_FAN_CLUB\n" + "\t.4byte _080F0AE2_break @ TVSHOW_CUTIES\n" + "\t.4byte _080F09F4 @ TVSHOW_FRONTIER\n" + "\t.4byte _080F0AE2_break @ TVSHOW_NUMBER_ONE\n" + "\t.4byte _080F0AE2_break @ TVSHOW_SECRET_BASE_SECRETS\n" + "\t.4byte _080F0AE2_break @ TVSHOW_SAFARI_FAN_CLUB\n" + "\t.4byte _080F0AD8 @ \n" + "\t.4byte _080F0AE2_break @ TVSHOW_MASS_OUTBREAK\n" + "_080F07F0:\n" + "\tldr r0, [r3]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0x12]\n" + "\tlsls r5, r1, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0x2]\n" + "\tb _080F09E6\n" + "\t.pool\n" + "_080F081C:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r4, r7, r2\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0x16]\n" + "\tlsls r5, r2, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0x2]\n" + "\tb _080F09E6\n" + "\t.pool\n" + "_080F0848:\n" + "\tldr r0, [r3]\n" + "\tmov r4, r9\n" + "\tadds r1, r7, r4\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r0, =0x000027cc\n" + "\tadds r1, r0\n" + "\tldrh r0, [r1, 0x2]\n" + "\tb _080F09B0\n" + "\t.pool\n" + "_080F0860:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r1, r7, r2\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r4, =0x000027cc\n" + "\tadds r1, r4\n" + "\tldrh r0, [r1, 0x2]\n" + "\tlsls r1, r2, 24\n" + "\tb _080F09B2\n" + "\t.pool\n" + "_080F0878:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r1, r7, r2\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r4, =0x000027cc\n" + "\tadds r1, r4\n" + "\tldrh r0, [r1, 0x6]\n" + "\tlsls r1, r2, 24\n" + "\tb _080F09B2\n" + "\t.pool\n" + "_080F0890:\n" + "\tldr r0, [r3]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0x2]\n" + "\tlsls r5, r1, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0x1C]\n" + "\tb _080F09E6\n" + "\t.pool\n" + "_080F08BC:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r1, r7, r2\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r4, =0x000027cc\n" + "\tadds r1, r4\n" + "\tldrh r0, [r1, 0x2]\n" + "\tlsls r1, r2, 24\n" + "\tb _080F09B2\n" + "\t.pool\n" + "_080F08D4:\n" + "\tldr r0, [r3]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0xA]\n" + "\tlsls r5, r1, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0x14]\n" + "\tb _080F09E6\n" + "\t.pool\n" + "_080F0900:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r1, r7, r2\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r4, =0x000027cc\n" + "\tadds r1, r4\n" + "\tldrh r0, [r1, 0x10]\n" + "\tlsls r1, r2, 24\n" + "\tb _080F09B2\n" + "\t.pool\n" + "_080F0918:\n" + "\tldr r0, [r3]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0xC]\n" + "\tlsls r5, r1, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0xE]\n" + "\tb _080F09E6\n" + "\t.pool\n" + "_080F0944:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r1, r7, r2\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r4, =0x000027cc\n" + "\tadds r1, r4\n" + "\tldrh r0, [r1, 0x4]\n" + "\tlsls r1, r2, 24\n" + "\tb _080F09B2\n" + "\t.pool\n" + "_080F095C:\n" + "\tldr r0, [r3]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0x8]\n" + "\tb _080F09D0\n" + "\t.pool\n" + "_080F0974:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r4, r7, r2\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0x2]\n" + "\tlsls r5, r2, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0xA]\n" + "\tb _080F09E6\n" + "\t.pool\n" + "_080F09A0:\n" + "\tldr r0, [r3]\n" + "\tmov r4, r9\n" + "\tadds r1, r7, r4\n" + "\tlsls r1, 2\n" + "\tadds r1, r0\n" + "\tldr r0, =0x000027cc\n" + "\tadds r1, r0\n" + "\tldrh r0, [r1, 0x8]\n" + "_080F09B0:\n" + "\tlsls r1, r4, 24\n" + "_080F09B2:\n" + "\tlsrs r1, 24\n" + "\tbl sub_80F0B24\n" + "\tb _080F0AE2_break\n" + "\t.pool\n" + "_080F09C0:\n" + "\tldr r0, [r3]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r6, =0x000027cc\n" + "\tadds r0, r6\n" + "\tldrh r0, [r0, 0x6]\n" + "_080F09D0:\n" + "\tlsls r5, r1, 24\n" + "\tlsrs r5, 24\n" + "\tadds r1, r5, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r6\n" + "\tldrh r0, [r4, 0x4]\n" + "_080F09E6:\n" + "\tadds r1, r5, 0\n" + "\tbl sub_80F0B24\n" + "\tb _080F0AE2_break\n" + "\t.pool\n" + "_080F09F4:\n" + "\tldr r0, [r3]\n" + "\tmov r2, r9\n" + "\tadds r4, r7, r2\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r5, =0x000027cc\n" + "\tadds r0, r5\n" + "\tldrh r0, [r0, 0x4]\n" + "\tlsls r2, 24\n" + "\tmov r8, r2\n" + "\tlsrs r6, r2, 24\n" + "\tadds r1, r6, 0\n" + "\tstr r3, [sp, 0x4]\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r0, r4, r0\n" + "\tadds r0, r5\n" + "\tldrh r0, [r0, 0x6]\n" + "\tadds r1, r6, 0\n" + "\tbl sub_80F0B24\n" + "\tldr r3, [sp, 0x4]\n" + "\tldr r0, [r3]\n" + "\tadds r4, r0\n" + "\tadds r4, r5\n" + "\tldrb r0, [r4, 0xD]\n" + "\tsubs r0, 0x1\n" + "\tmov r6, r8\n" + "\tcmp r0, 0xC\n" + "\tbhi _080F0AE2_break\n" + "\tlsls r0, 2\n" + "\tldr r1, =_080F0A48\n" + "\tadds r0, r1\n" + "\tldr r0, [r0]\n" + "\tmov pc, r0\n" + "\t.pool\n" + "\t.align 2, 0\n" + "_080F0A48:\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0AA0\n" + "\t.4byte _080F0AE2_break\n" + "\t.4byte _080F0AE2_break\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "\t.4byte _080F0A7C\n" + "_080F0A7C:\n" + "\tldr r0, =gSaveBlock1Ptr\n" + "\tldr r1, [r0]\n" + "\tmov r4, r9\n" + "\tadds r0, r7, r4\n" + "\tlsls r0, 2\n" + "\tadds r0, r1\n" + "\tldr r1, =0x000027cc\n" + "\tadds r0, r1\n" + "\tldrh r0, [r0, 0x8]\n" + "\tlsrs r1, r6, 24\n" + "\tbl sub_80F0B24\n" + "\tb _080F0AE2_break\n" + "\t.pool\n" + "_080F0AA0:\n" + "\tldr r2, =gSaveBlock1Ptr\n" + "\tldr r0, [r2]\n" + "\tmov r1, r9\n" + "\tadds r4, r7, r1\n" + "\tlsls r4, 2\n" + "\tadds r0, r4, r0\n" + "\tldr r5, =0x000027cc\n" + "\tadds r0, r5\n" + "\tldrh r0, [r0, 0x8]\n" + "\tlsrs r6, 24\n" + "\tadds r1, r6, 0\n" + "\tstr r2, [sp]\n" + "\tbl sub_80F0B24\n" + "\tldr r2, [sp]\n" + "\tldr r0, [r2]\n" + "\tadds r4, r0\n" + "\tadds r4, r5\n" + "\tldrh r0, [r4, 0xA]\n" + "\tadds r1, r6, 0\n" + "\tbl sub_80F0B24\n" + "\tb _080F0AE2_break\n" + "\t.pool\n" + "_080F0AD8:\n" + "\tmov r2, r9\n" + "\tlsls r0, r2, 24\n" + "\tlsrs r0, 24\n" + "\tbl sub_80F0B00\n" + "_080F0AE2_break:\n" + "\tmov r0, r9\n" + "\tadds r0, 0x1\n" + "\tlsls r0, 16\n" + "\tlsrs r0, 16\n" + "\tmov r9, r0\n" + "\tcmp r0, 0x17\n" + "\tbhi _080F0AF2\n" + "\tb _080F0716\n" + "_080F0AF2:\n" + "\tadd sp, 0x8\n" + "\tpop {r3,r4}\n" + "\tmov r8, r3\n" + "\tmov r9, r4\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0"); +} +#endif + +void sub_80F0B00(u8 showIdx) +{ + gSaveBlock1Ptr->tvShows[showIdx].common.active = FALSE; +} + +void sub_80F0B24(u16 species, u8 showIdx) +{ + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), 0) == 0) + { + gSaveBlock1Ptr->tvShows[showIdx].common.active = FALSE; + } +} + +void sub_80F0B64(void) +{ + u16 i; + + if (FlagGet(SYS_GAME_CLEAR) != TRUE) + { + for (i = 0; i < 24; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind == TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE) + { + gSaveBlock1Ptr->tvShows[i].common.active = FALSE; + } + else if (gSaveBlock1Ptr->tvShows[i].common.kind == TVSHOW_MASS_OUTBREAK) + { + gSaveBlock1Ptr->tvShows[i].common.active = FALSE; + } + } + } +} + +void sub_80F0BB8(void) +{ + u8 i; + + for (i = 0; i < 5; i ++) + { + if (GetTVChannelByShowType(gSaveBlock1Ptr->tvShows[i].common.kind) == 2) + { + gSaveBlock1Ptr->tvShows[i].common.active = FALSE; + } + } +} + +void sub_80F0C04(void) +{ + s8 i; + s8 ct; + + ct = 0; + for (i = 5; i < 24; i ++) + { + if (gSaveBlock1Ptr->tvShows[i].common.kind == TVSHOW_OFF_AIR) + { + ct ++; + } + } + for (i = 0; i < 5 - ct; i ++) + { + DeleteTVShowInArrayByIdx(gSaveBlock1Ptr->tvShows, i + 5); + } +} + +void sub_80F0C7C(void *src, u32 size, u8 masterIdx) +{ + u8 i; + PokeNews (*rmBuffer2)[4][16]; + PokeNews (*rmBuffer)[4][16]; + + rmBuffer2 = malloc(4 * 16 * sizeof(PokeNews)); + if (rmBuffer2 != NULL) + { + for (i = 0; i < 4; i ++) + { + memcpy((*rmBuffer2)[i], src + i * size, sizeof((*rmBuffer2)[i])); + } + rmBuffer = rmBuffer2; + switch (masterIdx) + { + case 0: + sub_80F0D60(gSaveBlock1Ptr->pokeNews, (*rmBuffer)[1], (*rmBuffer)[2], (*rmBuffer)[3]); + break; + case 1: + sub_80F0D60((*rmBuffer)[0], gSaveBlock1Ptr->pokeNews, (*rmBuffer)[2], (*rmBuffer)[3]); + break; + case 2: + sub_80F0D60((*rmBuffer)[0], (*rmBuffer)[1], gSaveBlock1Ptr->pokeNews, (*rmBuffer)[3]); + break; + case 3: + sub_80F0D60((*rmBuffer)[0], (*rmBuffer)[1], (*rmBuffer)[2], gSaveBlock1Ptr->pokeNews); + break; + } + sub_80F0EEC(); + sub_80F0F24(); + free(rmBuffer2); + } +} + +void sub_80F0D60(PokeNews player1[16], PokeNews player2[16], PokeNews player3[16], PokeNews player4[16]) +{ + u8 i; + u8 j; + u8 k; + PokeNews **argslist[4]; + + argslist[0] = &player1; + argslist[1] = &player2; + argslist[2] = &player3; + argslist[3] = &player4; + sTVShowNewsMixingNumPlayers = GetLinkPlayerCount(); + for (i = 0; i < 16; i ++) + { + for (j = 0; j < sTVShowNewsMixingNumPlayers; j ++) + { + sTVShowMixingCurSlot = sub_80F0ECC(*argslist[j], i); + if (sTVShowMixingCurSlot != -1) + { + for (k = 0; k < sTVShowNewsMixingNumPlayers - 1; k++) + { + sCurTVShowSlot = sub_80EEE30(*argslist[(j + k + 1) % sTVShowNewsMixingNumPlayers]); + if (sCurTVShowSlot != -1) + { + sub_80F0E58(argslist[(j + k + 1) % sTVShowNewsMixingNumPlayers], argslist[j]); + } + } + } + } + } +} + +void sub_80F0E58(PokeNews *dest[16], PokeNews *src[16]) +{ + PokeNews *ptr1; + PokeNews *ptr2; + + ptr1 = *dest; + ptr2 = *src; + ptr2 += sTVShowMixingCurSlot; + sub_80F0E84(ptr1, ptr2, sCurTVShowSlot); +} + +bool8 sub_80F0E84(PokeNews *dest, PokeNews *src, s8 slot) +{ + u8 i; + u8 kind; + + if (src->kind == POKENEWS_NONE) + { + return FALSE; + } + for (i = 0; i < 16; i ++) + { + if (dest[i].kind == src->kind) + { + return FALSE; + } + } + dest[slot].kind = src->kind; + dest[slot].state = 1; + dest[slot].days = src->days; + return TRUE; +} + +s8 sub_80F0ECC(PokeNews *pokeNews, u8 idx) +{ + if (pokeNews[idx].kind == POKENEWS_NONE) + { + return -1; + } + return idx; +} + +void sub_80F0EEC(void) +{ + u8 i; + + for (i = 0; i < 16; i ++) + { + if (gSaveBlock1Ptr->pokeNews[i].kind > POKENEWS_BLENDMASTER) + { + ClearPokemonNewsI(i); + } + } + sub_80EEEB8(); +} + +void sub_80F0F24(void) +{ + u8 i; + + if (FlagGet(SYS_GAME_CLEAR) != TRUE) + { + for (i = 0; i < 16; i ++) + { + gSaveBlock1Ptr->pokeNews[i].state = 0; + } + } +} + +#define tvlangfix(strptr, langptr, langfix) \ +if (IsStringJapanese(strptr)) \ +{ \ + (langptr) = LANGUAGE_JAPANESE; \ +} \ +else \ +{ \ + (langptr) = langfix; \ +} + +void sub_80F0F64(TVShow *show, u32 language) +{ + int i; + TVShow **r4; + + r4 = calloc(11, sizeof(TVShow *)); + for (i = 0; i < 24; i ++) + { + switch (show[i].common.kind) + { + case TVSHOW_FAN_CLUB_LETTER: + case TVSHOW_RECENT_HAPPENINGS: + r4[0] = &show[i]; + tvlangfix(r4[0]->fanclubLetter.playerName, r4[0]->fanclubLetter.language, language); + break; + case TVSHOW_PKMN_FAN_CLUB_OPINIONS: + r4[1] = &show[i]; + tvlangfix(r4[1]->fanclubOpinions.playerName, r4[1]->fanclubOpinions.language, language); + tvlangfix(r4[1]->fanclubOpinions.nickname, r4[1]->fanclubOpinions.pokemonNameLanguage, language); + break; + case TVSHOW_POKEMON_TODAY_CAUGHT: + r4[6] = &show[i]; + tvlangfix(r4[6]->pokemonToday.playerName, r4[6]->pokemonToday.language, language); + tvlangfix(r4[6]->pokemonToday.nickname, r4[6]->pokemonToday.language2, language); + break; + case TVSHOW_SMART_SHOPPER: + r4[7] = &show[i]; + tvlangfix(r4[7]->smartshopperShow.playerName, r4[7]->smartshopperShow.language, language); + break; + case TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE: + r4[5] = &show[i]; + tvlangfix(r4[5]->bravoTrainerTower.trainerName, r4[5]->bravoTrainerTower.language, language); + tvlangfix(r4[5]->bravoTrainerTower.pokemonName, r4[5]->bravoTrainerTower.pokemonNameLanguage, language); + break; + case TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE: + r4[4] = &show[i]; + tvlangfix(r4[4]->bravoTrainer.playerName, r4[4]->bravoTrainer.language, language); + tvlangfix(r4[4]->bravoTrainer.pokemonNickname, r4[4]->bravoTrainer.pokemonNameLanguage, language); + break; + case TVSHOW_NAME_RATER_SHOW: + r4[3] = &show[i]; + tvlangfix(r4[3]->nameRaterShow.trainerName, r4[3]->nameRaterShow.language, language); + tvlangfix(r4[3]->nameRaterShow.pokemonName, r4[3]->nameRaterShow.pokemonNameLanguage, language); + break; + case TVSHOW_POKEMON_TODAY_FAILED: + r4[2] = &show[i]; + tvlangfix(r4[2]->pokemonTodayFailed.playerName, r4[2]->pokemonTodayFailed.language, language); + break; + case TVSHOW_FISHING_ADVICE: + r4[8] = &show[i]; + tvlangfix(r4[8]->pokemonAngler.playerName, r4[8]->pokemonAngler.language, language); + break; + case TVSHOW_WORLD_OF_MASTERS: + r4[9] = &show[i]; + tvlangfix(r4[9]->worldOfMasters.playerName, r4[9]->worldOfMasters.language, language); + break; + case TVSHOW_MASS_OUTBREAK: + r4[10] = &show[i]; + r4[10]->massOutbreak.language = language; + break; + } + } + free(r4); +} + +void sub_80F1208(TVShow *shows) +{ + TVShow *curShow; + + sub_80F14F8(shows); + for (curShow = shows; curShow < shows + 24; curShow ++) + { + if (curShow->bravoTrainerTower.kind == TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE) + { + if ((curShow->bravoTrainerTower.language == LANGUAGE_JAPANESE && curShow->bravoTrainerTower.pokemonNameLanguage != LANGUAGE_JAPANESE) || (curShow->bravoTrainerTower.language != LANGUAGE_JAPANESE && curShow->bravoTrainerTower.pokemonNameLanguage == LANGUAGE_JAPANESE)) + { + memset(curShow, 0, sizeof(TVShow)); + } + } + } +} + +void sub_80F1254(TVShow *shows) +{ + TVShow *curShow; + + for (curShow = shows; curShow < shows + 24; curShow ++) + { + if (curShow->bravoTrainerTower.kind == TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE) + { + if (IsStringJapanese(curShow->bravoTrainerTower.pokemonName)) + { + curShow->bravoTrainerTower.pokemonNameLanguage = LANGUAGE_JAPANESE; + } + else + { + curShow->bravoTrainerTower.pokemonNameLanguage = LANGUAGE_ENGLISH; + } + } + } +} + +u8 TV_GetStringLanguage(u8 *str) +{ + return IsStringJapanese(str) ? LANGUAGE_JAPANESE : LANGUAGE_ENGLISH; +} + +void sub_80F12A4(TVShow *shows) +{ + TVShow *curShow; + + for (curShow = shows; curShow < shows + 24; curShow ++) + { + switch(curShow->common.kind) + { + case TVSHOW_FAN_CLUB_LETTER: + curShow->fanclubLetter.language = TV_GetStringLanguage(curShow->fanclubLetter.playerName); + break; + case TVSHOW_RECENT_HAPPENINGS: + curShow->recentHappenings.language = TV_GetStringLanguage(curShow->recentHappenings.playerName); + break; + case TVSHOW_PKMN_FAN_CLUB_OPINIONS: + curShow->fanclubOpinions.language = TV_GetStringLanguage(curShow->fanclubOpinions.playerName); + curShow->fanclubOpinions.pokemonNameLanguage = TV_GetStringLanguage(curShow->fanclubOpinions.nickname); + break; + case TVSHOW_UNKN_SHOWTYPE_04: + curShow->unkShow04.language = TV_GetStringLanguage(curShow->unkShow04.string_0b); + break; + case TVSHOW_NAME_RATER_SHOW: + curShow->nameRaterShow.language = TV_GetStringLanguage(curShow->nameRaterShow.trainerName); + curShow->nameRaterShow.pokemonNameLanguage = TV_GetStringLanguage(curShow->nameRaterShow.pokemonName); + break; + case TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE: + curShow->bravoTrainer.language = TV_GetStringLanguage(curShow->bravoTrainer.playerName); + curShow->bravoTrainer.pokemonNameLanguage = TV_GetStringLanguage(curShow->bravoTrainer.pokemonNickname); + break; + case TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE: + curShow->bravoTrainerTower.language = TV_GetStringLanguage(curShow->bravoTrainerTower.trainerName); + curShow->bravoTrainerTower.pokemonNameLanguage = TV_GetStringLanguage(curShow->bravoTrainerTower.pokemonName); + break; + case TVSHOW_CONTEST_LIVE_UPDATES: + curShow->contestLiveUpdates.language = TV_GetStringLanguage(curShow->contestLiveUpdates.playerName); + curShow->contestLiveUpdates.winningTrainerLanguage = TV_GetStringLanguage(curShow->contestLiveUpdates.winningTrainerName); + break; + case TVSHOW_3_CHEERS_FOR_POKEBLOCKS: + curShow->threeCheers.language = TV_GetStringLanguage(curShow->threeCheers.playerName); + curShow->threeCheers.worstBlenderLanguage = TV_GetStringLanguage(curShow->threeCheers.worstBlenderName); + break; + case TVSHOW_BATTLE_UPDATE: + curShow->battleUpdate.language = TV_GetStringLanguage(curShow->battleUpdate.playerName); + curShow->battleUpdate.linkOpponentLanguage = TV_GetStringLanguage(curShow->battleUpdate.linkOpponentName); + break; + case TVSHOW_FAN_CLUB_SPECIAL: + curShow->fanClubSpecial.language = TV_GetStringLanguage(curShow->fanClubSpecial.playerName); + curShow->fanClubSpecial.idolNameLanguage = TV_GetStringLanguage(curShow->fanClubSpecial.idolName); + break; + case TVSHOW_CONTEST_LIVE_UPDATES_2: + curShow->contestLiveUpdates2.language = TV_GetStringLanguage(curShow->contestLiveUpdates2.playerName); + curShow->contestLiveUpdates2.pokemonNameLanguage = TV_GetStringLanguage(curShow->contestLiveUpdates2.nickname); + break; + + case TVSHOW_POKEMON_TODAY_CAUGHT: + curShow->pokemonToday.language = TV_GetStringLanguage(curShow->pokemonToday.playerName); + curShow->pokemonToday.language2 = TV_GetStringLanguage(curShow->pokemonToday.nickname); + break; + case TVSHOW_SMART_SHOPPER: + curShow->smartshopperShow.language = TV_GetStringLanguage(curShow->smartshopperShow.playerName); + break; + case TVSHOW_POKEMON_TODAY_FAILED: + curShow->pokemonTodayFailed.language = TV_GetStringLanguage(curShow->pokemonTodayFailed.playerName); + break; + case TVSHOW_FISHING_ADVICE: + curShow->pokemonAngler.language = TV_GetStringLanguage(curShow->pokemonAngler.playerName); + break; + case TVSHOW_WORLD_OF_MASTERS: + curShow->worldOfMasters.language = TV_GetStringLanguage(curShow->worldOfMasters.playerName); + break; + case TVSHOW_TREND_WATCHER: + curShow->trendWatcher.language = TV_GetStringLanguage(curShow->trendWatcher.playerName); + break; + case TVSHOW_BREAKING_NEWS: + curShow->breakingNews.language = TV_GetStringLanguage(curShow->breakingNews.playerName); + break; + case TVSHOW_BATTLE_SEMINAR: + curShow->battleSeminar.language = TV_GetStringLanguage(curShow->battleSeminar.playerName); + break; + case TVSHOW_FIND_THAT_GAMER: + case TVSHOW_TRAINER_FAN_CLUB: + curShow->trainerFanClub.language = TV_GetStringLanguage(curShow->trainerFanClub.playerName); + break; + case TVSHOW_CUTIES: + curShow->cuties.language = TV_GetStringLanguage(curShow->cuties.playerName); + curShow->cuties.pokemonNameLanguage = TV_GetStringLanguage(curShow->cuties.nickname); + break; + case TVSHOW_TODAYS_RIVAL_TRAINER: + case TVSHOW_SECRET_BASE_VISIT: + case TVSHOW_FRONTIER: + curShow->rivalTrainer.language = TV_GetStringLanguage(curShow->rivalTrainer.playerName); + break; + case TVSHOW_TREASURE_INVESTIGATORS: + case TVSHOW_LOTTO_WINNER: + case TVSHOW_NUMBER_ONE: + curShow->treasureInvestigators.language = TV_GetStringLanguage(curShow->treasureInvestigators.playerName); + break; + case TVSHOW_SECRET_BASE_SECRETS: + curShow->secretBaseSecrets.language = TV_GetStringLanguage(curShow->secretBaseSecrets.playerName); + curShow->secretBaseSecrets.baseOwnersNameLanguage = TV_GetStringLanguage(curShow->secretBaseSecrets.baseOwnersName); + break; + case TVSHOW_SAFARI_FAN_CLUB: + curShow->safariFanClub.language = TV_GetStringLanguage(curShow->safariFanClub.playerName); + break; + case TVSHOW_MASS_OUTBREAK: + break; + } + } +} + +void sub_80F14F8(TVShow *shows) +{ + int i; + + for (i = 0; i < 24; i ++) + { + switch (shows[i].common.kind) + { + case TVSHOW_WORLD_OF_MASTERS: + if (shows[i].worldOfMasters.location > 0x58) + { + memset(&shows[i], 0, sizeof(TVShow)); + } + break; + case TVSHOW_POKEMON_TODAY_FAILED: + if (shows[i].pokemonTodayFailed.location > 0x58) + { + memset(&shows[i], 0, sizeof(TVShow)); + } + break; + } + } +} + +void DoTVShow(void) +{ + if (gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004].common.active) + { + switch (gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004].common.kind) + { + case TVSHOW_FAN_CLUB_LETTER: + DoTVShowPokemonFanClubLetter(); + break; + case TVSHOW_RECENT_HAPPENINGS: + DoTVShowRecentHappenings(); + break; + case TVSHOW_PKMN_FAN_CLUB_OPINIONS: + DoTVShowPokemonFanClubOpinions(); + break; + case TVSHOW_UNKN_SHOWTYPE_04: + DoTVShowDummiedOut(); + break; + case TVSHOW_MASS_OUTBREAK: + DoTVShowPokemonNewsMassOutbreak(); + break; + case TVSHOW_BRAVO_TRAINER_POKEMON_PROFILE: + DoTVShowBravoTrainerPokemonProfile(); + break; + case TVSHOW_BRAVO_TRAINER_BATTLE_TOWER_PROFILE: + DoTVShowBravoTrainerBattleTower(); + break; + case TVSHOW_POKEMON_TODAY_CAUGHT: + DoTVShowPokemonTodaySuccessfulCapture(); + break; + case TVSHOW_SMART_SHOPPER: + DoTVShowTodaysSmartShopper(); + break; + case TVSHOW_NAME_RATER_SHOW: + DoTVShowTheNameRaterShow(); + break; + case TVSHOW_CONTEST_LIVE_UPDATES: + DoTVShowPokemonContestLiveUpdates(); + break; + case TVSHOW_BATTLE_UPDATE: + DoTVShowPokemonBattleUpdate(); + break; + case TVSHOW_3_CHEERS_FOR_POKEBLOCKS: + DoTVShow3CheersForPokeblocks(); + break; + case TVSHOW_POKEMON_TODAY_FAILED: + DoTVShowPokemonTodayFailedCapture(); + break; + case TVSHOW_FISHING_ADVICE: + DoTVShowPokemonAngler(); + break; + case TVSHOW_WORLD_OF_MASTERS: + DoTVShowTheWorldOfMasters(); + break; + case TVSHOW_TODAYS_RIVAL_TRAINER: + DoTVShowTodaysRivalTrainer(); + break; + case TVSHOW_TREND_WATCHER: + DoTVShowDewfordTrendWatcherNetwork(); + break; + case TVSHOW_TREASURE_INVESTIGATORS: + DoTVShowHoennTreasureInvestigators(); + break; + case TVSHOW_FIND_THAT_GAMER: + DoTVShowFindThatGamer(); + break; + case TVSHOW_BREAKING_NEWS: + DoTVShowBreakingNewsTV(); + break; + case TVSHOW_SECRET_BASE_VISIT: + DoTVShowSecretBaseVisit(); + break; + case TVSHOW_LOTTO_WINNER: + DoTVShowPokemonLotteryWinnerFlashReport(); + break; + case TVSHOW_BATTLE_SEMINAR: + DoTVShowThePokemonBattleSeminar(); + break; + case TVSHOW_FAN_CLUB_SPECIAL: + DoTVShowTrainerFanClubSpecial(); + break; + case TVSHOW_TRAINER_FAN_CLUB: + DoTVShowTrainerFanClub(); + break; + case TVSHOW_CUTIES: + DoTVShowSpotTheCuties(); + break; + case TVSHOW_FRONTIER: + DoTVShowPokemonNewsBattleFrontier(); + break; + case TVSHOW_NUMBER_ONE: + DoTVShowWhatsNo1InHoennToday(); + break; + case TVSHOW_SECRET_BASE_SECRETS: + DoTVShowSecretBaseSecrets(); + break; + case TVSHOW_SAFARI_FAN_CLUB: + DoTVShowSafariFanClub(); + break; + case TVSHOW_CONTEST_LIVE_UPDATES_2: + DoTVShowPokemonContestLiveUpdates2(); + break; + } + } +} + +void DoTVShowBravoTrainerPokemonProfile(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainer.playerName, show->bravoTrainer.language); + CopyContestCategoryToStringVar(1, show->bravoTrainer.contestCategory); + CopyContestRankToStringVar(2, show->bravoTrainer.contestRank); + if (!StringCompare(gSpeciesNames[show->bravoTrainer.species], show->bravoTrainer.pokemonNickname)) + sTVShowState = 8; + else + sTVShowState = 1; + break; + case 1: + StringCopy(gStringVar1, gSpeciesNames[show->bravoTrainer.species]); + TVShowConvertInternationalString(gStringVar2, show->bravoTrainer.pokemonNickname, show->bravoTrainer.pokemonNameLanguage); + CopyContestCategoryToStringVar(2, show->bravoTrainer.contestCategory); + sTVShowState = 2; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainer.playerName, show->bravoTrainer.language); + if (show->bravoTrainer.contestResult == 0) // placed first + sTVShowState = 3; + else + sTVShowState = 4; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainer.playerName, show->bravoTrainer.language); + CopyEasyChatWord(gStringVar2, show->bravoTrainer.words[0]); + TV_PrintIntToStringVar(2, show->bravoTrainer.contestResult + 1); + sTVShowState = 5; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainer.playerName, show->bravoTrainer.language); + CopyEasyChatWord(gStringVar2, show->bravoTrainer.words[0]); + TV_PrintIntToStringVar(2, show->bravoTrainer.contestResult + 1); + sTVShowState = 5; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainer.playerName, show->bravoTrainer.language); + CopyContestCategoryToStringVar(1, show->bravoTrainer.contestCategory); + CopyEasyChatWord(gStringVar3, show->bravoTrainer.words[1]); + if (show->bravoTrainer.move) + sTVShowState = 6; + else + sTVShowState = 7; + break; + case 6: + StringCopy(gStringVar1, gSpeciesNames[show->bravoTrainer.species]); + StringCopy(gStringVar2, gMoveNames[show->bravoTrainer.move]); + CopyEasyChatWord(gStringVar3, show->bravoTrainer.words[1]); + sTVShowState = 7; + break; + case 7: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainer.playerName, show->bravoTrainer.language); + StringCopy(gStringVar2, gSpeciesNames[show->bravoTrainer.species]); + TVShowDone(); + break; + case 8: + StringCopy(gStringVar1, gSpeciesNames[show->bravoTrainer.species]); + sTVShowState = 2; + break; + } + ShowFieldMessage(sTVBravoTrainerTextGroup[state]); +} + +void DoTVShowBravoTrainerBattleTower(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch(state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.trainerName, show->bravoTrainerTower.language); + StringCopy(gStringVar2, gSpeciesNames[show->bravoTrainerTower.species]); + if (show->bravoTrainerTower.numFights >= 7) + sTVShowState = 1; + else + sTVShowState = 2; + break; + case 1: + if (show->bravoTrainerTower.btLevel == 50) + { + StringCopy(gStringVar1, gText_Lv50); + } + else + { + StringCopy(gStringVar1, gText_OpenLevel); + } + TV_PrintIntToStringVar(1, show->bravoTrainerTower.numFights); + if (show->bravoTrainerTower.wonTheChallenge == TRUE) + sTVShowState = 3; + else + sTVShowState = 4; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.pokemonName, show->bravoTrainerTower.pokemonNameLanguage); + TV_PrintIntToStringVar(1, show->bravoTrainerTower.numFights + 1); + if (show->bravoTrainerTower.interviewResponse == 0) + sTVShowState = 5; + else + sTVShowState = 6; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.pokemonName, show->bravoTrainerTower.pokemonNameLanguage); + StringCopy(gStringVar2, gSpeciesNames[show->bravoTrainerTower.defeatedSpecies]); + if (show->bravoTrainerTower.interviewResponse == 0) + sTVShowState = 5; + else + sTVShowState = 6; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.pokemonName, show->bravoTrainerTower.pokemonNameLanguage); + StringCopy(gStringVar2, gSpeciesNames[show->bravoTrainerTower.defeatedSpecies]); + if (show->bravoTrainerTower.interviewResponse == 0) + sTVShowState = 5; + else + sTVShowState = 6; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.pokemonName, show->bravoTrainerTower.pokemonNameLanguage); + sTVShowState = 11; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.pokemonName, show->bravoTrainerTower.pokemonNameLanguage); + sTVShowState = 11; + break; + case 7: + sTVShowState = 11; + break; + case 8: + case 9: + case 10: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.trainerName, show->bravoTrainerTower.language); + sTVShowState = 11; + break; + case 11: + CopyEasyChatWord(gStringVar1, show->bravoTrainerTower.words[0]); + if (show->bravoTrainerTower.interviewResponse == 0) + sTVShowState = 12; + else + sTVShowState = 13; + break; + case 12: + case 13: + CopyEasyChatWord(gStringVar1, show->bravoTrainerTower.words[0]); + TVShowConvertInternationalString(gStringVar2, show->bravoTrainerTower.trainerName, show->bravoTrainerTower.language); + TVShowConvertInternationalString(gStringVar3, show->bravoTrainerTower.pokemonName, show->bravoTrainerTower.pokemonNameLanguage); + sTVShowState = 14; + break; + case 14: + TVShowConvertInternationalString(gStringVar1, show->bravoTrainerTower.trainerName, show->bravoTrainerTower.language); + StringCopy(gStringVar2, gSpeciesNames[show->bravoTrainerTower.species]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVBravoTrainerBattleTowerTextGroup[state]); +} + +void DoTVShowTodaysSmartShopper(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch(state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); + GetMapName(gStringVar2, show->smartshopperShow.shopLocation, 0); + if (show->smartshopperShow.itemAmounts[0] >= 255) + { + sTVShowState = 11; + } + else + { + sTVShowState = 1; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); + StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[0])->name); + TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[0]); + sTVShowState += 1 + (Random() % 4); + break; + case 2: + case 4: + case 5: + if (show->smartshopperShow.itemIds[1] != ITEM_NONE) + { + sTVShowState = 6; + } + else + { + sTVShowState = 10; + } + break; + case 3: + TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[0] + 1); + if (show->smartshopperShow.itemIds[1] != ITEM_NONE) + { + sTVShowState = 6; + } + else + { + sTVShowState = 10; + } + break; + case 6: + StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[1])->name); + TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[1]); + if (show->smartshopperShow.itemIds[2] != ITEM_NONE) + { + sTVShowState = 7; + } + else if (show->smartshopperShow.priceReduced == TRUE) + { + sTVShowState = 8; + } + else + { + sTVShowState = 9; + } + break; + case 7: + StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[2])->name); + TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[2]); + if (show->smartshopperShow.priceReduced == TRUE) + { + sTVShowState = 8; + } + else + { + sTVShowState = 9; + } + break; + case 8: + if (show->smartshopperShow.itemAmounts[0] >= 255) + { + sTVShowState = 12; + } + else + { + sTVShowState = 9; + } + break; + case 9: + sub_80EF40C(1, show); + TVShowDone(); + break; + case 10: + if (show->smartshopperShow.priceReduced == TRUE) + { + sTVShowState = 8; + } + else + { + sTVShowState = 9; + } + break; + case 11: + TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); + StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[0])->name); + if (show->smartshopperShow.priceReduced == TRUE) + { + sTVShowState = 8; + } + else + { + sTVShowState = 12; + } + break; + case 12: + TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); + TVShowDone(); + break; + } + ShowFieldMessage(sTVTodaysSmartShopperTextGroup[state]); +} + +void DoTVShowTheNameRaterShow(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->nameRaterShow.trainerName, show->nameRaterShow.language); + StringCopy(gStringVar2, gSpeciesNames[show->nameRaterShow.species]); + TVShowConvertInternationalString(gStringVar3, show->nameRaterShow.pokemonName, show->nameRaterShow.pokemonNameLanguage); + sTVShowState = TV_GetNicknameSumMod8(show) + 1; + break; + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + if (show->nameRaterShow.random == 0) + { + sTVShowState = 9; + } + else if (show->nameRaterShow.random == 1) + { + sTVShowState = 10; + } + else if (show->nameRaterShow.random == 2) + { + sTVShowState = 11; + } + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->nameRaterShow.trainerName, show->nameRaterShow.language); + if (show->nameRaterShow.random == 0) + { + sTVShowState = 9; + } + else if (show->nameRaterShow.random == 1) + { + sTVShowState = 10; + } + else if (show->nameRaterShow.random == 2) + { + sTVShowState = 11; + } + break; + case 9: + case 10: + case 11: + TVShowConvertInternationalString(gStringVar1, show->nameRaterShow.pokemonName, show->nameRaterShow.pokemonNameLanguage); + TV_GetNicknameSubstring(1, 0, 0, 1, 0, show); + TV_GetNicknameSubstring(2, 1, 0, 1, 0, show); + sTVShowState = 12; + break; + case 13: + TVShowConvertInternationalString(gStringVar1, show->nameRaterShow.trainerName, show->nameRaterShow.language); + TV_GetNicknameSubstring(1, 0, 2, 0, 0, show); + TV_GetNicknameSubstring(2, 0, 3, 1, 0, show); + sTVShowState = 14; + break; + case 14: + TV_GetNicknameSubstring(1, 0, 2, 1, 0, show); + TV_GetNicknameSubstring(2, 0, 3, 0, 0, show); + sTVShowState = 18; + break; + case 15: + TV_GetNicknameSubstring(0, 0, 2, 1, 0, show); + StringCopy(gStringVar2, gSpeciesNames[show->nameRaterShow.species]); + TV_GetNicknameSubstring(2, 0, 3, 2, show->nameRaterShow.species, show); + sTVShowState = 16; + break; + case 16: + TV_GetNicknameSubstring(0, 0, 2, 2, show->nameRaterShow.species, show); + TV_GetNicknameSubstring(2, 0, 3, 1, 0, show); + sTVShowState = 17; + break; + case 17: + TV_GetNicknameSubstring(0, 0, 2, 1, 0, show); + StringCopy(gStringVar2, gSpeciesNames[show->nameRaterShow.randomSpecies]); + TV_GetNicknameSubstring(2, 0, 3, 2, show->nameRaterShow.randomSpecies, show); + sTVShowState = 18; + break; + case 12: + state = 18; + sTVShowState = 18; + case 18: + TVShowConvertInternationalString(gStringVar1, show->nameRaterShow.pokemonName, show->nameRaterShow.pokemonNameLanguage); + TVShowDone(); + break; + } + ShowFieldMessage(sTVNameRaterTextGroup[state]); +} + +void DoTVShowPokemonTodaySuccessfulCapture(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->pokemonToday.playerName, show->pokemonToday.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonToday.species]); + TVShowConvertInternationalString(gStringVar3, show->pokemonToday.nickname, show->pokemonToday.language2); + if (show->pokemonToday.ball == ITEM_MASTER_BALL) + { + sTVShowState = 5; + } + else + { + sTVShowState = 1; + } + break; + case 1: + sTVShowState = 2; + break; + case 2: + StringCopy(gStringVar2, ItemId_GetItem(show->pokemonToday.ball)->name); + TV_PrintIntToStringVar(2, show->pokemonToday.nBallsUsed); + if (show->pokemonToday.nBallsUsed < 4) + { + sTVShowState = 3; + } + else + { + sTVShowState = 4; + } + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->pokemonToday.playerName, show->pokemonToday.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonToday.species]); + TVShowConvertInternationalString(gStringVar3, show->pokemonToday.nickname, show->pokemonToday.language2); + sTVShowState = 6; + break; + case 4: + sTVShowState = 6; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->pokemonToday.playerName, show->pokemonToday.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonToday.species]); + sTVShowState = 6; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->pokemonToday.playerName, show->pokemonToday.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonToday.species]); + TVShowConvertInternationalString(gStringVar3, show->pokemonToday.nickname, show->pokemonToday.language2); + sTVShowState += 1 + (Random() % 4); + break; + case 7: + case 8: + StringCopy(gStringVar1, gSpeciesNames[show->pokemonToday.species]); + TVShowConvertInternationalString(gStringVar2, show->pokemonToday.nickname, show->pokemonToday.language2); + TV_GetSomeOtherSpeciesAlreadySeenByPlayer_AndPrintName(2, show->pokemonToday.species); + sTVShowState = 11; + break; + case 9: + case 10: + StringCopy(gStringVar1, gSpeciesNames[show->pokemonToday.species]); + TVShowConvertInternationalString(gStringVar2, show->pokemonToday.nickname, show->pokemonToday.language2); + sTVShowState = 11; + break; + case 11: + TVShowDone(); + break; + } + ShowFieldMessage(sTVPokemonTodaySuccessfulTextGroup[state]); +} + +void DoTVShowPokemonTodayFailedCapture(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->pokemonTodayFailed.playerName, show->pokemonTodayFailed.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonTodayFailed.species]); + sTVShowState = 1; + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->pokemonTodayFailed.playerName, show->pokemonTodayFailed.language); + GetMapName(gStringVar2, show->pokemonTodayFailed.location, 0); + StringCopy(gStringVar3, gSpeciesNames[show->pokemonTodayFailed.species2]); + if (show->pokemonTodayFailed.outcome == 1) + { + sTVShowState = 3; + } + else + { + sTVShowState = 2; + } + break; + case 2: + case 3: + TVShowConvertInternationalString(gStringVar1, show->pokemonTodayFailed.playerName, show->pokemonTodayFailed.language); + TV_PrintIntToStringVar(1, show->pokemonTodayFailed.nBallsUsed); + if (Random() % 3 == 0) + { + sTVShowState = 5; + } + else + { + sTVShowState = 4; + } + break; + case 4: + case 5: + TVShowConvertInternationalString(gStringVar1, show->pokemonTodayFailed.playerName, show->pokemonTodayFailed.language); + sTVShowState = 6; + break; + case 6: + TVShowDone(); + break; + } + ShowFieldMessage(sTVPokemonTodayFailedTextGroup[state]); +} + +void DoTVShowPokemonFanClubLetter(void) +{ + TVShow *show; + u8 state; + u16 rval; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->fanclubLetter.playerName, show->fanclubLetter.language); + StringCopy(gStringVar2, gSpeciesNames[show->fanclubLetter.species]); + sTVShowState = 50; + break; + case 1: + rval = (Random() % 4) + 1; + if (rval == 1) + sTVShowState = 2; + else + sTVShowState = rval + 2; + break; + case 2: + sTVShowState = 51; + break; + case 3: + sTVShowState += (Random() % 3) + 1; + break; + case 4: + case 5: + case 6: + TV_FanClubLetter_RandomWordToStringVar3(show); + sTVShowState = 7; + break; + case 7: + rval = (Random() % 0x1f) + 0x46; + TV_PrintIntToStringVar(2, rval); + TVShowDone(); + break; + case 50: + ConvertEasyChatWordsToString(gStringVar4, show->fanclubLetter.words, 2, 2); + ShowFieldMessage(gStringVar4); + sTVShowState = 1; + return; + case 51: + ConvertEasyChatWordsToString(gStringVar4, show->fanclubLetter.words, 2, 2); + ShowFieldMessage(gStringVar4); + sTVShowState = 3; + return; + } + ShowFieldMessage(sTVFanClubTextGroup[state]); +} + +void DoTVShowRecentHappenings(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->recentHappenings.playerName, show->recentHappenings.language); + TV_FanClubLetter_RandomWordToStringVar3(show); + sTVShowState = 50; + break; + case 1: + sTVShowState += 1 + (Random() % 3); + break; + case 2: + case 3: + case 4: + sTVShowState = 5; + break; + case 5: + TVShowDone(); + break; + case 50: + ConvertEasyChatWordsToString(gStringVar4, show->recentHappenings.words, 2, 2); + ShowFieldMessage(gStringVar4); + sTVShowState = 1; + return; + } + ShowFieldMessage(sTVRecentHappeninssTextGroup[state]); +} + +void DoTVShowPokemonFanClubOpinions(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->fanclubOpinions.playerName, show->fanclubOpinions.language); + StringCopy(gStringVar2, gSpeciesNames[show->fanclubOpinions.species]); + TVShowConvertInternationalString(gStringVar3, show->fanclubOpinions.nickname, show->fanclubOpinions.pokemonNameLanguage); + sTVShowState = show->fanclubOpinions.questionAsked + 1; + break; + case 1: + case 2: + case 3: + TVShowConvertInternationalString(gStringVar1, show->fanclubOpinions.playerName, show->fanclubOpinions.language); + StringCopy(gStringVar2, gSpeciesNames[show->fanclubOpinions.species]); + CopyEasyChatWord(gStringVar3, show->fanclubOpinions.words[0]); + sTVShowState = 4; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->fanclubOpinions.playerName, show->fanclubOpinions.language); + CopyEasyChatWord(gStringVar3, show->fanclubOpinions.words[1]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVFanClubOpinionsTextGroup[state]); +} + +void DoTVShowDummiedOut(void) +{ + +} + +void DoTVShowPokemonNewsMassOutbreak(void) +{ + TVShow *show; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + GetMapName(gStringVar1, show->massOutbreak.locationMapNum, 0); + StringCopy(gStringVar2, gSpeciesNames[show->massOutbreak.species]); + TVShowDone(); + StartMassOutbreak(); + ShowFieldMessage(sTVMassOutbreakTextGroup[sTVShowState]); +} + +void DoTVShowPokemonContestLiveUpdates(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + sub_818E868(gStringVar1, show->contestLiveUpdates.category); + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + TVShowConvertInternationalString(gStringVar3, show->contestLiveUpdates.playerName, show->contestLiveUpdates.language); + if (show->contestLiveUpdates.round1Rank == show->contestLiveUpdates.round2Rank) + { + if (show->contestLiveUpdates.round1Rank == 0) + { + sTVShowState = 1; + } + else + { + sTVShowState = 3; + } + } + else if (show->contestLiveUpdates.round1Rank > show->contestLiveUpdates.round2Rank) + { + sTVShowState = 2; + } + else + { + sTVShowState = 4; + } + break; + case 1: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + switch (show->contestLiveUpdates.appealFlags1) + { + case 0x01: + sTVShowState = 8; + break; + case 0x02: + sTVShowState = 5; + break; + case 0x04: + sTVShowState = 14; + break; + case 0x08: + sTVShowState = 7; + break; + case 0x10: + sTVShowState = 6; + break; + case 0x20: + sTVShowState = 20; + break; + case 0x40: + sTVShowState = 21; + break; + case 0x80: + sTVShowState = 22; + break; + } + break; + case 2: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + switch (show->contestLiveUpdates.appealFlags1) + { + case 0x01: + sTVShowState = 8; + break; + case 0x02: + sTVShowState = 5; + break; + case 0x04: + sTVShowState = 14; + break; + case 0x08: + sTVShowState = 7; + break; + case 0x10: + sTVShowState = 6; + break; + case 0x20: + sTVShowState = 20; + break; + case 0x40: + sTVShowState = 21; + break; + case 0x80: + sTVShowState = 22; + break; + } + break; + case 3: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + TVShowConvertInternationalString(gStringVar3, show->contestLiveUpdates.playerName, show->contestLiveUpdates.language); + switch (show->contestLiveUpdates.appealFlags1) + { + case 0x01: + sTVShowState = 8; + break; + case 0x02: + sTVShowState = 5; + break; + case 0x04: + sTVShowState = 14; + break; + case 0x08: + sTVShowState = 7; + break; + case 0x10: + sTVShowState = 6; + break; + case 0x20: + sTVShowState = 20; + break; + case 0x40: + sTVShowState = 21; + break; + case 0x80: + sTVShowState = 22; + break; + } + break; + case 4: + switch (show->contestLiveUpdates.category) + { + case 0: + StringCopy(gStringVar1, gText_Cool); + break; + case 1: + StringCopy(gStringVar1, gText_Beauty); + break; + case 2: + StringCopy(gStringVar1, gText_Cute); + break; + case 3: + StringCopy(gStringVar1, gText_Smart); + break; + case 4: + StringCopy(gStringVar1, gText_Tough); + break; + } + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + switch (show->contestLiveUpdates.appealFlags1) + { + case 0x01: + sTVShowState = 8; + break; + case 0x02: + sTVShowState = 5; + break; + case 0x04: + sTVShowState = 14; + break; + case 0x08: + sTVShowState = 7; + break; + case 0x10: + sTVShowState = 6; + break; + case 0x20: + sTVShowState = 20; + break; + case 0x40: + sTVShowState = 21; + break; + case 0x80: + sTVShowState = 22; + break; + } + break; + case 5: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 6: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 7: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 8: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + switch (show->contestLiveUpdates.category) + { + case 0: + sTVShowState = 9; + break; + case 1: + sTVShowState = 10; + break; + case 2: + sTVShowState = 11; + break; + case 3: + sTVShowState = 12; + break; + case 4: + sTVShowState = 13; + break; + } + break; + case 9: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 10: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 11: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 12: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 13: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 14: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + switch (show->contestLiveUpdates.category) + { + case 0: + sTVShowState = 15; + break; + case 1: + sTVShowState = 16; + break; + case 2: + sTVShowState = 17; + break; + case 3: + sTVShowState = 18; + break; + case 4: + sTVShowState = 19; + break; + } + break; + case 15: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 16: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 17: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 18: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 19: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 20: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 21: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + sTVShowState = 23; + break; + case 22: + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + StringCopy(gStringVar3, gMoveNames[show->contestLiveUpdates.move]); + sTVShowState = 23; + break; + case 23: + StringCopy(gStringVar1, gSpeciesNames[show->contestLiveUpdates.species]); + TVShowConvertInternationalString(gStringVar2, show->contestLiveUpdates.winningTrainerName, show->contestLiveUpdates.winningTrainerLanguage); + StringCopy(gStringVar3, gSpeciesNames[show->contestLiveUpdates.winningSpecies]); + switch (show->contestLiveUpdates.appealFlags2) + { + case 0x01: + sTVShowState = 31; + break; + case 0x02: + sTVShowState = 30; + break; + case 0x04: + sTVShowState = 29; + break; + case 0x08: + sTVShowState = 28; + break; + case 0x10: + sTVShowState = 27; + break; + case 0x20: + sTVShowState = 26; + break; + case 0x40: + sTVShowState = 25; + break; + case 0x80: + sTVShowState = 24; + break; + } + break; + case 24: + StringCopy(gStringVar1, gSpeciesNames[show->contestLiveUpdates.winningSpecies]); + sTVShowState = 32; + break; + case 25: + TVShowConvertInternationalString(gStringVar1, show->contestLiveUpdates.winningTrainerName, show->contestLiveUpdates.winningTrainerLanguage); + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.winningSpecies]); + sTVShowState = 32; + break; + case 28: + sTVShowState = 32; + break; + case 29: + TVShowConvertInternationalString(gStringVar1, show->contestLiveUpdates.playerName, show->contestLiveUpdates.language); + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + TVShowConvertInternationalString(gStringVar3, show->contestLiveUpdates.winningTrainerName, show->contestLiveUpdates.winningTrainerLanguage); + sTVShowState = 32; + break; + case 26: + case 27: + case 30: + case 31: + TVShowConvertInternationalString(gStringVar1, show->contestLiveUpdates.winningTrainerName, show->contestLiveUpdates.winningTrainerLanguage); + sTVShowState = 32; + break; + case 32: + + TVShowConvertInternationalString(gStringVar1, show->contestLiveUpdates.playerName, show->contestLiveUpdates.language); + StringCopy(gStringVar2, gSpeciesNames[show->contestLiveUpdates.species]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVContestLiveUpdatesTextGroup[state]); +} + +void DoTVShowPokemonBattleUpdate(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + switch (show->battleUpdate.battleType) + { + case 0: + case 1: + sTVShowState = 1; + break; + case 2: + sTVShowState = 5; + break; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.playerName, show->battleUpdate.language); + TVShowConvertInternationalString(gStringVar2, show->battleUpdate.linkOpponentName, show->battleUpdate.linkOpponentLanguage); + if (show->battleUpdate.battleType == 0) + { + StringCopy(gStringVar3, gText_Single); + } + else + { + StringCopy(gStringVar3, gText_Double); + } + sTVShowState = 2; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.playerName, show->battleUpdate.language); + StringCopy(gStringVar2, gSpeciesNames[show->battleUpdate.species2]); + StringCopy(gStringVar3, gMoveNames[show->battleUpdate.move]); + sTVShowState = 3; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.linkOpponentName, show->battleUpdate.linkOpponentLanguage); + StringCopy(gStringVar2, gSpeciesNames[show->battleUpdate.species]); + sTVShowState = 4; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.playerName, show->battleUpdate.language); + TVShowConvertInternationalString(gStringVar2, show->battleUpdate.linkOpponentName, show->battleUpdate.linkOpponentLanguage); + TVShowDone(); + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.playerName, show->battleUpdate.language); + TVShowConvertInternationalString(gStringVar2, show->battleUpdate.linkOpponentName, show->battleUpdate.linkOpponentLanguage); + sTVShowState = 6; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.playerName, show->battleUpdate.language); + StringCopy(gStringVar2, gSpeciesNames[show->battleUpdate.species2]); + StringCopy(gStringVar3, gMoveNames[show->battleUpdate.move]); + sTVShowState = 7; + break; + case 7: + TVShowConvertInternationalString(gStringVar1, show->battleUpdate.playerName, show->battleUpdate.language); + TVShowConvertInternationalString(gStringVar2, show->battleUpdate.linkOpponentName, show->battleUpdate.linkOpponentLanguage); + StringCopy(gStringVar3, gSpeciesNames[show->battleUpdate.species]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVPokemonBattleUpdateTextGroup[state]); +} + +void DoTVShow3CheersForPokeblocks(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->threeCheers.playerName, show->threeCheers.language); + if (show->threeCheers.sheen > 20) + { + sTVShowState = 1; + } + else + { + sTVShowState = 3; + } + break; + case 1: + switch (show->threeCheers.flavor) + { + case 0: + StringCopy(gStringVar1, gText_Spicy2); + break; + case 1: + StringCopy(gStringVar1, gText_Dry2); + break; + case 2: + StringCopy(gStringVar1, gText_Sweet2); + break; + case 3: + StringCopy(gStringVar1, gText_Bitter2); + break; + case 4: + StringCopy(gStringVar1, gText_Sour2); + break; + } + if (show->threeCheers.sheen > 24) + { + StringCopy(gStringVar2, gText_Excellent); + } else if (show->threeCheers.sheen > 22) + { + StringCopy(gStringVar2, gText_VeryGood); + } + else + { + StringCopy(gStringVar2, gText_Good); + } + TVShowConvertInternationalString(gStringVar3, show->threeCheers.playerName, show->threeCheers.language); + sTVShowState = 2; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->threeCheers.worstBlenderName, show->threeCheers.worstBlenderLanguage); + sTVShowState = 5; + break; + case 3: + switch (show->threeCheers.flavor) + { + case 0: + StringCopy(gStringVar1, gText_Spicy2); + break; + case 1: + StringCopy(gStringVar1, gText_Dry2); + break; + case 2: + StringCopy(gStringVar1, gText_Sweet2); + break; + case 3: + StringCopy(gStringVar1, gText_Bitter2); + break; + case 4: + StringCopy(gStringVar1, gText_Sour2); + break; + } + if (show->threeCheers.sheen > 16) + { + StringCopy(gStringVar2, gText_SoSo); + } else if (show->threeCheers.sheen > 13) + { + StringCopy(gStringVar2, gText_Bad); + } + else + { + StringCopy(gStringVar2, gText_TheWorst); + } + TVShowConvertInternationalString(gStringVar3, show->threeCheers.playerName, show->threeCheers.language); + sTVShowState = 4; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->threeCheers.worstBlenderName, show->threeCheers.worstBlenderLanguage); + TVShowConvertInternationalString(gStringVar2, show->threeCheers.playerName, show->threeCheers.language); + sTVShowState = 5; + break; + case 5: + TVShowDone(); + break; + } + ShowFieldMessage(sTV3CheersForPokeblocksTextGroup[state]); +} + +void DoTVShowInSearchOfTrainers(void) +{ + u8 state; + + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + GetMapName(gStringVar1, gSaveBlock1Ptr->gabbyAndTyData.mapnum, 0); + if (gSaveBlock1Ptr->gabbyAndTyData.battleNum > 1) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 1: + sTVShowState = 2; + break; + case 2: + if (!gSaveBlock1Ptr->gabbyAndTyData.battleTookMoreThanOneTurn) + { + sTVShowState = 4; + } + else if (gSaveBlock1Ptr->gabbyAndTyData.playerThrewABall) + { + sTVShowState = 5; + } + else if (gSaveBlock1Ptr->gabbyAndTyData.playerUsedAnItem) + { + sTVShowState = 6; + } + else if (gSaveBlock1Ptr->gabbyAndTyData.playerLostAMon) + { + sTVShowState = 7; + } + else + { + sTVShowState = 3; + } + break; + case 3: + StringCopy(gStringVar1, gSpeciesNames[gSaveBlock1Ptr->gabbyAndTyData.mon1]); + StringCopy(gStringVar2, gMoveNames[gSaveBlock1Ptr->gabbyAndTyData.lastMove]); + StringCopy(gStringVar3, gSpeciesNames[gSaveBlock1Ptr->gabbyAndTyData.mon2]); + sTVShowState = 8; + break; + case 4: + case 5: + case 6: + case 7: + sTVShowState = 8; + break; + case 8: + CopyEasyChatWord(gStringVar1, gSaveBlock1Ptr->gabbyAndTyData.quote[0]); + StringCopy(gStringVar2, gSpeciesNames[gSaveBlock1Ptr->gabbyAndTyData.mon1]); + StringCopy(gStringVar3, gSpeciesNames[gSaveBlock1Ptr->gabbyAndTyData.mon2]); + gScriptResult = TRUE; + sTVShowState = 0; + TakeTVShowInSearchOfTrainersOffTheAir(); + break; + } + ShowFieldMessage(sTVInSearchOfTrainersTextGroup[state]); +} + +void DoTVShowPokemonAngler(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + if (show->pokemonAngler.nBites < show->pokemonAngler.nFails) + { + sTVShowState = 0; + } + else + { + sTVShowState = 1; + } + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->pokemonAngler.playerName, show->pokemonAngler.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonAngler.species]); + TV_PrintIntToStringVar(2, show->pokemonAngler.nFails); + TVShowDone(); + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->pokemonAngler.playerName, show->pokemonAngler.language); + StringCopy(gStringVar2, gSpeciesNames[show->pokemonAngler.species]); + TV_PrintIntToStringVar(2, show->pokemonAngler.nBites); + TVShowDone(); + break; + } + ShowFieldMessage(sTVPokemonAnslerTextGroup[state]); +} + +void DoTVShowTheWorldOfMasters(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->worldOfMasters.playerName, show->worldOfMasters.language); + TV_PrintIntToStringVar(1, show->worldOfMasters.steps); + TV_PrintIntToStringVar(2, show->worldOfMasters.numPokeCaught); + sTVShowState = 1; + break; + case 1: + StringCopy(gStringVar1, gSpeciesNames[show->worldOfMasters.species]); + sTVShowState = 2; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->worldOfMasters.playerName, show->worldOfMasters.language); + GetMapName(gStringVar2, show->worldOfMasters.location, 0); + StringCopy(gStringVar3, gSpeciesNames[show->worldOfMasters.caughtPoke]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVWorldOfMastersTextGroup[state]); +} + +void DoTVShowTodaysRivalTrainer(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + switch (show->rivalTrainer.location) + { + default: + sTVShowState = 7; + break; + case REGION_MAP_SECRET_BASE: + sTVShowState = 8; + break; + case REGION_MAP_NONE: + switch (show->rivalTrainer.mapDataId) + { + case 0x115 ... 0x117: + sTVShowState = 10; + break; + default: + sTVShowState = 9; + break; + } + break; + } + break; + case 7: + TVShowConvertInternationalString(gStringVar1, show->rivalTrainer.playerName, show->rivalTrainer.language); + TV_PrintIntToStringVar(1, show->rivalTrainer.dexCount); + GetMapName(gStringVar3, show->rivalTrainer.location, 0); + if (show->rivalTrainer.badgeCount != 0) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 8: + TVShowConvertInternationalString(gStringVar1, show->rivalTrainer.playerName, show->rivalTrainer.language); + TV_PrintIntToStringVar(1, show->rivalTrainer.dexCount); + if (show->rivalTrainer.badgeCount != 0) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 9: + TVShowConvertInternationalString(gStringVar1, show->rivalTrainer.playerName, show->rivalTrainer.language); + TV_PrintIntToStringVar(1, show->rivalTrainer.dexCount); + if (show->rivalTrainer.badgeCount != 0) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 10: + TVShowConvertInternationalString(gStringVar1, show->rivalTrainer.playerName, show->rivalTrainer.language); + TV_PrintIntToStringVar(1, show->rivalTrainer.dexCount); + if (show->rivalTrainer.badgeCount != 0) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 1: + TV_PrintIntToStringVar(0, show->rivalTrainer.badgeCount); + if (FlagGet(CODE_FLAGS + 0x48)) + { + if (show->rivalTrainer.nSilverSymbols || show->rivalTrainer.nGoldSymbols) + { + sTVShowState = 4; + } + else + { + sTVShowState = 3; + } + } + else + { + sTVShowState = 6; + } + break; + case 2: + if (FlagGet(CODE_FLAGS + 0x48)) + { + if (show->rivalTrainer.nSilverSymbols || show->rivalTrainer.nGoldSymbols) + { + sTVShowState = 4; + } + else + { + sTVShowState = 3; + } + } + else + { + sTVShowState = 6; + } + break; + case 3: + if (show->rivalTrainer.battlePoints == 0) + { + sTVShowState = 6; + } + else + { + sTVShowState = 5; + } + break; + case 4: + TV_PrintIntToStringVar(0, show->rivalTrainer.nGoldSymbols); + TV_PrintIntToStringVar(1, show->rivalTrainer.nSilverSymbols); + if (show->rivalTrainer.battlePoints == 0) + { + sTVShowState = 6; + } + else + { + sTVShowState = 5; + } + break; + case 5: + TV_PrintIntToStringVar(0, show->rivalTrainer.battlePoints); + sTVShowState = 6; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->rivalTrainer.playerName, show->rivalTrainer.language); + TVShowDone(); + } + ShowFieldMessage(sTVTodaysRivalTrainerTextGroup[state]); +} + +void DoTVShowDewfordTrendWatcherNetwork(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + CopyEasyChatWord(gStringVar1, show->trendWatcher.words[0]); + CopyEasyChatWord(gStringVar2, show->trendWatcher.words[1]); + if (show->trendWatcher.gender == MALE) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 1: + case 2: + CopyEasyChatWord(gStringVar1, show->trendWatcher.words[0]); + CopyEasyChatWord(gStringVar2, show->trendWatcher.words[1]); + TVShowConvertInternationalString(gStringVar3, show->trendWatcher.playerName, show->trendWatcher.language); + sTVShowState = 3; + break; + case 3: + CopyEasyChatWord(gStringVar1, show->trendWatcher.words[0]); + CopyEasyChatWord(gStringVar2, show->trendWatcher.words[1]); + if (show->trendWatcher.gender == MALE) + { + sTVShowState = 4; + } + else + { + sTVShowState = 5; + } + break; + case 4: + case 5: + CopyEasyChatWord(gStringVar1, show->trendWatcher.words[0]); + CopyEasyChatWord(gStringVar2, show->trendWatcher.words[1]); + TVShowConvertInternationalString(gStringVar3, show->trendWatcher.playerName, show->trendWatcher.language); + sTVShowState = 6; + break; + case 6: + CopyEasyChatWord(gStringVar1, show->trendWatcher.words[0]); + CopyEasyChatWord(gStringVar2, show->trendWatcher.words[1]); + TVShowDone(); + } + ShowFieldMessage(sTVDewfordTrendWatcherNetworkTextGroup[state]); +} + +void DoTVShowHoennTreasureInvestigators(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name); + if (show->treasureInvestigators.location == REGION_MAP_NONE) + { + switch (show->treasureInvestigators.mapDataId) + { + case 0x115 ... 0x117: + sTVShowState = 2; + break; + default: + sTVShowState = 1; + break; + } + } + else + { + sTVShowState = 1; + } + break; + case 1: + StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name); + TVShowConvertInternationalString(gStringVar2, show->treasureInvestigators.playerName, show->treasureInvestigators.language); + GetMapName(gStringVar3, show->treasureInvestigators.location, 0); + TVShowDone(); + break; + case 2: + StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name); + TVShowConvertInternationalString(gStringVar2, show->treasureInvestigators.playerName, show->treasureInvestigators.language); + TVShowDone(); + break; + } + ShowFieldMessage(sTVHoennTreasureInvestisatorsTextGroup[state]); +} + +void DoTVShowFindThatGamer(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->findThatGamer.playerName, show->findThatGamer.language); + switch (show->findThatGamer.whichGame) + { + case 0: + StringCopy(gStringVar2, gText_Slots); + break; + case 1: + StringCopy(gStringVar2, gText_Roulette); + break; + } + if (show->findThatGamer.won == TRUE) + { + sTVShowState = 1; + } + else + { + sTVShowState = 2; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->findThatGamer.playerName, show->findThatGamer.language); + switch (show->findThatGamer.whichGame) + { + case 0: + StringCopy(gStringVar2, gText_Slots); + break; + case 1: + StringCopy(gStringVar2, gText_Roulette); + break; + } + TV_PrintIntToStringVar(2, show->findThatGamer.nCoins); + TVShowDone(); break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->findThatGamer.playerName, show->findThatGamer.language); + switch (show->findThatGamer.whichGame) + { + case 0: + StringCopy(gStringVar2, gText_Slots); + break; + case 1: + StringCopy(gStringVar2, gText_Roulette); + break; + } + TV_PrintIntToStringVar(2, show->findThatGamer.nCoins); + sTVShowState = 3; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->findThatGamer.playerName, show->findThatGamer.language); + switch (show->findThatGamer.whichGame) + { + case 0: + StringCopy(gStringVar2, gText_Roulette); + break; + case 1: + StringCopy(gStringVar2, gText_Slots); + break; + } + TVShowDone(); + break; + } + ShowFieldMessage(sTVFindThatGamerTextGroup[state]); +} + +void DoTVShowBreakingNewsTV(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + if (show->breakingNews.outcome == 0) + { + sTVShowState = 1; + } + else + { + sTVShowState = 5; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.lastOpponentSpecies]); + GetMapName(gStringVar3, show->breakingNews.location, 0); + sTVShowState = 2; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.lastOpponentSpecies]); + StringCopy(gStringVar3, gSpeciesNames[show->breakingNews.poke1Species]); + sTVShowState = 3; + break; + case 3: + TV_PrintIntToStringVar(0, show->breakingNews.balls); + StringCopy(gStringVar2, ItemId_GetItem(show->breakingNews.caughtMonBall)->name); + sTVShowState = 4; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + GetMapName(gStringVar2, show->breakingNews.location, 0); + TVShowDone(); + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.lastOpponentSpecies]); + GetMapName(gStringVar3, show->breakingNews.location, 0); + sTVShowState = 6; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.lastOpponentSpecies]); + StringCopy(gStringVar3, gSpeciesNames[show->breakingNews.poke1Species]); + switch (show->breakingNews.outcome) + { + case 1: + if (show->breakingNews.lastUsedMove == MOVE_NONE) + { + sTVShowState = 12; + } + else + { + sTVShowState = 7; + } + break; + case 2: + sTVShowState = 9; + break; + case 3: + sTVShowState = 10; + break; + } + break; + case 7: + StringCopy(gStringVar1, gMoveNames[show->breakingNews.lastUsedMove]); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.poke1Species]); + sTVShowState = 8; + break; + case 12: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.lastOpponentSpecies]); + StringCopy(gStringVar3, gSpeciesNames[show->breakingNews.poke1Species]); + sTVShowState = 8; + break; + case 8: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + GetMapName(gStringVar2, show->breakingNews.location, 0); + sTVShowState = 11; + break; + case 9: + case 10: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + StringCopy(gStringVar2, gSpeciesNames[show->breakingNews.lastOpponentSpecies]); + GetMapName(gStringVar3, show->breakingNews.location, 0); + sTVShowState = 11; + break; + case 11: + TVShowConvertInternationalString(gStringVar1, show->breakingNews.playerName, show->breakingNews.language); + TVShowDone(); + break; + } + ShowFieldMessage(sTVBreakinsNewsTextGroup[state]); +} + +void DoTVShowSecretBaseVisit(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->secretBaseVisit.playerName, show->secretBaseVisit.language); + if (show->secretBaseVisit.nDecorations == 0) + { + sTVShowState = 2; + } + else + { + sTVShowState = 1; + } + break; + case 1: + StringCopy(gStringVar2, gDecorations[show->secretBaseVisit.decorations[0]].name); + if (show->secretBaseVisit.nDecorations == 1) + { + sTVShowState = 4; + } + else + { + sTVShowState = 3; + } + break; + case 3: + StringCopy(gStringVar2, gDecorations[show->secretBaseVisit.decorations[1]].name); + switch (show->secretBaseVisit.nDecorations) + { + case 2: + sTVShowState = 7; + break; + case 3: + sTVShowState = 6; + break; + case 4: + sTVShowState = 5; + break; + } + break; + case 5: + StringCopy(gStringVar2, gDecorations[show->secretBaseVisit.decorations[2]].name); + StringCopy(gStringVar3, gDecorations[show->secretBaseVisit.decorations[3]].name); + sTVShowState = 8; + break; + case 6: + StringCopy(gStringVar2, gDecorations[show->secretBaseVisit.decorations[2]].name); + sTVShowState = 8; + break; + case 2: + case 4: + case 7: + sTVShowState = 8; + break; + case 8: + TVShowConvertInternationalString(gStringVar1, show->secretBaseVisit.playerName, show->secretBaseVisit.language); + if (show->secretBaseVisit.avgLevel < 25) + { + sTVShowState = 12; + } + else if (show->secretBaseVisit.avgLevel < 50) + { + sTVShowState = 11; + } + else if (show->secretBaseVisit.avgLevel < 70) + { + sTVShowState = 10; + } + else + { + sTVShowState = 9; + } + break; + case 9: + case 10: + case 11: + case 12: + TVShowConvertInternationalString(gStringVar1, show->secretBaseVisit.playerName, show->secretBaseVisit.language); + StringCopy(gStringVar2, gSpeciesNames[show->secretBaseVisit.species]); + StringCopy(gStringVar3, gMoveNames[show->secretBaseVisit.move]); + sTVShowState = 13; + break; + case 13: + TVShowDone(); + break; + } + ShowFieldMessage(sTVSecretBaseVisitTextGroup[state]); +} + +void DoTVShowPokemonLotteryWinnerFlashReport(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + TVShowConvertInternationalString(gStringVar1, show->lottoWinner.playerName, show->lottoWinner.language); + if (show->lottoWinner.whichPrize == 0) + { + StringCopy(gStringVar2, gText_Jackpot); + } + else if (show->lottoWinner.whichPrize == 1) + { + StringCopy(gStringVar2, gText_First); + } + else if (show->lottoWinner.whichPrize == 2) + { + StringCopy(gStringVar2, gText_Second); + } + else + { + StringCopy(gStringVar2, gText_Third); + } + StringCopy(gStringVar3, ItemId_GetItem(show->lottoWinner.item)->name); + TVShowDone(); + ShowFieldMessage(sTVPokemonLotteryWinnerFlashReportTextGroup[state]); +} + +void DoTVShowThePokemonBattleSeminar(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->battleSeminar.playerName, show->battleSeminar.language); + StringCopy(gStringVar2, gSpeciesNames[show->battleSeminar.species]); + StringCopy(gStringVar3, gSpeciesNames[show->battleSeminar.foeSpecies]); + sTVShowState = 1; + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->battleSeminar.playerName, show->battleSeminar.language); + StringCopy(gStringVar2, gSpeciesNames[show->battleSeminar.foeSpecies]); + StringCopy(gStringVar3, gMoveNames[show->battleSeminar.move]); + sTVShowState = 2; + break; + case 2: + StringCopy(gStringVar1, gSpeciesNames[show->battleSeminar.species]); + switch (show->battleSeminar.nOtherMoves) + { + case 1: + sTVShowState = 5; + break; + case 2: + sTVShowState = 4; + break; + case 3: + sTVShowState = 3; + break; + default: + sTVShowState = 6; + break; + } + break; + case 3: + StringCopy(gStringVar1, gMoveNames[show->battleSeminar.otherMoves[0]]); + StringCopy(gStringVar2, gMoveNames[show->battleSeminar.otherMoves[1]]); + StringCopy(gStringVar3, gMoveNames[show->battleSeminar.otherMoves[2]]); + sTVShowState = 6; + break; + case 4: + StringCopy(gStringVar1, gMoveNames[show->battleSeminar.otherMoves[0]]); + StringCopy(gStringVar2, gMoveNames[show->battleSeminar.otherMoves[1]]); + sTVShowState = 6; + break; + case 5: + StringCopy(gStringVar2, gMoveNames[show->battleSeminar.otherMoves[0]]); + sTVShowState = 6; + break; + case 6: + StringCopy(gStringVar1, gMoveNames[show->battleSeminar.betterMove]); + StringCopy(gStringVar2, gMoveNames[show->battleSeminar.move]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVThePokemonBattleSeminarTextGroup[state]); +} + +void DoTVShowTrainerFanClubSpecial(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->fanClubSpecial.idolName, show->fanClubSpecial.idolNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->fanClubSpecial.playerName, show->fanClubSpecial.language); + CopyEasyChatWord(gStringVar3, show->fanClubSpecial.words[0]); + if (show->fanClubSpecial.score >= 90) + { + sTVShowState = 1; + } + else if (show->fanClubSpecial.score >= 70) + { + sTVShowState = 2; + } + else if (show->fanClubSpecial.score >= 30) + { + sTVShowState = 3; + } + else + { + sTVShowState = 4; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->fanClubSpecial.idolName, show->fanClubSpecial.idolNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->fanClubSpecial.playerName, show->fanClubSpecial.language); + TV_PrintIntToStringVar(2, show->fanClubSpecial.score); + sTVShowState = 5; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->fanClubSpecial.idolName, show->fanClubSpecial.idolNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->fanClubSpecial.playerName, show->fanClubSpecial.language); + TV_PrintIntToStringVar(2, show->fanClubSpecial.score); + sTVShowState = 5; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->fanClubSpecial.idolName, show->fanClubSpecial.idolNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->fanClubSpecial.playerName, show->fanClubSpecial.language); + TV_PrintIntToStringVar(2, show->fanClubSpecial.score); + sTVShowState = 5; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->fanClubSpecial.idolName, show->fanClubSpecial.idolNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->fanClubSpecial.playerName, show->fanClubSpecial.language); + TV_PrintIntToStringVar(2, show->fanClubSpecial.score); + sTVShowState = 5; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->fanClubSpecial.idolName, show->fanClubSpecial.idolNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->fanClubSpecial.playerName, show->fanClubSpecial.language); + CopyEasyChatWord(gStringVar3, show->fanClubSpecial.words[0]); + TVShowDone(); + break; + } + ShowFieldMessage(sTVTrainerFanClubSpecialTextGroup[state]); +} + +void DoTVShowTrainerFanClub(void) +{ + TVShow *show; + u8 state; + u32 playerId; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->trainerFanClub.playerName, show->trainerFanClub.language); + playerId = ((show->common.trainerIdHi << 8) + show->common.trainerIdLo); + switch (playerId % 10) + { + case 0: + sTVShowState = 1; + break; + case 1: + sTVShowState = 2; + break; + case 2: + sTVShowState = 3; + break; + case 3: + sTVShowState = 4; + break; + case 4: + sTVShowState = 5; + break; + case 5: + sTVShowState = 6; + break; + case 6: + sTVShowState = 7; + break; + case 7: + sTVShowState = 8; + break; + case 8: + sTVShowState = 9; + break; + case 9: + sTVShowState = 10; + break; + } + break; + case 1: + sTVShowState = 11; + break; + case 2: + sTVShowState = 11; + break; + case 3: + sTVShowState = 11; + break; + case 4: + sTVShowState = 11; + break; + case 5: + sTVShowState = 11; + break; + case 6: + sTVShowState = 11; + break; + case 7: + sTVShowState = 11; + break; + case 8: + sTVShowState = 11; + break; + case 9: + sTVShowState = 11; + break; + case 10: + sTVShowState = 11; + break; + case 11: + TVShowConvertInternationalString(gStringVar1, show->trainerFanClub.playerName, show->trainerFanClub.language); + CopyEasyChatWord(gStringVar2, show->trainerFanClub.words[0]); + CopyEasyChatWord(gStringVar3, show->trainerFanClub.words[1]); + TVShowDone(); + } + ShowFieldMessage(sTVTrainerFanClubTextGroup[state]); +} + +void DoTVShowSpotTheCuties(void) +{ + TVShow *show; + u8 state; + u32 playerId; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->cuties.playerName, show->cuties.language); + TVShowConvertInternationalString(gStringVar2, show->cuties.nickname, show->cuties.pokemonNameLanguage); + if (show->cuties.nRibbons < 10) + { + sTVShowState = 1; + } + else if (show->cuties.nRibbons < 20) + { + sTVShowState = 2; + } + else + { + sTVShowState = 3; + } + break; + case 1: + case 2: + case 3: + TVShowConvertInternationalString(gStringVar1, show->cuties.playerName, show->cuties.language); + TVShowConvertInternationalString(gStringVar2, show->cuties.nickname, show->cuties.pokemonNameLanguage); + TV_PrintIntToStringVar(2, show->cuties.nRibbons); + sTVShowState = 4; + break; + case 4: + TVShowConvertInternationalString(gStringVar2, show->cuties.nickname, show->cuties.pokemonNameLanguage); + switch (show->cuties.selectedRibbon) + { + case 0: + sTVShowState = 5; + break; + case 1: + case 2: + case 3: + case 4: + sTVShowState = 6; + break; + case 5: + case 6: + case 7: + case 8: + sTVShowState = 7; + break; + case 9: + case 10: + case 11: + case 12: + sTVShowState = 8; + break; + case 13: + case 14: + case 15: + case 16: + sTVShowState = 9; + break; + case 17: + case 18: + case 19: + case 20: + sTVShowState = 10; + break; + case 21: + sTVShowState = 11; + break; + case 22: + sTVShowState = 12; + break; + case 23: + sTVShowState = 13; + break; + case 24: + sTVShowState = 14; + break; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + TVShowConvertInternationalString(gStringVar2, show->cuties.nickname, show->cuties.pokemonNameLanguage); + sTVShowState = 15; + break; + case 15: + TVShowDone(); + } + ShowFieldMessage(sTVCutiesTextGroup[state]); +} + +void DoTVShowPokemonNewsBattleFrontier(void) +{ + TVShow *show; + u8 state; + u32 playerId; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + switch (show->frontier.facility) + { + case 1: + sTVShowState = 1; + break; + case 2: + sTVShowState = 2; + break; + case 3: + sTVShowState = 3; + break; + case 4: + sTVShowState = 4; + break; + case 5: + sTVShowState = 5; + break; + case 6: + sTVShowState = 6; + break; + case 7: + sTVShowState = 7; + break; + case 8: + sTVShowState = 8; + break; + case 9: + sTVShowState = 9; + break; + case 10: + sTVShowState = 10; + break; + case 11: + sTVShowState = 11; + break; + case 12: + sTVShowState = 12; + break; + case 13: + sTVShowState = 13; + break; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 16; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 15; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 15; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 7: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 8: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 9: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 10: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 11: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 12: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 13: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TV_PrintIntToStringVar(1, show->frontier.winStreak); + sTVShowState = 14; + break; + case 14: + StringCopy(gStringVar1, gSpeciesNames[show->frontier.species1]); + StringCopy(gStringVar2, gSpeciesNames[show->frontier.species2]); + StringCopy(gStringVar3, gSpeciesNames[show->frontier.species3]); + sTVShowState = 18; + break; + case 15: + StringCopy(gStringVar1, gSpeciesNames[show->frontier.species1]); + StringCopy(gStringVar2, gSpeciesNames[show->frontier.species2]); + sTVShowState = 18; + break; + case 16: + StringCopy(gStringVar1, gSpeciesNames[show->frontier.species1]); + StringCopy(gStringVar2, gSpeciesNames[show->frontier.species2]); + StringCopy(gStringVar3, gSpeciesNames[show->frontier.species3]); + sTVShowState = 17; + break; + case 17: + StringCopy(gStringVar1, gSpeciesNames[show->frontier.species4]); + sTVShowState = 18; + break; + case 18: + TVShowConvertInternationalString(gStringVar1, show->frontier.playerName, show->frontier.language); + TVShowDone(); + break; + } + ShowFieldMessage(sTVPokemonNewsBattleFrontierTextGroup[state]); +} + +void DoTVShowWhatsNo1InHoennToday(void) +{ + TVShow *show; + u8 state; + u32 playerId; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + switch (show->numberOne.actionIdx) + { + case 0: + sTVShowState = 1; + break; + case 1: + sTVShowState = 2; + break; + case 2: + sTVShowState = 3; + break; + case 3: + sTVShowState = 4; + break; + case 4: + sTVShowState = 5; + break; + case 5: + sTVShowState = 6; + break; + case 6: + sTVShowState = 7; + break; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 2: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 7: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TV_PrintIntToStringVar(1, show->numberOne.count); + sTVShowState = 8; + break; + case 8: + TVShowConvertInternationalString(gStringVar1, show->numberOne.playerName, show->numberOne.language); + TVShowDone(); + break; + } + ShowFieldMessage(sTVWhatsNo1InHoennTodayTextGroup[state]); +} + +u8 sub_80F5180(TVShow *show) +{ + u8 i; + u8 tot; + + for (i = 0, tot = 0; i < 32; i ++) + { + if ((show->secretBaseSecrets.flags >> i) & 1) + { + tot ++; + } + } + return tot; +} + +u8 sub_80F51AC(TVShow *show, u8 a1) +{ + u8 i; + u8 tot; + + for (i = 0, tot = 0; i < 32; i ++) + { + if ((show->secretBaseSecrets.flags >> i) & 1) + { + if (tot == a1) + { + return sTVSecretBaseSecretsStateLookup[i]; + } + tot ++; + } + } + return 0; +} + +void DoTVShowSecretBaseSecrets(void) +{ + TVShow *show; + u8 state; + u8 bitCount; + u16 i; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + TVShowConvertInternationalString(gStringVar1, show->secretBaseSecrets.baseOwnersName, show->secretBaseSecrets.baseOwnersNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + bitCount = sub_80F5180(show); + if (bitCount == 0) + { + sTVShowState = 8; + } + else + { + show->secretBaseSecrets.savedState = 1; + sTVSecretBaseSecretsRandomValues[0] = Random() % bitCount; + sTVShowState = sub_80F51AC(show, sTVSecretBaseSecretsRandomValues[0]); + } + break; + case 1: + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + bitCount = sub_80F5180(show); + switch (bitCount) + { + case 1: + sTVShowState = 9; + break; + case 2: + show->secretBaseSecrets.savedState = 2; + if (sTVSecretBaseSecretsRandomValues[0] == 0) + { + sTVShowState = sub_80F51AC(show, 1); + } + else + { + sTVShowState = sub_80F51AC(show, 0); + } + break; + default: + for (i = 0; i < 0xFFFF; i ++) + { + sTVSecretBaseSecretsRandomValues[1] = Random() % bitCount; + if (sTVSecretBaseSecretsRandomValues[1] != sTVSecretBaseSecretsRandomValues[0]) + { + break; + } + } + show->secretBaseSecrets.savedState = 2; + sTVShowState = sub_80F51AC(show, sTVSecretBaseSecretsRandomValues[1]); + break; + } + break; + case 2: + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + bitCount = sub_80F5180(show); + if (bitCount == 2) + { + sTVShowState = 9; + } + else + { + for (i = 0; i < 0xFFFF; i ++) + { + sTVSecretBaseSecretsRandomValues[2] = Random() % bitCount; + if (sTVSecretBaseSecretsRandomValues[2] != sTVSecretBaseSecretsRandomValues[0] && sTVSecretBaseSecretsRandomValues[2] != sTVSecretBaseSecretsRandomValues[1]) + { + break; + } + } + show->secretBaseSecrets.savedState = 3; + sTVShowState = sub_80F51AC(show, sTVSecretBaseSecretsRandomValues[2]); + } + break; + case 3: + TVShowConvertInternationalString(gStringVar1, show->secretBaseSecrets.baseOwnersName, show->secretBaseSecrets.baseOwnersNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + TV_PrintIntToStringVar(2, show->secretBaseSecrets.stepsInBase); + if (show->secretBaseSecrets.stepsInBase <= 30) + { + sTVShowState = 4; + } + else if (show->secretBaseSecrets.stepsInBase <= 100) + { + sTVShowState = 5; + } + else + { + sTVShowState = 6; + } + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->secretBaseSecrets.baseOwnersName, show->secretBaseSecrets.baseOwnersNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + sTVShowState = 7; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->secretBaseSecrets.baseOwnersName, show->secretBaseSecrets.baseOwnersNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + sTVShowState = 7; + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->secretBaseSecrets.baseOwnersName, show->secretBaseSecrets.baseOwnersNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + sTVShowState = 7; + break; + case 7: + TVShowConvertInternationalString(gStringVar1, show->secretBaseSecrets.baseOwnersName, show->secretBaseSecrets.baseOwnersNameLanguage); + TVShowConvertInternationalString(gStringVar2, show->secretBaseSecrets.playerName, show->secretBaseSecrets.language); + TVShowDone(); + break; + case 8: + sTVShowState = 3; + break; + case 9: + sTVShowState = 3; + break; + case 10: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 11: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 12: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 13: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 14: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 15: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 16: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 17: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 18: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 19: + StringCopy(gStringVar2, ItemId_GetItem(show->secretBaseSecrets.item)->name); + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 20: + if (show->common.trainerIdLo & 1) + { + sTVShowState = 22; + } + else + { + sTVShowState = 21; + } + break; + case 21: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 22: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 23: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 24: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 25: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 26: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 27: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 28: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 29: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 30: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 31: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 32: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 33: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 34: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 35: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 36: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 37: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 38: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 39: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 40: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 41: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 42: + sTVShowState = show->secretBaseSecrets.savedState; + break; + case 43: + sTVShowState = show->secretBaseSecrets.savedState; + break; + } + ShowFieldMessage(sTVSecretBaseSecretsTextGroup[state]); +} + +void DoTVShowSafariFanClub(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + if (show->safariFanClub.nMonsCaught == 0) + { + sTVShowState = 6; + } + else if (show->safariFanClub.nMonsCaught < 4) + { + sTVShowState = 5; + } + else + { + sTVShowState = 1; + } + break; + case 1: + TVShowConvertInternationalString(gStringVar1, show->safariFanClub.playerName, show->safariFanClub.language); + TV_PrintIntToStringVar(1, show->safariFanClub.nMonsCaught); + if (show->safariFanClub.nPkblkUsed == 0) + { + sTVShowState = 3; + } + else + { + sTVShowState = 2; + } + break; + case 2: + TV_PrintIntToStringVar(1, show->safariFanClub.nPkblkUsed); + sTVShowState = 4; + break; + case 3: + sTVShowState = 4; + break; + case 4: + TVShowConvertInternationalString(gStringVar1, show->safariFanClub.playerName, show->safariFanClub.language); + sTVShowState = 10; + break; + case 5: + TVShowConvertInternationalString(gStringVar1, show->safariFanClub.playerName, show->safariFanClub.language); + TV_PrintIntToStringVar(1, show->safariFanClub.nMonsCaught); + if (show->safariFanClub.nPkblkUsed == 0) + { + sTVShowState = 8; + } + else + { + sTVShowState = 7; + } + break; + case 6: + TVShowConvertInternationalString(gStringVar1, show->safariFanClub.playerName, show->safariFanClub.language); + if (show->safariFanClub.nPkblkUsed == 0) + { + sTVShowState = 8; + } + else + { + sTVShowState = 7; + } + break; + case 7: + TV_PrintIntToStringVar(1, show->safariFanClub.nPkblkUsed); + sTVShowState = 9; + break; + case 8: + sTVShowState = 9; + break; + case 9: + TVShowConvertInternationalString(gStringVar1, show->safariFanClub.playerName, show->safariFanClub.language); + sTVShowState = 10; + break; + case 10: + TVShowDone(); + } + ShowFieldMessage(sTVSafariFanClubTextGroup[state]); +} + +void DoTVShowPokemonContestLiveUpdates2(void) +{ + TVShow *show; + u8 state; + + show = &gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004]; + gScriptResult = FALSE; + state = sTVShowState; + switch (state) + { + case 0: + sub_818E868(gStringVar1, show->contestLiveUpdates2.contestCategory); + if (show->contestLiveUpdates2.pokeblockState == 1) + { + sTVShowState = 1; + } + else if (show->contestLiveUpdates2.pokeblockState == 0) + { + sTVShowState = 2; + } + else + { + sTVShowState = 3; + } + break; + case 1: + case 2: + TVShowConvertInternationalString(gStringVar3, show->contestLiveUpdates2.playerName, show->contestLiveUpdates2.language); + case 3: + TVShowConvertInternationalString(gStringVar2, show->contestLiveUpdates2.nickname, show->contestLiveUpdates2.pokemonNameLanguage); + TVShowDone(); + break; + } + ShowFieldMessage(sTVPokemonContestLiveUpdates2TextGroup[state]); +} + +void TVShowDone(void) +{ + gScriptResult = TRUE; + sTVShowState = 0; + gSaveBlock1Ptr->tvShows[gSpecialVar_0x8004].common.active = FALSE; +} + +void ResetTVShowState(void) +{ + sTVShowState = 0; +} diff --git a/src/unk_text_util_2.c b/src/unk_text_util_2.c new file mode 100644 index 000000000..d88af611f --- /dev/null +++ b/src/unk_text_util_2.c @@ -0,0 +1,219 @@ +#include "global.h" +#include "main.h" +#include "window.h" +#include "text.h" +#include "sound.h" + +static const u8 gUnknown_08616124[] = {1, 2, 4}; +static const u16 gFont6BrailleGlyphs[] = INCBIN_U16("data/graphics/fonts/font6.fwjpnfont"); + +static void DecompressGlyphFont6(u16); + +u16 Font6Func(struct TextPrinter *textPrinter) +{ + u16 char_; + struct TextPrinterSubStruct *sub; + + sub = &textPrinter->sub_union.sub; + switch (textPrinter->state) + { + case 0: + if (gMain.heldKeys & (A_BUTTON | B_BUTTON) && sub->font_type_upper) + { + textPrinter->delayCounter = 0; + } + if (textPrinter->delayCounter && textPrinter->text_speed) + { + textPrinter->delayCounter --; + if (gTextFlags.flag_0 && gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + sub->font_type_upper = TRUE; + textPrinter->delayCounter = 0; + } + return 3; + } + if (gTextFlags.flag_2) + { + textPrinter->delayCounter = 3; + } + else + { + textPrinter->delayCounter = textPrinter->text_speed; + } + char_ = *textPrinter->subPrinter.current_text_offset ++; + switch (char_) + { + case EOS: + return 1; + case CHAR_NEWLINE: + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x; + textPrinter->subPrinter.currentY += gFonts[textPrinter->subPrinter.fontId].maxLetterHeight + textPrinter->subPrinter.lineSpacing; + return 2; + case PLACEHOLDER_BEGIN: + textPrinter->subPrinter.current_text_offset ++; + return 2; + case EXT_CTRL_CODE_BEGIN: + char_ = *textPrinter->subPrinter.current_text_offset ++; + switch (char_) + { + case 1: + textPrinter->subPrinter.fontColor_h = *textPrinter->subPrinter.current_text_offset ++; + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fontColor_h, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 2: + textPrinter->subPrinter.bgColor = *textPrinter->subPrinter.current_text_offset ++; + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fontColor_h, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 3: + textPrinter->subPrinter.shadowColor = *textPrinter->subPrinter.current_text_offset ++; + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fontColor_h, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 4: + textPrinter->subPrinter.fontColor_h = *textPrinter->subPrinter.current_text_offset; + textPrinter->subPrinter.bgColor = *++ textPrinter->subPrinter.current_text_offset; + textPrinter->subPrinter.shadowColor = *++ textPrinter->subPrinter.current_text_offset; + textPrinter->subPrinter.current_text_offset ++; + + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fontColor_h, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 5: + textPrinter->subPrinter.current_text_offset ++; + return 2; + case 6: + sub->font_type = *textPrinter->subPrinter.current_text_offset; + textPrinter->subPrinter.current_text_offset ++; + return 2; + case 7: + return 2; + case 8: + textPrinter->delayCounter = *textPrinter->subPrinter.current_text_offset ++; + textPrinter->state = 6; + return 2; + case 9: + textPrinter->state = 1; + if (gTextFlags.flag_2) + { + sub->frames_visible_counter = 0; + } + return 3; + case 10: + textPrinter->state = 5; + return 3; + case 11: + case 16: + textPrinter->subPrinter.current_text_offset += 2; + return 2; + case 12: + char_ = *++textPrinter->subPrinter.current_text_offset; + break; + case 13: + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x + *textPrinter->subPrinter.current_text_offset ++; + return 2; + case 14: + textPrinter->subPrinter.currentY = textPrinter->subPrinter.y + *textPrinter->subPrinter.current_text_offset ++; + return 2; + case 15: + FillWindowPixelBuffer(textPrinter->subPrinter.windowId, textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); + return 2; + } + break; + case CHAR_PROMPT_CLEAR: + textPrinter->state = 2; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case CHAR_PROMPT_SCROLL: + textPrinter->state = 3; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case 0xF9: + char_ = *textPrinter->subPrinter.current_text_offset ++ | 0x100; + break; + case 0xF8: + textPrinter->subPrinter.current_text_offset ++; + return 0; + } + DecompressGlyphFont6(char_); + CopyGlyphToWindow(textPrinter); + textPrinter->subPrinter.currentX += gUnknown_03002F90[0x80] + textPrinter->subPrinter.letterSpacing; + return 0; + case 1: + if (TextPrinterWait(textPrinter)) + { + textPrinter->state = 0; + } + return 3; + case 2: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + FillWindowPixelBuffer(textPrinter->subPrinter.windowId, textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x; + textPrinter->subPrinter.currentY = textPrinter->subPrinter.y; + textPrinter->state = 0; + } + return 3; + case 3: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + TextPrinterClearDownArrow(textPrinter); + textPrinter->scrollDistance = gFonts[textPrinter->subPrinter.fontId].maxLetterHeight + textPrinter->subPrinter.lineSpacing; + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x; + textPrinter->state = 4; + } + return 3; + case 4: + if (textPrinter->scrollDistance) + { + if (textPrinter->scrollDistance < gUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed]) + { + ScrollWindow(textPrinter->subPrinter.windowId, 0, textPrinter->scrollDistance, textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); + textPrinter->scrollDistance = 0; + } + else + { + ScrollWindow(textPrinter->subPrinter.windowId, 0, gUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed], textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); + textPrinter->scrollDistance -= gUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed]; + } + CopyWindowToVram(textPrinter->subPrinter.windowId, 2); + } + else + { + textPrinter->state = 0; + } + return 3; + case 5: + if (!IsSEPlaying()) + { + textPrinter->state = 0; + } + return 3; + case 6: + if (textPrinter->delayCounter) + { + textPrinter->delayCounter --; + } + else + { + textPrinter->state = 0; + } + return 3; + } + return 1; +} + +static void DecompressGlyphFont6(u16 glyph) +{ + const u16 *glyphs; + + glyphs = gFont6BrailleGlyphs + 0x100 * (glyph / 8) + 0x10 * (glyph % 8); + DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); + DecompressGlyphTile(glyphs + 0x8, (u16 *)(gUnknown_03002F90 + 0x20)); + DecompressGlyphTile(glyphs + 0x80, (u16 *)(gUnknown_03002F90 + 0x40)); + DecompressGlyphTile(glyphs + 0x88, (u16 *)(gUnknown_03002F90 + 0x60)); + gUnknown_03002F90[0x80] = 0x10; + gUnknown_03002F90[0x81] = 0x10; +} + +u8 GetGlyphWidthFont6(void) +{ + return 0x10; +} diff --git a/src/util.c b/src/util.c index 27b7c5ee5..58088c3ee 100644 --- a/src/util.c +++ b/src/util.c @@ -112,7 +112,7 @@ static const u16 sCrc16Table[] = 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78, }; -const u8 gMiscBlank_Gfx[] = INCBIN_U8("graphics/interface/blank.4bpp"); // unused in Emerald +const u8 gMiscBlank_Gfx[] = INCBIN_U8("graphics/interface/blank.4bpp"); u8 CreateInvisibleSpriteWithCallback(void (*callback)(struct Sprite *)) { 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; +} diff --git a/src/window.c b/src/window.c index 164031bee..f4cb48ec0 100644 --- a/src/window.c +++ b/src/window.c @@ -190,7 +190,7 @@ u16 AddWindow(const struct WindowTemplate *template) return win; } -int AddWindowWithoutTileMap(struct WindowTemplate *template) +int AddWindowWithoutTileMap(const struct WindowTemplate *template) { u16 win; u8 bgLayer; @@ -451,7 +451,7 @@ void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); } -void CopyToWindowPixelBuffer(u8 windowId, u8 *src, u16 size, u16 tileOffset) +void CopyToWindowPixelBuffer(u8 windowId, const u8 *src, u16 size, u16 tileOffset) { if (size != 0) CpuCopy16(src, gWindows[windowId].tileData + (0x20 * tileOffset), size); |