diff options
author | Diegoisawesome <diego@domoreaweso.me> | 2017-10-09 13:32:26 -0500 |
---|---|---|
committer | Diegoisawesome <diego@domoreaweso.me> | 2017-10-09 13:32:26 -0500 |
commit | 41db0259759c8e4c3c31c5cf09daed9f85ab5b63 (patch) | |
tree | ab77e37580ab0eb0ee18c28f749d8c8da15dbcf7 /src | |
parent | ae06c13e99162cebd3617f5aafb135bdd8b3f237 (diff) | |
parent | 96c5966ff3676eb1b3463808b83b42e13e1591fd (diff) |
Merge remote-tracking branch 'pret/master' into baserom_extraction
Diffstat (limited to 'src')
33 files changed, 9369 insertions, 204 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..0462615b8 --- /dev/null +++ b/src/battle_2.c @@ -0,0 +1,5653 @@ +#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 "safari_zone.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 u32 gBattleTypeFlags; +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 gBattleOutcome; +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 u16 gLastUsedItem; +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 u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1]; +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 HandleLinkBattleSetup(void); // rom_3 +extern void SetUpBattleVarsAndBirchZigzagoon(void); // rom_3 +extern void sub_8032768(void); // rom_3 +extern void dp12_8087EA4(void); +extern void sub_80356D0(void); +extern void GetFrontierTrainerName(u8* dst, u16 trainerId); // battle tower +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 sub_80729D0(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 void sub_80EC728(void); // tv +extern void sub_80EE184(void); // tv +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[][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) == 3; 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) == 3; 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); + sub_80729D0(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(0, gActiveBank); + gBattleMainFunc = BattleIntroPrintOpponentSendsOut; + } +} + +static void BattleIntroPrintWildMonAttacked(void) +{ + if (gBattleExecBuffer == 0) + { + gBattleMainFunc = BattleIntroPrintPlayerSendsOut; + PrepareStringBattle(0, 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(1, 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(1, 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.ppNumbers[i] = gBattleMons[gActiveBank].pp[i]; + moveInfo.ppWithBonusNumbers[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) + { + Emit_x32(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); + } + Emit_x32(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); + } + } + } + sub_80EC728(); + } + + 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->field_C4 + (gBankAttacker >> 1))) + { + case 1: + case 2: + break; + case 3: + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + if (*(gBattleStruct->field_C6 + gBankAttacker / 2) & 1) + { + if (*(gBattleStruct->field_C6 + gBankAttacker / 2) & 0x3E) + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + while (!(*(gBattleStruct->field_C6 + gBankAttacker / 2) & 1)) + { + *(gBattleStruct->field_C6 + gBankAttacker / 2) >>= 1; + gBattleCommunication[MULTISTRING_CHOOSER]++; + } + } + break; + case 4: + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + if (*(gBattleStruct->field_C6 + (gBankAttacker >> 1)) & 0x80) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK) + PREPARE_STRING_BUFFER(gBattleTextBuff2, 0xD2) + + while (!((*(gBattleStruct->field_C6 + (gBankAttacker >> 1))) & 1)) + { + *(gBattleStruct->field_C6 + gBankAttacker / 2) >>= 1; + gBattleTextBuff1[2]++; + } + + gBattleScripting.animArg1 = gBattleTextBuff1[2] + 14; + gBattleScripting.animArg2 = 0; + } + break; + case 5: + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + break; + } + + gBattlescriptCurrInstr = gUnknown_082DBD3C[*(gBattleStruct->field_C4 + 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_ai_script_commands.c b/src/battle_ai_script_commands.c index dae43f13c..92126e40c 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -73,7 +73,7 @@ extern const struct BaseStats gBaseStats[]; extern const u32 gBitTable[]; extern u8 * const gBattleAI_ScriptsTable[]; -extern u8 b_first_side(u8, u8, u8); +extern u8 GetWhoStrikesFirst(u8, u8, u8); extern void AI_CalcDmg(u8, u8); extern u8 CheckMoveLimitations(); @@ -1756,7 +1756,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, 1) == gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; @@ -1764,7 +1764,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, 1) != gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e0cb3e941..e53292442 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -47,8 +47,8 @@ extern u8 gActiveBank; extern u32 gBattleExecBuffer; extern u8 gNoOfAllBanks; extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; -extern u8 gTurnOrder[BATTLE_BANKS_COUNT]; -extern u8 gUnknown_0202407A[BATTLE_BANKS_COUNT]; +extern u8 gBanksByTurnOrder[BATTLE_BANKS_COUNT]; +extern u8 gActionsByTurnOrder[BATTLE_BANKS_COUNT]; extern u16 gCurrentMove; extern u8 gLastUsedAbility; extern u16 gBattleWeather; @@ -67,7 +67,7 @@ extern u8 gBankAttacker; extern u8 gBankTarget; extern const u8* gBattlescriptCurrInstr; extern u8 gCurrMovePos; -extern u8 gFightStateTracker; +extern u8 gCurrentActionFuncId; extern u32 gHitMarker; extern u8 gBattleMoveFlags; extern u8 gBattleCommunication[]; @@ -92,7 +92,7 @@ extern u16 gMoveToLearn; extern u16 gRandomMove; extern u8 gBankInMenu; extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; -extern u8 gCurrentMoveTurn; +extern u8 gCurrentTurnActionNumber; extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; extern u16 gPartnerTrainerId; @@ -145,8 +145,7 @@ 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 c2_berry_program_update_menu(void); -extern void sub_8035AA4(void); +extern void sub_80356D0(void); // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -332,7 +331,7 @@ 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(void); +static void atk44_end_selection_script(void); static void atk45_playanimation(void); static void atk46_playanimation2(void); static void atk47_setgraphicalstatchangevalues(void); @@ -361,7 +360,7 @@ static void atk5D_getmoneyreward(void); static void atk5E_8025A70(void); static void atk5F_8025B24(void); static void atk60_increment_gamestat(void); -static void atk61_8025BA4(void); +static void atk61_draw_party_status_summary(void); static void atk62_08025C6C(void); static void atk63_jumptorandomattack(void); static void atk64_statusanimation(void); @@ -378,7 +377,7 @@ 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_can_run_frombattle(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); @@ -510,8 +509,8 @@ 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_802BF48(void); -static void atkF7_802BF54(void); +static void atkF6_action_finished(void); +static void atkF7_turn_finished(void); static void atkF8_trainer_slide_back(void); void (* const gBattleScriptingCommandsTable[])(void) = @@ -584,7 +583,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk41_call, atk42_jumpiftype2, atk43_jumpifabilitypresent, - atk44, + atk44_end_selection_script, atk45_playanimation, atk46_playanimation2, atk47_setgraphicalstatchangevalues, @@ -613,7 +612,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk5E_8025A70, atk5F_8025B24, atk60_increment_gamestat, - atk61_8025BA4, + atk61_draw_party_status_summary, atk62_08025C6C, atk63_jumptorandomattack, atk64_statusanimation, @@ -630,7 +629,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk6F_set_visible, atk70_record_last_used_ability, atk71_buffer_move_to_learn, - atk72_jump_if_can_run_frombattle, + atk72_jump_if_run_attempt_success, atk73_hp_thresholds, atk74_hp_thresholds2, atk75_item_effect_on_opponent, @@ -762,8 +761,8 @@ void (* const gBattleScriptingCommandsTable[])(void) = atkF3_nickname_caught_poke, atkF4_subattackerhpbydmg, atkF5_removeattackerstatus1, - atkF6_802BF48, - atkF7_802BF54, + atkF6_action_finished, + atkF7_turn_finished, atkF8_trainer_slide_back }; @@ -1098,9 +1097,9 @@ static void atk00_attackcanceler(void) { s32 i; - if (gBattleOutcome) + if (gBattleOutcome != 0) { - gFightStateTracker = 0xC; + gCurrentActionFuncId = ACTION_FINISHED; return; } if (gBattleMons[gBankAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) @@ -1152,11 +1151,11 @@ static void atk00_attackcanceler(void) for (i = 0; i < gNoOfAllBanks; i++) { - if ((gProtectStructs[gTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) + if ((gProtectStructs[gBanksByTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) { - PressurePPLose(gBankAttacker, gTurnOrder[i], MOVE_SNATCH); - gProtectStructs[gTurnOrder[i]].stealMove = 0; - gBattleScripting.bank = gTurnOrder[i]; + PressurePPLose(gBankAttacker, gBanksByTurnOrder[i], MOVE_SNATCH); + gProtectStructs[gBanksByTurnOrder[i]].stealMove = 0; + gBattleScripting.bank = gBanksByTurnOrder[i]; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SnatchedMove; return; @@ -1601,7 +1600,7 @@ static void atk06_typecalc(void) RecordAbilityBattle(gBankTarget, gLastUsedAbility); } if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - gProtectStructs[gBankAttacker].notEffective = 1; + gProtectStructs[gBankAttacker].targetNotAffected = 1; gBattlescriptCurrInstr++; } @@ -1640,14 +1639,14 @@ static void CheckWonderGuardAndLevitate(void) if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 0) { gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - gProtectStructs[gBankAttacker].notEffective = 1; + 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].notEffective = 1; + gProtectStructs[gBankAttacker].targetNotAffected = 1; } // check super effective @@ -2379,7 +2378,7 @@ u8 BankGetTurnOrder(u8 bank) s32 i; for (i = 0; i < gNoOfAllBanks; i++) { - if (gTurnOrder[i] == bank) + if (gBanksByTurnOrder[i] == bank) break; } return i; @@ -2737,7 +2736,7 @@ void SetMoveEffect(bool8 primary, u8 certain) } else { - if (BankGetTurnOrder(gEffectBank) > gCurrentMoveTurn) + if (BankGetTurnOrder(gEffectBank) > gCurrentTurnActionNumber) gBattleMons[gEffectBank].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; gBattlescriptCurrInstr++; } @@ -3209,7 +3208,7 @@ static void atk19_faint_pokemon(void) && gBattleMons[gBankAttacker].hp != 0 && gCurrentMove != MOVE_STRUGGLE) { - u8 moveIndex = *(gBattleStruct->chosenMovesIds + gBankAttacker); + u8 moveIndex = *(gBattleStruct->chosenMovePositions + gBankAttacker); gBattleMons[gBankAttacker].pp[moveIndex] = 0; BattleScriptPush(gBattlescriptCurrInstr); @@ -3252,7 +3251,7 @@ static void atk1B_faint_effects_clear(void) MarkBufferBankForExecution(gActiveBank); } - UndoEffectsAfterFainting(); // Effects like attractions, trapping, etc. + FaintClearSetData(); // Effects like attractions, trapping, etc. gBattlescriptCurrInstr += 2; } } @@ -4422,13 +4421,13 @@ static void atk3D_end(void) gBattleMoveFlags = 0; gActiveBank = 0; - gFightStateTracker = 0xB; + gCurrentActionFuncId = 0xB; } static void atk3E_end2(void) { gActiveBank = 0; - gFightStateTracker = 0xB; + gCurrentActionFuncId = 0xB; } static void atk3F_end3(void) // pops the main function stack @@ -4463,9 +4462,9 @@ static void atk43_jumpifabilitypresent(void) gBattlescriptCurrInstr += 6; } -static void atk44(void) +static void atk44_end_selection_script(void) { - *(gBankAttacker + gBattleStruct->field_54) = 1; + *(gBankAttacker + gBattleStruct->selectionScriptFinished) = TRUE; } static void atk45_playanimation(void) @@ -5067,7 +5066,7 @@ static void atk49_moveend(void) case 9: // make attacker sprite visible if (gBattleMoveFlags & MOVESTATUS_NOEFFECT || !(gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE)) - || HasMoveFailed(gBankAttacker)) + || WasUnableToUseMove(gBankAttacker)) { gActiveBank = gBankAttacker; EmitSpriteInvisibility(0, FALSE); @@ -5298,7 +5297,7 @@ static void atk4A_typecalc2(void) RecordAbilityBattle(gBankTarget, gLastUsedAbility); } if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - gProtectStructs[gBankAttacker].notEffective = 1; + gProtectStructs[gBankAttacker].targetNotAffected = 1; gBattlescriptCurrInstr++; } @@ -5367,7 +5366,7 @@ static void atk4D_switch_data_update(void) gBattleMons[gActiveBank].status2 = oldData.status2; } - SwitchInClearStructs(); + SwitchInClearSetData(); if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp && gBattleMons[gActiveBank].hp != 0 && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) @@ -5904,15 +5903,15 @@ static void atk51_switch_handle_order(void) gBattleCommunication[0] = gBattleBufferB[gActiveBank][1]; *(gBattleStruct->field_5C + gActiveBank) = gBattleBufferB[gActiveBank][1]; - if ((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) == (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) + 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 ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0); - *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4; - *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 2) = 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) { @@ -5984,8 +5983,8 @@ static void atk52_switch_in_effects(void) for (i = 0; i < gNoOfAllBanks; i++) { - if (gTurnOrder[i] == gActiveBank) - gUnknown_0202407A[i] = 0xC; + if (gBanksByTurnOrder[i] == gActiveBank) + gActionsByTurnOrder[i] = ACTION_CANCEL_PARTNER; } for (i = 0; i < gNoOfAllBanks; i++) @@ -6412,7 +6411,7 @@ static void atk60_increment_gamestat(void) gBattlescriptCurrInstr += 2; } -static void atk61_8025BA4(void) +static void atk61_draw_party_status_summary(void) { s32 i; struct Pokemon* party; @@ -6443,7 +6442,7 @@ static void atk61_8025BA4(void) } } - EmitCmd48(0, hpStatuses, 1); + EmitDrawPartyStatusSummary(0, hpStatuses, 1); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; @@ -6570,7 +6569,7 @@ static void atk68_80246A0(void) s32 i; for (i = 0; i < gNoOfAllBanks; i++) - gUnknown_0202407A[i] = 0xC; + gActionsByTurnOrder[i] = ACTION_CANCEL_PARTNER; gBattlescriptCurrInstr++; } @@ -6957,9 +6956,9 @@ static void atk71_buffer_move_to_learn(void) gBattlescriptCurrInstr++; } -static void atk72_jump_if_can_run_frombattle(void) +static void atk72_jump_if_run_attempt_success(void) { - if (CanRunFromBattle(gBank1)) + if (TryRunFromBattle(gBank1)) gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); else gBattlescriptCurrInstr += 5; @@ -7046,7 +7045,7 @@ static void atk76_various(void) else gBankTarget = gActiveBank; break; - case 2: + case VARIOUS_CAN_RUN_FROM_BATTLE: gBattleCommunication[0] = IsRunningFromBattleImpossible(); break; case VARIOUS_GET_MOVE_TARGET: @@ -7197,7 +7196,7 @@ static void atk76_various(void) gBattleOutcome = BATTLE_OPPONENT_TELEPORTED; break; case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC: - EmitPlaySound(0, 0x19C, 1); + EmitPlaySound(0, BGM_KACHI1, 1); MarkBufferBankForExecution(gActiveBank); break; } @@ -7213,7 +7212,7 @@ static void atk77_set_protect_like(void) // protect and endure if (lastMove != MOVE_PROTECT && lastMove != MOVE_DETECT && lastMove != MOVE_ENDURE) gDisableStructs[gBankAttacker].protectUses = 0; - if (gCurrentMoveTurn == (gNoOfAllBanks - 1)) + if (gCurrentTurnActionNumber == (gNoOfAllBanks - 1)) notLastTurn = FALSE; if (sProtectSuccessRates[gDisableStructs[gBankAttacker].protectUses] >= Random() && notLastTurn) @@ -9519,19 +9518,19 @@ static void atkB3_rolloutdamagecalculation(void) if (!(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) // first hit { - gDisableStructs[gBankAttacker].rolloutTimer1 = 5; - gDisableStructs[gBankAttacker].rolloutTimer2 = 5; + gDisableStructs[gBankAttacker].rolloutCounter1 = 5; + gDisableStructs[gBankAttacker].rolloutCounter2 = 5; gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gBankAttacker] = gCurrentMove; } - if (--gDisableStructs[gBankAttacker].rolloutTimer1 == 0) // last hit + if (--gDisableStructs[gBankAttacker].rolloutCounter1 == 0) // last hit { gBattleMons[gBankAttacker].status2 &= ~(STATUS2_MULTIPLETURNS); } gDynamicBasePower = gBattleMoves[gCurrentMove].power; - for (i = 1; i < (5 - gDisableStructs[gBankAttacker].rolloutTimer1); i++) + for (i = 1; i < (5 - gDisableStructs[gBankAttacker].rolloutCounter1); i++) gDynamicBasePower *= 2; if (gBattleMons[gBankAttacker].status2 & STATUS2_DEFENSE_CURL) @@ -9711,12 +9710,12 @@ static void atkBA_jumpifnopursuitswitchdmg(void) for (i = 0; i < gNoOfAllBanks; i++) { - if (gTurnOrder[i] == gBankTarget) - gUnknown_0202407A[i] = 11; + if (gBanksByTurnOrder[i] == gBankTarget) + gActionsByTurnOrder[i] = 11; } gCurrentMove = MOVE_PURSUIT; - gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovesIds + gBankTarget); + gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovePositions + gBankTarget); gBattlescriptCurrInstr += 5; gBattleScripting.animTurn = 1; gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); @@ -10632,7 +10631,7 @@ static void atkDF_setmagiccoat(void) { gBankTarget = gBankAttacker; gSpecialStatuses[gBankAttacker].flag20 = 1; - if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn + if (gCurrentTurnActionNumber == gNoOfAllBanks - 1) // moves last turn { gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); } @@ -10646,7 +10645,7 @@ static void atkDF_setmagiccoat(void) static void atkE0_setstealstatchange(void) // snatch { gSpecialStatuses[gBankAttacker].flag20 = 1; - if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn + if (gCurrentTurnActionNumber == gNoOfAllBanks - 1) // moves last turn { gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); } @@ -10943,7 +10942,7 @@ static void atkEC_pursuit_sth(void) && gActionForBanks[gActiveBank] == 0 && gChosenMovesByBanks[gActiveBank] == MOVE_PURSUIT) { - gUnknown_0202407A[gActiveBank] = 11; + gActionsByTurnOrder[gActiveBank] = 11; gCurrentMove = MOVE_PURSUIT; gBattlescriptCurrInstr += 5; gBattleScripting.animTurn = 1; @@ -11217,8 +11216,8 @@ static void atkF2_display_dex_info(void) } break; case 3: - c2_berry_program_update_menu(); - sub_8035AA4(); + sub_80356D0(); + LoadBattleTextboxAndBackground(); gBattle_BG3_X = 0x100; gBattleCommunication[0]++; break; @@ -11394,15 +11393,15 @@ static void atkF5_removeattackerstatus1(void) gBattlescriptCurrInstr++; } -static void atkF6_802BF48(void) +static void atkF6_action_finished(void) { - gFightStateTracker = 0xC; + gCurrentActionFuncId = ACTION_FINISHED; } -static void atkF7_802BF54(void) +static void atkF7_turn_finished(void) { - gFightStateTracker = 0xC; - gCurrentMoveTurn = gNoOfAllBanks; + gCurrentActionFuncId = ACTION_FINISHED; + gCurrentTurnActionNumber = gNoOfAllBanks; } static void atkF8_trainer_slide_back(void) diff --git a/src/battle_3.c b/src/battle_util.c index e42d9317d..c6762dd99 100644 --- a/src/battle_3.c +++ b/src/battle_util.c @@ -17,9 +17,10 @@ #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; @@ -32,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; @@ -45,16 +46,17 @@ 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[]; @@ -169,24 +171,278 @@ 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 u8 b_first_side(u8, u8, u8); -extern void sub_803CEDC(u8, u8); -extern void BattleTurnPassed(void); -extern void sub_803F9EC(); -extern bool8 sub_80423F4(u8 bank, u8, 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); + +// 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 < sub_8009FCC(); 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; +} + +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) { @@ -203,7 +459,7 @@ 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]]; @@ -221,7 +477,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DAE1F; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DAE1F; limitations = 1; } } @@ -236,7 +492,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB089; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB089; limitations++; } } @@ -251,7 +507,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB0A0; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB0A0; limitations++; } } @@ -266,7 +522,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB181; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB181; limitations++; } } @@ -288,7 +544,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB812; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB812; limitations++; } } @@ -301,7 +557,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } else { - gUnknown_02024220[gActiveBank] = gUnknown_082DB076; + gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB076; limitations++; } } @@ -352,7 +608,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 { @@ -407,15 +663,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); } } @@ -540,7 +796,7 @@ 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) @@ -652,7 +908,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++; @@ -833,7 +1089,7 @@ u8 TurnBasedEffects(void) { gBankAttacker = gActiveBank; gBattleMons[gActiveBank].status2 -= 0x10; // uproar timer goes down - if (HasMoveFailed(gActiveBank)) + if (WasUnableToUseMove(gActiveBank)) { CancelMultiTurnMoves(gActiveBank); gBattleCommunication[MULTISTRING_CHOOSER] = 1; @@ -859,7 +1115,7 @@ u8 TurnBasedEffects(void) if (gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE) { gBattleMons[gActiveBank].status2 -= 0x400; - if (HasMoveFailed(gActiveBank)) + if (WasUnableToUseMove(gActiveBank)) CancelMultiTurnMoves(gActiveBank); else if (!(gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE) && (gBattleMons[gActiveBank].status2 & STATUS2_MULTIPLETURNS)) @@ -1021,7 +1277,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++; @@ -1130,7 +1386,7 @@ 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])) { @@ -1159,7 +1415,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++) @@ -1667,7 +1923,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBankAttacker = bank; switch (gLastUsedAbility) { - case 0xFF: //weather from overworld + case ABILITYEFFECT_SWITCH_IN_WEATHER: //_08042A86 switch (weather_get_current()) { @@ -1850,12 +2106,12 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) //_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; @@ -3156,7 +3412,7 @@ _08042EF8:\n\ bl _0804441E\n\ _08042F02:\n\ movs r4, 0\n\ - ldr r0, =gSoundMovesTable\n\ + ldr r0, =sSoundMovesTable\n\ ldrh r2, [r0]\n\ ldr r3, =0x0000ffff\n\ adds r1, r0, 0\n\ @@ -5444,8 +5700,8 @@ 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 BattleScriptPushCursorAndCallback(const u8* BS_ptr) @@ -5453,7 +5709,7 @@ void BattleScriptPushCursorAndCallback(const u8* BS_ptr) BattleScriptPushCursor(); gBattlescriptCurrInstr = BS_ptr; BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size++] = gBattleMainFunc; - gBattleMainFunc = sub_803E08C; + gBattleMainFunc = RunBattleScriptCommands; } enum @@ -5523,7 +5779,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: @@ -6188,14 +6444,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](); 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..83d32b56c --- /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) +{ + gFieldEffectSpawnParams[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) +{ + gFieldEffectSpawnParams[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); + FlagReset(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 FlagReset\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/diploma.c b/src/diploma.c new file mode 100755 index 000000000..f2cbcabb7 --- /dev/null +++ b/src/diploma.c @@ -0,0 +1,218 @@ +#include "global.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 void **gDiplomaTilemapPtr = {NULL}; + +static void VBlankCB(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static const u16 gDiplomaPalettes[][16] = +{ + INCBIN_U16("graphics/misc/diploma_national.gbapal"), + INCBIN_U16("graphics/misc/diploma_hoenn.gbapal"), +}; + +static const u8 gDiplomaTilemap[] = INCBIN_U8("graphics/misc/diploma_map.bin.lz"); +static const u8 gDiplomaTiles[] = 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(gDiplomaPalettes, 0, 64); + gDiplomaTilemapPtr = malloc(0x1000); + InitDiplomaBg(); + InitDiplomaWindow(); + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, &gDiplomaTiles, 0, 0, 0); + while (free_temp_tile_data_buffers_if_possible()) + ; + LZDecompressWram(&gDiplomaTilemap, gDiplomaTilemapPtr); + 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(gDiplomaTilemapPtr); + 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 gDiplomaBgTemplates[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, gDiplomaBgTemplates, 2); + SetBgTilemapBuffer(1, gDiplomaTilemapPtr); + 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 gDiplomaWinTemplates[2] = +{ + { + .priority = 0, + .tilemapLeft = 5, + .tilemapTop = 2, + .width = 20, + .height = 16, + .paletteNum = 15, + .baseBlock = 1, + }, + DUMMY_WIN_TEMPLATE, +}; + +static void InitDiplomaWindow(void) +{ + InitWindows(gDiplomaWinTemplates); + 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/egg_hatch.c b/src/egg_hatch.c index 6d14e92f0..4e4c10090 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -64,8 +64,8 @@ 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); @@ -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; @@ -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/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_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/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/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/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/palette.c b/src/palette.c index aa9a84e4c..d60efdbc5 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[0x200] = {0}; +EWRAM_DATA u16 gPlttBufferFaded[0x200] = {0}; +EWRAM_DATA struct PaletteStruct sPaletteStructs[0x10] = {0}; +EWRAM_DATA struct PaletteFadeControl gPaletteFade = {0}; +static EWRAM_DATA u32 gFiller_2037FE0 = 0; +static EWRAM_DATA u32 sPlttBufferTransferPending = 0; +EWRAM_DATA u8 gPaletteDecompressionBuffer[0x400] = {0}; -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_2.c b/src/pokemon_2.c index c3d3bf8cf..ee54f0e4d 100644 --- a/src/pokemon_2.c +++ b/src/pokemon_2.c @@ -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]) @@ -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; diff --git a/src/pokemon_3.c b/src/pokemon_3.c index d44c0cb2f..5ff99aee2 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -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++) @@ -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_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/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/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/save.c b/src/save.c index aee20d451..2c1b26ca9 100644 --- a/src/save.c +++ b/src/save.c @@ -15,7 +15,6 @@ 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; @@ -806,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 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..87067e14d --- /dev/null +++ b/src/save_location.c @@ -0,0 +1,145 @@ +#include "global.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 gSaveLocationPokeCenterList[] = +{ + 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(gSaveLocationPokeCenterList); +} + +static const u16 gSaveLocationReloadLocList[] = // 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(gSaveLocationReloadLocList); +} + +// nulled out list. unknown what this would have been +static const u16 gUnknown_0861440E[] = +{ + 0xFFFF, +}; + +bool32 sub_81AFCEC(void) +{ + return IsCurMapInLocationList(gUnknown_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..b56a53caf --- /dev/null +++ b/src/scrcmd.c @@ -0,0 +1,15 @@ + +// Includes +#include "global.h" + +// Static type declarations + +// Static RAM declarations + +IWRAM_DATA u8 gUnknown_03000F30; + +// Static ROM declarations + +// .rodata + +// .text 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/text.c b/src/text.c index 0081a8244..7cc46cd92 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, @@ -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/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/window.c b/src/window.c index 704060b9d..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; |