pokeemerald/src/battle_main.c

5229 lines
190 KiB
C
Raw Normal View History

2017-10-01 01:12:42 +02:00
#include "global.h"
#include "battle.h"
#include "battle_anim.h"
2018-11-13 23:28:46 +01:00
#include "battle_ai_script_commands.h"
#include "battle_arena.h"
#include "battle_controllers.h"
2018-02-09 01:09:02 +01:00
#include "battle_interface.h"
2018-12-07 20:47:20 +01:00
#include "battle_main.h"
2018-11-13 23:28:46 +01:00
#include "battle_message.h"
2018-11-18 17:52:22 +01:00
#include "battle_pyramid.h"
2018-11-13 23:28:46 +01:00
#include "battle_scripts.h"
#include "battle_setup.h"
#include "battle_tower.h"
#include "battle_util.h"
2017-10-01 01:12:42 +02:00
#include "berry.h"
2018-11-13 23:28:46 +01:00
#include "bg.h"
2019-04-04 23:53:06 +02:00
#include "data.h"
2018-11-13 23:28:46 +01:00
#include "decompress.h"
2018-11-14 01:01:50 +01:00
#include "dma3.h"
2018-11-13 23:28:46 +01:00
#include "event_data.h"
#include "evolution_scene.h"
2018-12-19 03:15:59 +01:00
#include "graphics.h"
2018-11-13 23:28:46 +01:00
#include "gpu_regs.h"
#include "international_string_util.h"
2017-10-02 23:32:39 +02:00
#include "item.h"
2017-10-01 01:12:42 +02:00
#include "link.h"
2017-11-11 04:08:17 +01:00
#include "link_rfu.h"
2018-11-13 23:28:46 +01:00
#include "load_save.h"
#include "main.h"
#include "malloc.h"
2017-10-01 18:54:01 +02:00
#include "m4a.h"
2018-11-13 23:28:46 +01:00
#include "palette.h"
#include "party_menu.h"
#include "pokeball.h"
#include "pokedex.h"
#include "pokemon.h"
#include "random.h"
2018-11-13 23:28:46 +01:00
#include "recorded_battle.h"
#include "roamer.h"
#include "safari_zone.h"
#include "scanline_effect.h"
2017-10-01 18:54:01 +02:00
#include "sound.h"
#include "sprite.h"
2018-11-13 23:28:46 +01:00
#include "string_util.h"
2018-12-24 00:02:29 +01:00
#include "strings.h"
2018-11-13 23:28:46 +01:00
#include "task.h"
#include "text.h"
2017-10-02 23:32:39 +02:00
#include "trig.h"
2018-11-13 23:28:46 +01:00
#include "tv.h"
#include "util.h"
#include "window.h"
2017-12-05 18:55:48 +01:00
#include "constants/abilities.h"
2018-11-13 23:28:46 +01:00
#include "constants/battle_move_effects.h"
#include "constants/battle_string_ids.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
2017-12-11 19:27:51 +01:00
#include "constants/moves.h"
2019-10-18 01:22:03 +02:00
#include "constants/party_menu.h"
2018-06-20 23:07:51 +02:00
#include "constants/rgb.h"
2018-11-13 23:28:46 +01:00
#include "constants/songs.h"
2018-11-14 01:01:50 +01:00
#include "constants/trainers.h"
2019-03-02 04:32:50 +01:00
#include "cable_club.h"
2017-10-01 01:12:42 +02:00
2018-06-17 16:48:58 +02:00
extern const struct BgTemplate gBattleBgTemplates[];
2018-06-28 21:06:32 +02:00
extern const struct WindowTemplate *const gBattleWindowTemplates[];
2017-10-02 23:32:39 +02:00
2017-10-01 01:12:42 +02:00
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);
2017-10-01 18:54:01 +02:00
static void TryCorrectShedinjaLanguage(struct Pokemon *mon);
static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer);
2017-10-06 19:09:37 +02:00
static void BattleMainCB1(void);
2021-01-23 02:03:21 +01:00
static void CB2_EndLinkBattle(void);
static void EndLinkBattleInSteps(void);
2021-10-04 16:21:03 +02:00
static void CB2_InitAskRecordBattle(void);
static void CB2_AskRecordBattle(void);
static void AskRecordBattle(void);
static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite);
static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite);
static void SpriteCB_WildMonAnimate(struct Sprite *sprite);
2021-10-04 16:21:03 +02:00
static void SpriteCB_Flicker(struct Sprite *sprite);
2018-06-20 23:07:51 +02:00
static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite);
static void SpriteCB_BlinkVisible(struct Sprite *sprite);
2021-10-04 16:21:03 +02:00
static void SpriteCB_Idle(struct Sprite *sprite);
2021-01-23 05:22:37 +01:00
static void SpriteCB_BattleSpriteSlideLeft(struct Sprite *sprite);
2017-10-06 19:09:37 +02:00
static void TurnValuesCleanUp(bool8 var0);
2018-06-20 23:07:51 +02:00
static void SpriteCB_BounceEffect(struct Sprite *sprite);
2017-10-02 23:32:39 +02:00
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);
2017-10-06 19:09:37 +02:00
static void HandleTurnActionSelectionState(void);
2017-10-06 00:12:01 +02:00
static void RunTurnActionsFunctions(void);
2018-02-08 11:17:41 +01:00
static void SetActionsAndBattlersTurnOrder(void);
static void UpdateBattlerPartyOrdersOnSwitch(void);
static bool8 AllAtActionConfirmed(void);
2017-10-06 00:12:01 +02:00
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void);
static void FreeResetData_ReturnToOvOrDoEvolutions(void);
static void ReturnFromBattleToOverworld(void);
static void TryEvolvePokemon(void);
static void WaitForEvoSceneToFinish(void);
2017-10-06 19:09:37 +02:00
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);
2022-07-29 17:15:33 +02:00
static void SpriteCB_UnusedBattleInit(struct Sprite *sprite);
2021-10-04 16:21:03 +02:00
static void SpriteCB_UnusedBattleInit_Main(struct Sprite *sprite);
2018-11-19 17:36:39 +01:00
EWRAM_DATA u16 gBattle_BG0_X = 0;
EWRAM_DATA u16 gBattle_BG0_Y = 0;
EWRAM_DATA u16 gBattle_BG1_X = 0;
EWRAM_DATA u16 gBattle_BG1_Y = 0;
EWRAM_DATA u16 gBattle_BG2_X = 0;
EWRAM_DATA u16 gBattle_BG2_Y = 0;
EWRAM_DATA u16 gBattle_BG3_X = 0;
EWRAM_DATA u16 gBattle_BG3_Y = 0;
EWRAM_DATA u16 gBattle_WIN0H = 0;
EWRAM_DATA u16 gBattle_WIN0V = 0;
EWRAM_DATA u16 gBattle_WIN1H = 0;
EWRAM_DATA u16 gBattle_WIN1V = 0;
2018-06-30 15:35:54 +02:00
EWRAM_DATA u8 gDisplayedStringBattle[300] = {0};
EWRAM_DATA u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT] = {0};
EWRAM_DATA u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT] = {0};
EWRAM_DATA u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT] = {0};
2021-10-04 16:21:03 +02:00
// The below array is never intentionally used. However, Juan's
// defeat text (SootopolisCity_Gym_1F_Text_JuanDefeat) is too long
// for gDisplayedStringBattle and overflows into this array. If it
// is removed (and none of the buffers above are increased in size)
// it will instead overflow into useful data.
EWRAM_DATA static u32 sFlickerArray[25] = {0};
2018-02-07 22:53:40 +01:00
EWRAM_DATA u32 gBattleTypeFlags = 0;
EWRAM_DATA u8 gBattleTerrain = 0;
EWRAM_DATA u32 gUnusedFirstBattleVar1 = 0; // Never read
2021-10-04 16:21:03 +02:00
EWRAM_DATA struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE] = {0};
EWRAM_DATA static struct MultiPartnerMenuPokemon* sMultiPartnerPartyBuffer = NULL;
EWRAM_DATA u8 *gBattleAnimBgTileBuffer = NULL;
EWRAM_DATA u8 *gBattleAnimBgTilemapBuffer = NULL;
2018-02-07 22:53:40 +01:00
EWRAM_DATA u8 gBattleBufferA[MAX_BATTLERS_COUNT][0x200] = {0};
EWRAM_DATA u8 gBattleBufferB[MAX_BATTLERS_COUNT][0x200] = {0};
EWRAM_DATA u8 gActiveBattler = 0;
EWRAM_DATA u32 gBattleControllerExecFlags = 0;
EWRAM_DATA u8 gBattlersCount = 0;
EWRAM_DATA u16 gBattlerPartyIndexes[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gBattlerPositions[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gActionsByTurnOrder[MAX_BATTLERS_COUNT] = {0};
2018-06-28 21:06:32 +02:00
EWRAM_DATA u8 gBattlerByTurnOrder[MAX_BATTLERS_COUNT] = {0};
2018-02-07 22:53:40 +01:00
EWRAM_DATA u8 gCurrentTurnActionNumber = 0;
EWRAM_DATA u8 gCurrentActionFuncId = 0;
EWRAM_DATA struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gBattlerSpriteIds[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gCurrMovePos = 0;
2018-02-08 11:17:41 +01:00
EWRAM_DATA u8 gChosenMovePos = 0;
2018-02-07 22:53:40 +01:00
EWRAM_DATA u16 gCurrentMove = 0;
EWRAM_DATA u16 gChosenMove = 0;
2018-09-22 18:41:00 +02:00
EWRAM_DATA u16 gCalledMove = 0;
2018-02-07 22:53:40 +01:00
EWRAM_DATA s32 gBattleMoveDamage = 0;
EWRAM_DATA s32 gHpDealt = 0;
EWRAM_DATA s32 gTakenDmg[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastUsedItem = 0;
EWRAM_DATA u8 gLastUsedAbility = 0;
EWRAM_DATA u8 gBattlerAttacker = 0;
EWRAM_DATA u8 gBattlerTarget = 0;
2018-02-08 11:17:41 +01:00
EWRAM_DATA u8 gBattlerFainted = 0;
EWRAM_DATA u8 gEffectBattler = 0;
2018-02-08 12:13:29 +01:00
EWRAM_DATA u8 gPotentialItemEffectBattler = 0;
2018-02-07 22:53:40 +01:00
EWRAM_DATA u8 gAbsentBattlerFlags = 0;
EWRAM_DATA u8 gCritMultiplier = 0;
EWRAM_DATA u8 gMultiHitCounter = 0;
EWRAM_DATA const u8 *gBattlescriptCurrInstr = NULL;
EWRAM_DATA u32 gUnusedBattleMainVar = 0;
EWRAM_DATA u8 gChosenActionByBattler[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA const u8 *gSelectionBattleScripts[MAX_BATTLERS_COUNT] = {NULL};
EWRAM_DATA const u8 *gPalaceSelectionBattleScripts[MAX_BATTLERS_COUNT] = {NULL};
EWRAM_DATA u16 gLastPrintedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastLandedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastHitByType[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastResultingMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLockedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gLastHitBy[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gChosenMoveByBattler[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gMoveResultFlags = 0;
EWRAM_DATA u32 gHitMarker = 0;
2018-02-08 11:17:41 +01:00
EWRAM_DATA static u8 sUnusedBattlersArray[MAX_BATTLERS_COUNT] = {0};
2018-02-07 22:53:40 +01:00
EWRAM_DATA u8 gTakenDmgByBattler[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gUnusedFirstBattleVar2 = 0; // Never read
2018-02-07 22:53:40 +01:00
EWRAM_DATA u16 gSideStatuses[2] = {0};
EWRAM_DATA struct SideTimer gSideTimers[2] = {0};
EWRAM_DATA u32 gStatuses3[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gPauseCounterBattle = 0;
EWRAM_DATA u16 gPaydayMoney = 0;
EWRAM_DATA u16 gRandomTurnNumber = 0;
EWRAM_DATA u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT] = {0};
EWRAM_DATA u8 gBattleOutcome = 0;
EWRAM_DATA struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA struct SpecialStatus gSpecialStatuses[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gBattleWeather = 0;
EWRAM_DATA struct WishFutureKnock gWishFutureKnock = {0};
2018-02-08 11:17:41 +01:00
EWRAM_DATA u16 gIntroSlideFlags = 0;
2018-02-07 22:53:40 +01:00
EWRAM_DATA u8 gSentPokesToOpponent[2] = {0};
EWRAM_DATA u16 gDynamicBasePower = 0;
EWRAM_DATA u16 gExpShareExp = 0;
EWRAM_DATA struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA struct BattleScripting gBattleScripting = {0};
EWRAM_DATA struct BattleStruct *gBattleStruct = NULL;
EWRAM_DATA u8 *gLinkBattleSendBuffer = NULL;
EWRAM_DATA u8 *gLinkBattleRecvBuffer = NULL;
EWRAM_DATA struct BattleResources *gBattleResources = NULL;
EWRAM_DATA u8 gActionSelectionCursor[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gMoveSelectionCursor[MAX_BATTLERS_COUNT] = {0};
2018-02-08 11:17:41 +01:00
EWRAM_DATA u8 gBattlerStatusSummaryTaskId[MAX_BATTLERS_COUNT] = {0};
2018-02-07 22:53:40 +01:00
EWRAM_DATA u8 gBattlerInMenuId = 0;
EWRAM_DATA bool8 gDoingBattleAnim = FALSE;
EWRAM_DATA u32 gTransformedPersonalities[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gPlayerDpadHoldFrames = 0;
EWRAM_DATA struct BattleSpriteData *gBattleSpritesDataPtr = NULL;
EWRAM_DATA struct MonSpritesGfx *gMonSpritesGfxPtr = NULL;
2021-01-23 03:35:16 +01:00
EWRAM_DATA struct BattleHealthboxInfo *gBattleControllerOpponentHealthboxData = NULL; // Never read
EWRAM_DATA struct BattleHealthboxInfo *gBattleControllerOpponentFlankHealthboxData = NULL; // Never read
2018-02-07 22:53:40 +01:00
EWRAM_DATA u16 gBattleMovePower = 0;
EWRAM_DATA u16 gMoveToLearn = 0;
EWRAM_DATA u8 gBattleMonForms[MAX_BATTLERS_COUNT] = {0};
2018-02-07 23:21:51 +01:00
void (*gPreBattleCallback1)(void);
void (*gBattleMainFunc)(void);
struct BattleResults gBattleResults;
u8 gLeveledUpInBattle;
void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(void);
u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
u8 gMultiUsePlayerCursor;
u8 gNumberOfMovesToChoose;
2021-01-23 02:03:21 +01:00
u8 gBattleControllerData[MAX_BATTLERS_COUNT]; // Used by the battle controllers to store misc sprite/task IDs for each battler
2018-02-07 23:21:51 +01:00
2018-12-23 14:52:47 +01:00
static const struct ScanlineEffectParams sIntroScanlineParams16Bit =
{
2021-11-10 23:01:21 +01:00
&REG_BG3HOFS, SCANLINE_EFFECT_DMACNT_16BIT, 1
2018-12-23 14:52:47 +01:00
};
// unused
static const struct ScanlineEffectParams sIntroScanlineParams32Bit =
{
2021-11-10 23:01:21 +01:00
&REG_BG3HOFS, SCANLINE_EFFECT_DMACNT_32BIT, 1
2018-12-23 14:52:47 +01:00
};
2021-10-04 16:21:03 +02:00
const struct SpriteTemplate gUnusedBattleInitSprite =
2018-12-23 14:52:47 +01:00
{
.tileTag = 0,
.paletteTag = 0,
.oam = &gDummyOamData,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
2021-10-04 16:21:03 +02:00
.callback = SpriteCB_UnusedBattleInit,
2018-12-23 14:52:47 +01:00
};
static const u8 sText_ShedinjaJpnName[] = _("ヌケニン"); // Nukenin
2021-01-23 05:22:37 +01:00
const struct OamData gOamData_BattleSpriteOpponentSide =
2018-12-23 14:52:47 +01:00
{
.y = 0,
2019-04-02 00:31:10 +02:00
.affineMode = ST_OAM_AFFINE_NORMAL,
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
2018-12-23 14:52:47 +01:00
.x = 0,
.size = SPRITE_SIZE(64x64),
2018-12-23 14:52:47 +01:00
.tileNum = 0,
.priority = 2,
.paletteNum = 0,
2019-04-02 00:31:10 +02:00
.affineParam = 0,
2018-12-23 14:52:47 +01:00
};
2021-01-23 05:22:37 +01:00
const struct OamData gOamData_BattleSpritePlayerSide =
2018-12-23 14:52:47 +01:00
{
.y = 0,
2019-04-02 00:31:10 +02:00
.affineMode = ST_OAM_AFFINE_NORMAL,
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
2018-12-23 14:52:47 +01:00
.x = 0,
.size = SPRITE_SIZE(64x64),
2018-12-23 14:52:47 +01:00
.tileNum = 0,
.priority = 2,
.paletteNum = 2,
2019-04-02 00:31:10 +02:00
.affineParam = 0,
2018-12-23 14:52:47 +01:00
};
2018-12-23 13:52:53 +01:00
// Unknown and unused data. Feel free to remove.
2021-01-23 05:22:37 +01:00
static const u16 sUnused1[] = {0, 5, 0xfffe, 0};
static const u16 *const sUnused1Ptr = sUnused1;
static const u16 sUnused2[] = {0xfff0, 0, 0x0400, 0, 0, 0, 0x3c00, 0, 0x7ffe, 1, 0, 0};
static const u16 *const sUnused2Ptr = sUnused2;
2018-12-23 13:52:53 +01:00
2021-11-08 19:18:58 +01:00
static const s8 sCenterToCornerVecXs[8] ={-32, -16, -16, -32, -32};
2018-02-26 14:29:17 +01:00
// format: attacking type, defending type, damage multiplier
// the multiplier is a (decimal) fixed-point number:
// 20 is ×2.0 TYPE_MUL_SUPER_EFFECTIVE
// 10 is ×1.0 TYPE_MUL_NORMAL
// 05 is ×0.5 TYPE_MUL_NOT_EFFECTIVE
// 00 is ×0.0 TYPE_MUL_NO_EFFECT
const u8 gTypeEffectiveness[336] =
{
TYPE_NORMAL, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE,
TYPE_NORMAL, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIRE, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIRE, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIRE, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIRE, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIRE, TYPE_BUG, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIRE, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIRE, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIRE, TYPE_STEEL, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_WATER, TYPE_FIRE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_WATER, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE,
TYPE_WATER, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE,
TYPE_WATER, TYPE_GROUND, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_WATER, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_WATER, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ELECTRIC, TYPE_WATER, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ELECTRIC, TYPE_ELECTRIC, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ELECTRIC, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ELECTRIC, TYPE_GROUND, TYPE_MUL_NO_EFFECT,
TYPE_ELECTRIC, TYPE_FLYING, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ELECTRIC, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_WATER, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GRASS, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_GROUND, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GRASS, TYPE_FLYING, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_BUG, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GRASS, TYPE_DRAGON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GRASS, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ICE, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ICE, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ICE, TYPE_ICE, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ICE, TYPE_GROUND, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ICE, TYPE_FLYING, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ICE, TYPE_DRAGON, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ICE, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ICE, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIGHTING, TYPE_NORMAL, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIGHTING, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIGHTING, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIGHTING, TYPE_FLYING, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIGHTING, TYPE_PSYCHIC, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIGHTING, TYPE_BUG, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FIGHTING, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIGHTING, TYPE_DARK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FIGHTING, TYPE_STEEL, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_POISON, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_POISON, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_POISON, TYPE_GROUND, TYPE_MUL_NOT_EFFECTIVE,
TYPE_POISON, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE,
TYPE_POISON, TYPE_GHOST, TYPE_MUL_NOT_EFFECTIVE,
TYPE_POISON, TYPE_STEEL, TYPE_MUL_NO_EFFECT,
TYPE_GROUND, TYPE_FIRE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GROUND, TYPE_ELECTRIC, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GROUND, TYPE_GRASS, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GROUND, TYPE_POISON, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GROUND, TYPE_FLYING, TYPE_MUL_NO_EFFECT,
TYPE_GROUND, TYPE_BUG, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GROUND, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GROUND, TYPE_STEEL, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FLYING, TYPE_ELECTRIC, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FLYING, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FLYING, TYPE_FIGHTING, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FLYING, TYPE_BUG, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_FLYING, TYPE_ROCK, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FLYING, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_PSYCHIC, TYPE_FIGHTING, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_PSYCHIC, TYPE_POISON, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_PSYCHIC, TYPE_PSYCHIC, TYPE_MUL_NOT_EFFECTIVE,
TYPE_PSYCHIC, TYPE_DARK, TYPE_MUL_NO_EFFECT,
TYPE_PSYCHIC, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_BUG, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE,
TYPE_BUG, TYPE_GRASS, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_BUG, TYPE_FIGHTING, TYPE_MUL_NOT_EFFECTIVE,
TYPE_BUG, TYPE_POISON, TYPE_MUL_NOT_EFFECTIVE,
TYPE_BUG, TYPE_FLYING, TYPE_MUL_NOT_EFFECTIVE,
TYPE_BUG, TYPE_PSYCHIC, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_BUG, TYPE_GHOST, TYPE_MUL_NOT_EFFECTIVE,
TYPE_BUG, TYPE_DARK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_BUG, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ROCK, TYPE_FIRE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ROCK, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ROCK, TYPE_FIGHTING, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ROCK, TYPE_GROUND, TYPE_MUL_NOT_EFFECTIVE,
TYPE_ROCK, TYPE_FLYING, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ROCK, TYPE_BUG, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_ROCK, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GHOST, TYPE_NORMAL, TYPE_MUL_NO_EFFECT,
TYPE_GHOST, TYPE_PSYCHIC, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_GHOST, TYPE_DARK, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GHOST, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_GHOST, TYPE_GHOST, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_DRAGON, TYPE_DRAGON, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_DRAGON, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_DARK, TYPE_FIGHTING, TYPE_MUL_NOT_EFFECTIVE,
TYPE_DARK, TYPE_PSYCHIC, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_DARK, TYPE_GHOST, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_DARK, TYPE_DARK, TYPE_MUL_NOT_EFFECTIVE,
TYPE_DARK, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_STEEL, TYPE_FIRE, TYPE_MUL_NOT_EFFECTIVE,
TYPE_STEEL, TYPE_WATER, TYPE_MUL_NOT_EFFECTIVE,
TYPE_STEEL, TYPE_ELECTRIC, TYPE_MUL_NOT_EFFECTIVE,
TYPE_STEEL, TYPE_ICE, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_STEEL, TYPE_ROCK, TYPE_MUL_SUPER_EFFECTIVE,
TYPE_STEEL, TYPE_STEEL, TYPE_MUL_NOT_EFFECTIVE,
TYPE_FORESIGHT, TYPE_FORESIGHT, TYPE_MUL_NO_EFFECT,
TYPE_NORMAL, TYPE_GHOST, TYPE_MUL_NO_EFFECT,
TYPE_FIGHTING, TYPE_GHOST, TYPE_MUL_NO_EFFECT,
TYPE_ENDTABLE, TYPE_ENDTABLE, TYPE_MUL_NO_EFFECT
};
2019-10-18 01:22:03 +02:00
const u8 gTypeNames[NUMBER_OF_MON_TYPES][TYPE_NAME_LENGTH + 1] =
2018-02-26 14:29:17 +01:00
{
[TYPE_NORMAL] = _("NORMAL"),
[TYPE_FIGHTING] = _("FIGHT"),
[TYPE_FLYING] = _("FLYING"),
[TYPE_POISON] = _("POISON"),
[TYPE_GROUND] = _("GROUND"),
[TYPE_ROCK] = _("ROCK"),
[TYPE_BUG] = _("BUG"),
[TYPE_GHOST] = _("GHOST"),
[TYPE_STEEL] = _("STEEL"),
[TYPE_MYSTERY] = _("???"),
[TYPE_FIRE] = _("FIRE"),
[TYPE_WATER] = _("WATER"),
[TYPE_GRASS] = _("GRASS"),
[TYPE_ELECTRIC] = _("ELECTR"),
[TYPE_PSYCHIC] = _("PSYCHC"),
[TYPE_ICE] = _("ICE"),
[TYPE_DRAGON] = _("DRAGON"),
[TYPE_DARK] = _("DARK"),
2018-02-26 14:29:17 +01:00
};
// This is a factor in how much money you get for beating a trainer.
const struct TrainerMoney gTrainerMoneyTable[] =
{
{TRAINER_CLASS_TEAM_AQUA, 5},
{TRAINER_CLASS_AQUA_ADMIN, 10},
{TRAINER_CLASS_AQUA_LEADER, 20},
{TRAINER_CLASS_AROMA_LADY, 10},
{TRAINER_CLASS_RUIN_MANIAC, 15},
{TRAINER_CLASS_INTERVIEWER, 12},
2018-12-03 04:35:11 +01:00
{TRAINER_CLASS_TUBER_F, 1},
{TRAINER_CLASS_TUBER_M, 1},
2018-02-26 14:29:17 +01:00
{TRAINER_CLASS_SIS_AND_BRO, 3},
2018-12-03 04:35:11 +01:00
{TRAINER_CLASS_COOLTRAINER, 12},
2018-02-26 14:29:17 +01:00
{TRAINER_CLASS_HEX_MANIAC, 6},
{TRAINER_CLASS_LADY, 50},
{TRAINER_CLASS_BEAUTY, 20},
{TRAINER_CLASS_RICH_BOY, 50},
{TRAINER_CLASS_POKEMANIAC, 15},
{TRAINER_CLASS_SWIMMER_M, 2},
{TRAINER_CLASS_BLACK_BELT, 8},
{TRAINER_CLASS_GUITARIST, 8},
{TRAINER_CLASS_KINDLER, 8},
{TRAINER_CLASS_CAMPER, 4},
{TRAINER_CLASS_OLD_COUPLE, 10},
{TRAINER_CLASS_BUG_MANIAC, 15},
{TRAINER_CLASS_PSYCHIC, 6},
{TRAINER_CLASS_GENTLEMAN, 20},
{TRAINER_CLASS_ELITE_FOUR, 25},
{TRAINER_CLASS_LEADER, 25},
{TRAINER_CLASS_SCHOOL_KID, 5},
{TRAINER_CLASS_SR_AND_JR, 4},
{TRAINER_CLASS_POKEFAN, 20},
{TRAINER_CLASS_EXPERT, 10},
{TRAINER_CLASS_YOUNGSTER, 4},
{TRAINER_CLASS_CHAMPION, 50},
{TRAINER_CLASS_FISHERMAN, 10},
{TRAINER_CLASS_TRIATHLETE, 10},
{TRAINER_CLASS_DRAGON_TAMER, 12},
{TRAINER_CLASS_BIRD_KEEPER, 8},
{TRAINER_CLASS_NINJA_BOY, 3},
{TRAINER_CLASS_BATTLE_GIRL, 6},
{TRAINER_CLASS_PARASOL_LADY, 10},
{TRAINER_CLASS_SWIMMER_F, 2},
{TRAINER_CLASS_PICNICKER, 4},
{TRAINER_CLASS_TWINS, 3},
{TRAINER_CLASS_SAILOR, 8},
{TRAINER_CLASS_COLLECTOR, 15},
{TRAINER_CLASS_RIVAL, 15},
2018-02-26 14:29:17 +01:00
{TRAINER_CLASS_PKMN_BREEDER, 10},
{TRAINER_CLASS_PKMN_RANGER, 12},
{TRAINER_CLASS_TEAM_MAGMA, 5},
{TRAINER_CLASS_MAGMA_ADMIN, 10},
{TRAINER_CLASS_MAGMA_LEADER, 20},
{TRAINER_CLASS_LASS, 4},
{TRAINER_CLASS_BUG_CATCHER, 4},
{TRAINER_CLASS_HIKER, 10},
{TRAINER_CLASS_YOUNG_COUPLE, 8},
{TRAINER_CLASS_WINSTRATE, 10},
2021-10-04 16:21:03 +02:00
{0xFF, 5}, // Any trainer class not listed above uses this
2018-02-26 14:29:17 +01:00
};
#include "data/text/abilities.h"
2017-10-06 19:09:37 +02:00
static void (* const sTurnActionsFuncsTable[])(void) =
{
2021-10-04 16:21:03 +02:00
[B_ACTION_USE_MOVE] = HandleAction_UseMove,
[B_ACTION_USE_ITEM] = HandleAction_UseItem,
[B_ACTION_SWITCH] = HandleAction_Switch,
[B_ACTION_RUN] = HandleAction_Run,
2018-12-08 07:10:30 +01:00
[B_ACTION_SAFARI_WATCH_CAREFULLY] = HandleAction_WatchesCarefully,
2021-10-04 16:21:03 +02:00
[B_ACTION_SAFARI_BALL] = HandleAction_SafariZoneBallThrow,
[B_ACTION_SAFARI_POKEBLOCK] = HandleAction_ThrowPokeblock,
[B_ACTION_SAFARI_GO_NEAR] = HandleAction_GoNear,
[B_ACTION_SAFARI_RUN] = HandleAction_SafariZoneRun,
[B_ACTION_WALLY_THROW] = HandleAction_WallyBallThrow,
[B_ACTION_EXEC_SCRIPT] = HandleAction_RunBattleScript,
[B_ACTION_TRY_FINISH] = HandleAction_TryFinish,
[B_ACTION_FINISHED] = HandleAction_ActionFinished,
[B_ACTION_NOTHING_FAINTED] = HandleAction_NothingIsFainted,
2017-10-06 19:09:37 +02:00
};
static void (* const sEndTurnFuncsTable[])(void) =
{
2021-10-04 16:21:03 +02:00
[0] = HandleEndTurn_ContinueBattle,
[B_OUTCOME_WON] = HandleEndTurn_BattleWon,
[B_OUTCOME_LOST] = HandleEndTurn_BattleLost,
[B_OUTCOME_DREW] = HandleEndTurn_BattleLost,
[B_OUTCOME_RAN] = HandleEndTurn_RanFromBattle,
2018-12-08 07:10:30 +01:00
[B_OUTCOME_PLAYER_TELEPORTED] = HandleEndTurn_FinishBattle,
2021-10-04 16:21:03 +02:00
[B_OUTCOME_MON_FLED] = HandleEndTurn_MonFled,
[B_OUTCOME_CAUGHT] = HandleEndTurn_FinishBattle,
[B_OUTCOME_NO_SAFARI_BALLS] = HandleEndTurn_FinishBattle,
[B_OUTCOME_FORFEITED] = HandleEndTurn_FinishBattle,
[B_OUTCOME_MON_TELEPORTED] = HandleEndTurn_FinishBattle,
2017-10-06 19:09:37 +02:00
};
2021-10-04 16:21:03 +02:00
const u8 gStatusConditionString_PoisonJpn[] = _("どく$$$$$");
const u8 gStatusConditionString_SleepJpn[] = _("ねむり$$$$");
const u8 gStatusConditionString_ParalysisJpn[] = _("まひ$$$$$");
const u8 gStatusConditionString_BurnJpn[] = _("やけど$$$$");
const u8 gStatusConditionString_IceJpn[] = _("こおり$$$$");
const u8 gStatusConditionString_ConfusionJpn[] = _("こんらん$$$");
const u8 gStatusConditionString_LoveJpn[] = _("メロメロ$$$");
2017-10-06 19:09:37 +02:00
2022-08-16 02:41:12 +02:00
const u8 * const gStatusConditionStringsTable[][2] =
2017-10-06 19:09:37 +02:00
{
{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}
};
2017-10-01 01:12:42 +02:00
void CB2_InitBattle(void)
{
MoveSaveBlocks_ResetHeap();
2017-11-12 16:39:21 +01:00
AllocateBattleResources();
2017-10-01 01:12:42 +02:00
AllocateBattleSpritesData();
AllocateMonSpritesGfx();
2021-03-12 22:55:58 +01:00
RecordedBattle_ClearFrontierPassFlag();
2017-10-01 01:12:42 +02:00
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);
2022-07-29 16:52:35 +02:00
CpuFill32(0, (void *)(VRAM), VRAM_SIZE);
2017-10-01 01:12:42 +02:00
SetGpuReg(REG_OFFSET_MOSAIC, 0);
2021-04-15 08:04:01 +02:00
SetGpuReg(REG_OFFSET_WIN0H, DISPLAY_WIDTH);
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1));
2017-10-01 01:12:42 +02:00
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
2021-04-15 08:04:01 +02:00
gBattle_WIN0H = DISPLAY_WIDTH;
2017-10-01 01:12:42 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != TRAINER_STEVEN_PARTNER)
2017-10-01 01:12:42 +02:00
{
2021-04-15 08:04:01 +02:00
gBattle_WIN0V = DISPLAY_HEIGHT - 1;
gBattle_WIN1H = DISPLAY_WIDTH;
2017-10-01 01:12:42 +02:00
gBattle_WIN1V = 32;
}
else
{
2021-04-15 08:04:01 +02:00
gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1);
2018-01-29 17:47:12 +01:00
ScanlineEffect_Clear();
2017-10-01 01:12:42 +02:00
i = 0;
while (i < 80)
2017-10-01 01:12:42 +02:00
{
2018-01-29 17:47:12 +01:00
gScanlineEffectRegBuffers[0][i] = 0xF0;
gScanlineEffectRegBuffers[1][i] = 0xF0;
i++;
2017-10-01 01:12:42 +02:00
}
2019-01-05 19:25:46 +01:00
while (i < 160)
2017-10-01 01:12:42 +02:00
{
2018-01-29 17:47:12 +01:00
gScanlineEffectRegBuffers[0][i] = 0xFF10;
gScanlineEffectRegBuffers[1][i] = 0xFF10;
i++;
2017-10-01 01:12:42 +02:00
}
2018-12-23 14:52:47 +01:00
ScanlineEffect_SetParams(sIntroScanlineParams16Bit);
2017-10-01 01:12:42 +02:00
}
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)
2017-12-16 01:08:55 +01:00
gBattleTerrain = BATTLE_TERRAIN_BUILDING;
2017-10-01 01:12:42 +02:00
2019-11-07 01:18:11 +01:00
InitBattleBgsVideo();
2017-10-01 01:12:42 +02:00
LoadBattleTextboxAndBackground();
ResetSpriteData();
ResetTasks();
2018-06-17 16:48:58 +02:00
DrawBattleEntryBackground();
2017-10-01 01:12:42 +02:00
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[PARTY_SIZE / 2], gTrainerBattleOpponent_B, FALSE);
2017-10-01 01:12:42 +02:00
SetWildMonHeldItem();
}
gMain.inBattle = TRUE;
2019-12-14 09:58:20 +01:00
gSaveBlock2Ptr->frontier.disableRecordBattle = FALSE;
2017-10-01 01:12:42 +02:00
2018-06-20 23:07:51 +02:00
for (i = 0; i < PARTY_SIZE; i++)
2020-02-02 19:28:54 +01:00
AdjustFriendship(&gPlayerParty[i], FRIENDSHIP_EVENT_LEAGUE_BATTLE);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 0;
}
2021-01-23 05:22:37 +01:00
#define BUFFER_PARTY_VS_SCREEN_STATUS(party, flags, i) \
for ((i) = 0; (i) < PARTY_SIZE; (i)++) \
{ \
u16 species = GetMonData(&(party)[(i)], MON_DATA_SPECIES2); \
u16 hp = GetMonData(&(party)[(i)], MON_DATA_HP); \
u32 status = GetMonData(&(party)[(i)], MON_DATA_STATUS); \
\
if (species == SPECIES_NONE) \
continue; \
\
/* Is healthy mon? */ \
if (species != SPECIES_EGG && hp != 0 && status == 0) \
(flags) |= 1 << (i) * 2; \
\
if (species == SPECIES_NONE) /* Redundant */ \
continue; \
\
/* Is Egg or statused? */ \
if (hp != 0 && (species == SPECIES_EGG || status != 0)) \
(flags) |= 2 << (i) * 2; \
\
if (species == SPECIES_NONE) /* Redundant */ \
continue; \
\
/* Is fainted? */ \
if (species != SPECIES_EGG && hp == 0) \
(flags) |= 3 << (i) * 2; \
}
// For Vs Screen at link battle start
static void BufferPartyVsScreenHealth_AtStart(void)
2017-10-01 01:12:42 +02:00
{
2021-01-23 05:22:37 +01:00
u16 flags = 0;
2017-10-01 01:12:42 +02:00
s32 i;
2021-01-23 05:22:37 +01:00
BUFFER_PARTY_VS_SCREEN_STATUS(gPlayerParty, flags, i);
2021-03-15 20:22:41 +01:00
gBattleStruct->multiBuffer.linkBattlerHeader.vsScreenHealthFlagsLo = flags;
*(&gBattleStruct->multiBuffer.linkBattlerHeader.vsScreenHealthFlagsHi) = flags >> 8;
gBattleStruct->multiBuffer.linkBattlerHeader.vsScreenHealthFlagsHi |= FlagGet(FLAG_SYS_FRONTIER_PASS) << 7;
2017-10-01 01:12:42 +02:00
}
static void SetPlayerBerryDataInBattleStruct(void)
{
s32 i;
struct BattleStruct *battleStruct = gBattleStruct;
2021-03-15 20:22:41 +01:00
struct BattleEnigmaBerry *battleBerry = &battleStruct->multiBuffer.linkBattlerHeader.battleEnigmaBerry;
2017-10-01 01:12:42 +02:00
if (IsEnigmaBerryValid() == TRUE)
{
2018-09-01 22:03:21 +02:00
for (i = 0; i < BERRY_NAME_LENGTH; i++)
2017-10-01 01:12:42 +02:00
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
{
2018-06-20 23:07:51 +02:00
const struct Berry *berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY));
2017-10-01 01:12:42 +02:00
2018-09-01 22:03:21 +02:00
for (i = 0; i < BERRY_NAME_LENGTH; i++)
2017-10-01 01:12:42 +02:00
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)
{
2022-08-16 00:27:37 +02:00
s32 i, j;
2017-10-01 01:12:42 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
if (IsEnigmaBerryValid() == TRUE)
{
2018-09-01 22:03:21 +02:00
for (i = 0; i < BERRY_NAME_LENGTH; i++)
2017-10-01 01:12:42 +02:00
{
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
{
2018-06-20 23:07:51 +02:00
const struct Berry *berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY));
2017-10-01 01:12:42 +02:00
2018-09-01 22:03:21 +02:00
for (i = 0; i < BERRY_NAME_LENGTH; i++)
2017-10-01 01:12:42 +02:00
{
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 = HOLD_EFFECT_NONE;
gEnigmaBerries[2].holdEffect = HOLD_EFFECT_NONE;
2017-10-01 01:12:42 +02:00
gEnigmaBerries[0].holdEffectParam = 0;
gEnigmaBerries[2].holdEffectParam = 0;
}
}
else
{
s32 numPlayers;
struct BattleEnigmaBerry *src;
2018-06-20 23:07:51 +02:00
u8 battlerId;
2017-10-01 01:12:42 +02:00
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);
2018-07-22 13:14:58 +02:00
battlerId = gLinkPlayers[i].id;
2017-10-01 01:12:42 +02:00
2018-09-01 22:03:21 +02:00
for (j = 0; j < BERRY_NAME_LENGTH; j++)
2018-06-20 23:07:51 +02:00
gEnigmaBerries[battlerId].name[j] = src->name[j];
gEnigmaBerries[battlerId].name[j] = EOS;
2017-10-01 01:12:42 +02:00
for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; j++)
2018-06-20 23:07:51 +02:00
gEnigmaBerries[battlerId].itemEffect[j] = src->itemEffect[j];
2017-10-01 01:12:42 +02:00
2018-06-20 23:07:51 +02:00
gEnigmaBerries[battlerId].holdEffect = src->holdEffect;
gEnigmaBerries[battlerId].holdEffectParam = src->holdEffectParam;
2017-10-01 01:12:42 +02:00
}
}
else
{
for (i = 0; i < 2; i++)
{
src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2);
2018-09-01 22:03:21 +02:00
for (j = 0; j < BERRY_NAME_LENGTH; j++)
2017-10-01 01:12:42 +02:00
{
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;
}
}
}
}
2021-03-12 22:55:58 +01:00
// This was inlined in Ruby/Sapphire
static void FindLinkBattleMaster(u8 numPlayers, u8 multiPlayerId)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
u8 found = 0;
2017-10-01 01:12:42 +02:00
2021-03-12 22:55:58 +01:00
// If player 1 is playing the minimum version, player 1 is master.
if (gBlockRecvBuffer[0][0] == 0x100)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
if (multiPlayerId == 0)
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER;
2017-10-01 01:12:42 +02:00
else
gBattleTypeFlags |= BATTLE_TYPE_TRAINER;
2021-03-12 22:55:58 +01:00
found++;
2017-10-01 01:12:42 +02:00
}
2021-03-12 22:55:58 +01:00
if (found == 0)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
// If multiple different versions are being used, player 1 is master.
2017-10-01 01:12:42 +02:00
s32 i;
2021-03-12 22:55:58 +01:00
for (i = 0; i < numPlayers; i++)
2017-10-01 01:12:42 +02:00
{
if (gBlockRecvBuffer[0][0] != gBlockRecvBuffer[i][0])
break;
}
2021-03-12 22:55:58 +01:00
if (i == numPlayers)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
if (multiPlayerId == 0)
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER;
2017-10-01 01:12:42 +02:00
else
gBattleTypeFlags |= BATTLE_TYPE_TRAINER;
2021-03-12 22:55:58 +01:00
found++;
2017-10-01 01:12:42 +02:00
}
2021-03-12 22:55:58 +01:00
if (found == 0)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
// Lowest index player with the highest game version is master.
for (i = 0; i < numPlayers; i++)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
if (gBlockRecvBuffer[i][0] == 0x300 && i != multiPlayerId)
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
if (i < multiPlayerId)
2017-10-01 01:12:42 +02:00
break;
}
2021-03-12 22:55:58 +01:00
if (gBlockRecvBuffer[i][0] > 0x300 && i != multiPlayerId)
2017-10-01 01:12:42 +02:00
break;
}
2021-03-12 22:55:58 +01:00
if (i == numPlayers)
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER;
2017-10-01 01:12:42 +02:00
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);
2021-09-24 20:30:15 +02:00
FillAroundBattleWindows();
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 1;
}
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2019-04-04 23:05:46 +02:00
LoadWirelessStatusIndicatorSpriteGfx();
2017-10-01 01:12:42 +02:00
break;
case 1:
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (gReceivedRemoteLinkPlayers)
2017-10-01 01:12:42 +02:00
{
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
// 0x300
2021-03-15 20:22:41 +01:00
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureLo) = 0;
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureHi) = 3;
2021-01-23 05:22:37 +01:00
BufferPartyVsScreenHealth_AtStart();
2017-10-01 01:12:42 +02:00
SetPlayerBerryDataInBattleStruct();
2020-06-03 21:28:29 +02:00
if (gTrainerBattleOpponent_A == TRAINER_UNION_ROOM)
2017-10-01 01:12:42 +02:00
{
2018-07-22 12:49:49 +02:00
gLinkPlayers[0].id = 0;
gLinkPlayers[1].id = 1;
2017-10-01 01:12:42 +02:00
}
SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 2;
}
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2017-12-04 04:01:06 +01:00
CreateWirelessStatusIndicatorSprite(0, 0);
2017-10-01 01:12:42 +02:00
}
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER;
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 15;
SetAllPlayersBerryData();
}
break;
case 2:
if ((GetBlockReceivedStatus() & 3) == 3)
{
u8 taskId;
ResetBlockReceivedFlags();
2021-03-12 22:55:58 +01:00
FindLinkBattleMaster(2, playerMultiplayerId);
2017-10-01 01:12:42 +02:00
SetAllPlayersBerryData();
2019-11-07 01:18:11 +01:00
taskId = CreateTask(InitLinkBattleVsScreen, 0);
2017-10-01 01:12:42 +02:00
gTasks[taskId].data[1] = 0x10E;
gTasks[taskId].data[2] = 0x5A;
gTasks[taskId].data[5] = 0;
2021-03-15 20:22:41 +01:00
gTasks[taskId].data[3] = gBattleStruct->multiBuffer.linkBattlerHeader.vsScreenHealthFlagsLo | (gBattleStruct->multiBuffer.linkBattlerHeader.vsScreenHealthFlagsHi << 8);
2017-10-01 01:12:42 +02:00
gTasks[taskId].data[4] = gBlockRecvBuffer[enemyMultiplayerId][1];
2021-03-12 22:55:58 +01:00
RecordedBattle_SetFrontierPassFlagFromHword(gBlockRecvBuffer[playerMultiplayerId][1]);
RecordedBattle_SetFrontierPassFlagFromHword(gBlockRecvBuffer[enemyMultiplayerId][1]);
2018-02-09 15:55:12 +01:00
SetDeoxysStats();
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 3:
2021-10-04 16:21:03 +02:00
// Link battle, send/receive party Pokémon 2 at a time
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send Pokémon 1-2
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv Pokémon 1-2
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
memcpy(gEnemyParty, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send Pokémon 3-4
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[2], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv Pokémon 3-4
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
2021-10-04 16:21:03 +02:00
memcpy(&gEnemyParty[2], gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 11:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send Pokémon 5-6
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[4], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 12:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv Pokémon 5-6
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
2021-10-04 16:21:03 +02:00
memcpy(&gEnemyParty[4], gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
2017-10-01 18:54:01 +02:00
TryCorrectShedinjaLanguage(&gEnemyParty[0]);
TryCorrectShedinjaLanguage(&gEnemyParty[1]);
TryCorrectShedinjaLanguage(&gEnemyParty[2]);
TryCorrectShedinjaLanguage(&gEnemyParty[3]);
TryCorrectShedinjaLanguage(&gEnemyParty[4]);
TryCorrectShedinjaLanguage(&gEnemyParty[5]);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 15:
InitBattleControllers();
2021-10-04 16:21:03 +02:00
RecordedBattle_SetTrainerInfo();
2017-10-01 01:12:42 +02:00
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
gBattleCommunication[SPRITES_INIT_STATE2] = 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
2021-10-04 16:21:03 +02:00
// Check if both players are using Emerald
// to determine if the recorded battle rng
// seed needs to be sent
2017-10-01 01:12:42 +02:00
s32 i;
Decompile TV (#80) * ClearTVShowData * special_0x44 * DoTVShow (nonmatching because align) * DoTVShowBravoTrainerPokemonProfile * Update field names * DoTVShowBravoTrainerBattleTower * Renaming of struct fields * sub_80EBFF4 and UpdateTVScreensOnMap * SetTVMetatilesOnMap * Power buttons for the TV screens on the map * special_0x45 * sub_80EC18C * special_0x4a * ResetGabbyAndTy * GabbyAndTyBeforeInterview * GabbyAndTyAfterInterview * Through IsTVShowInSearchOfTrainersAiring * GabbyAndTyGetLastQuote * GabbyAndTyGetLastBattleTrivia * GabbyAndTySetScriptVarsToFieldObjectLocalIds * InterviewAfter; use TVShow as a precursor for making the individual show structs anonymous * Make TV structs anonymous within the union * Move the TV union to its own subheader * Move TV show enums to the global.tv.h subheader * Funcion renaming * Apply static attributes where able * PutPokemonTodayCaughtOnAir * sub_80EC8A4 * PutPokemonTodayFailedOnTheAir * sub_80EC9E8, sub_80ECA10 * sub_80ECA38 * sub_80ECB00 * Put3CheersForPokeblocksOnTheAir * PutFanClubSpecialOnTheAir * ContestLiveUpdates_BeforeInterview * Other before-interview Contest Live Updates functions * ContestLiveUpdates_BeforeInterview_5 * InterviewAfter_BravoTrainerPokemonProfile * BravoTrainerPokemonProfile_BeforeInterview1 * BravoTrainerPokemonProfile_BeforeInterview2 * Disassemble TV data * Decompile TV data * InterviewAfter_BravoTrainerBattleTowerProfile * SaveRecordedItemPurchasesForTVShow * PutNameRaterShowOnTheAir * StartMassOutbreak * PutLilycoveContestLadyShowOnTheAir * InterviewAfter_FanClubLetter * Rip TV strings * InterviewAfter_RecentHappenings * InterviewAfter_PkmnFanClubOpinions * sub_80ED718 * EndMassOutbreak * sub_80ED888 * sub_80ED8B4 * UpdateMassOutbreakTimeLeft * sub_80ED950 * PutFishingAdviceShowOnTheAir * through sub_80EDA80 * ewram and common syms are now fetched from the object files * BSS symbols are taken from the tv.o file * through sub_80EDC60 * sub_80EDCE8 * sub_80EDD78 * through sub_80EDE84 * nomatching sub_80EDE98 * sub_80EDFB4 * sub_80EE104 * sub_80EE104 * sub_80EE184 * sub_80EE2CC * sub_80EE35C * sub_80EE44C * sub_80EE4DC * sub_80EE5A4 * sub_80EE69C * sub_80EE72C * sub_80EE7C0 * sub_80EE818 * sub_80EE8C8 * sub_80EEA70 * sub_80EEB98 * sub_80EEBF4 * through sub_80EED60 * Functions relating to Pokemon News * sub_80EEF6C * GetPriceReduction * IsPriceDiscounted * sub_80EF120 * through sub_80EF370 * sub_80EF40C * HasMixableShowAlreadyBeenSpawnedWithPlayerID * TV_SortPurchasesByQuantity * FindActiveBroadcastByShowType_SetScriptResult * InterviewBefore * through sub_80EF88C * through sub_80EF93C * through sub_80EFA24 * through TV_BernoulliTrial * sub_80EFB58 * sub_80EFBA4 * sub_80EFBDC * through sub_80EFD98 * ChangePokemonNickname * ChangeBoxPokemonNickname * sub_80EFF9C * through player_id_to_dword * CheckForBigMovieOrEmergencyNewsOnTV * GetMomOrDadStringForTVMessage * sub_80F01E8 * sub_80F0358 * sub_80F049C * TV record mixing functions * sub_80F06D0 * sub_80F0708 nonmatching * through sub_80F0B24 * sub_80F0B64 * through sub_80F0C04 * sub_80F0C7C * sub_80F0D60 * sub_80F0E58 * sub_80F0E84 * through sub_80F0F24 * sub_80F0F64 * sub_80F1208 * sub_80F1254 * sub_80F1290 * sub_80F12A4 * sub_80F14F8 * DoTVShowTodaysSmartShopper * DoTVShowTheNameRaterShow * DoTVShowPokemonTodaySuccessfulCapture * DoTVShowPokemonTodayFailedCapture * DoTVShowPokemonFanClubLetter * DoTVShowRecentHappenings * DoTVShowPokemonFanClubOpinions * DoTVShowPokemonNewsMassOutbreak * DoTVShowPokemonContestLiveUpdates * DoTVShowPokemonBattleUpdate * DoTVShow3CheersForPokeblocks * DoTVShowInSearchOfTrainers * Label GabbyAndTyData fields; remove ddump comments from data/text/tv.inc * DoTVShowPokemonAngler * DoTVShowTheWorldOfMasters; update RAM symbols and field names * Decorate static functions * DoTVShowTodaysRivalTrainer; region map enums * TVDewfordTrendWatcherNetworkTextGroup * DoTVShowHoennTreasureInvestigators * DoTVShowFindThatGamer * DoTVShowBreakingNewsTV * DoTVShowSecretBaseVisit * DoTVShowPokemonLotterWinnerFlashReport * DoTVShowThePokemonBattleSeminar * DoTVShowTrainerFanClubSpecial, DoTVShowTrainerFanClub * DoTVShowSpotTheCuties * DoTVShowPokemonNewsBattleFrontier * DoTVShowWhatsNo1InHoennToday * Helpers for DoTVShowSecretBaseSecrets * DoTVShowSecretBaseSecrets * DoTVShowSafariFanClub * Finish decompilation of tv.s * Some renaming * Rename text group pointers * revoke statis; pokenews enums * Labels are number one * Label all TV struct fields * Make data/text/tv.inc more readable * Split data/text/tv.inc * Rename pokenews text pointers * Frontier Symbol constants; indicate static rodata objects with 's' prefix * Fix leading spaces/tabs F*** CLion sometimes * Fix inconsequential warning
2017-10-13 17:09:36 +02:00
for (i = 0; i < 2 && (gLinkPlayers[i].version & 0xFF) == VERSION_EMERALD; i++);
2017-10-01 01:12:42 +02:00
if (i == 2)
gBattleCommunication[MULTIUSE_STATE] = 16;
else
gBattleCommunication[MULTIUSE_STATE] = 18;
}
else
{
gBattleCommunication[MULTIUSE_STATE] = 18;
}
break;
case 16:
2021-10-04 16:21:03 +02:00
// Both players are using Emerald, send rng seed for recorded battle
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
SendBlock(BitmaskAllOtherLinkPlayers(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 17:
2021-10-04 16:21:03 +02:00
// Receive rng seed for recorded battle (only read it if partner is the link master)
2017-10-01 01:12:42 +02:00
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (!(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER))
2017-10-01 01:12:42 +02:00
memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[enemyMultiplayerId], sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 18:
2021-10-04 16:21:03 +02:00
// Finish, start battle
2017-10-01 01:12:42 +02:00
if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2]))
{
gPreBattleCallback1 = gMain.callback1;
gMain.callback1 = BattleMainCB1;
SetMainCallback2(BattleMainCB2);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
2021-01-13 21:17:32 +01:00
gBattleTypeFlags |= BATTLE_TYPE_LINK_IN_BATTLE;
2017-10-01 01:12:42 +02:00
}
break;
2021-10-04 16:21:03 +02:00
// Introduce short delays between sending party Pokémon for link
2017-10-01 01:12:42 +02:00
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;
2021-10-04 16:21:03 +02:00
u8 partnerMultiplayerId;
2017-10-01 01:12:42 +02:00
RunTasks();
AnimateSprites();
BuildOamBuffer();
playerMultiplayerId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplayerId;
2021-10-04 16:21:03 +02:00
partnerMultiplayerId = playerMultiplayerId ^ BIT_SIDE;
2017-10-01 01:12:42 +02:00
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (!IsDma3ManagerBusyWithBgCopy())
{
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
2021-09-24 20:30:15 +02:00
FillAroundBattleWindows();
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 1;
}
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2019-04-04 23:05:46 +02:00
LoadWirelessStatusIndicatorSpriteGfx();
2017-10-01 01:12:42 +02:00
// fall through
case 1:
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (gReceivedRemoteLinkPlayers)
2017-10-01 01:12:42 +02:00
{
u8 language;
2018-07-22 12:49:49 +02:00
gLinkPlayers[0].id = 0;
gLinkPlayers[1].id = 2;
gLinkPlayers[2].id = 1;
gLinkPlayers[3].id = 3;
2017-10-01 01:12:42 +02:00
GetFrontierTrainerName(gLinkPlayers[2].name, gTrainerBattleOpponent_A);
GetFrontierTrainerName(gLinkPlayers[3].name, gTrainerBattleOpponent_B);
GetBattleTowerTrainerLanguage(&language, gTrainerBattleOpponent_A);
2017-10-01 01:12:42 +02:00
gLinkPlayers[2].language = language;
GetBattleTowerTrainerLanguage(&language, gTrainerBattleOpponent_B);
2017-10-01 01:12:42 +02:00
gLinkPlayers[3].language = language;
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
// 0x300
2021-03-15 20:22:41 +01:00
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureLo) = 0;
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureHi) = 3;
2021-01-23 05:22:37 +01:00
BufferPartyVsScreenHealth_AtStart();
2017-10-01 01:12:42 +02:00
SetPlayerBerryDataInBattleStruct();
SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 2;
}
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2017-12-04 04:01:06 +01:00
CreateWirelessStatusIndicatorSprite(0, 0);
2017-10-01 01:12:42 +02:00
}
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER;
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 13;
SetAllPlayersBerryData();
}
break;
case 2:
if ((GetBlockReceivedStatus() & 3) == 3)
{
u8 taskId;
ResetBlockReceivedFlags();
2021-03-12 22:55:58 +01:00
FindLinkBattleMaster(2, playerMultiplayerId);
2017-10-01 01:12:42 +02:00
SetAllPlayersBerryData();
2019-11-07 01:18:11 +01:00
taskId = CreateTask(InitLinkBattleVsScreen, 0);
2017-10-01 01:12:42 +02:00
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:
2021-10-04 16:21:03 +02:00
// Link battle, send/receive party Pokémon in groups
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send Pokémon 1-2
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv partner's Pokémon 1-2, and copy partner's and own Pokémon into party positions
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
2018-07-22 12:49:49 +02:00
if (gLinkPlayers[playerMultiplayerId].id != 0)
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
memcpy(gPlayerParty, gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon) * 2);
memcpy(&gPlayerParty[MULTI_PARTY_SIZE], gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
}
else
{
memcpy(gPlayerParty, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2);
2021-10-04 16:21:03 +02:00
memcpy(&gPlayerParty[MULTI_PARTY_SIZE], gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 5:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send Pokémon 3
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[2], sizeof(struct Pokemon));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 6:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv partner's Pokémon 3, and copy partner's and own Pokémon into party positions
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
2018-07-22 12:49:49 +02:00
if (gLinkPlayers[playerMultiplayerId].id != 0)
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
memcpy(&gPlayerParty[2], gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon));
memcpy(&gPlayerParty[2 + MULTI_PARTY_SIZE], gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon));
2017-10-01 01:12:42 +02:00
}
else
{
2021-10-04 16:21:03 +02:00
memcpy(&gPlayerParty[2], gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon));
memcpy(&gPlayerParty[2 + MULTI_PARTY_SIZE], gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon));
2017-10-01 01:12:42 +02:00
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send enemy Pokémon 1-2 to partner
SendBlock(BitmaskAllOtherLinkPlayers(), gEnemyParty, sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv enemy Pokémon 1-2 (if not master)
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
memcpy(gEnemyParty, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 9:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send enemy Pokémon 3-4 to partner
SendBlock(BitmaskAllOtherLinkPlayers(), &gEnemyParty[2], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 10:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv enemy Pokémon 3-4 (if not master)
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
2021-10-04 16:21:03 +02:00
memcpy(&gEnemyParty[2], gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 11:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
// Send enemy Pokémon 5-6 to partner
SendBlock(BitmaskAllOtherLinkPlayers(), &gEnemyParty[4], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 12:
if ((GetBlockReceivedStatus() & 3) == 3)
{
2021-10-04 16:21:03 +02:00
// Recv enemy Pokémon 5-6 (if not master)
2017-10-01 01:12:42 +02:00
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
2021-10-04 16:21:03 +02:00
memcpy(&gEnemyParty[4], gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
2017-10-01 18:54:01 +02:00
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]);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 13:
InitBattleControllers();
2021-10-04 16:21:03 +02:00
RecordedBattle_SetTrainerInfo();
2017-10-01 01:12:42 +02:00
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:
2021-10-04 16:21:03 +02:00
// Send rng seed for recorded battle
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
SendBlock(BitmaskAllOtherLinkPlayers(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 15:
2021-10-04 16:21:03 +02:00
// Receive rng seed for recorded battle (only read it if partner is the link master)
2017-10-01 01:12:42 +02:00
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (!(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER))
2021-10-04 16:21:03 +02:00
memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[partnerMultiplayerId], sizeof(gRecordedBattleRngSeed));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 16:
2021-10-04 16:21:03 +02:00
// Finish, start battle
2017-10-01 01:12:42 +02:00
if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2]))
{
2020-12-24 22:18:47 +01:00
TrySetLinkBattleTowerEnemyPartyLevel();
2017-10-01 01:12:42 +02:00
gPreBattleCallback1 = gMain.callback1;
gMain.callback1 = BattleMainCB1;
SetMainCallback2(BattleMainCB2);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
2021-01-13 21:17:32 +01:00
gBattleTypeFlags |= BATTLE_TYPE_LINK_IN_BATTLE;
2017-10-01 01:12:42 +02:00
}
break;
}
}
2021-10-04 16:21:03 +02:00
static void SetMultiPartnerMenuParty(u8 offset)
2017-10-01 01:12:42 +02:00
{
s32 i;
2021-10-04 16:21:03 +02:00
for (i = 0; i < MULTI_PARTY_SIZE; i++)
{
gMultiPartnerParty[i].species = GetMonData(&gPlayerParty[offset + i], MON_DATA_SPECIES);
gMultiPartnerParty[i].heldItem = GetMonData(&gPlayerParty[offset + i], MON_DATA_HELD_ITEM);
GetMonData(&gPlayerParty[offset + i], MON_DATA_NICKNAME, gMultiPartnerParty[i].nickname);
gMultiPartnerParty[i].level = GetMonData(&gPlayerParty[offset + i], MON_DATA_LEVEL);
gMultiPartnerParty[i].hp = GetMonData(&gPlayerParty[offset + i], MON_DATA_HP);
gMultiPartnerParty[i].maxhp = GetMonData(&gPlayerParty[offset + i], MON_DATA_MAX_HP);
gMultiPartnerParty[i].status = GetMonData(&gPlayerParty[offset + i], MON_DATA_STATUS);
gMultiPartnerParty[i].personality = GetMonData(&gPlayerParty[offset + i], MON_DATA_PERSONALITY);
gMultiPartnerParty[i].gender = GetMonGender(&gPlayerParty[offset + i]);
2019-10-18 01:22:03 +02:00
StripExtCtrlCodes(gMultiPartnerParty[i].nickname);
2021-10-04 16:21:03 +02:00
if (GetMonData(&gPlayerParty[offset + i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE)
2019-10-18 01:22:03 +02:00
PadNameString(gMultiPartnerParty[i].nickname, CHAR_SPACE);
2017-10-01 01:12:42 +02:00
}
2019-10-18 01:22:03 +02:00
memcpy(sMultiPartnerPartyBuffer, gMultiPartnerParty, sizeof(gMultiPartnerParty));
2017-10-01 01:12:42 +02:00
}
static void CB2_PreInitMultiBattle(void)
{
s32 i;
u8 playerMultiplierId;
2021-10-04 16:21:03 +02:00
s32 numPlayers = MAX_BATTLERS_COUNT;
u8 blockMask = 0xF;
2018-06-20 23:07:51 +02:00
u32 *savedBattleTypeFlags;
2017-10-01 01:12:42 +02:00
void (**savedCallback)(void);
if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
{
numPlayers = 2;
2021-10-04 16:21:03 +02:00
blockMask = 3;
2017-10-01 01:12:42 +02:00
}
playerMultiplierId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplierId;
savedCallback = &gBattleStruct->savedCallback;
savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags;
RunTasks();
AnimateSprites();
BuildOamBuffer();
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (gReceivedRemoteLinkPlayers && IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
sMultiPartnerPartyBuffer = Alloc(sizeof(gMultiPartnerParty));
SetMultiPartnerMenuParty(0);
SendBlock(BitmaskAllOtherLinkPlayers(), sMultiPartnerPartyBuffer, sizeof(gMultiPartnerParty));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 1:
2021-10-04 16:21:03 +02:00
if ((GetBlockReceivedStatus() & blockMask) == blockMask)
2017-10-01 01:12:42 +02:00
{
ResetBlockReceivedFlags();
for (i = 0; i < numPlayers; i++)
{
if (i == playerMultiplierId)
continue;
2019-10-18 01:22:03 +02:00
if (numPlayers == MAX_LINK_PLAYERS)
2017-10-01 01:12:42 +02:00
{
2018-07-22 12:49:49 +02:00
if ((!(gLinkPlayers[i].id & 1) && !(gLinkPlayers[playerMultiplierId].id & 1))
|| (gLinkPlayers[i].id & 1 && gLinkPlayers[playerMultiplierId].id & 1))
2017-10-01 01:12:42 +02:00
{
2021-10-04 16:21:03 +02:00
memcpy(gMultiPartnerParty, gBlockRecvBuffer[i], sizeof(gMultiPartnerParty));
2017-10-01 01:12:42 +02:00
}
}
else
{
2021-10-04 16:21:03 +02:00
memcpy(gMultiPartnerParty, gBlockRecvBuffer[i], sizeof(gMultiPartnerParty));
2017-10-01 01:12:42 +02:00
}
}
gBattleCommunication[MULTIUSE_STATE]++;
*savedCallback = gMain.savedCallback;
*savedBattleTypeFlags = gBattleTypeFlags;
gMain.savedCallback = CB2_PreInitMultiBattle;
2019-10-18 01:22:03 +02:00
ShowPartyMenuToShowcaseMultiBattleParty();
2017-10-01 01:12:42 +02:00
}
break;
case 2:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished() && !gPaletteFade.active)
2017-10-01 01:12:42 +02:00
{
gBattleCommunication[MULTIUSE_STATE]++;
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback();
2017-10-01 01:12:42 +02:00
else
2020-08-13 09:09:47 +02:00
SetCloseLinkCallback();
2017-10-01 01:12:42 +02:00
}
break;
case 3:
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2017-10-01 01:12:42 +02:00
{
2019-10-09 11:56:44 +02:00
if (IsLinkRfuTaskFinished())
2017-10-01 01:12:42 +02:00
{
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
FREE_AND_SET_NULL(sMultiPartnerPartyBuffer);
2017-10-01 01:12:42 +02:00
}
}
else if (gReceivedRemoteLinkPlayers == 0)
{
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
FREE_AND_SET_NULL(sMultiPartnerPartyBuffer);
2017-10-01 01:12:42 +02:00
}
break;
}
}
static void CB2_PreInitIngamePlayerPartnerBattle(void)
{
2018-06-20 23:07:51 +02:00
u32 *savedBattleTypeFlags;
2017-10-01 01:12:42 +02:00
void (**savedCallback)(void);
savedCallback = &gBattleStruct->savedCallback;
savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags;
RunTasks();
AnimateSprites();
BuildOamBuffer();
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
2021-10-04 16:21:03 +02:00
sMultiPartnerPartyBuffer = Alloc(sizeof(gMultiPartnerParty));
SetMultiPartnerMenuParty(MULTI_PARTY_SIZE);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
*savedCallback = gMain.savedCallback;
*savedBattleTypeFlags = gBattleTypeFlags;
gMain.savedCallback = CB2_PreInitIngamePlayerPartnerBattle;
2019-10-18 01:22:03 +02:00
ShowPartyMenuToShowcaseMultiBattleParty();
2017-10-01 01:12:42 +02:00
break;
case 1:
if (!gPaletteFade.active)
{
gBattleCommunication[MULTIUSE_STATE] = 2;
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
FREE_AND_SET_NULL(sMultiPartnerPartyBuffer);
2017-10-01 01:12:42 +02:00
}
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);
2021-09-24 20:30:15 +02:00
FillAroundBattleWindows();
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 1;
}
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2019-04-04 23:05:46 +02:00
LoadWirelessStatusIndicatorSpriteGfx();
2017-10-01 01:12:42 +02:00
break;
case 1:
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (gReceivedRemoteLinkPlayers)
2017-10-01 01:12:42 +02:00
{
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
2021-03-12 22:55:58 +01:00
// 0x300
2021-03-15 20:22:41 +01:00
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureLo) = 0;
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureHi) = 3;
2021-01-23 05:22:37 +01:00
BufferPartyVsScreenHealth_AtStart();
2017-10-01 01:12:42 +02:00
SetPlayerBerryDataInBattleStruct();
SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
2017-11-13 05:58:05 +01:00
if (gWirelessCommType)
2017-12-04 04:01:06 +01:00
CreateWirelessStatusIndicatorSprite(0, 0);
2017-10-01 01:12:42 +02:00
}
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER;
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 7;
SetAllPlayersBerryData();
}
break;
case 2:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
2021-03-12 22:55:58 +01:00
FindLinkBattleMaster(4, playerMultiplayerId);
2017-10-01 01:12:42 +02:00
SetAllPlayersBerryData();
2018-02-09 15:55:12 +01:00
SetDeoxysStats();
2019-11-07 01:18:11 +01:00
var = CreateTask(InitLinkBattleVsScreen, 0);
2017-10-01 01:12:42 +02:00
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++)
{
2021-03-12 22:55:58 +01:00
RecordedBattle_SetFrontierPassFlagFromHword(gBlockRecvBuffer[id][1]);
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
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:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
for (id = 0; id < MAX_LINK_PLAYERS; id++)
{
if (id == playerMultiplayerId)
{
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
case 0:
case 3:
memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
case 1:
case 2:
2019-11-01 02:33:01 +01:00
memcpy(gPlayerParty + MULTI_PARTY_SIZE, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
break;
}
}
else
{
2018-07-22 12:49:49 +02:00
if ((!(gLinkPlayers[id].id & 1) && !(gLinkPlayers[playerMultiplayerId].id & 1))
|| ((gLinkPlayers[id].id & 1) && (gLinkPlayers[playerMultiplayerId].id & 1)))
2017-10-01 01:12:42 +02:00
{
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
case 0:
case 3:
memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
case 1:
case 2:
2019-11-01 02:33:01 +01:00
memcpy(gPlayerParty + MULTI_PARTY_SIZE, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
break;
}
}
else
{
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
case 0:
case 3:
memcpy(gEnemyParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
case 1:
case 2:
2019-11-01 02:33:01 +01:00
memcpy(gEnemyParty + MULTI_PARTY_SIZE, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
2017-10-01 01:12:42 +02:00
break;
}
}
}
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 5:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty + 2, sizeof(struct Pokemon));
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 6:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
for (id = 0; id < MAX_LINK_PLAYERS; id++)
{
if (id == playerMultiplayerId)
{
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
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
{
2018-07-22 12:49:49 +02:00
if ((!(gLinkPlayers[id].id & 1) && !(gLinkPlayers[playerMultiplayerId].id & 1))
|| ((gLinkPlayers[id].id & 1) && (gLinkPlayers[playerMultiplayerId].id & 1)))
2017-10-01 01:12:42 +02:00
{
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
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
{
2018-07-22 12:49:49 +02:00
switch (gLinkPlayers[id].id)
2017-10-01 01:12:42 +02:00
{
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;
}
}
}
}
2017-10-01 18:54:01 +02:00
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]);
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
InitBattleControllers();
2021-10-04 16:21:03 +02:00
RecordedBattle_SetTrainerInfo();
2017-10-01 01:12:42 +02:00
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
gBattleCommunication[SPRITES_INIT_STATE2] = 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
2019-09-08 18:21:24 +02:00
for (id = 0; id < MAX_LINK_PLAYERS && (gLinkPlayers[id].version & 0xFF) == VERSION_EMERALD; id++);
2017-10-01 01:12:42 +02:00
2019-09-08 18:21:24 +02:00
if (id == MAX_LINK_PLAYERS)
2017-10-01 01:12:42 +02:00
gBattleCommunication[MULTIUSE_STATE] = 8;
else
gBattleCommunication[MULTIUSE_STATE] = 10;
}
else
{
gBattleCommunication[MULTIUSE_STATE] = 10;
}
break;
case 8:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished())
2017-10-01 01:12:42 +02:00
{
u32 *ptr = gBattleStruct->multiBuffer.battleVideo;
2017-10-01 01:12:42 +02:00
ptr[0] = gBattleTypeFlags;
ptr[1] = gRecordedBattleRngSeed; // UB: overwrites berry data
SendBlock(BitmaskAllOtherLinkPlayers(), ptr, sizeof(gBattleStruct->multiBuffer.battleVideo));
2017-10-01 01:12:42 +02:00
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)
{
2018-07-01 11:15:42 +02:00
gTrainerBattleOpponent_A = TRAINER_LINK_OPPONENT;
2021-01-13 21:17:32 +01:00
gBattleTypeFlags |= BATTLE_TYPE_LINK_IN_BATTLE;
2017-10-01 01:12:42 +02:00
}
}
break;
}
}
2017-10-01 18:54:01 +02:00
void BattleMainCB2(void)
{
AnimateSprites();
BuildOamBuffer();
RunTextPrinters();
UpdatePaletteFade();
RunTasks();
2021-10-04 16:21:03 +02:00
if (JOY_HELD(B_BUTTON) && gBattleTypeFlags & BATTLE_TYPE_RECORDED && RecordedBattle_CanStopPlayback())
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
// Player pressed B during recorded battle playback, end battle
2018-01-16 22:12:38 +01:00
gSpecialVar_Result = gBattleOutcome = B_OUTCOME_PLAYER_TELEPORTED;
2017-10-01 18:54:01 +02:00
ResetPaletteFadeControl();
2021-10-04 16:21:03 +02:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
2017-10-01 18:54:01 +02:00
SetMainCallback2(CB2_QuitRecordedBattle);
}
}
static void FreeRestoreBattleData(void)
{
gMain.callback1 = gPreBattleCallback1;
2018-01-29 17:47:12 +01:00
gScanlineEffect.state = 3;
2021-10-04 16:21:03 +02:00
gMain.inBattle = FALSE;
2017-10-01 18:54:01 +02:00
ZeroEnemyPartyMons();
2020-08-21 00:02:00 +02:00
m4aSongNumStop(SE_LOW_HEALTH);
2017-10-01 18:54:01 +02:00
FreeMonSpritesGfx();
FreeBattleSpritesData();
FreeBattleResources();
}
void CB2_QuitRecordedBattle(void)
{
UpdatePaletteFade();
if (!gPaletteFade.active)
{
m4aMPlayStop(&gMPlayInfo_SE1);
m4aMPlayStop(&gMPlayInfo_SE2);
2017-10-01 18:54:01 +02:00
FreeRestoreBattleData();
FreeAllWindowBuffers();
SetMainCallback2(gMain.savedCallback);
}
}
2021-10-04 16:21:03 +02:00
#define sState data[0]
#define sDelay data[4]
2022-07-29 17:15:33 +02:00
static void SpriteCB_UnusedBattleInit(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->sState = 0;
sprite->callback = SpriteCB_UnusedBattleInit_Main;
2017-10-01 18:54:01 +02:00
}
2021-10-04 16:21:03 +02:00
static void SpriteCB_UnusedBattleInit_Main(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
u16 *arr = (u16 *)gDecompressionBuffer;
2017-10-01 18:54:01 +02:00
2021-10-04 16:21:03 +02:00
switch (sprite->sState)
2017-10-01 18:54:01 +02:00
{
case 0:
2021-10-04 16:21:03 +02:00
sprite->sState++;
2017-12-02 21:44:50 +01:00
sprite->data[1] = 0;
sprite->data[2] = 0x281;
sprite->data[3] = 0;
2021-10-04 16:21:03 +02:00
sprite->sDelay = 1;
2017-10-01 18:54:01 +02:00
// fall through
case 1:
2021-10-04 16:21:03 +02:00
sprite->sDelay--;
if (sprite->sDelay == 0)
2017-10-01 18:54:01 +02:00
{
s32 i;
s32 r2;
s32 r0;
2021-10-04 16:21:03 +02:00
sprite->sDelay = 2;
2017-12-02 21:44:50 +01:00
r2 = sprite->data[1] + sprite->data[3] * 32;
r0 = sprite->data[2] - sprite->data[3] * 32;
2017-10-01 18:54:01 +02:00
for (i = 0; i < 29; i += 2)
{
arr[r2 + i] = 0x3D;
arr[r0 + i] = 0x3D;
}
2017-12-02 21:44:50 +01:00
sprite->data[3]++;
if (sprite->data[3] == 21)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->sState++;
2017-12-02 21:44:50 +01:00
sprite->data[1] = 32;
2017-10-01 18:54:01 +02:00
}
}
break;
case 2:
2017-12-02 21:44:50 +01:00
sprite->data[1]--;
if (sprite->data[1] == 20)
2017-10-01 18:54:01 +02:00
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 == TRAINER_SECRET_BASE)
2017-10-01 18:54:01 +02:00
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_EREADER_TRAINER
2018-09-20 22:00:00 +02:00
| BATTLE_TYPE_TRAINER_HILL)))
2017-10-01 18:54:01 +02:00
{
if (firstTrainer == TRUE)
ZeroEnemyPartyMons();
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
2021-10-04 16:21:03 +02:00
if (gTrainers[trainerNum].partySize > PARTY_SIZE / 2)
monsCount = PARTY_SIZE / 2;
2017-10-01 18:54:01 +02:00
else
monsCount = gTrainers[trainerNum].partySize;
}
else
{
monsCount = gTrainers[trainerNum].partySize;
}
for (i = 0; i < monsCount; i++)
{
if (gTrainers[trainerNum].doubleBattle == TRUE)
personalityValue = 0x80;
2021-06-25 17:50:09 +02:00
else if (gTrainers[trainerNum].encounterMusic_gender & F_TRAINER_FEMALE)
personalityValue = 0x78; // Use personality more likely to result in a female Pokémon
2017-10-01 18:54:01 +02:00
else
2021-06-25 17:50:09 +02:00
personalityValue = 0x88; // Use personality more likely to result in a male Pokémon
2017-10-01 18:54:01 +02:00
2018-02-08 11:17:41 +01:00
for (j = 0; gTrainers[trainerNum].trainerName[j] != EOS; j++)
2017-10-01 18:54:01 +02:00
nameHash += gTrainers[trainerNum].trainerName[j];
switch (gTrainers[trainerNum].partyFlags)
{
case 0:
{
const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves;
2017-12-17 21:19:08 +01:00
for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
2017-10-01 18:54:01 +02:00
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
2017-10-01 18:54:01 +02:00
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
break;
}
2017-12-17 21:19:08 +01:00
case F_TRAINER_PARTY_CUSTOM_MOVESET:
2017-10-01 18:54:01 +02:00
{
const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves;
2017-12-17 21:19:08 +01:00
for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
2017-10-01 18:54:01 +02:00
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
2019-08-31 05:06:43 +02:00
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
2017-10-01 18:54:01 +02:00
for (j = 0; j < MAX_MON_MOVES; j++)
2017-10-01 18:54:01 +02:00
{
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;
}
2017-12-17 21:19:08 +01:00
case F_TRAINER_PARTY_HELD_ITEM:
2017-10-01 18:54:01 +02:00
{
const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves;
2017-12-17 21:19:08 +01:00
for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
2017-10-01 18:54:01 +02:00
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
2019-08-31 05:06:43 +02:00
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
2017-10-01 18:54:01 +02:00
SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
break;
}
2017-12-17 21:19:08 +01:00
case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM:
2017-10-01 18:54:01 +02:00
{
const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves;
2017-12-17 21:19:08 +01:00
for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
2017-10-01 18:54:01 +02:00
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
2019-08-31 05:06:43 +02:00
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
2017-10-01 18:54:01 +02:00
SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
for (j = 0; j < MAX_MON_MOVES; j++)
2017-10-01 18:54:01 +02:00
{
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;
}
// Unused
static void HBlankCB_Battle(void)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
if (REG_VCOUNT < DISPLAY_HEIGHT && REG_VCOUNT >= 111)
2021-04-15 09:00:01 +02:00
SetGpuReg(REG_OFFSET_BG0CNT, BGCNT_SCREENBASE(24) | BGCNT_TXT256x512);
2017-10-01 18:54:01 +02:00
}
void VBlankCB_Battle(void)
{
2018-06-20 23:07:51 +02:00
// Change gRngSeed every vblank unless the battle could be recorded.
2017-10-01 18:54:01 +02:00
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();
2018-01-29 17:47:12 +01:00
ScanlineEffect_InitHBlankDmaTransfer();
2017-10-01 18:54:01 +02:00
}
2021-01-23 05:22:37 +01:00
void SpriteCB_VsLetterDummy(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
}
2021-01-23 05:22:37 +01:00
static void SpriteCB_VsLetter(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2017-12-02 21:44:50 +01:00
if (sprite->data[0] != 0)
2021-07-07 15:11:52 +02:00
sprite->x = sprite->data[1] + ((sprite->data[2] & 0xFF00) >> 8);
2017-10-01 18:54:01 +02:00
else
2021-07-07 15:11:52 +02:00
sprite->x = sprite->data[1] - ((sprite->data[2] & 0xFF00) >> 8);
2017-10-01 18:54:01 +02:00
2017-12-02 21:44:50 +01:00
sprite->data[2] += 0x180;
2017-10-01 18:54:01 +02:00
if (sprite->affineAnimEnded)
{
2021-01-23 02:03:21 +01:00
FreeSpriteTilesByTag(ANIM_SPRITES_START);
FreeSpritePaletteByTag(ANIM_SPRITES_START);
2017-10-01 18:54:01 +02:00
FreeSpriteOamMatrix(sprite);
DestroySprite(sprite);
}
}
2021-01-23 05:22:37 +01:00
void SpriteCB_VsLetterInit(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
StartSpriteAffineAnim(sprite, 1);
2021-01-23 05:22:37 +01:00
sprite->callback = SpriteCB_VsLetter;
2020-08-21 00:02:00 +02:00
PlaySE(SE_MUGSHOT);
2017-10-01 18:54:01 +02:00
}
2021-01-23 05:22:37 +01:00
static void BufferPartyVsScreenHealth_AtEnd(u8 taskId)
2017-10-01 18:54:01 +02:00
{
2021-01-23 02:03:21 +01:00
struct Pokemon *party1 = NULL;
struct Pokemon *party2 = NULL;
u8 multiplayerId = gBattleScripting.multiplayerId;
2021-01-23 05:22:37 +01:00
u32 flags;
2017-10-01 18:54:01 +02:00
s32 i;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
2021-01-23 02:03:21 +01:00
switch (gLinkPlayers[multiplayerId].id)
2017-10-01 18:54:01 +02:00
{
case 0:
case 2:
2021-01-23 02:03:21 +01:00
party1 = gPlayerParty;
party2 = gEnemyParty;
2017-10-01 18:54:01 +02:00
break;
case 1:
case 3:
2021-01-23 02:03:21 +01:00
party1 = gEnemyParty;
party2 = gPlayerParty;
2017-10-01 18:54:01 +02:00
break;
}
}
else
{
2021-01-23 02:03:21 +01:00
party1 = gPlayerParty;
party2 = gEnemyParty;
2017-10-01 18:54:01 +02:00
}
2021-01-23 05:22:37 +01:00
flags = 0;
BUFFER_PARTY_VS_SCREEN_STATUS(party1, flags, i);
gTasks[taskId].data[3] = flags;
2017-10-01 18:54:01 +02:00
2021-01-23 05:22:37 +01:00
flags = 0;
BUFFER_PARTY_VS_SCREEN_STATUS(party2, flags, i);
gTasks[taskId].data[4] = flags;
2017-10-01 18:54:01 +02:00
}
2021-01-23 02:03:21 +01:00
void CB2_InitEndLinkBattle(void)
2017-10-01 18:54:01 +02:00
{
s32 i;
u8 taskId;
SetHBlankCallback(NULL);
SetVBlankCallback(NULL);
2021-09-24 20:30:15 +02:00
gBattleTypeFlags &= ~BATTLE_TYPE_LINK_IN_BATTLE;
2017-10-01 18:54:01 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
else
{
2022-07-29 16:52:35 +02:00
CpuFill32(0, (void *)(VRAM), VRAM_SIZE);
2017-10-01 18:54:01 +02:00
SetGpuReg(REG_OFFSET_MOSAIC, 0);
2021-01-23 02:03:21 +01:00
SetGpuReg(REG_OFFSET_WIN0H, DISPLAY_WIDTH);
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1));
2017-10-01 18:54:01 +02:00
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
2021-01-23 02:03:21 +01:00
gBattle_WIN0H = DISPLAY_WIDTH;
gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1);
2018-01-29 17:47:12 +01:00
ScanlineEffect_Clear();
2017-10-01 18:54:01 +02:00
2019-01-05 19:25:46 +01:00
i = 0;
while (i < 80)
2017-10-01 18:54:01 +02:00
{
2018-01-29 17:47:12 +01:00
gScanlineEffectRegBuffers[0][i] = 0xF0;
gScanlineEffectRegBuffers[1][i] = 0xF0;
2019-01-05 19:25:46 +01:00
i++;
2017-10-01 18:54:01 +02:00
}
2019-01-05 19:25:46 +01:00
while (i < 160)
2017-10-01 18:54:01 +02:00
{
2018-01-29 17:47:12 +01:00
gScanlineEffectRegBuffers[0][i] = 0xFF10;
gScanlineEffectRegBuffers[1][i] = 0xFF10;
2019-01-05 19:25:46 +01:00
i++;
2017-10-01 18:54:01 +02:00
}
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;
2019-11-07 01:18:11 +01:00
InitBattleBgsVideo();
2017-12-17 20:10:57 +01:00
LoadCompressedPalette(gBattleTextboxPalette, 0, 64);
2018-06-17 16:48:58 +02:00
LoadBattleMenuWindowGfx();
2017-10-01 18:54:01 +02:00
ResetSpriteData();
ResetTasks();
2018-06-17 16:48:58 +02:00
DrawBattleEntryBackground();
2021-01-23 02:03:21 +01:00
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
2017-10-01 18:54:01 +02:00
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 4;
SetVBlankCallback(VBlankCB_Battle);
2021-01-23 02:03:21 +01:00
// Show end Vs screen with battle results
2019-11-07 01:18:11 +01:00
taskId = CreateTask(InitLinkBattleVsScreen, 0);
2017-10-01 18:54:01 +02:00
gTasks[taskId].data[1] = 0x10E;
gTasks[taskId].data[2] = 0x5A;
gTasks[taskId].data[5] = 1;
2021-01-23 05:22:37 +01:00
BufferPartyVsScreenHealth_AtEnd(taskId);
2021-01-23 02:03:21 +01:00
SetMainCallback2(CB2_EndLinkBattle);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE] = 0;
}
}
2021-01-23 02:03:21 +01:00
static void CB2_EndLinkBattle(void)
2017-10-01 18:54:01 +02:00
{
2021-01-23 02:03:21 +01:00
EndLinkBattleInSteps();
2017-10-01 18:54:01 +02:00
AnimateSprites();
BuildOamBuffer();
RunTextPrinters();
UpdatePaletteFade();
RunTasks();
}
2021-01-23 02:03:21 +01:00
static void EndLinkBattleInSteps(void)
2017-10-01 18:54:01 +02:00
{
s32 i;
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
ShowBg(0);
ShowBg(1);
ShowBg(2);
gBattleCommunication[1] = 0xFF;
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 1:
if (--gBattleCommunication[1] == 0)
{
2021-10-04 16:21:03 +02:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 2:
if (!gPaletteFade.active)
{
2021-10-04 16:21:03 +02:00
u8 battlerCount;
2017-10-01 18:54:01 +02:00
2021-03-15 20:22:41 +01:00
gMain.anyLinkBattlerHasFrontierPass = RecordedBattle_GetFrontierPassFlag();
2017-10-01 18:54:01 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
2021-10-04 16:21:03 +02:00
battlerCount = 4;
2017-10-01 18:54:01 +02:00
else
2021-10-04 16:21:03 +02:00
battlerCount = 2;
2017-10-01 18:54:01 +02:00
2021-10-04 16:21:03 +02:00
for (i = 0; i < battlerCount && (gLinkPlayers[i].version & 0xFF) == VERSION_EMERALD; i++);
2017-10-01 18:54:01 +02:00
2021-10-04 16:21:03 +02:00
if (!gSaveBlock2Ptr->frontier.disableRecordBattle && i == battlerCount)
2017-10-01 18:54:01 +02:00
{
2017-11-08 22:20:10 +01:00
if (FlagGet(FLAG_SYS_FRONTIER_PASS))
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
// Ask player if they want to record the battle
2017-10-01 18:54:01 +02:00
FreeAllWindowBuffers();
2021-10-04 16:21:03 +02:00
SetMainCallback2(CB2_InitAskRecordBattle);
2017-10-01 18:54:01 +02:00
}
2021-03-15 20:22:41 +01:00
else if (!gMain.anyLinkBattlerHasFrontierPass)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
// No players can record this battle, end
2017-10-01 18:54:01 +02:00
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
else if (gReceivedRemoteLinkPlayers == 0)
{
2021-10-04 16:21:03 +02:00
// Player can't record battle but
// another player can, reconnect with them
2021-03-04 23:48:40 +01:00
CreateTask(Task_ReconnectWithLinkPlayers, 5);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
else
{
gBattleCommunication[MULTIUSE_STATE]++;
}
}
else
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
}
break;
case 3:
2022-07-29 16:52:35 +02:00
CpuFill32(0, (void *)VRAM, VRAM_SIZE);
2017-10-01 18:54:01 +02:00
for (i = 0; i < 2; i++)
LoadChosenBattleElement(i);
2021-10-04 16:21:03 +02:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 4:
if (!gPaletteFade.active)
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 5:
2021-03-04 23:48:40 +01:00
if (!FuncIsActiveTask(Task_ReconnectWithLinkPlayers))
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 6:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished() == TRUE)
2017-10-01 18:54:01 +02:00
{
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback();
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_LinkStandby3, B_WIN_MSG);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
2021-10-08 22:50:52 +02:00
if (!IsTextPrinterActive(B_WIN_MSG))
2017-10-01 18:54:01 +02:00
{
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished() == TRUE)
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
2017-11-13 05:58:05 +01:00
if (!gWirelessCommType)
2020-08-13 09:09:47 +02:00
SetCloseLinkCallback();
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 9:
2021-03-15 20:22:41 +01:00
if (!gMain.anyLinkBattlerHasFrontierPass || gWirelessCommType || gReceivedRemoteLinkPlayers != 1)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
gMain.anyLinkBattlerHasFrontierPass = FALSE;
2017-10-01 18:54:01 +02:00
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
break;
}
}
2021-01-23 05:22:37 +01:00
u32 GetBattleBgTemplateData(u8 arrayId, u8 caseId)
2017-10-01 18:54:01 +02:00
{
u32 ret = 0;
switch (caseId)
{
case 0:
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].bg;
2017-10-01 18:54:01 +02:00
break;
case 1:
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].charBaseIndex;
2017-10-01 18:54:01 +02:00
break;
case 2:
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].mapBaseIndex;
2017-10-01 18:54:01 +02:00
break;
case 3:
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].screenSize;
2017-10-01 18:54:01 +02:00
break;
case 4:
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].paletteMode;
2017-10-01 18:54:01 +02:00
break;
2021-01-23 05:22:37 +01:00
case 5: // Only this case is used
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].priority;
2017-10-01 18:54:01 +02:00
break;
case 6:
2018-06-17 16:48:58 +02:00
ret = gBattleBgTemplates[arrayId].baseTile;
2017-10-01 18:54:01 +02:00
break;
}
return ret;
}
2021-10-04 16:21:03 +02:00
static void CB2_InitAskRecordBattle(void)
2017-10-01 18:54:01 +02:00
{
s32 i;
SetHBlankCallback(NULL);
SetVBlankCallback(NULL);
2022-07-29 16:52:35 +02:00
CpuFill32(0, (void *)(VRAM), VRAM_SIZE);
2017-10-01 18:54:01 +02:00
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;
2019-11-07 01:18:11 +01:00
InitBattleBgsVideo();
2017-10-01 18:54:01 +02:00
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
2018-06-17 16:48:58 +02:00
LoadBattleMenuWindowGfx();
2017-10-01 18:54:01 +02:00
for (i = 0; i < 2; i++)
LoadChosenBattleElement(i);
ResetSpriteData();
ResetTasks();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 4;
SetVBlankCallback(VBlankCB_Battle);
2021-10-04 16:21:03 +02:00
SetMainCallback2(CB2_AskRecordBattle);
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE] = 0;
}
2021-10-04 16:21:03 +02:00
static void CB2_AskRecordBattle(void)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
AskRecordBattle();
2017-10-01 18:54:01 +02:00
AnimateSprites();
BuildOamBuffer();
RunTextPrinters();
UpdatePaletteFade();
RunTasks();
}
2021-10-04 16:21:03 +02:00
// States for AskRecordBattle
#define STATE_INIT 0
#define STATE_LINK 1
#define STATE_WAIT_LINK 2
#define STATE_ASK_RECORD 3
#define STATE_PRINT_YES_NO 4
#define STATE_HANDLE_YES_NO 5
#define STATE_RECORD_NO 6
#define STATE_END_RECORD_NO 7
#define STATE_WAIT_END 8
#define STATE_END 9
#define STATE_RECORD_YES 10
#define STATE_RECORD_WAIT 11
#define STATE_END_RECORD_YES 12
static void AskRecordBattle(void)
2017-10-01 18:54:01 +02:00
{
switch (gBattleCommunication[MULTIUSE_STATE])
{
2021-10-04 16:21:03 +02:00
case STATE_INIT:
2017-10-01 18:54:01 +02:00
ShowBg(0);
ShowBg(1);
ShowBg(2);
gBattleCommunication[MULTIUSE_STATE]++;
break;
2021-10-04 16:21:03 +02:00
case STATE_LINK:
2021-03-15 20:22:41 +01:00
if (gMain.anyLinkBattlerHasFrontierPass && gReceivedRemoteLinkPlayers == 0)
2021-03-04 23:48:40 +01:00
CreateTask(Task_ReconnectWithLinkPlayers, 5);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
2021-10-04 16:21:03 +02:00
case STATE_WAIT_LINK:
2021-03-04 23:48:40 +01:00
if (!FuncIsActiveTask(Task_ReconnectWithLinkPlayers))
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
2021-10-04 16:21:03 +02:00
case STATE_ASK_RECORD:
2017-10-01 18:54:01 +02:00
if (!gPaletteFade.active)
{
2021-10-04 16:21:03 +02:00
// "Would you like to record your battle on your FRONTIER PASS?"
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_RecordBattleToPass, B_WIN_MSG);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
2021-10-04 16:21:03 +02:00
case STATE_PRINT_YES_NO:
2021-10-08 22:50:52 +02:00
if (!IsTextPrinterActive(B_WIN_MSG))
2017-10-01 18:54:01 +02:00
{
HandleBattleWindow(YESNOBOX_X_Y, 0);
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_BattleYesNoChoice, B_WIN_YESNO);
2017-10-01 18:54:01 +02:00
gBattleCommunication[CURSOR_POSITION] = 1;
2017-10-29 16:15:23 +01:00
BattleCreateYesNoCursorAt(1);
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
2021-10-04 16:21:03 +02:00
case STATE_HANDLE_YES_NO:
2020-09-05 03:11:55 +02:00
if (JOY_NEW(DPAD_UP))
2017-10-01 18:54:01 +02:00
{
if (gBattleCommunication[CURSOR_POSITION] != 0)
{
2021-10-04 16:21:03 +02:00
// Moved cursor onto Yes
2017-10-01 18:54:01 +02:00
PlaySE(SE_SELECT);
2017-10-29 16:15:23 +01:00
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
2017-10-01 18:54:01 +02:00
gBattleCommunication[CURSOR_POSITION] = 0;
2017-10-29 16:15:23 +01:00
BattleCreateYesNoCursorAt(0);
2017-10-01 18:54:01 +02:00
}
}
2020-09-05 03:11:55 +02:00
else if (JOY_NEW(DPAD_DOWN))
2017-10-01 18:54:01 +02:00
{
if (gBattleCommunication[CURSOR_POSITION] == 0)
{
2021-10-04 16:21:03 +02:00
// Moved cursor onto No
2017-10-01 18:54:01 +02:00
PlaySE(SE_SELECT);
2017-10-29 16:15:23 +01:00
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
2017-10-01 18:54:01 +02:00
gBattleCommunication[CURSOR_POSITION] = 1;
2017-10-29 16:15:23 +01:00
BattleCreateYesNoCursorAt(1);
2017-10-01 18:54:01 +02:00
}
}
2020-09-05 03:11:55 +02:00
else if (JOY_NEW(A_BUTTON))
2017-10-01 18:54:01 +02:00
{
PlaySE(SE_SELECT);
if (gBattleCommunication[CURSOR_POSITION] == 0)
{
2021-10-04 16:21:03 +02:00
// Selected Yes
HandleBattleWindow(YESNOBOX_X_Y, WINDOW_CLEAR);
2017-10-01 18:54:01 +02:00
gBattleCommunication[1] = MoveRecordedBattleToSaveData();
2021-10-04 16:21:03 +02:00
gBattleCommunication[MULTIUSE_STATE] = STATE_RECORD_YES;
2017-10-01 18:54:01 +02:00
}
else
{
2021-10-04 16:21:03 +02:00
// Selected No
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
}
2020-09-05 03:11:55 +02:00
else if (JOY_NEW(B_BUTTON))
2017-10-01 18:54:01 +02:00
{
PlaySE(SE_SELECT);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
2021-10-04 16:21:03 +02:00
case STATE_RECORD_NO:
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished() == TRUE)
2017-10-01 18:54:01 +02:00
{
HandleBattleWindow(YESNOBOX_X_Y, WINDOW_CLEAR);
2021-03-15 20:22:41 +01:00
if (gMain.anyLinkBattlerHasFrontierPass)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
// Other battlers may be recording, wait for them
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback();
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_LinkStandby3, B_WIN_MSG);
2017-10-01 18:54:01 +02:00
}
2021-10-04 16:21:03 +02:00
gBattleCommunication[MULTIUSE_STATE]++; // STATE_END_RECORD_NO
2017-10-01 18:54:01 +02:00
}
break;
2021-10-04 16:21:03 +02:00
case STATE_WAIT_END:
2017-10-01 18:54:01 +02:00
if (--gBattleCommunication[1] == 0)
{
2021-03-15 20:22:41 +01:00
if (gMain.anyLinkBattlerHasFrontierPass && !gWirelessCommType)
2020-08-13 09:09:47 +02:00
SetCloseLinkCallback();
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
2021-10-04 16:21:03 +02:00
case STATE_END:
2021-03-15 20:22:41 +01:00
if (!gMain.anyLinkBattlerHasFrontierPass || gWirelessCommType || gReceivedRemoteLinkPlayers != 1)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
gMain.anyLinkBattlerHasFrontierPass = FALSE;
2017-10-01 18:54:01 +02:00
if (!gPaletteFade.active)
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
}
break;
2021-10-04 16:21:03 +02:00
case STATE_RECORD_YES:
2017-10-01 18:54:01 +02:00
if (gBattleCommunication[1] == 1)
{
PlaySE(SE_SAVE);
BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordedOnPass);
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
2021-10-04 16:21:03 +02:00
gBattleCommunication[1] = 128; // Delay
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
else
{
2019-12-14 09:58:20 +01:00
BattleStringExpandPlaceholdersToDisplayedString(BattleFrontier_BattleTowerBattleRoom_Text_RecordCouldntBeSaved);
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
2021-10-04 16:21:03 +02:00
gBattleCommunication[1] = 128; // Delay
2017-10-01 18:54:01 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
2021-10-04 16:21:03 +02:00
case STATE_RECORD_WAIT:
2021-10-08 22:50:52 +02:00
if (IsLinkTaskFinished() == TRUE && !IsTextPrinterActive(B_WIN_MSG) && --gBattleCommunication[1] == 0)
2017-10-01 18:54:01 +02:00
{
2021-03-15 20:22:41 +01:00
if (gMain.anyLinkBattlerHasFrontierPass)
2017-10-01 18:54:01 +02:00
{
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback();
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_LinkStandby3, B_WIN_MSG);
2017-10-01 18:54:01 +02:00
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
2021-10-04 16:21:03 +02:00
case STATE_END_RECORD_YES:
case STATE_END_RECORD_NO:
2021-10-08 22:50:52 +02:00
if (!IsTextPrinterActive(B_WIN_MSG))
2017-10-01 18:54:01 +02:00
{
2021-03-15 20:22:41 +01:00
if (gMain.anyLinkBattlerHasFrontierPass)
2017-10-01 18:54:01 +02:00
{
2018-12-31 09:22:21 +01:00
if (IsLinkTaskFinished() == TRUE)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gBattleCommunication[1] = 32; // Delay
gBattleCommunication[MULTIUSE_STATE] = STATE_WAIT_END;
2017-10-01 18:54:01 +02:00
}
}
else
{
2021-10-04 16:21:03 +02:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gBattleCommunication[1] = 32; // Delay
gBattleCommunication[MULTIUSE_STATE] = STATE_WAIT_END;
2017-10-01 18:54:01 +02:00
}
}
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);
2018-12-23 14:52:47 +01:00
if (StringCompareWithoutExtCtrlCodes(nickname, sText_ShedinjaJpnName) == 0)
2017-10-01 18:54:01 +02:00
SetMonData(mon, MON_DATA_LANGUAGE, &language);
}
}
2021-10-04 16:21:03 +02:00
u32 GetBattleWindowTemplatePixelWidth(u32 windowsType, u32 tableId)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
return gBattleWindowTemplates[windowsType][tableId].width * 8;
2017-10-01 18:54:01 +02:00
}
2018-02-06 23:09:39 +01:00
#define sBattler data[0]
#define sSpeciesId data[2]
2017-10-01 18:54:01 +02:00
void SpriteCB_WildMon(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
sprite->callback = SpriteCB_MoveWildMonToRight;
2017-10-01 18:54:01 +02:00
StartSpriteAnimIfDifferent(sprite, 0);
2018-06-20 23:07:51 +02:00
BeginNormalPaletteFade(0x20000, 0, 10, 10, RGB(8, 8, 8));
2017-10-01 18:54:01 +02:00
}
static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2018-02-08 11:17:41 +01:00
if ((gIntroSlideFlags & 1) == 0)
2017-10-01 18:54:01 +02:00
{
2021-07-07 15:11:52 +02:00
sprite->x2 += 2;
if (sprite->x2 == 0)
2017-10-01 18:54:01 +02:00
{
sprite->callback = SpriteCB_WildMonShowHealthbox;
2017-10-01 18:54:01 +02:00
}
}
}
static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
if (sprite->animEnded)
{
2021-01-23 02:03:21 +01:00
StartHealthboxSlideIn(sprite->sBattler);
2018-02-06 23:09:39 +01:00
SetHealthboxSpriteVisible(gHealthboxSpriteIds[sprite->sBattler]);
sprite->callback = SpriteCB_WildMonAnimate;
2017-10-01 18:54:01 +02:00
StartSpriteAnimIfDifferent(sprite, 0);
2018-06-20 23:07:51 +02:00
BeginNormalPaletteFade(0x20000, 0, 10, 0, RGB(8, 8, 8));
2017-10-01 18:54:01 +02:00
}
}
static void SpriteCB_WildMonAnimate(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
if (!gPaletteFade.active)
{
2018-02-06 23:09:39 +01:00
BattleAnimateFrontSprite(sprite, sprite->sSpeciesId, FALSE, 1);
2017-10-01 18:54:01 +02:00
}
}
void SpriteCallbackDummy_2(struct Sprite *sprite)
{
}
2021-10-04 16:21:03 +02:00
#define sNumFlickers data[3]
#define sDelay data[4]
2021-01-23 05:22:37 +01:00
// Unused
2021-10-04 16:21:03 +02:00
static void SpriteCB_InitFlicker(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->sNumFlickers = 6;
sprite->sDelay = 1;
sprite->callback = SpriteCB_Flicker;
2017-10-01 18:54:01 +02:00
}
2021-10-04 16:21:03 +02:00
static void SpriteCB_Flicker(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->sDelay--;
if (sprite->sDelay == 0)
2017-10-01 18:54:01 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->sDelay = 8;
2017-10-01 18:54:01 +02:00
sprite->invisible ^= 1;
2021-10-04 16:21:03 +02:00
sprite->sNumFlickers--;
if (sprite->sNumFlickers == 0)
2017-10-01 18:54:01 +02:00
{
sprite->invisible = FALSE;
sprite->callback = SpriteCallbackDummy_2;
2021-10-04 16:21:03 +02:00
sFlickerArray[0] = 0;
2017-10-01 18:54:01 +02:00
}
}
}
2021-10-04 16:21:03 +02:00
#undef sNumFlickers
#undef sDelay
2017-10-01 18:54:01 +02:00
extern const struct MonCoords gMonFrontPicCoords[];
extern const struct MonCoords gCastformFrontSpriteCoords[];
2018-06-20 23:07:51 +02:00
void SpriteCB_FaintOpponentMon(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2018-02-06 23:09:39 +01:00
u8 battler = sprite->sBattler;
2017-10-01 18:54:01 +02:00
u16 species;
u8 yOffset;
2018-02-06 23:09:39 +01:00
if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies != 0)
species = gBattleSpritesDataPtr->battlerData[battler].transformSpecies;
2017-10-01 18:54:01 +02:00
else
2018-02-06 23:09:39 +01:00
species = sprite->sSpeciesId;
2017-10-01 18:54:01 +02:00
2018-06-20 23:07:51 +02:00
GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); // Unused return value.
2017-10-01 18:54:01 +02:00
if (species == SPECIES_UNOWN)
{
2018-02-06 23:09:39 +01:00
u32 personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY);
2021-01-19 10:03:16 +01:00
u16 unownForm = GET_UNOWN_LETTER(personalityValue);
2017-10-01 18:54:01 +02:00
u16 unownSpecies;
if (unownForm == 0)
2018-06-20 23:07:51 +02:00
unownSpecies = SPECIES_UNOWN; // Use the A Unown form.
2017-10-01 18:54:01 +02:00
else
2018-06-20 23:07:51 +02:00
unownSpecies = NUM_SPECIES + unownForm; // Use one of the other Unown letters.
2017-10-01 18:54:01 +02:00
yOffset = gMonFrontPicCoords[unownSpecies].y_offset;
}
else if (species == SPECIES_CASTFORM)
{
2018-02-06 23:09:39 +01:00
yOffset = gCastformFrontSpriteCoords[gBattleMonForms[battler]].y_offset;
2017-10-01 18:54:01 +02:00
}
else if (species > NUM_SPECIES)
{
yOffset = gMonFrontPicCoords[SPECIES_NONE].y_offset;
}
else
{
yOffset = gMonFrontPicCoords[species].y_offset;
}
2017-12-02 21:44:50 +01:00
sprite->data[3] = 8 - yOffset / 8;
sprite->data[4] = 1;
2018-06-20 23:07:51 +02:00
sprite->callback = SpriteCB_AnimFaintOpponent;
2017-10-01 18:54:01 +02:00
}
2018-06-20 23:07:51 +02:00
static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
s32 i;
2018-06-20 23:07:51 +02:00
if (--sprite->data[4] == 0)
2017-10-01 18:54:01 +02:00
{
2017-12-02 21:44:50 +01:00
sprite->data[4] = 2;
2021-07-07 15:11:52 +02:00
sprite->y2 += 8; // Move the sprite down.
2018-06-20 23:07:51 +02:00
if (--sprite->data[3] < 0)
2017-10-01 18:54:01 +02:00
{
FreeSpriteOamMatrix(sprite);
DestroySprite(sprite);
}
2018-06-20 23:07:51 +02:00
else // Erase bottom part of the sprite to create a smooth illusion of mon falling down.
2017-10-01 18:54:01 +02:00
{
u8 *dst = gMonSpritesGfxPtr->sprites.byte[GetBattlerPosition(sprite->sBattler)] + (gBattleMonForms[sprite->sBattler] << 11) + (sprite->data[3] << 8);
2017-10-01 18:54:01 +02:00
for (i = 0; i < 0x100; i++)
*(dst++) = 0;
2018-02-06 23:09:39 +01:00
StartSpriteAnim(sprite, gBattleMonForms[sprite->sBattler]);
2017-10-01 18:54:01 +02:00
}
}
}
2020-07-14 11:13:03 +02:00
// Used when selecting a move, which can hit multiple targets, in double battles.
void SpriteCB_ShowAsMoveTarget(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2017-12-02 21:44:50 +01:00
sprite->data[3] = 8;
sprite->data[4] = sprite->invisible;
sprite->callback = SpriteCB_BlinkVisible;
2017-10-01 18:54:01 +02:00
}
static void SpriteCB_BlinkVisible(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2020-07-14 11:13:03 +02:00
if (--sprite->data[3] == 0)
2017-10-01 18:54:01 +02:00
{
sprite->invisible ^= 1;
2017-12-02 21:44:50 +01:00
sprite->data[3] = 8;
2017-10-01 18:54:01 +02:00
}
}
void SpriteCB_HideAsMoveTarget(struct Sprite *sprite)
2017-10-01 18:54:01 +02:00
{
2017-12-02 21:44:50 +01:00
sprite->invisible = sprite->data[4];
sprite->data[4] = FALSE;
2017-10-01 18:54:01 +02:00
sprite->callback = SpriteCallbackDummy_2;
}
2021-10-04 16:21:03 +02:00
void SpriteCB_OpponentMonFromBall(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
if (sprite->affineAnimEnded)
{
2021-01-13 21:17:32 +01:00
if (!(gHitMarker & HITMARKER_NO_ANIMATIONS) || gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
2017-10-02 23:32:39 +02:00
{
2018-02-06 23:09:39 +01:00
if (HasTwoFramesAnimation(sprite->sSpeciesId))
2017-10-02 23:32:39 +02:00
StartSpriteAnim(sprite, 1);
}
2018-02-06 23:09:39 +01:00
BattleAnimateFrontSprite(sprite, sprite->sSpeciesId, TRUE, 1);
2017-10-02 23:32:39 +02:00
}
}
2021-01-23 05:22:37 +01:00
// This callback is frequently overwritten by SpriteCB_TrainerSlideIn
void SpriteCB_BattleSpriteStartSlideLeft(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
2021-01-23 05:22:37 +01:00
sprite->callback = SpriteCB_BattleSpriteSlideLeft;
2017-10-02 23:32:39 +02:00
}
2021-01-23 05:22:37 +01:00
static void SpriteCB_BattleSpriteSlideLeft(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
if (!(gIntroSlideFlags & 1))
2017-10-02 23:32:39 +02:00
{
2021-07-07 15:11:52 +02:00
sprite->x2 -= 2;
if (sprite->x2 == 0)
2017-10-02 23:32:39 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->callback = SpriteCB_Idle;
2017-12-02 21:44:50 +01:00
sprite->data[1] = 0;
2017-10-02 23:32:39 +02:00
}
}
}
2021-01-23 05:22:37 +01:00
// Unused
2021-10-04 16:21:03 +02:00
static void SetIdleSpriteCallback(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
2021-10-04 16:21:03 +02:00
sprite->callback = SpriteCB_Idle;
2017-10-02 23:32:39 +02:00
}
2021-10-04 16:21:03 +02:00
static void SpriteCB_Idle(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
}
2021-01-23 02:03:21 +01:00
#define sSpeedX data[1]
#define sSpeedY data[2]
void SpriteCB_FaintSlideAnim(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
2018-02-08 11:17:41 +01:00
if (!(gIntroSlideFlags & 1))
2017-10-02 23:32:39 +02:00
{
2021-07-07 15:11:52 +02:00
sprite->x2 += sprite->sSpeedX;
sprite->y2 += sprite->sSpeedY;
2017-10-02 23:32:39 +02:00
}
}
2021-01-23 02:03:21 +01:00
#undef sSpeedX
#undef sSpeedY
2018-06-20 23:07:51 +02:00
#define sSinIndex data[0]
#define sDelta data[1]
#define sAmplitude data[2]
#define sBouncerSpriteId data[3]
#define sWhich data[4]
void DoBounceEffect(u8 battler, u8 which, s8 delta, s8 amplitude)
2017-10-02 23:32:39 +02:00
{
2018-06-20 23:07:51 +02:00
u8 invisibleSpriteId;
u8 bouncerSpriteId;
2017-10-02 23:32:39 +02:00
2018-06-20 23:07:51 +02:00
switch (which)
2017-10-02 23:32:39 +02:00
{
2018-06-20 23:07:51 +02:00
case BOUNCE_HEALTHBOX:
default:
if (gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing)
2017-10-02 23:32:39 +02:00
return;
2018-06-20 23:07:51 +02:00
break;
case BOUNCE_MON:
if (gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing)
2017-10-02 23:32:39 +02:00
return;
2018-06-20 23:07:51 +02:00
break;
2017-10-02 23:32:39 +02:00
}
2018-06-20 23:07:51 +02:00
invisibleSpriteId = CreateInvisibleSpriteWithCallback(SpriteCB_BounceEffect);
if (which == BOUNCE_HEALTHBOX)
2017-10-02 23:32:39 +02:00
{
2018-06-20 23:07:51 +02:00
bouncerSpriteId = gHealthboxSpriteIds[battler];
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxBounceSpriteId = invisibleSpriteId;
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing = 1;
gSprites[invisibleSpriteId].sSinIndex = 128; // 0
2017-10-02 23:32:39 +02:00
}
else
{
2018-06-20 23:07:51 +02:00
bouncerSpriteId = gBattlerSpriteIds[battler];
gBattleSpritesDataPtr->healthBoxesData[battler].battlerBounceSpriteId = invisibleSpriteId;
gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing = 1;
gSprites[invisibleSpriteId].sSinIndex = 192; // -1
}
gSprites[invisibleSpriteId].sDelta = delta;
gSprites[invisibleSpriteId].sAmplitude = amplitude;
gSprites[invisibleSpriteId].sBouncerSpriteId = bouncerSpriteId;
gSprites[invisibleSpriteId].sWhich = which;
2021-07-07 15:11:52 +02:00
gSprites[bouncerSpriteId].x2 = 0;
gSprites[bouncerSpriteId].y2 = 0;
2017-10-02 23:32:39 +02:00
}
2018-06-20 23:07:51 +02:00
void EndBounceEffect(u8 battler, u8 which)
2017-10-02 23:32:39 +02:00
{
2018-06-20 23:07:51 +02:00
u8 bouncerSpriteId;
2017-10-02 23:32:39 +02:00
2018-06-20 23:07:51 +02:00
if (which == BOUNCE_HEALTHBOX)
2017-10-02 23:32:39 +02:00
{
2018-06-20 23:07:51 +02:00
if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing)
2017-10-02 23:32:39 +02:00
return;
2018-06-20 23:07:51 +02:00
bouncerSpriteId = gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].healthboxBounceSpriteId].sBouncerSpriteId;
DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].healthboxBounceSpriteId]);
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxIsBouncing = 0;
2017-10-02 23:32:39 +02:00
}
else
{
2018-06-20 23:07:51 +02:00
if (!gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing)
2017-10-02 23:32:39 +02:00
return;
2018-06-20 23:07:51 +02:00
bouncerSpriteId = gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].battlerBounceSpriteId].sBouncerSpriteId;
DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].battlerBounceSpriteId]);
gBattleSpritesDataPtr->healthBoxesData[battler].battlerIsBouncing = 0;
2017-10-02 23:32:39 +02:00
}
2018-06-20 23:07:51 +02:00
2021-07-07 15:11:52 +02:00
gSprites[bouncerSpriteId].x2 = 0;
gSprites[bouncerSpriteId].y2 = 0;
2017-10-02 23:32:39 +02:00
}
2018-06-20 23:07:51 +02:00
static void SpriteCB_BounceEffect(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
2018-06-20 23:07:51 +02:00
u8 bouncerSpriteId = sprite->sBouncerSpriteId;
s32 index;
2017-10-02 23:32:39 +02:00
2018-06-20 23:07:51 +02:00
if (sprite->sWhich == BOUNCE_HEALTHBOX)
index = sprite->sSinIndex;
2017-10-02 23:32:39 +02:00
else
2018-06-20 23:07:51 +02:00
index = sprite->sSinIndex;
2017-10-02 23:32:39 +02:00
2021-07-07 15:11:52 +02:00
gSprites[bouncerSpriteId].y2 = Sin(index, sprite->sAmplitude) + sprite->sAmplitude;
2018-06-20 23:07:51 +02:00
sprite->sSinIndex = (sprite->sSinIndex + sprite->sDelta) & 0xFF;
2017-10-02 23:32:39 +02:00
}
2018-06-20 23:07:51 +02:00
#undef sSinIndex
#undef sDelta
#undef sAmplitude
#undef sBouncerSpriteId
#undef sWhich
2021-10-04 16:21:03 +02:00
void SpriteCB_PlayerMonFromBall(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
if (sprite->affineAnimEnded)
2018-02-06 23:09:39 +01:00
BattleAnimateBackSprite(sprite, sprite->sSpeciesId);
2017-10-02 23:32:39 +02:00
}
2021-10-04 16:21:03 +02:00
static void SpriteCB_TrainerThrowObject_Main(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
2021-11-08 19:18:58 +01:00
AnimSetCenterToCornerVecX(sprite);
2017-10-02 23:32:39 +02:00
if (sprite->animEnded)
2021-10-04 16:21:03 +02:00
sprite->callback = SpriteCB_Idle;
2017-10-02 23:32:39 +02:00
}
// Sprite callback for a trainer back pic to throw an object
2021-10-04 16:21:03 +02:00
// (Wally throwing a ball, throwing Pokéblocks/balls in the Safari Zone)
2020-08-30 21:11:44 +02:00
void SpriteCB_TrainerThrowObject(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
StartSpriteAnim(sprite, 1);
2021-10-04 16:21:03 +02:00
sprite->callback = SpriteCB_TrainerThrowObject_Main;
2017-10-02 23:32:39 +02:00
}
2021-11-08 19:18:58 +01:00
void AnimSetCenterToCornerVecX(struct Sprite *sprite)
2017-10-02 23:32:39 +02:00
{
if (sprite->animDelayCounter == 0)
2021-11-08 19:18:58 +01:00
sprite->centerToCornerVecX = sCenterToCornerVecXs[sprite->animCmdIndex];
2017-10-02 23:32:39 +02:00
}
void BeginBattleIntroDummy(void)
2017-10-02 23:32:39 +02:00
{
}
void BeginBattleIntro(void)
{
BattleStartClearSetData();
gBattleCommunication[1] = 0;
gBattleMainFunc = BattleIntroGetMonsData;
}
2017-10-06 19:09:37 +02:00
static void BattleMainCB1(void)
2017-10-02 23:32:39 +02:00
{
gBattleMainFunc();
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2018-02-06 20:48:02 +01:00
gBattlerControllerFuncs[gActiveBattler]();
2017-10-02 23:32:39 +02:00
}
static void BattleStartClearSetData(void)
{
s32 i;
u32 j;
u8 *dataPtr;
2017-10-06 00:12:01 +02:00
TurnValuesCleanUp(FALSE);
2017-10-02 23:32:39 +02:00
SpecialStatusesClear();
2018-02-06 02:46:59 +01:00
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
2017-10-02 23:32:39 +02:00
{
gStatuses3[i] = 0;
dataPtr = (u8 *)&gDisableStructs[i];
for (j = 0; j < sizeof(struct DisableStruct); j++)
dataPtr[j] = 0;
gDisableStructs[i].isFirstTurn = 2;
2018-02-08 11:17:41 +01:00
sUnusedBattlersArray[i] = 0;
gLastMoves[i] = MOVE_NONE;
gLastLandedMoves[i] = MOVE_NONE;
2017-11-26 14:17:02 +01:00
gLastHitByType[i] = 0;
gLastResultingMoves[i] = MOVE_NONE;
gLastHitBy[i] = 0xFF;
gLockedMoves[i] = MOVE_NONE;
gLastPrintedMoves[i] = MOVE_NONE;
2017-10-02 23:32:39 +02:00
gBattleResources->flags->flags[i] = 0;
2017-11-26 17:15:28 +01:00
gPalaceSelectionBattleScripts[i] = 0;
2017-10-02 23:32:39 +02:00
}
for (i = 0; i < 2; i++)
{
2018-01-16 22:12:38 +01:00
gSideStatuses[i] = 0;
2017-10-02 23:32:39 +02:00
dataPtr = (u8 *)&gSideTimers[i];
for (j = 0; j < sizeof(struct SideTimer); j++)
dataPtr[j] = 0;
}
2018-02-06 23:09:39 +01:00
gBattlerAttacker = 0;
gBattlerTarget = 0;
2017-10-02 23:32:39 +02:00
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;
}
2021-01-13 21:17:32 +01:00
else if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) && GetBattleSceneInRecordedBattle())
2017-10-02 23:32:39 +02:00
gHitMarker |= HITMARKER_NO_ANIMATIONS;
gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle;
gMultiHitCounter = 0;
gBattleOutcome = 0;
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags = 0;
2017-10-02 23:32:39 +02:00
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;
2018-02-08 11:17:41 +01:00
gIntroSlideFlags = 0;
2017-10-02 23:32:39 +02:00
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
gLeveledUpInBattle = 0;
2018-02-06 02:46:59 +01:00
gAbsentBattlerFlags = 0;
2017-10-06 00:12:01 +02:00
gBattleStruct->runTries = 0;
2018-07-01 11:15:42 +02:00
gBattleStruct->safariGoNearCounter = 0;
gBattleStruct->safariPkblThrowCounter = 0;
*(&gBattleStruct->safariCatchFactor) = gBaseStats[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].catchRate * 100 / 1275;
gBattleStruct->safariEscapeFactor = 3;
2017-10-02 23:32:39 +02:00
gBattleStruct->wildVictorySong = 0;
gBattleStruct->moneyMultiplier = 1;
for (i = 0; i < 8; i++)
{
*((u8 *)gBattleStruct->lastTakenMove + i) = MOVE_NONE;
*((u8 *)gBattleStruct->usedHeldItems + i) = ITEM_NONE;
*((u8 *)gBattleStruct->choicedMove + i) = MOVE_NONE;
*((u8 *)gBattleStruct->changedItems + i) = ITEM_NONE;
*(i + 0 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(i + 1 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(i + 2 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(i + 3 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
2017-10-02 23:32:39 +02:00
{
2018-06-28 21:06:32 +02:00
*(gBattleStruct->AI_monToSwitchIntoId + i) = PARTY_SIZE;
2017-10-02 23:32:39 +02:00
}
2018-12-07 23:50:56 +01:00
gBattleStruct->givenExpMons = 0;
2020-07-17 02:12:12 +02:00
gBattleStruct->palaceFlags = 0;
2017-10-02 23:32:39 +02:00
gRandomTurnNumber = Random();
dataPtr = (u8 *)(&gBattleResults);
for (i = 0; i < sizeof(struct BattleResults); i++)
dataPtr[i] = 0;
2018-06-28 21:06:32 +02:00
gBattleResults.shinyWildMon = IsMonShiny(&gEnemyParty[0]);
2017-10-02 23:32:39 +02:00
2018-11-11 18:33:16 +01:00
gBattleStruct->arenaLostPlayerMons = 0;
gBattleStruct->arenaLostOpponentMons = 0;
2017-10-02 23:32:39 +02:00
}
void SwitchInClearSetData(void)
{
2018-02-06 02:46:59 +01:00
struct DisableStruct disableStructCopy = gDisableStructs[gActiveBattler];
2017-10-02 23:32:39 +02:00
s32 i;
u8 *ptr;
if (gBattleMoves[gCurrentMove].effect != EFFECT_BATON_PASS)
{
2018-11-18 20:00:36 +01:00
for (i = 0; i < NUM_BATTLE_STATS; i++)
2020-08-05 02:33:05 +02:00
gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 23:09:39 +01:00
if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == gActiveBattler)
2017-10-02 23:32:39 +02:00
gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION;
2018-02-06 23:09:39 +01:00
if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].battlerWithSureHit == gActiveBattler)
2017-10-02 23:32:39 +02:00
{
gStatuses3[i] &= ~STATUS3_ALWAYS_HITS;
2018-02-06 23:09:39 +01:00
gDisableStructs[i].battlerWithSureHit = 0;
2017-10-02 23:32:39 +02:00
}
}
}
if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS)
{
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED);
2018-07-01 12:16:52 +02:00
gStatuses3[gActiveBattler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED | STATUS3_MUDSPORT | STATUS3_WATERSPORT);
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(gActiveBattler) != GetBattlerSide(i)
2017-10-02 23:32:39 +02:00
&& (gStatuses3[i] & STATUS3_ALWAYS_HITS) != 0
2018-02-06 23:09:39 +01:00
&& (gDisableStructs[i].battlerWithSureHit == gActiveBattler))
2017-10-02 23:32:39 +02:00
{
2021-09-24 20:30:15 +02:00
gStatuses3[i] &= ~STATUS3_ALWAYS_HITS;
2020-07-17 02:12:12 +02:00
gStatuses3[i] |= STATUS3_ALWAYS_HITS_TURN(2);
2017-10-02 23:32:39 +02:00
}
}
}
else
{
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 = 0;
gStatuses3[gActiveBattler] = 0;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBattler))
2021-09-24 20:30:15 +02:00
gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(gActiveBattler);
2018-02-06 02:46:59 +01:00
if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBattler)
2021-09-24 20:30:15 +02:00
gBattleMons[i].status2 &= ~STATUS2_WRAPPED;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
gActionSelectionCursor[gActiveBattler] = 0;
gMoveSelectionCursor[gActiveBattler] = 0;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
ptr = (u8 *)&gDisableStructs[gActiveBattler];
2017-10-02 23:32:39 +02:00
for (i = 0; i < sizeof(struct DisableStruct); i++)
ptr[i] = 0;
if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS)
{
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].substituteHP = disableStructCopy.substituteHP;
2018-02-06 23:09:39 +01:00
gDisableStructs[gActiveBattler].battlerWithSureHit = disableStructCopy.battlerWithSureHit;
2018-10-14 18:10:54 +02:00
gDisableStructs[gActiveBattler].perishSongTimer = disableStructCopy.perishSongTimer;
gDisableStructs[gActiveBattler].perishSongTimerStartValue = disableStructCopy.perishSongTimerStartValue;
2018-02-06 23:09:39 +01:00
gDisableStructs[gActiveBattler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape;
2017-10-02 23:32:39 +02:00
}
2018-01-16 22:12:38 +01:00
gMoveResultFlags = 0;
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].isFirstTurn = 2;
gDisableStructs[gActiveBattler].truantSwitchInHack = disableStructCopy.truantSwitchInHack;
gLastMoves[gActiveBattler] = MOVE_NONE;
gLastLandedMoves[gActiveBattler] = MOVE_NONE;
2018-02-06 02:46:59 +01:00
gLastHitByType[gActiveBattler] = 0;
gLastResultingMoves[gActiveBattler] = MOVE_NONE;
gLastPrintedMoves[gActiveBattler] = MOVE_NONE;
gLastHitBy[gActiveBattler] = 0xFF;
2017-10-02 23:32:39 +02:00
*(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 0) = MOVE_NONE;
*(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 1) = MOVE_NONE;
*(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
*(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
*(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
*(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
2017-10-02 23:32:39 +02:00
2020-07-17 02:12:12 +02:00
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (i != gActiveBattler && GetBattlerSide(i) != GetBattlerSide(gActiveBattler))
2017-10-02 23:32:39 +02:00
{
*(gBattleStruct->lastTakenMove + i * 2 + 0) = MOVE_NONE;
*(gBattleStruct->lastTakenMove + i * 2 + 1) = MOVE_NONE;
2017-10-02 23:32:39 +02:00
}
*(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
2017-10-02 23:32:39 +02:00
}
*(u8 *)((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 0) = MOVE_NONE;
*(u8 *)((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 1) = MOVE_NONE;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
gBattleResources->flags->flags[gActiveBattler] = 0;
gCurrentMove = MOVE_NONE;
2018-12-07 23:50:56 +01:00
gBattleStruct->arenaTurnCounter = 0xFF;
2017-10-02 23:32:39 +02:00
2018-02-06 23:09:39 +01:00
ClearBattlerMoveHistory(gActiveBattler);
ClearBattlerAbilityHistory(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
void FaintClearSetData(void)
{
s32 i;
u8 *ptr;
2018-11-18 20:00:36 +01:00
for (i = 0; i < NUM_BATTLE_STATS; i++)
2020-08-05 02:33:05 +02:00
gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 = 0;
gStatuses3[gActiveBattler] = 0;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 23:09:39 +01:00
if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == gActiveBattler)
2017-10-02 23:32:39 +02:00
gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION;
2018-02-06 02:46:59 +01:00
if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBattler))
2021-09-24 20:30:15 +02:00
gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(gActiveBattler);
2018-02-06 02:46:59 +01:00
if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBattler)
2021-09-24 20:30:15 +02:00
gBattleMons[i].status2 &= ~STATUS2_WRAPPED;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
gActionSelectionCursor[gActiveBattler] = 0;
gMoveSelectionCursor[gActiveBattler] = 0;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
ptr = (u8 *)&gDisableStructs[gActiveBattler];
2017-10-02 23:32:39 +02:00
for (i = 0; i < sizeof(struct DisableStruct); i++)
ptr[i] = 0;
gProtectStructs[gActiveBattler].protected = FALSE;
gProtectStructs[gActiveBattler].endured = FALSE;
gProtectStructs[gActiveBattler].noValidMoves = FALSE;
gProtectStructs[gActiveBattler].helpingHand = FALSE;
gProtectStructs[gActiveBattler].bounceMove = FALSE;
gProtectStructs[gActiveBattler].stealMove = FALSE;
gProtectStructs[gActiveBattler].flag0Unknown = FALSE;
gProtectStructs[gActiveBattler].prlzImmobility = FALSE;
gProtectStructs[gActiveBattler].confusionSelfDmg = FALSE;
gProtectStructs[gActiveBattler].targetNotAffected = FALSE;
gProtectStructs[gActiveBattler].chargingTurn = FALSE;
2022-07-29 21:38:23 +02:00
gProtectStructs[gActiveBattler].fleeType = 0;
gProtectStructs[gActiveBattler].usedImprisonedMove = FALSE;
gProtectStructs[gActiveBattler].loveImmobility = FALSE;
gProtectStructs[gActiveBattler].usedDisabledMove = FALSE;
gProtectStructs[gActiveBattler].usedTauntedMove = FALSE;
gProtectStructs[gActiveBattler].flag2Unknown = FALSE;
gProtectStructs[gActiveBattler].flinchImmobility = FALSE;
gProtectStructs[gActiveBattler].notFirstStrike = FALSE;
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].isFirstTurn = 2;
gLastMoves[gActiveBattler] = MOVE_NONE;
gLastLandedMoves[gActiveBattler] = MOVE_NONE;
2018-02-06 02:46:59 +01:00
gLastHitByType[gActiveBattler] = 0;
gLastResultingMoves[gActiveBattler] = MOVE_NONE;
gLastPrintedMoves[gActiveBattler] = MOVE_NONE;
gLastHitBy[gActiveBattler] = 0xFF;
2018-02-06 02:46:59 +01:00
*(u8 *)((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 0) = MOVE_NONE;
*(u8 *)((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 1) = MOVE_NONE;
2018-02-06 02:46:59 +01:00
*(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 0) = MOVE_NONE;
*(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 1) = MOVE_NONE;
*(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
*(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
*(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
*(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
2018-02-06 02:46:59 +01:00
2020-07-17 02:12:12 +02:00
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
{
if (i != gActiveBattler && GetBattlerSide(i) != GetBattlerSide(gActiveBattler))
2017-10-02 23:32:39 +02:00
{
*(gBattleStruct->lastTakenMove + i * 2 + 0) = MOVE_NONE;
*(gBattleStruct->lastTakenMove + i * 2 + 1) = MOVE_NONE;
2017-10-02 23:32:39 +02:00
}
*(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0;
*(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
gBattleResources->flags->flags[gActiveBattler] = 0;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1;
gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2;
2017-10-02 23:32:39 +02:00
2018-02-06 23:09:39 +01:00
ClearBattlerMoveHistory(gActiveBattler);
ClearBattlerAbilityHistory(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
static void BattleIntroGetMonsData(void)
{
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
2018-02-06 02:46:59 +01:00
gActiveBattler = gBattleCommunication[1];
BtlController_EmitGetMonData(BUFFER_A, REQUEST_ALL_BATTLE, 0);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 1:
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
gBattleCommunication[1]++;
2018-02-06 02:46:59 +01:00
if (gBattleCommunication[1] == gBattlersCount)
2017-10-02 23:32:39 +02:00
gBattleMainFunc = BattleIntroPrepareBackgroundSlide;
else
gBattleCommunication[MULTIUSE_STATE] = 0;
}
break;
}
}
static void BattleIntroPrepareBackgroundSlide(void)
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = GetBattlerAtPosition(0);
BtlController_EmitIntroSlide(BUFFER_A, gBattleTerrain);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
gBattleMainFunc = BattleIntroDrawTrainersOrMonsSprites;
gBattleCommunication[MULTIUSE_STATE] = 0;
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
2017-10-02 23:32:39 +02:00
}
}
static void BattleIntroDrawTrainersOrMonsSprites(void)
{
u8 *ptr;
s32 i;
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags)
2017-10-02 23:32:39 +02:00
return;
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI)
&& GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
ptr = (u8 *)&gBattleMons[gActiveBattler];
2017-10-02 23:32:39 +02:00
for (i = 0; i < sizeof(struct BattlePokemon); i++)
ptr[i] = 0;
}
else
{
u16 *hpOnSwitchout;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
ptr = (u8 *)&gBattleMons[gActiveBattler];
2017-10-02 23:32:39 +02:00
for (i = 0; i < sizeof(struct BattlePokemon); i++)
2018-02-06 02:46:59 +01:00
ptr[i] = gBattleBufferB[gActiveBattler][4 + i];
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1;
gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2;
2019-05-14 15:22:16 +02:00
gBattleMons[gActiveBattler].ability = GetAbilityBySpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].abilityNum);
2018-02-06 02:46:59 +01:00
hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(gActiveBattler)];
*hpOnSwitchout = gBattleMons[gActiveBattler].hp;
2018-11-18 20:00:36 +01:00
for (i = 0; i < NUM_BATTLE_STATS; i++)
2020-08-05 02:33:05 +02:00
gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE;
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 = 0;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_LEFT)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitDrawTrainerPic(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
2018-02-06 02:46:59 +01:00
if (GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_LEFT)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitDrawTrainerPic(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
2017-10-02 23:32:39 +02:00
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
2021-01-13 21:17:32 +01:00
| BATTLE_TYPE_RECORDED_LINK
2018-09-20 22:00:00 +02:00
| BATTLE_TYPE_TRAINER_HILL)))
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality);
2017-10-02 23:32:39 +02:00
}
}
else
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
2017-10-02 23:32:39 +02:00
{
if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
2021-01-13 21:17:32 +01:00
| BATTLE_TYPE_RECORDED_LINK
2018-09-20 22:00:00 +02:00
| BATTLE_TYPE_TRAINER_HILL)))
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality);
2017-10-02 23:32:39 +02:00
}
BtlController_EmitLoadMonSprite(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
2017-10-02 23:32:39 +02:00
}
}
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
2017-10-02 23:32:39 +02:00
{
if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT
|| GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT)
{
BtlController_EmitDrawTrainerPic(BUFFER_A);
MarkBattlerForControllerExec(gActiveBattler);
}
2017-10-02 23:32:39 +02:00
}
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitDrawTrainerPic(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
2018-11-11 18:33:16 +01:00
BattleArena_InitPoints();
2017-10-02 23:32:39 +02:00
}
gBattleMainFunc = BattleIntroDrawPartySummaryScreens;
}
static void BattleIntroDrawPartySummaryScreens(void)
{
s32 i;
2018-06-28 21:06:32 +02:00
struct HpAndStatus hpStatus[PARTY_SIZE];
2017-10-02 23:32:39 +02:00
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags)
2017-10-02 23:32:39 +02:00
return;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
2017-11-26 14:17:02 +01:00
for (i = 0; i < PARTY_SIZE; i++)
2017-10-02 23:32:39 +02:00
{
if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = HP_EMPTY_SLOT;
2017-10-02 23:32:39 +02:00
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS);
}
}
2018-02-06 02:46:59 +01:00
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
BtlController_EmitDrawPartyStatusSummary(BUFFER_A, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
2017-11-26 14:17:02 +01:00
for (i = 0; i < PARTY_SIZE; i++)
2017-10-02 23:32:39 +02:00
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = HP_EMPTY_SLOT;
2017-10-02 23:32:39 +02:00
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
}
}
2018-02-06 02:46:59 +01:00
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
BtlController_EmitDrawPartyStatusSummary(BUFFER_A, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
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.
2018-06-28 21:06:32 +02:00
for (i = 0; i < PARTY_SIZE; i++)
2017-10-02 23:32:39 +02:00
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = HP_EMPTY_SLOT;
2017-10-02 23:32:39 +02:00
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)
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
PrepareStringBattle(STRINGID_INTROMSG, gActiveBattler);
2017-10-02 23:32:39 +02:00
gBattleMainFunc = BattleIntroPrintOpponentSendsOut;
}
}
static void BattleIntroPrintWildMonAttacked(void)
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
2017-10-07 15:15:47 +02:00
PrepareStringBattle(STRINGID_INTROMSG, 0);
2017-10-02 23:32:39 +02:00
}
}
static void BattleIntroPrintOpponentSendsOut(void)
{
u32 position;
2017-10-02 23:32:39 +02:00
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags)
2017-10-02 23:32:39 +02:00
return;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_LEFT;
2021-01-13 21:17:32 +01:00
else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK)
2017-10-02 23:32:39 +02:00
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_LEFT;
2017-10-02 23:32:39 +02:00
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2017-10-02 23:32:39 +02:00
}
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_LEFT;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(position));
2017-10-02 23:32:39 +02:00
gBattleMainFunc = BattleIntroOpponent1SendsOutMonAnimation;
}
static void BattleIntroOpponent2SendsOutMonAnimation(void)
{
u32 position;
2017-10-02 23:32:39 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_RIGHT;
2021-01-13 21:17:32 +01:00
else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK)
2017-10-02 23:32:39 +02:00
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_RIGHT;
2017-10-02 23:32:39 +02:00
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_RIGHT;
2017-10-02 23:32:39 +02:00
}
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_RIGHT;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerPosition(gActiveBattler) == position)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitIntroTrainerBallThrow(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
}
gBattleMainFunc = BattleIntroRecordMonsToDex;
}
static void BattleIntroOpponent1SendsOutMonAnimation(void)
{
u32 position;
2017-10-02 23:32:39 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
2017-10-02 23:32:39 +02:00
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK)
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)
position = B_POSITION_OPPONENT_LEFT;
else
position = B_POSITION_PLAYER_LEFT;
}
2017-10-02 23:32:39 +02:00
else
position = B_POSITION_OPPONENT_LEFT;
2017-10-02 23:32:39 +02:00
}
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_LEFT;
2017-10-02 23:32:39 +02:00
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags)
2017-10-02 23:32:39 +02:00
return;
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerPosition(gActiveBattler) == position)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitIntroTrainerBallThrow(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS))
{
gBattleMainFunc = BattleIntroOpponent2SendsOutMonAnimation;
return;
}
}
}
gBattleMainFunc = BattleIntroRecordMonsToDex;
}
static void BattleIntroRecordMonsToDex(void)
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
2017-10-02 23:32:39 +02:00
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
2021-01-13 21:17:32 +01:00
| BATTLE_TYPE_RECORDED_LINK
2018-09-20 22:00:00 +02:00
| BATTLE_TYPE_TRAINER_HILL)))
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality);
2017-10-02 23:32:39 +02:00
}
}
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
}
// Unused
static void BattleIntroSkipRecordMonsToDex(void)
2017-10-02 23:32:39 +02:00
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
static void BattleIntroPrintPlayerSendsOut(void)
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
2018-01-16 23:42:31 +01:00
u8 position;
2017-10-02 23:32:39 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2021-01-13 21:17:32 +01:00
else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK)
2017-10-02 23:32:39 +02:00
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2017-10-02 23:32:39 +02:00
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_LEFT;
2017-10-02 23:32:39 +02:00
}
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2017-10-02 23:32:39 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
2018-02-06 02:46:59 +01:00
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(position));
2017-10-02 23:32:39 +02:00
gBattleMainFunc = BattleIntroPlayer1SendsOutMonAnimation;
}
}
static void BattleIntroPlayer2SendsOutMonAnimation(void)
{
u32 position;
2017-10-02 23:32:39 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_RIGHT;
2021-01-13 21:17:32 +01:00
else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK)
2017-10-02 23:32:39 +02:00
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_RIGHT;
2017-10-02 23:32:39 +02:00
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_RIGHT;
2017-10-02 23:32:39 +02:00
}
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_RIGHT;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerPosition(gActiveBattler) == position)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitIntroTrainerBallThrow(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
static void BattleIntroPlayer1SendsOutMonAnimation(void)
{
u32 position;
2017-10-02 23:32:39 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2021-01-13 21:17:32 +01:00
else if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK)
2017-10-02 23:32:39 +02:00
{
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2017-10-02 23:32:39 +02:00
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_OPPONENT_LEFT;
2017-10-02 23:32:39 +02:00
}
else
2018-01-16 23:42:31 +01:00
position = B_POSITION_PLAYER_LEFT;
2017-10-02 23:32:39 +02:00
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags)
2017-10-02 23:32:39 +02:00
return;
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerPosition(gActiveBattler) == position)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitIntroTrainerBallThrow(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI))
{
gBattleMainFunc = BattleIntroPlayer2SendsOutMonAnimation;
return;
}
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
// Unused
static void BattleIntroSwitchInPlayerMons(void)
2017-10-02 23:32:39 +02:00
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
2017-10-02 23:32:39 +02:00
{
BtlController_EmitSwitchInAnim(BUFFER_A, gBattlerPartyIndexes[gActiveBattler], FALSE);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-10-02 23:32:39 +02:00
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
}
static void TryDoEventsBeforeFirstTurn(void)
{
s32 i;
s32 j;
2017-10-02 23:32:39 +02:00
u8 effect = 0;
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags)
2017-10-02 23:32:39 +02:00
return;
if (gBattleStruct->switchInAbilitiesCounter == 0)
{
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2018-06-28 21:06:32 +02:00
gBattlerByTurnOrder[i] = i;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount - 1; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
for (j = i + 1; j < gBattlersCount; j++)
2017-10-02 23:32:39 +02:00
{
2018-06-28 21:06:32 +02:00
if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) != 0)
2017-10-04 19:25:14 +02:00
SwapTurnOrder(i, j);
2017-10-02 23:32:39 +02:00
}
}
}
if (!gBattleStruct->overworldWeatherDone
&& AbilityBattleEffects(0, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0)
{
gBattleStruct->overworldWeatherDone = TRUE;
return;
}
2018-06-28 21:06:32 +02:00
// Check all switch in abilities happening from the fastest mon to slowest.
2018-02-06 02:46:59 +01:00
while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount)
2017-10-02 23:32:39 +02:00
{
2018-06-28 21:06:32 +02:00
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter], 0, 0, 0) != 0)
2017-10-02 23:32:39 +02:00
effect++;
gBattleStruct->switchInAbilitiesCounter++;
if (effect != 0)
2017-10-02 23:32:39 +02:00
return;
}
if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) != 0)
return;
if (AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) != 0)
return;
2018-06-28 21:06:32 +02:00
// Check all switch in items having effect from the fastest mon to slowest.
2018-02-06 02:46:59 +01:00
while (gBattleStruct->switchInItemsCounter < gBattlersCount)
2017-10-02 23:32:39 +02:00
{
2018-09-01 20:00:13 +02:00
if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInItemsCounter], FALSE))
2017-10-02 23:32:39 +02:00
effect++;
gBattleStruct->switchInItemsCounter++;
if (effect != 0)
2017-10-02 23:32:39 +02:00
return;
}
2018-02-06 02:46:59 +01:00
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
2017-10-02 23:32:39 +02:00
{
2018-06-28 21:06:32 +02:00
*(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE;
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
2017-10-02 23:32:39 +02:00
}
2017-10-06 00:12:01 +02:00
TurnValuesCleanUp(FALSE);
2017-10-02 23:32:39 +02:00
SpecialStatusesClear();
*(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags;
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
2017-10-04 19:25:14 +02:00
gBattleMainFunc = HandleTurnActionSelectionState;
2017-10-02 23:32:39 +02:00
ResetSentPokesToOpponentValue();
for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2021-09-24 20:30:15 +02:00
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
2017-10-02 23:32:39 +02:00
*(&gBattleStruct->turnEffectsTracker) = 0;
2018-02-07 22:53:40 +01:00
*(&gBattleStruct->turnEffectsBattlerId) = 0;
2017-12-02 14:08:55 +01:00
*(&gBattleStruct->wishPerishSongState) = 0;
2018-02-07 22:53:40 +01:00
*(&gBattleStruct->wishPerishSongBattlerId) = 0;
2019-08-23 14:46:21 +02:00
gBattleScripting.moveendState = 0;
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 0;
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker = 0;
2018-01-16 22:12:38 +01:00
gMoveResultFlags = 0;
2017-10-02 23:32:39 +02:00
gRandomTurnNumber = Random();
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
{
StopCryAndClearCrySongs();
2018-08-25 21:04:12 +02:00
BattleScriptExecute(BattleScript_ArenaTurnBeginning);
2017-10-02 23:32:39 +02:00
}
}
2017-10-06 19:09:37 +02:00
static void HandleEndTurn_ContinueBattle(void)
2017-10-02 23:32:39 +02:00
{
s32 i;
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-02 23:32:39 +02:00
{
gBattleMainFunc = BattleTurnPassed;
for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2021-09-24 20:30:15 +02:00
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
2018-01-16 22:12:38 +01:00
if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS))
2017-10-02 23:32:39 +02:00
CancelMultiTurnMoves(i);
}
gBattleStruct->turnEffectsTracker = 0;
2018-02-07 22:53:40 +01:00
gBattleStruct->turnEffectsBattlerId = 0;
2017-12-02 14:08:55 +01:00
gBattleStruct->wishPerishSongState = 0;
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId = 0;
gBattleStruct->turnCountersTracker = 0;
2018-01-16 22:12:38 +01:00
gMoveResultFlags = 0;
2017-10-02 23:32:39 +02:00
}
}
void BattleTurnPassed(void)
{
s32 i;
2017-10-06 00:12:01 +02:00
TurnValuesCleanUp(TRUE);
2017-10-02 23:32:39 +02:00
if (gBattleOutcome == 0)
{
2018-08-03 00:13:44 +02:00
if (DoFieldEndTurnEffects())
2017-10-02 23:32:39 +02:00
return;
2018-08-03 00:13:44 +02:00
if (DoBattlerEndTurnEffects())
2017-10-02 23:32:39 +02:00
return;
}
2018-06-28 21:06:32 +02:00
if (HandleFaintedMonActions())
2017-10-02 23:32:39 +02:00
return;
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 0;
2018-06-28 21:06:32 +02:00
if (HandleWishPerishSongOnTurnEnd())
2017-10-02 23:32:39 +02:00
return;
2017-10-06 00:12:01 +02:00
TurnValuesCleanUp(FALSE);
2021-09-24 20:30:15 +02:00
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE;
gHitMarker &= ~HITMARKER_PLAYER_FAINTED;
gHitMarker &= ~HITMARKER_PASSIVE_DAMAGE;
2017-10-02 23:32:39 +02:00
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
2019-08-23 14:46:21 +02:00
gBattleScripting.moveendState = 0;
2017-10-02 23:32:39 +02:00
gBattleMoveDamage = 0;
2018-01-16 22:12:38 +01:00
gMoveResultFlags = 0;
2017-10-02 23:32:39 +02:00
for (i = 0; i < 5; i++)
gBattleCommunication[i] = 0;
if (gBattleOutcome != 0)
{
2019-09-03 21:08:25 +02:00
gCurrentActionFuncId = B_ACTION_FINISHED;
2017-10-06 00:12:01 +02:00
gBattleMainFunc = RunTurnActionsFunctions;
2017-10-02 23:32:39 +02:00
return;
}
if (gBattleResults.battleTurnCounter < 0xFF)
2017-10-02 23:32:39 +02:00
{
gBattleResults.battleTurnCounter++;
2018-12-07 23:50:56 +01:00
gBattleStruct->arenaTurnCounter++;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
2017-10-02 23:32:39 +02:00
}
2018-08-03 00:13:44 +02:00
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
2018-06-28 21:06:32 +02:00
*(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE;
2017-10-02 23:32:39 +02:00
*(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags;
2021-10-08 22:50:52 +02:00
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
2017-10-04 19:25:14 +02:00
gBattleMainFunc = HandleTurnActionSelectionState;
2017-10-02 23:32:39 +02:00
gRandomTurnNumber = Random();
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
2020-07-17 02:12:12 +02:00
BattleScriptExecute(BattleScript_PalacePrintFlavorText);
2018-12-07 23:50:56 +01:00
else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->arenaTurnCounter == 0)
2018-08-25 21:04:12 +02:00
BattleScriptExecute(BattleScript_ArenaTurnBeginning);
2017-10-02 23:32:39 +02:00
}
u8 IsRunningFromBattleImpossible(void)
{
u8 holdEffect;
u8 side;
s32 i;
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].item == ITEM_ENIGMA_BERRY)
holdEffect = gEnigmaBerries[gActiveBattler].holdEffect;
2017-10-02 23:32:39 +02:00
else
2018-02-06 02:46:59 +01:00
holdEffect = ItemId_GetHoldEffect(gBattleMons[gActiveBattler].item);
2017-10-02 23:32:39 +02:00
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = gActiveBattler;
2017-10-02 23:32:39 +02:00
if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
return BATTLE_RUN_SUCCESS;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
return BATTLE_RUN_SUCCESS;
if (gBattleMons[gActiveBattler].ability == ABILITY_RUN_AWAY)
return BATTLE_RUN_SUCCESS;
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
side = GetBattlerSide(gActiveBattler);
2017-10-02 23:32:39 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
if (side != GetBattlerSide(i)
2017-10-02 23:32:39 +02:00
&& gBattleMons[i].ability == ABILITY_SHADOW_TAG)
{
2018-02-06 02:46:59 +01:00
gBattleScripting.battler = i;
2017-10-02 23:32:39 +02:00
gLastUsedAbility = gBattleMons[i].ability;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PREVENTS_ESCAPE;
return BATTLE_RUN_FAILURE;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
if (side != GetBattlerSide(i)
&& gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE
2018-03-01 00:59:52 +01:00
&& !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING)
2017-10-02 23:32:39 +02:00
&& gBattleMons[i].ability == ABILITY_ARENA_TRAP)
{
2018-02-06 02:46:59 +01:00
gBattleScripting.battler = i;
2017-10-02 23:32:39 +02:00
gLastUsedAbility = gBattleMons[i].ability;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PREVENTS_ESCAPE;
return BATTLE_RUN_FAILURE;
2017-10-02 23:32:39 +02:00
}
}
2018-07-01 12:16:52 +02:00
i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0);
2018-03-01 00:59:52 +01:00
if (i != 0 && IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL))
2017-10-02 23:32:39 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleScripting.battler = i - 1;
2017-10-02 23:32:39 +02:00
gLastUsedAbility = gBattleMons[i - 1].ability;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PREVENTS_ESCAPE;
return BATTLE_RUN_FAILURE;
2017-10-02 23:32:39 +02:00
}
2018-02-06 02:46:59 +01:00
if ((gBattleMons[gActiveBattler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))
|| (gStatuses3[gActiveBattler] & STATUS3_ROOTED))
2017-10-02 23:32:39 +02:00
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CANT_ESCAPE;
return BATTLE_RUN_FORBIDDEN;
2017-10-02 23:32:39 +02:00
}
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DONT_LEAVE_BIRCH;
return BATTLE_RUN_FORBIDDEN;
2017-10-02 23:32:39 +02:00
}
return BATTLE_RUN_SUCCESS;
2017-10-02 23:32:39 +02:00
}
2019-10-26 03:55:01 +02:00
void SwitchPartyOrder(u8 battler)
{
s32 i;
2019-10-26 03:55:01 +02:00
u8 partyId1;
u8 partyId2;
2019-10-18 01:22:03 +02:00
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
gBattlePartyCurrentOrder[i] = *(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders));
2019-10-26 03:55:01 +02:00
partyId1 = GetPartyIdFromBattlePartyId(gBattlerPartyIndexes[battler]);
partyId2 = GetPartyIdFromBattlePartyId(*(gBattleStruct->monToSwitchIntoId + battler));
SwitchPartyMonSlots(partyId1, partyId2);
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
2019-10-18 01:22:03 +02:00
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
{
*(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)) = gBattlePartyCurrentOrder[i];
*(BATTLE_PARTNER(battler) * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)) = gBattlePartyCurrentOrder[i];
}
}
else
{
2019-10-18 01:22:03 +02:00
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
{
*(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)) = gBattlePartyCurrentOrder[i];
}
}
}
2017-10-06 17:06:45 +02:00
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
};
2017-10-04 19:25:14 +02:00
2017-10-06 19:09:37 +02:00
static void HandleTurnActionSelectionState(void)
{
s32 i;
2017-10-04 19:25:14 +02:00
gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0;
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
2018-02-06 02:46:59 +01:00
u8 position = GetBattlerPosition(gActiveBattler);
switch (gBattleCommunication[gActiveBattler])
{
2018-07-07 19:57:09 +02:00
case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn.
2018-02-08 11:17:41 +01:00
RecordedBattle_CopyBattlerMoves();
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
break;
2018-07-07 19:57:09 +02:00
case STATE_BEFORE_ACTION_CHOSEN: // Choose an action.
2018-06-28 21:06:32 +02:00
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = PARTY_SIZE;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI
2018-06-28 21:06:32 +02:00
|| (position & BIT_FLANK) == B_FLANK_LEFT
|| gBattleStruct->absentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(position))]
2018-06-28 21:06:32 +02:00
|| gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED)
{
if (gBattleStruct->absentBattlerFlags & gBitTable[gActiveBattler])
{
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[gActiveBattler] = B_ACTION_NOTHING_FAINTED;
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED;
else
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].status2 & STATUS2_MULTIPLETURNS
|| gBattleMons[gActiveBattler].status2 & STATUS2_RECHARGE)
{
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[gActiveBattler] = B_ACTION_USE_MOVE;
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
BtlController_EmitChooseAction(BUFFER_A, gChosenActionByBattler[0], gBattleBufferB[0][1] | (gBattleBufferB[0][2] << 8));
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
}
}
}
break;
2018-07-07 19:57:09 +02:00
case STATE_WAIT_ACTION_CHOSEN: // Try to perform an action.
2021-03-30 23:38:09 +02:00
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
{
2018-02-06 20:48:02 +01:00
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleBufferB[gActiveBattler][1]);
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[gActiveBattler] = gBattleBufferB[gActiveBattler][1];
2018-02-06 02:46:59 +01:00
switch (gBattleBufferB[gActiveBattler][1])
{
2018-02-06 23:09:39 +01:00
case B_ACTION_USE_MOVE:
if (AreAllMovesUnusable())
{
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
*(gBattleStruct->moveTarget + gActiveBattler) = gBattleBufferB[gActiveBattler][3];
return;
}
2018-02-06 02:46:59 +01:00
else if (gDisableStructs[gActiveBattler].encoredMove != 0)
{
2018-02-06 23:09:39 +01:00
gChosenMoveByBattler[gActiveBattler] = gDisableStructs[gActiveBattler].encoredMove;
2018-02-06 02:46:59 +01:00
*(gBattleStruct->chosenMovePositions + gActiveBattler) = gDisableStructs[gActiveBattler].encoredMovePos;
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
return;
}
else
{
struct ChooseMoveStruct moveInfo;
2018-02-06 02:46:59 +01:00
moveInfo.species = gBattleMons[gActiveBattler].species;
moveInfo.monType1 = gBattleMons[gActiveBattler].type1;
moveInfo.monType2 = gBattleMons[gActiveBattler].type2;
2019-09-08 18:21:24 +02:00
for (i = 0; i < MAX_MON_MOVES; i++)
{
2018-02-06 02:46:59 +01:00
moveInfo.moves[i] = gBattleMons[gActiveBattler].moves[i];
moveInfo.currentPp[i] = gBattleMons[gActiveBattler].pp[i];
2017-10-08 14:54:51 +02:00
moveInfo.maxPp[i] = CalculatePPWithBonus(
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].moves[i],
gBattleMons[gActiveBattler].ppBonuses,
i);
}
BtlController_EmitChooseMove(BUFFER_A, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
}
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_USE_ITEM:
if (gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_FRONTIER_NO_PYRAMID
| BATTLE_TYPE_EREADER_TRAINER
2021-01-13 21:17:32 +01:00
| BATTLE_TYPE_RECORDED_LINK))
{
2018-02-06 20:48:02 +01:00
RecordedBattle_ClearBattlerAction(gActiveBattler, 1);
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_ActionSelectionItemsCantBeUsed;
gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
else
{
BtlController_EmitChooseItem(BUFFER_A, gBattleStruct->battlerPartyOrders[gActiveBattler]);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
}
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SWITCH:
*(gBattleStruct->battlerPartyIndexes + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler];
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)
|| gBattleTypeFlags & BATTLE_TYPE_ARENA
2018-02-06 02:46:59 +01:00
|| gStatuses3[gActiveBattler] & STATUS3_ROOTED)
{
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
2018-07-01 12:16:52 +02:00
else if ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_SHADOW_TAG))
|| ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_ARENA_TRAP))
2018-03-01 00:59:52 +01:00
&& !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING)
2018-02-06 02:46:59 +01:00
&& gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE)
2018-07-01 12:16:52 +02:00
|| ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0))
2018-03-01 00:59:52 +01:00
&& IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL)))
{
BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gLastUsedAbility, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
else
{
2018-02-06 23:09:39 +01:00
if (gActiveBattler == 2 && gChosenActionByBattler[0] == B_ACTION_SWITCH)
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CHOOSE_MON, *(gBattleStruct->monToSwitchIntoId + 0), ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
2018-02-06 23:09:39 +01:00
else if (gActiveBattler == 3 && gChosenActionByBattler[1] == B_ACTION_SWITCH)
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CHOOSE_MON, *(gBattleStruct->monToSwitchIntoId + 1), ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
else
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CHOOSE_MON, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_BALL:
if (IsPlayerPartyAndPokemonStorageFull())
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_PrintFullBox;
gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_POKEBLOCK:
BtlController_EmitChooseItem(BUFFER_A, gBattleStruct->battlerPartyOrders[gActiveBattler]);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_CANCEL_PARTNER:
gBattleCommunication[gActiveBattler] = STATE_WAIT_SET_BEFORE_ACTION;
gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))] = STATE_BEFORE_ACTION_CHOSEN;
2018-02-06 20:48:02 +01:00
RecordedBattle_ClearBattlerAction(gActiveBattler, 1);
2018-02-06 23:09:39 +01:00
if (gBattleMons[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))].status2 & STATUS2_MULTIPLETURNS
|| gBattleMons[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))].status2 & STATUS2_RECHARGE)
{
BtlController_EmitEndBounceEffect(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
return;
}
2018-02-06 23:09:39 +01:00
else if (gChosenActionByBattler[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))] == B_ACTION_SWITCH)
{
2018-02-06 23:09:39 +01:00
RecordedBattle_ClearBattlerAction(GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))), 2);
}
2018-02-06 23:09:39 +01:00
else if (gChosenActionByBattler[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))] == B_ACTION_RUN)
{
2018-02-06 23:09:39 +01:00
RecordedBattle_ClearBattlerAction(GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))), 1);
}
2018-02-06 23:09:39 +01:00
else if (gChosenActionByBattler[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))] == B_ACTION_USE_MOVE
2018-07-07 19:57:09 +02:00
&& (gProtectStructs[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))].noValidMoves
2018-02-06 23:09:39 +01:00
|| gDisableStructs[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))].encoredMove))
{
2018-02-06 23:09:39 +01:00
RecordedBattle_ClearBattlerAction(GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))), 1);
}
else if (gBattleTypeFlags & BATTLE_TYPE_PALACE
2018-02-06 23:09:39 +01:00
&& gChosenActionByBattler[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))] == B_ACTION_USE_MOVE)
{
gRngValue = gBattlePalaceMoveSelectionRngValue;
2018-02-06 23:09:39 +01:00
RecordedBattle_ClearBattlerAction(GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))), 1);
}
else
{
2018-02-06 23:09:39 +01:00
RecordedBattle_ClearBattlerAction(GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))), 3);
}
BtlController_EmitEndBounceEffect(BUFFER_A);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
return;
}
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
2018-09-20 22:00:00 +02:00
&& gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_TRAINER_HILL)
2018-02-06 23:09:39 +01:00
&& gBattleBufferB[gActiveBattler][1] == B_ACTION_RUN)
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_AskIfWantsToForfeitMatch;
gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT_MAY_RUN;
2018-02-06 02:46:59 +01:00
*(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
2021-01-13 21:17:32 +01:00
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
2018-02-06 23:09:39 +01:00
&& gBattleBufferB[gActiveBattler][1] == B_ACTION_RUN)
{
2017-11-26 17:26:11 +01:00
BattleScriptExecute(BattleScript_PrintCantRunFromTrainer);
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
}
else if (IsRunningFromBattleImpossible() != BATTLE_RUN_SUCCESS
2018-02-06 23:09:39 +01:00
&& gBattleBufferB[gActiveBattler][1] == B_ACTION_RUN)
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_PrintCantEscapeFromBattle;
gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
else
{
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
}
}
break;
2017-10-04 19:25:14 +02:00
case STATE_WAIT_ACTION_CASE_CHOSEN:
2021-03-30 23:38:09 +02:00
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
{
2018-02-06 23:09:39 +01:00
switch (gChosenActionByBattler[gActiveBattler])
{
2018-02-06 23:09:39 +01:00
case B_ACTION_USE_MOVE:
2018-02-06 02:46:59 +01:00
switch (gBattleBufferB[gActiveBattler][1])
{
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[gActiveBattler] = gBattleBufferB[gActiveBattler][1];
return;
case 15:
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[gActiveBattler] = B_ACTION_SWITCH;
UpdateBattlerPartyOrdersOnSwitch();
return;
default:
RecordedBattle_CheckMovesetChanges(B_RECORD_MODE_PLAYBACK);
if ((gBattleBufferB[gActiveBattler][2] | (gBattleBufferB[gActiveBattler][3] << 8)) == 0xFFFF)
{
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
2018-02-06 20:48:02 +01:00
RecordedBattle_ClearBattlerAction(gActiveBattler, 1);
}
else if (TrySetCantSelectMoveBattleScript())
{
2018-02-06 20:48:02 +01:00
RecordedBattle_ClearBattlerAction(gActiveBattler, 1);
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBattler) = FALSE;
2020-03-18 02:11:14 +01:00
gBattleBufferB[gActiveBattler][1] = B_ACTION_USE_MOVE;
2018-02-06 02:46:59 +01:00
*(gBattleStruct->stateIdAfterSelScript + gActiveBattler) = STATE_WAIT_ACTION_CHOSEN;
return;
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_PALACE))
{
2018-02-06 20:48:02 +01:00
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleBufferB[gActiveBattler][2]);
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleBufferB[gActiveBattler][3]);
}
2018-02-06 02:46:59 +01:00
*(gBattleStruct->chosenMovePositions + gActiveBattler) = gBattleBufferB[gActiveBattler][2];
2018-02-06 23:09:39 +01:00
gChosenMoveByBattler[gActiveBattler] = gBattleMons[gActiveBattler].moves[*(gBattleStruct->chosenMovePositions + gActiveBattler)];
2018-02-06 02:46:59 +01:00
*(gBattleStruct->moveTarget + gActiveBattler) = gBattleBufferB[gActiveBattler][3];
gBattleCommunication[gActiveBattler]++;
}
break;
}
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_USE_ITEM:
2018-02-06 02:46:59 +01:00
if ((gBattleBufferB[gActiveBattler][1] | (gBattleBufferB[gActiveBattler][2] << 8)) == 0)
{
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
}
else
{
2018-02-06 02:46:59 +01:00
gLastUsedItem = (gBattleBufferB[gActiveBattler][1] | (gBattleBufferB[gActiveBattler][2] << 8));
gBattleCommunication[gActiveBattler]++;
}
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SWITCH:
2018-06-28 21:06:32 +02:00
if (gBattleBufferB[gActiveBattler][1] == PARTY_SIZE)
{
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
2018-02-06 20:48:02 +01:00
RecordedBattle_ClearBattlerAction(gActiveBattler, 1);
}
else
{
UpdateBattlerPartyOrdersOnSwitch();
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
}
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_RUN:
2017-10-06 17:06:45 +02:00
gHitMarker |= HITMARKER_RUN;
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_WATCH_CAREFULLY:
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_BALL:
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_POKEBLOCK:
2018-02-06 02:46:59 +01:00
if ((gBattleBufferB[gActiveBattler][1] | (gBattleBufferB[gActiveBattler][2] << 8)) != 0)
gBattleCommunication[gActiveBattler]++;
else
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_GO_NEAR:
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
break;
2018-02-06 23:09:39 +01:00
case B_ACTION_SAFARI_RUN:
2017-10-06 17:06:45 +02:00
gHitMarker |= HITMARKER_RUN;
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
break;
2018-06-20 23:07:51 +02:00
case B_ACTION_WALLY_THROW:
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
break;
}
}
break;
2017-10-04 19:25:14 +02:00
case STATE_WAIT_ACTION_CONFIRMED_STANDBY:
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler])
2021-03-30 23:38:09 +02:00
| (0xF << 28)
| (gBitTable[gActiveBattler] << 4)
| (gBitTable[gActiveBattler] << 8)
| (gBitTable[gActiveBattler] << 12))))
{
if (AllAtActionConfirmed())
i = TRUE;
else
i = FALSE;
if (((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|| (position & BIT_FLANK) != B_FLANK_LEFT
2022-08-27 07:26:13 +02:00
|| (*(&gBattleStruct->absentBattlerFlags) & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(position))]))
{
BtlController_EmitLinkStandbyMsg(BUFFER_A, LINK_STANDBY_MSG_STOP_BOUNCE, i);
}
else
{
BtlController_EmitLinkStandbyMsg(BUFFER_A, LINK_STANDBY_STOP_BOUNCE_ONLY, i);
}
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler]++;
}
break;
2017-10-04 19:25:14 +02:00
case STATE_WAIT_ACTION_CONFIRMED:
2021-03-30 23:38:09 +02:00
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
{
2017-10-04 19:25:14 +02:00
gBattleCommunication[ACTIONS_CONFIRMED_COUNT]++;
}
break;
2017-10-04 19:25:14 +02:00
case STATE_SELECTION_SCRIPT:
2018-02-06 02:46:59 +01:00
if (*(gBattleStruct->selectionScriptFinished + gActiveBattler))
{
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = *(gBattleStruct->stateIdAfterSelScript + gActiveBattler);
}
else
{
2018-02-06 23:09:39 +01:00
gBattlerAttacker = gActiveBattler;
2018-02-06 02:46:59 +01:00
gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBattler];
2021-03-30 23:38:09 +02:00
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
{
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = gBattlescriptCurrInstr;
}
break;
2017-10-04 19:25:14 +02:00
case STATE_WAIT_SET_BEFORE_ACTION:
2021-03-30 23:38:09 +02:00
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
{
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
}
break;
2017-10-04 19:25:14 +02:00
case STATE_SELECTION_SCRIPT_MAY_RUN:
2018-02-06 02:46:59 +01:00
if (*(gBattleStruct->selectionScriptFinished + gActiveBattler))
{
2020-03-18 02:11:14 +01:00
if (gBattleBufferB[gActiveBattler][1] == B_ACTION_NOTHING_FAINTED)
{
2017-10-06 17:06:45 +02:00
gHitMarker |= HITMARKER_RUN;
2018-02-06 23:09:39 +01:00
gChosenActionByBattler[gActiveBattler] = B_ACTION_RUN;
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
2018-02-06 20:48:02 +01:00
RecordedBattle_ClearBattlerAction(gActiveBattler, 1);
2018-02-06 02:46:59 +01:00
gBattleCommunication[gActiveBattler] = *(gBattleStruct->stateIdAfterSelScript + gActiveBattler);
}
}
else
{
2018-02-06 23:09:39 +01:00
gBattlerAttacker = gActiveBattler;
2018-02-06 02:46:59 +01:00
gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBattler];
2021-03-30 23:38:09 +02:00
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
{
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = gBattlescriptCurrInstr;
}
break;
}
}
// Check if everyone chose actions.
2018-02-06 02:46:59 +01:00
if (gBattleCommunication[ACTIONS_CONFIRMED_COUNT] == gBattlersCount)
{
RecordedBattle_CheckMovesetChanges(B_RECORD_MODE_RECORDING);
2018-02-08 11:17:41 +01:00
gBattleMainFunc = SetActionsAndBattlersTurnOrder;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
{
2018-02-06 23:09:39 +01:00
if (gChosenActionByBattler[i] == B_ACTION_SWITCH)
2019-10-26 03:55:01 +02:00
SwitchPartyOrderInGameMulti(i, *(gBattleStruct->monToSwitchIntoId + i));
}
}
}
}
2017-10-04 19:25:14 +02:00
static bool8 AllAtActionConfirmed(void)
2017-10-04 19:25:14 +02:00
{
s32 i, count;
2017-10-04 19:25:14 +02:00
for (count = 0, i = 0; i < gBattlersCount; i++)
2017-10-04 19:25:14 +02:00
{
if (gBattleCommunication[i] == STATE_WAIT_ACTION_CONFIRMED)
count++;
2017-10-04 19:25:14 +02:00
}
if (count + 1 == gBattlersCount)
2017-10-04 19:25:14 +02:00
return TRUE;
else
return FALSE;
}
static void UpdateBattlerPartyOrdersOnSwitch(void)
2017-10-04 19:25:14 +02:00
{
2018-02-06 02:46:59 +01:00
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = gBattleBufferB[gActiveBattler][1];
2018-02-06 20:48:02 +01:00
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleBufferB[gActiveBattler][1]);
2017-10-04 19:25:14 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
*(gActiveBattler * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) &= 0xF;
*(gActiveBattler * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) |= (gBattleBufferB[gActiveBattler][2] & 0xF0);
*(gActiveBattler * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 1) = gBattleBufferB[gActiveBattler][3];
2017-10-04 19:25:14 +02:00
2022-08-27 07:26:13 +02:00
*((BATTLE_PARTNER(gActiveBattler)) * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) &= (0xF0);
*((BATTLE_PARTNER(gActiveBattler)) * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) |= (gBattleBufferB[gActiveBattler][2] & 0xF0) >> 4;
*((BATTLE_PARTNER(gActiveBattler)) * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 2) = gBattleBufferB[gActiveBattler][3];
2017-10-04 19:25:14 +02:00
}
}
void SwapTurnOrder(u8 id1, u8 id2)
{
u32 temp;
SWAP(gActionsByTurnOrder[id1], gActionsByTurnOrder[id2], temp);
SWAP(gBattlerByTurnOrder[id1], gBattlerByTurnOrder[id2], temp);
2017-10-04 19:25:14 +02:00
}
2018-02-08 11:17:41 +01:00
u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
2017-10-04 19:25:14 +02:00
{
u8 strikesFirst = 0;
2018-02-08 11:17:41 +01:00
u8 speedMultiplierBattler1 = 0, speedMultiplierBattler2 = 0;
u32 speedBattler1 = 0, speedBattler2 = 0;
2017-10-04 19:25:14 +02:00
u8 holdEffect = 0;
u8 holdEffectParam = 0;
2018-02-08 11:17:41 +01:00
u16 moveBattler1 = 0, moveBattler2 = 0;
2017-10-04 19:25:14 +02:00
if (WEATHER_HAS_EFFECT)
{
2021-09-30 12:08:20 +02:00
if ((gBattleMons[battler1].ability == ABILITY_SWIFT_SWIM && gBattleWeather & B_WEATHER_RAIN)
|| (gBattleMons[battler1].ability == ABILITY_CHLOROPHYLL && gBattleWeather & B_WEATHER_SUN))
2018-02-08 11:17:41 +01:00
speedMultiplierBattler1 = 2;
2017-10-04 19:25:14 +02:00
else
2018-02-08 11:17:41 +01:00
speedMultiplierBattler1 = 1;
2017-10-04 19:25:14 +02:00
2021-09-30 12:08:20 +02:00
if ((gBattleMons[battler2].ability == ABILITY_SWIFT_SWIM && gBattleWeather & B_WEATHER_RAIN)
|| (gBattleMons[battler2].ability == ABILITY_CHLOROPHYLL && gBattleWeather & B_WEATHER_SUN))
2018-02-08 11:17:41 +01:00
speedMultiplierBattler2 = 2;
2017-10-04 19:25:14 +02:00
else
2018-02-08 11:17:41 +01:00
speedMultiplierBattler2 = 1;
2017-10-04 19:25:14 +02:00
}
else
{
2018-02-08 11:17:41 +01:00
speedMultiplierBattler1 = 1;
speedMultiplierBattler2 = 1;
2017-10-04 19:25:14 +02:00
}
2018-02-08 11:17:41 +01:00
speedBattler1 = (gBattleMons[battler1].speed * speedMultiplierBattler1)
2018-02-08 12:13:29 +01:00
* (gStatStageRatios[gBattleMons[battler1].statStages[STAT_SPEED]][0])
/ (gStatStageRatios[gBattleMons[battler1].statStages[STAT_SPEED]][1]);
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
if (gBattleMons[battler1].item == ITEM_ENIGMA_BERRY)
2017-10-04 19:25:14 +02:00
{
2018-02-08 11:17:41 +01:00
holdEffect = gEnigmaBerries[battler1].holdEffect;
holdEffectParam = gEnigmaBerries[battler1].holdEffectParam;
2017-10-04 19:25:14 +02:00
}
else
{
2018-02-08 11:17:41 +01:00
holdEffect = ItemId_GetHoldEffect(gBattleMons[battler1].item);
holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[battler1].item);
2017-10-04 19:25:14 +02:00
}
// badge boost
2021-01-13 21:17:32 +01:00
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER))
2017-11-08 22:20:10 +01:00
&& FlagGet(FLAG_BADGE03_GET)
2018-02-08 11:17:41 +01:00
&& GetBattlerSide(battler1) == B_SIDE_PLAYER)
2017-10-04 19:25:14 +02:00
{
2018-02-08 11:17:41 +01:00
speedBattler1 = (speedBattler1 * 110) / 100;
2017-10-04 19:25:14 +02:00
}
if (holdEffect == HOLD_EFFECT_MACHO_BRACE)
2018-02-08 11:17:41 +01:00
speedBattler1 /= 2;
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
if (gBattleMons[battler1].status1 & STATUS1_PARALYSIS)
speedBattler1 /= 4;
2017-10-04 19:25:14 +02:00
if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100)
2018-02-08 11:17:41 +01:00
speedBattler1 = UINT_MAX;
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
// check second battlerId's speed
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
speedBattler2 = (gBattleMons[battler2].speed * speedMultiplierBattler2)
2018-02-08 12:13:29 +01:00
* (gStatStageRatios[gBattleMons[battler2].statStages[STAT_SPEED]][0])
/ (gStatStageRatios[gBattleMons[battler2].statStages[STAT_SPEED]][1]);
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
if (gBattleMons[battler2].item == ITEM_ENIGMA_BERRY)
2017-10-04 19:25:14 +02:00
{
2018-02-08 11:17:41 +01:00
holdEffect = gEnigmaBerries[battler2].holdEffect;
holdEffectParam = gEnigmaBerries[battler2].holdEffectParam;
2017-10-04 19:25:14 +02:00
}
else
{
2018-02-08 11:17:41 +01:00
holdEffect = ItemId_GetHoldEffect(gBattleMons[battler2].item);
holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[battler2].item);
2017-10-04 19:25:14 +02:00
}
// badge boost
2021-01-13 21:17:32 +01:00
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER))
2017-11-08 22:20:10 +01:00
&& FlagGet(FLAG_BADGE03_GET)
2018-02-08 11:17:41 +01:00
&& GetBattlerSide(battler2) == B_SIDE_PLAYER)
2017-10-04 19:25:14 +02:00
{
2018-02-08 11:17:41 +01:00
speedBattler2 = (speedBattler2 * 110) / 100;
2017-10-04 19:25:14 +02:00
}
if (holdEffect == HOLD_EFFECT_MACHO_BRACE)
2018-02-08 11:17:41 +01:00
speedBattler2 /= 2;
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
if (gBattleMons[battler2].status1 & STATUS1_PARALYSIS)
speedBattler2 /= 4;
2017-10-04 19:25:14 +02:00
if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100)
2018-02-08 11:17:41 +01:00
speedBattler2 = UINT_MAX;
2017-10-04 19:25:14 +02:00
if (ignoreChosenMoves)
{
2018-02-08 11:17:41 +01:00
moveBattler1 = MOVE_NONE;
moveBattler2 = MOVE_NONE;
2017-10-04 19:25:14 +02:00
}
else
{
2018-02-08 11:17:41 +01:00
if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE)
2017-10-04 19:25:14 +02:00
{
2018-07-07 19:57:09 +02:00
if (gProtectStructs[battler1].noValidMoves)
2018-02-08 11:17:41 +01:00
moveBattler1 = MOVE_STRUGGLE;
2017-10-04 19:25:14 +02:00
else
2018-02-08 11:17:41 +01:00
moveBattler1 = gBattleMons[battler1].moves[*(gBattleStruct->chosenMovePositions + battler1)];
2017-10-04 19:25:14 +02:00
}
else
2018-02-08 11:17:41 +01:00
moveBattler1 = MOVE_NONE;
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE)
2017-10-04 19:25:14 +02:00
{
2018-07-07 19:57:09 +02:00
if (gProtectStructs[battler2].noValidMoves)
2018-02-08 11:17:41 +01:00
moveBattler2 = MOVE_STRUGGLE;
2017-10-04 19:25:14 +02:00
else
2018-02-08 11:17:41 +01:00
moveBattler2 = gBattleMons[battler2].moves[*(gBattleStruct->chosenMovePositions + battler2)];
2017-10-04 19:25:14 +02:00
}
else
2018-02-08 11:17:41 +01:00
moveBattler2 = MOVE_NONE;
2017-10-04 19:25:14 +02:00
}
// both move priorities are different than 0
2018-02-08 11:17:41 +01:00
if (gBattleMoves[moveBattler1].priority != 0 || gBattleMoves[moveBattler2].priority != 0)
2017-10-04 19:25:14 +02:00
{
// both priorities are the same
2018-02-08 11:17:41 +01:00
if (gBattleMoves[moveBattler1].priority == gBattleMoves[moveBattler2].priority)
2017-10-04 19:25:14 +02:00
{
2018-02-08 11:17:41 +01:00
if (speedBattler1 == speedBattler2 && Random() & 1)
2017-10-04 19:25:14 +02:00
strikesFirst = 2; // same speeds, same priorities
2018-02-08 11:17:41 +01:00
else if (speedBattler1 < speedBattler2)
strikesFirst = 1; // battler2 has more speed
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
// else battler1 has more speed
2017-10-04 19:25:14 +02:00
}
2018-02-08 11:17:41 +01:00
else if (gBattleMoves[moveBattler1].priority < gBattleMoves[moveBattler2].priority)
strikesFirst = 1; // battler2's move has greater priority
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
// else battler1's move has greater priority
2017-10-04 19:25:14 +02:00
}
// both priorities are equal to 0
else
{
2018-02-08 11:17:41 +01:00
if (speedBattler1 == speedBattler2 && Random() & 1)
2017-10-04 19:25:14 +02:00
strikesFirst = 2; // same speeds, same priorities
2018-02-08 11:17:41 +01:00
else if (speedBattler1 < speedBattler2)
strikesFirst = 1; // battler2 has more speed
2017-10-04 19:25:14 +02:00
2018-02-08 11:17:41 +01:00
// else battler1 has more speed
2017-10-04 19:25:14 +02:00
}
return strikesFirst;
}
2018-02-08 11:17:41 +01:00
static void SetActionsAndBattlersTurnOrder(void)
2017-10-04 19:25:14 +02:00
{
2018-06-28 21:06:32 +02:00
s32 turnOrderId = 0;
2017-10-04 19:25:14 +02:00
s32 i, j;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
{
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-04 19:25:14 +02:00
{
2018-06-28 21:06:32 +02:00
gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
turnOrderId++;
2017-10-04 19:25:14 +02:00
}
}
else
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-04 19:25:14 +02:00
{
2018-02-06 23:09:39 +01:00
if (gChosenActionByBattler[gActiveBattler] == B_ACTION_RUN)
2017-10-04 19:25:14 +02:00
{
2018-06-28 21:06:32 +02:00
turnOrderId = 5;
2017-10-04 19:25:14 +02:00
break;
}
}
}
else
{
2018-02-06 23:09:39 +01:00
if (gChosenActionByBattler[0] == B_ACTION_RUN)
2017-10-04 19:25:14 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = 0;
2018-06-28 21:06:32 +02:00
turnOrderId = 5;
2017-10-04 19:25:14 +02:00
}
2018-02-06 23:09:39 +01:00
if (gChosenActionByBattler[2] == B_ACTION_RUN)
2017-10-04 19:25:14 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = 2;
2018-06-28 21:06:32 +02:00
turnOrderId = 5;
2017-10-04 19:25:14 +02:00
}
}
2018-06-28 21:06:32 +02:00
if (turnOrderId == 5) // One of battlers wants to run.
2017-10-04 19:25:14 +02:00
{
2018-02-06 23:09:39 +01:00
gActionsByTurnOrder[0] = gChosenActionByBattler[gActiveBattler];
2018-06-28 21:06:32 +02:00
gBattlerByTurnOrder[0] = gActiveBattler;
turnOrderId = 1;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-04 19:25:14 +02:00
{
2018-02-06 02:46:59 +01:00
if (i != gActiveBattler)
2017-10-04 19:25:14 +02:00
{
2018-06-28 21:06:32 +02:00
gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[i];
gBattlerByTurnOrder[turnOrderId] = i;
turnOrderId++;
2017-10-04 19:25:14 +02:00
}
}
2017-10-06 00:12:01 +02:00
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
2018-02-07 22:53:40 +01:00
gBattleStruct->focusPunchBattlerId = 0;
2017-10-04 19:25:14 +02:00
return;
}
else
2017-10-04 19:25:14 +02:00
{
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-04 19:25:14 +02:00
{
if (gChosenActionByBattler[gActiveBattler] == B_ACTION_USE_ITEM || gChosenActionByBattler[gActiveBattler] == B_ACTION_SWITCH)
{
gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
turnOrderId++;
}
2017-10-04 19:25:14 +02:00
}
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-04 19:25:14 +02:00
{
if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH)
{
gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler];
gBattlerByTurnOrder[turnOrderId] = gActiveBattler;
turnOrderId++;
}
2017-10-04 19:25:14 +02:00
}
for (i = 0; i < gBattlersCount - 1; i++)
2017-10-04 19:25:14 +02:00
{
for (j = i + 1; j < gBattlersCount; j++)
2017-10-04 19:25:14 +02:00
{
u8 battler1 = gBattlerByTurnOrder[i];
u8 battler2 = gBattlerByTurnOrder[j];
if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM
&& gActionsByTurnOrder[j] != B_ACTION_USE_ITEM
&& gActionsByTurnOrder[i] != B_ACTION_SWITCH
&& gActionsByTurnOrder[j] != B_ACTION_SWITCH)
{
if (GetWhoStrikesFirst(battler1, battler2, FALSE))
SwapTurnOrder(i, j);
}
2017-10-04 19:25:14 +02:00
}
}
}
}
2017-10-06 00:12:01 +02:00
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
2018-02-07 22:53:40 +01:00
gBattleStruct->focusPunchBattlerId = 0;
2017-10-06 00:12:01 +02:00
}
2017-10-06 19:09:37 +02:00
static void TurnValuesCleanUp(bool8 var0)
2017-10-06 00:12:01 +02:00
{
s32 i;
u8 *dataPtr;
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-06 00:12:01 +02:00
{
if (var0)
{
2018-02-06 02:46:59 +01:00
gProtectStructs[gActiveBattler].protected = 0;
gProtectStructs[gActiveBattler].endured = 0;
2017-10-06 00:12:01 +02:00
}
else
{
dataPtr = (u8 *)(&gProtectStructs[gActiveBattler]);
2017-10-06 00:12:01 +02:00
for (i = 0; i < sizeof(struct ProtectStruct); i++)
dataPtr[i] = 0;
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].isFirstTurn)
gDisableStructs[gActiveBattler].isFirstTurn--;
2017-10-06 00:12:01 +02:00
2018-10-14 18:10:54 +02:00
if (gDisableStructs[gActiveBattler].rechargeTimer)
2017-10-06 00:12:01 +02:00
{
2018-10-14 18:10:54 +02:00
gDisableStructs[gActiveBattler].rechargeTimer--;
if (gDisableStructs[gActiveBattler].rechargeTimer == 0)
2021-09-24 20:30:15 +02:00
gBattleMons[gActiveBattler].status2 &= ~STATUS2_RECHARGE;
2017-10-06 00:12:01 +02:00
}
}
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].substituteHP == 0)
2021-09-24 20:30:15 +02:00
gBattleMons[gActiveBattler].status2 &= ~STATUS2_SUBSTITUTE;
2017-10-06 00:12:01 +02:00
}
gSideTimers[0].followmeTimer = 0;
gSideTimers[1].followmeTimer = 0;
}
void SpecialStatusesClear(void)
2017-10-06 00:12:01 +02:00
{
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-06 00:12:01 +02:00
{
s32 i;
u8 *dataPtr = (u8 *)(&gSpecialStatuses[gActiveBattler]);
2017-10-06 00:12:01 +02:00
for (i = 0; i < sizeof(struct SpecialStatus); i++)
dataPtr[i] = 0;
}
}
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
{
2017-10-06 17:06:45 +02:00
if (!(gHitMarker & HITMARKER_RUN))
2017-10-06 00:12:01 +02:00
{
2018-02-07 22:53:40 +01:00
while (gBattleStruct->focusPunchBattlerId < gBattlersCount)
2017-10-06 00:12:01 +02:00
{
2018-02-07 22:53:40 +01:00
gActiveBattler = gBattlerAttacker = gBattleStruct->focusPunchBattlerId;
gBattleStruct->focusPunchBattlerId++;
2018-02-06 23:09:39 +01:00
if (gChosenMoveByBattler[gActiveBattler] == MOVE_FOCUS_PUNCH
2018-02-06 02:46:59 +01:00
&& !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
2018-02-06 23:09:39 +01:00
&& !(gDisableStructs[gBattlerAttacker].truantCounter)
2018-07-07 19:57:09 +02:00
&& !(gProtectStructs[gActiveBattler].noValidMoves))
2017-10-06 00:12:01 +02:00
{
BattleScriptExecute(BattleScript_FocusPunchSetUp);
return;
}
}
}
TryClearRageStatuses();
gCurrentTurnActionNumber = 0;
2020-10-22 11:45:53 +02:00
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
2017-10-06 00:12:01 +02:00
gDynamicBasePower = 0;
gBattleStruct->dynamicMoveType = 0;
gBattleMainFunc = RunTurnActionsFunctions;
gBattleCommunication[3] = 0;
gBattleCommunication[4] = 0;
gBattleScripting.multihitMoveEffect = 0;
2017-10-06 00:12:01 +02:00
gBattleResources->battleScriptsStack->size = 0;
}
static void RunTurnActionsFunctions(void)
{
if (gBattleOutcome != 0)
2019-09-03 21:08:25 +02:00
gCurrentActionFuncId = B_ACTION_FINISHED;
2017-10-06 00:12:01 +02:00
*(&gBattleStruct->savedTurnActionNumber) = gCurrentTurnActionNumber;
2017-10-06 19:09:37 +02:00
sTurnActionsFuncsTable[gCurrentActionFuncId]();
2017-10-06 00:12:01 +02:00
2018-02-06 02:46:59 +01:00
if (gCurrentTurnActionNumber >= gBattlersCount) // everyone did their actions, turn finished
2017-10-06 00:12:01 +02:00
{
2021-09-24 20:30:15 +02:00
gHitMarker &= ~HITMARKER_PASSIVE_DAMAGE;
2017-10-06 19:09:37 +02:00
gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F];
2017-10-06 00:12:01 +02:00
}
else
2017-10-06 00:12:01 +02:00
{
if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battlerId
{
2021-09-24 20:30:15 +02:00
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE;
}
2017-10-06 00:12:01 +02:00
}
}
2017-10-06 19:09:37 +02:00
static void HandleEndTurn_BattleWon(void)
2017-10-06 00:12:01 +02:00
{
gCurrentActionFuncId = 0;
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
2017-10-06 00:12:01 +02:00
{
2017-11-11 01:12:18 +01:00
gSpecialVar_Result = gBattleOutcome;
2017-10-06 00:12:01 +02:00
gBattleTextBuff1[0] = gBattleOutcome;
2018-02-06 23:09:39 +01:00
gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost;
2021-09-24 20:30:15 +02:00
gBattleOutcome &= ~B_OUTCOME_LINK_BATTLE_RAN;
2017-10-06 00:12:01 +02:00
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
2018-09-20 22:00:00 +02:00
&& gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_EREADER_TRAINER))
2017-10-06 00:12:01 +02:00
{
2017-11-04 16:11:13 +01:00
BattleStopLowHpSound();
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_FrontierTrainerBattleWon;
if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN)
2020-08-21 00:02:00 +02:00
PlayBGM(MUS_VICTORY_GYM_LEADER);
2017-10-06 00:12:01 +02:00
else
2020-08-21 00:02:00 +02:00
PlayBGM(MUS_VICTORY_TRAINER);
2017-10-06 00:12:01 +02:00
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
2017-11-04 16:11:13 +01:00
BattleStopLowHpSound();
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_LocalTrainerBattleWon;
switch (gTrainers[gTrainerBattleOpponent_A].trainerClass)
{
2017-12-17 21:19:08 +01:00
case TRAINER_CLASS_ELITE_FOUR:
case TRAINER_CLASS_CHAMPION:
2020-08-21 00:02:00 +02:00
PlayBGM(MUS_VICTORY_LEAGUE);
2017-10-06 00:12:01 +02:00
break;
2017-12-17 21:19:08 +01:00
case TRAINER_CLASS_TEAM_AQUA:
case TRAINER_CLASS_TEAM_MAGMA:
case TRAINER_CLASS_AQUA_ADMIN:
case TRAINER_CLASS_AQUA_LEADER:
case TRAINER_CLASS_MAGMA_ADMIN:
case TRAINER_CLASS_MAGMA_LEADER:
2020-08-21 00:02:00 +02:00
PlayBGM(MUS_VICTORY_AQUA_MAGMA);
2017-10-06 00:12:01 +02:00
break;
2017-12-17 21:19:08 +01:00
case TRAINER_CLASS_LEADER:
2020-08-21 00:02:00 +02:00
PlayBGM(MUS_VICTORY_GYM_LEADER);
2017-10-06 00:12:01 +02:00
break;
default:
2020-08-21 00:02:00 +02:00
PlayBGM(MUS_VICTORY_TRAINER);
2017-10-06 00:12:01 +02:00
break;
}
}
else
{
gBattlescriptCurrInstr = BattleScript_PayDayMoneyAndPickUpItems;
}
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
2017-10-06 19:09:37 +02:00
static void HandleEndTurn_BattleLost(void)
2017-10-06 00:12:01 +02:00
{
gCurrentActionFuncId = 0;
2021-01-13 21:17:32 +01:00
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
2017-10-06 00:12:01 +02:00
{
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
{
2018-01-16 22:12:38 +01:00
if (gBattleOutcome & B_OUTCOME_LINK_BATTLE_RAN)
2017-10-06 00:12:01 +02:00
{
2017-12-03 00:47:21 +01:00
gBattlescriptCurrInstr = BattleScript_PrintPlayerForfeitedLinkBattle;
2021-09-24 20:30:15 +02:00
gBattleOutcome &= ~B_OUTCOME_LINK_BATTLE_RAN;
2019-12-14 09:58:20 +01:00
gSaveBlock2Ptr->frontier.disableRecordBattle = TRUE;
2017-10-06 00:12:01 +02:00
}
else
{
gBattlescriptCurrInstr = BattleScript_FrontierLinkBattleLost;
2021-09-24 20:30:15 +02:00
gBattleOutcome &= ~B_OUTCOME_LINK_BATTLE_RAN;
2017-10-06 00:12:01 +02:00
}
}
else
{
gBattleTextBuff1[0] = gBattleOutcome;
2018-02-06 23:09:39 +01:00
gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost;
2021-09-24 20:30:15 +02:00
gBattleOutcome &= ~B_OUTCOME_LINK_BATTLE_RAN;
2017-10-06 00:12:01 +02:00
}
}
else
{
gBattlescriptCurrInstr = BattleScript_LocalBattleLost;
}
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
2017-10-06 19:09:37 +02:00
static void HandleEndTurn_RanFromBattle(void)
2017-10-06 00:12:01 +02:00
{
gCurrentActionFuncId = 0;
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER && gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
2017-12-03 00:47:21 +01:00
gBattlescriptCurrInstr = BattleScript_PrintPlayerForfeited;
2018-01-16 22:12:38 +01:00
gBattleOutcome = B_OUTCOME_FORFEITED;
2019-12-14 09:58:20 +01:00
gSaveBlock2Ptr->frontier.disableRecordBattle = TRUE;
2017-10-06 00:12:01 +02:00
}
2018-09-20 22:00:00 +02:00
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL)
2017-10-06 00:12:01 +02:00
{
2017-12-03 00:47:21 +01:00
gBattlescriptCurrInstr = BattleScript_PrintPlayerForfeited;
2018-01-16 22:12:38 +01:00
gBattleOutcome = B_OUTCOME_FORFEITED;
2017-10-06 00:12:01 +02:00
}
else
{
2021-10-04 16:21:03 +02:00
switch (gProtectStructs[gBattlerAttacker].fleeType)
2017-10-06 00:12:01 +02:00
{
default:
gBattlescriptCurrInstr = BattleScript_GotAwaySafely;
break;
2021-10-04 16:21:03 +02:00
case FLEE_ITEM:
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_SmokeBallEscape;
break;
2021-10-04 16:21:03 +02:00
case FLEE_ABILITY:
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_RanAwayUsingMonAbility;
break;
}
}
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
2017-10-06 19:09:37 +02:00
static void HandleEndTurn_MonFled(void)
2017-10-06 00:12:01 +02:00
{
gCurrentActionFuncId = 0;
2018-02-06 23:09:39 +01:00
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]);
2017-10-06 00:12:01 +02:00
gBattlescriptCurrInstr = BattleScript_WildMonFled;
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
2017-10-06 19:09:37 +02:00
static void HandleEndTurn_FinishBattle(void)
2017-10-06 00:12:01 +02:00
{
2019-09-03 21:08:25 +02:00
if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED)
2017-10-06 00:12:01 +02:00
{
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
2021-01-13 21:17:32 +01:00
| BATTLE_TYPE_RECORDED_LINK
2017-10-06 00:12:01 +02:00
| BATTLE_TYPE_FIRST_BATTLE
| BATTLE_TYPE_SAFARI
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_WALLY_TUTORIAL
| BATTLE_TYPE_FRONTIER)))
{
2018-02-06 02:46:59 +01:00
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
2017-10-06 00:12:01 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
2017-10-06 00:12:01 +02:00
{
if (gBattleResults.playerMon1Species == SPECIES_NONE)
{
2018-02-06 20:48:02 +01:00
gBattleResults.playerMon1Species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_NICKNAME, gBattleResults.playerMon1Name);
2017-10-06 00:12:01 +02:00
}
else
{
2018-02-06 20:48:02 +01:00
gBattleResults.playerMon2Species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_NICKNAME, gBattleResults.playerMon2Name);
2017-10-06 00:12:01 +02:00
}
}
}
2021-04-25 23:22:45 +02:00
TryPutPokemonTodayOnAir();
2017-10-06 00:12:01 +02:00
}
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
2021-01-13 21:17:32 +01:00
| BATTLE_TYPE_RECORDED_LINK
2017-10-06 00:12:01 +02:00
| BATTLE_TYPE_TRAINER
| BATTLE_TYPE_FIRST_BATTLE
| BATTLE_TYPE_SAFARI
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_WALLY_TUTORIAL))
2018-06-28 21:06:32 +02:00
&& gBattleResults.shinyWildMon)
2017-10-06 00:12:01 +02:00
{
2021-04-25 23:22:45 +02:00
TryPutBreakingNewsOnAir();
2017-10-06 00:12:01 +02:00
}
2021-10-04 16:21:03 +02:00
RecordedBattle_SetPlaybackFinished();
2017-10-06 00:12:01 +02:00
BeginFastPaletteFade(3);
FadeOutMapMusic(5);
gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions;
2017-10-29 16:15:23 +01:00
gCB2_AfterEvolution = BattleMainCB2;
2017-10-06 00:12:01 +02:00
}
else
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-06 00:12:01 +02:00
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
}
static void FreeResetData_ReturnToOvOrDoEvolutions(void)
{
if (!gPaletteFade.active)
{
ResetSpriteData();
2018-01-16 22:12:38 +01:00
if (gLeveledUpInBattle == 0 || gBattleOutcome != B_OUTCOME_WON)
2017-10-06 00:12:01 +02:00
{
gBattleMainFunc = ReturnFromBattleToOverworld;
return;
}
else
{
gBattleMainFunc = TryEvolvePokemon;
}
2017-10-06 00:12:01 +02:00
}
FreeAllWindowBuffers();
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
FreeMonSpritesGfx();
FreeBattleResources();
FreeBattleSpritesData();
}
}
static void TryEvolvePokemon(void)
{
s32 i;
while (gLeveledUpInBattle != 0)
{
2018-02-08 11:17:41 +01:00
for (i = 0; i < PARTY_SIZE; i++)
2017-10-06 00:12:01 +02:00
{
if (gLeveledUpInBattle & gBitTable[i])
{
u16 species;
u8 levelUpBits = gLeveledUpInBattle;
levelUpBits &= ~(gBitTable[i]);
gLeveledUpInBattle = levelUpBits;
2021-02-12 20:54:11 +01:00
species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_NORMAL, levelUpBits);
2017-10-06 00:12:01 +02:00
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)
2017-10-06 00:12:01 +02:00
return;
2017-11-11 01:12:18 +01:00
gSpecialVar_Result = gBattleOutcome;
2021-10-04 16:21:03 +02:00
gMain.inBattle = FALSE;
2017-10-06 00:12:01 +02:00
gMain.callback1 = gPreBattleCallback1;
if (gBattleTypeFlags & BATTLE_TYPE_ROAMER)
{
UpdateRoamerHPStatus(&gEnemyParty[0]);
#ifndef BUGFIX
2018-02-08 00:35:13 +01:00
if ((gBattleOutcome & B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT)
#else
if ((gBattleOutcome == B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) // Bug: When Roar is used by roamer, gBattleOutcome is B_OUTCOME_PLAYER_TELEPORTED (5).
#endif // & with B_OUTCOME_WON (1) will return TRUE and deactivates the roamer.
2017-10-06 00:12:01 +02:00
SetRoamerInactive();
}
2020-08-21 00:02:00 +02:00
m4aSongNumStop(SE_LOW_HEALTH);
2017-10-06 00:12:01 +02:00
SetMainCallback2(gMain.savedCallback);
}
void RunBattleScriptCommands_PopCallbacksStack(void)
{
2019-09-03 21:08:25 +02:00
if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED)
2017-10-06 00:12:01 +02:00
{
2018-02-06 23:09:39 +01:00
if (gBattleResources->battleCallbackStack->size != 0)
gBattleResources->battleCallbackStack->size--;
gBattleMainFunc = gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size];
2017-10-06 00:12:01 +02:00
}
else
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-06 00:12:01 +02:00
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
}
void RunBattleScriptCommands(void)
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-10-06 00:12:01 +02:00
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}