Merge branch 'upcoming' into ultraburst

This commit is contained in:
kittenchilly 2023-08-29 16:17:35 -05:00
commit d540eccbb1
26 changed files with 3977 additions and 13266 deletions

View File

@ -0,0 +1,3 @@
gBattlerControllerFuncs
gBattleControllerData
gBattlerControllerEndFuncs

View File

@ -2,8 +2,6 @@ gPreBattleCallback1
gBattleMainFunc gBattleMainFunc
gBattleResults gBattleResults
gLeveledUpInBattle gLeveledUpInBattle
gBattlerControllerFuncs
gHealthboxSpriteIds gHealthboxSpriteIds
gMultiUsePlayerCursor gMultiUsePlayerCursor
gNumberOfMovesToChoose gNumberOfMovesToChoose
gBattleControllerData

View File

@ -292,6 +292,8 @@ struct AiLogicData
s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 moveLimitations[MAX_BATTLERS_COUNT]; u8 moveLimitations[MAX_BATTLERS_COUNT];
bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler.
u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch.
}; };
struct AI_ThinkingStruct struct AI_ThinkingStruct
@ -304,8 +306,7 @@ struct AI_ThinkingStruct
u32 aiFlags; u32 aiFlags;
u8 aiAction; u8 aiAction;
u8 aiLogicId; u8 aiLogicId;
struct AI_SavedBattleMon saved[4]; struct AI_SavedBattleMon saved[MAX_BATTLERS_COUNT];
bool8 switchMon; // Because all available moves have no/little effect.
}; };
#define AI_MOVE_HISTORY_COUNT 3 #define AI_MOVE_HISTORY_COUNT 3
@ -1012,11 +1013,9 @@ extern void (*gPreBattleCallback1)(void);
extern void (*gBattleMainFunc)(void); extern void (*gBattleMainFunc)(void);
extern struct BattleResults gBattleResults; extern struct BattleResults gBattleResults;
extern u8 gLeveledUpInBattle; extern u8 gLeveledUpInBattle;
extern void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(void);
extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT]; extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
extern u8 gMultiUsePlayerCursor; extern u8 gMultiUsePlayerCursor;
extern u8 gNumberOfMovesToChoose; extern u8 gNumberOfMovesToChoose;
extern u8 gBattleControllerData[MAX_BATTLERS_COUNT];
extern bool8 gHasFetchedBall; extern bool8 gHasFetchedBall;
extern u8 gLastUsedBall; extern u8 gLastUsedBall;
extern u16 gLastThrownBall; extern u16 gLastThrownBall;

View File

@ -199,6 +199,9 @@ enum
}; };
extern struct UnusedControllerStruct gUnusedControllerStruct; extern struct UnusedControllerStruct gUnusedControllerStruct;
extern void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(u32 battler);
extern void (*gBattlerControllerEndFuncs[MAX_BATTLERS_COUNT])(u32 battler);
extern u8 gBattleControllerData[MAX_BATTLERS_COUNT];
// general functions // general functions
void HandleLinkBattleSetup(void); void HandleLinkBattleSetup(void);
@ -253,43 +256,88 @@ void BtlController_EmitResetActionMoveSelection(u8 bufferId, u8 caseId);
void BtlController_EmitEndLinkBattle(u8 bufferId, u8 battleOutcome); void BtlController_EmitEndLinkBattle(u8 bufferId, u8 battleOutcome);
void BtlController_EmitDebugMenu(u8 bufferId); void BtlController_EmitDebugMenu(u8 bufferId);
void BattleControllerComplete(u32 battler); // Can be used for all the controllers.
void BtlController_Empty(u32 battler); // Empty command, does nothing, only completes the execution.
void BtlController_TerminatorNop(u32 battler); // Dummy function at the end of the table.
void BattleControllerDummy(u32 battler);
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit);
void Controller_WaitForString(u32 battler);
void Controller_WaitForHealthBar(u32 battler);
// handlers
void BtlController_HandleGetMonData(u32 battler);
void BtlController_HandleGetRawMonData(u32 battler);
void BtlController_HandleSetMonData(u32 battler);
void BtlController_HandleSetRawMonData(u32 battler);
void BtlController_HandleLoadMonSprite(u32 battler, void (*controllerCallback)(u32 battler));
void BtlController_HandleSwitchInAnim(u32 battler, bool32 isPlayerSide, void (*controllerCallback)(u32 battler));
void BtlController_HandleReturnMonToBall(u32 battler);
void BtlController_HandleDrawTrainerPic(u32 battlerId, u32 trainerPicId, bool32 isFrontPic, s16 xPos, s16 yPos, s32 subpriority);
void BtlController_HandleTrainerSlide(u32 battler, u32 trainerPicId);
void BtlController_HandleTrainerSlideBack(u32 battlerId, s16 data0, bool32 startAnim);
void BtlController_HandleFaintAnimation(u32 battler);
void BtlController_HandleSuccessBallThrowAnim(u32 battler, u32 target, u32 animId, bool32 allowCriticalCapture);
void BtlController_HandleBallThrowAnim(u32 battler, u32 target, u32 animId, bool32 allowCriticalCapture);
void BtlController_HandleMoveAnimation(u32 battler, bool32 updateTvData);
void BtlController_HandlePrintString(u32 battler, bool32 updateTvData, bool32 arenaPtsDeduct);
void BtlController_HandleHealthBarUpdate(u32 battler, bool32 updateHpText);
void DoStatusIconUpdate(u32 battler);
void BtlController_HandleStatusIconUpdate(u32 battler);
void BtlController_HandleStatusAnimation(u32 battler);
void BtlController_HandleClearUnkVar(u32 battler);
void BtlController_HandleSetUnkVar(u32 battler);
void BtlController_HandleClearUnkFlag(u32 battler);
void BtlController_HandleToggleUnkFlag(u32 battler);
void BtlController_HandleHitAnimation(u32 battler);
void BtlController_HandlePlaySE(u32 battler);
void BtlController_HandlePlayFanfareOrBGM(u32 battler);
void BtlController_HandleFaintingCry(u32 battler);
void BtlController_HandleIntroSlide(u32 battler);
void BtlController_HandleSpriteInvisibility(u32 battler);
bool32 TwoPlayerIntroMons(u32 battlerId); // Double battle with both player pokemon active.
bool32 TwoOpponentIntroMons(u32 battlerId); // Double battle with both opponent pokemon active.
void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, const u32 *trainerPal, s16 framesToWait, void (*controllerCallback)(u32 battler));
void BtlController_HandleDrawPartyStatusSummary(u32 battler, u32 side, bool32 considerDelay);
void BtlController_HandleHidePartyStatusSummary(u32 battler);
void BtlController_HandleBattleAnimation(u32 battler, bool32 ignoreSE, bool32 updateTvData);
// player controller // player controller
void SetControllerToPlayer(void); void SetControllerToPlayer(u32 battler);
void BattleControllerDummy(void); void SetBattleEndCallbacks(u32 battler);
void PlayerHandleGetRawMonData(void); void PlayerHandleExpUpdate(u32 battler);
void SetBattleEndCallbacks(void); u32 LinkPlayerGetTrainerPicId(u32 multiplayerId);
void SpriteCB_FreePlayerSpriteLoadMonSprite(struct Sprite *sprite);
void CB2_SetUpReshowBattleScreenAfterMenu(void); void CB2_SetUpReshowBattleScreenAfterMenu(void);
void CB2_SetUpReshowBattleScreenAfterMenu2(void); void CB2_SetUpReshowBattleScreenAfterMenu2(void);
void Task_PlayerController_RestoreBgmAfterCry(u8 taskId); void Task_PlayerController_RestoreBgmAfterCry(u8 taskId);
void ActionSelectionCreateCursorAt(u8 cursorPos, u8 unused); void ActionSelectionCreateCursorAt(u8 cursorPos, u8 unused);
void ActionSelectionDestroyCursorAt(u8 cursorPos); void ActionSelectionDestroyCursorAt(u8 cursorPos);
void InitMoveSelectionsVarsAndStrings(void); void InitMoveSelectionsVarsAndStrings(u32 battler);
void MoveSelectionCreateCursorAt(u8 cursorPos, u8 arg1); void MoveSelectionCreateCursorAt(u8 cursorPos, u8 arg1);
void MoveSelectionDestroyCursorAt(u8 cursorPosition); void MoveSelectionDestroyCursorAt(u8 cursorPosition);
// recorded player controller // recorded player controller
void SetControllerToRecordedPlayer(void); void SetControllerToRecordedPlayer(u32 battler);
// opponent controller // opponent controller
void SetControllerToOpponent(void); void SetControllerToOpponent(u32 battler);
// player partner controller // player partner controller
void SetControllerToPlayerPartner(void); void Controller_PlayerPartnerShowIntroHealthbox(u32 battler); // Also used by the link partner.
void SetControllerToPlayerPartner(u32 battler);
// safari controller // safari controller
void SetControllerToSafari(void); void SetControllerToSafari(u32 battler);
// wally controller // wally controller
void SetControllerToWally(void); void SetControllerToWally(u32 battler);
// recorded opponent controller // recorded opponent controller
void SetControllerToRecordedOpponent(void); void SetControllerToRecordedOpponent(u32 battler);
// link opponent // link opponent
void SetControllerToLinkOpponent(void); void SetControllerToLinkOpponent(u32 battler);
// link partner // link partner
void SetControllerToLinkPartner(void); void SetControllerToLinkPartner(u32 battler);
#endif // GUARD_BATTLE_CONTROLLERS_H #endif // GUARD_BATTLE_CONTROLLERS_H

View File

@ -1,8 +1,6 @@
#ifndef GUARD_BATTLE_DOME_H #ifndef GUARD_BATTLE_DOME_H
#define GUARD_BATTLE_DOME_H #define GUARD_BATTLE_DOME_H
extern u32 gPlayerPartyLostHP;
int GetDomeTrainerSelectedMons(u16 tournamentTrainerId); int GetDomeTrainerSelectedMons(u16 tournamentTrainerId);
int TrainerIdToDomeTournamentId(u16 trainerId); int TrainerIdToDomeTournamentId(u16 trainerId);

View File

@ -10,12 +10,10 @@ void InitAndLaunchChosenStatusAnimation(bool8 isStatus2, u32 status);
bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId, u16 argument); bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId, u16 argument);
void InitAndLaunchSpecialAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId); void InitAndLaunchSpecialAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId);
bool8 IsBattleSEPlaying(u8 battlerId); bool8 IsBattleSEPlaying(u8 battlerId);
void BattleLoadOpponentMonSpriteGfx(struct Pokemon *mon, u8 battlerId); void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId);
void BattleLoadPlayerMonSpriteGfx(struct Pokemon *mon, u8 battlerId);
void BattleGfxSfxDummy2(u16 species); void BattleGfxSfxDummy2(u16 species);
void DecompressTrainerFrontPic(u16 frontPicId, u8 battlerId); void DecompressTrainerFrontPic(u16 frontPicId, u8 battlerId);
void DecompressTrainerBackPic(u16 backPicId, u8 battlerId); void DecompressTrainerBackPic(u16 backPicId, u8 battlerId);
void BattleGfxSfxDummy3(u8 gender);
void FreeTrainerFrontPicPalette(u16 frontPicId); void FreeTrainerFrontPicPalette(u16 frontPicId);
bool8 BattleLoadAllHealthBoxesGfx(u8 state); bool8 BattleLoadAllHealthBoxesGfx(u8 state);
void LoadBattleBarGfx(u8 unused); void LoadBattleBarGfx(u8 unused);

View File

@ -403,6 +403,78 @@ void GetAiLogicData(void)
} }
} }
static bool32 AI_SwitchMonIfSuitable(u32 battlerId)
{
u32 monToSwitchId = GetMostSuitableMonToSwitchInto();
if (monToSwitchId != PARTY_SIZE)
{
AI_DATA->shouldSwitchMon |= gBitTable[battlerId];
AI_DATA->monToSwitchId[battlerId] = monToSwitchId;
return TRUE;
}
return FALSE;
}
static bool32 AI_ShouldSwitchIfBadMoves(u32 battlerId, bool32 doubleBattle)
{
u32 i, j;
// If can switch.
if (CountUsablePartyMons(battlerId) > 0
&& !IsBattlerTrapped(battlerId, TRUE)
&& !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE))
&& AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS))
{
// Consider switching if all moves are worthless to use.
if (GetTotalBaseStat(gBattleMons[battlerId].species) >= 310 // Mon is not weak.
&& gBattleMons[battlerId].hp >= gBattleMons[battlerId].maxHP / 2) // Mon has more than 50% of its HP
{
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93;
if (doubleBattle)
{
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
if (i != battlerId && IsBattlerAlive(i))
{
for (j = 0; j < MAX_MON_MOVES; j++)
{
if (gBattleStruct->aiFinalScore[battlerId][i][j] > cap)
break;
}
if (j != MAX_MON_MOVES)
break;
}
}
if (i == MAX_BATTLERS_COUNT && AI_SwitchMonIfSuitable(battlerId))
return TRUE;
}
else
{
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (AI_THINKING_STRUCT->score[i] > cap)
break;
}
if (i == MAX_MON_MOVES && AI_SwitchMonIfSuitable(battlerId))
return TRUE;
}
}
// Consider switching if your mon with truant is bodied by Protect spam.
// Or is using a double turn semi invulnerable move(such as Fly) and is faster.
if (GetBattlerAbility(battlerId) == ABILITY_TRUANT
&& IsTruantMonVulnerable(battlerId, gBattlerTarget)
&& gDisableStructs[battlerId].truantCounter
&& gBattleMons[battlerId].hp >= gBattleMons[battlerId].maxHP / 2
&& AI_SwitchMonIfSuitable(battlerId))
{
return TRUE;
}
}
return FALSE;
}
static u8 ChooseMoveOrAction_Singles(void) static u8 ChooseMoveOrAction_Singles(void)
{ {
u8 currentMoveArray[MAX_MON_MOVES]; u8 currentMoveArray[MAX_MON_MOVES];
@ -436,46 +508,9 @@ static u8 ChooseMoveOrAction_Singles(void)
gActiveBattler = sBattler_AI; gActiveBattler = sBattler_AI;
// If can switch. // Switch mon if there are no good moves to use.
if (CountUsablePartyMons(sBattler_AI) > 0 if (AI_ShouldSwitchIfBadMoves(sBattler_AI, FALSE))
&& !IsAbilityPreventingEscape(sBattler_AI) return AI_CHOICE_SWITCH;
&& !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
&& !(gStatuses3[gActiveBattler] & STATUS3_ROOTED)
&& !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE))
&& AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS))
{
// Consider switching if all moves are worthless to use.
if (GetTotalBaseStat(gBattleMons[sBattler_AI].species) >= 310 // Mon is not weak.
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2)
{
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (AI_THINKING_STRUCT->score[i] > cap)
break;
}
if (i == MAX_MON_MOVES && GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
{
AI_THINKING_STRUCT->switchMon = TRUE;
return AI_CHOICE_SWITCH;
}
}
// Consider switching if your mon with truant is bodied by Protect spam.
// Or is using a double turn semi invulnerable move(such as Fly) and is faster.
if (GetBattlerAbility(sBattler_AI) == ABILITY_TRUANT
&& IsTruantMonVulnerable(sBattler_AI, gBattlerTarget)
&& gDisableStructs[sBattler_AI].truantCounter
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2)
{
if (GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
{
AI_THINKING_STRUCT->switchMon = TRUE;
return AI_CHOICE_SWITCH;
}
}
}
numOfBestMoves = 1; numOfBestMoves = 1;
currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; currentMoveArray[0] = AI_THINKING_STRUCT->score[0];
@ -590,7 +625,6 @@ static u8 ChooseMoveOrAction_Doubles(void)
if (i == BATTLE_PARTNER(sBattler_AI) && bestMovePointsForTarget[i] < 100) if (i == BATTLE_PARTNER(sBattler_AI) && bestMovePointsForTarget[i] < 100)
{ {
bestMovePointsForTarget[i] = -1; bestMovePointsForTarget[i] = -1;
mostViableMovesScores[0] = mostViableMovesScores[0]; // Needed to match.
} }
} }
@ -600,6 +634,10 @@ static u8 ChooseMoveOrAction_Doubles(void)
} }
} }
// Switch mon if all of the moves are bad to use against any of the target.
if (AI_ShouldSwitchIfBadMoves(sBattler_AI, TRUE))
return AI_CHOICE_SWITCH;
mostMovePoints = bestMovePointsForTarget[0]; mostMovePoints = bestMovePointsForTarget[0];
mostViableTargetsArray[0] = 0; mostViableTargetsArray[0] = 0;
mostViableTargetsNo = 1; mostViableTargetsNo = 1;
@ -1647,18 +1685,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
break; break;
case EFFECT_FAKE_OUT: case EFFECT_FAKE_OUT:
if (!gDisableStructs[battlerAtk].isFirstTurn) if (!gDisableStructs[battlerAtk].isFirstTurn)
{
score -= 10; score -= 10;
}
else if (move == MOVE_FAKE_OUT) // filter out first impression
{
if ((AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS)
&& (CountUsablePartyMons(battlerDef) > 0 || !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)))
{
if (CountUsablePartyMons(battlerAtk) == 0)
score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards.
}
}
break; break;
case EFFECT_STOCKPILE: case EFFECT_STOCKPILE:
if (gDisableStructs[battlerAtk].stockpileCounter >= 3) if (gDisableStructs[battlerAtk].stockpileCounter >= 3)
@ -3094,7 +3121,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|| IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_POISON)
|| IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_ROCK)) || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_ROCK))
score -= 10; // partner will be hit by earthquake and is weak to it score -= 10; // partner will be hit by earthquake and is weak to it
else else if (IsBattlerAlive(battlerAtkPartner))
score -= 3; score -= 3;
break; break;
} }
@ -4137,9 +4164,13 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score);
break; break;
case EFFECT_FAKE_OUT: case EFFECT_FAKE_OUT:
if (move == MOVE_FAKE_OUT // filter out first impression if (move == MOVE_FAKE_OUT) // filter out first impression
&& ShouldFakeOut(battlerAtk, battlerDef, move)) {
score += 8; if (ShouldFakeOut(battlerAtk, battlerDef, move))
score += 4;
else
score -= 10;
}
break; break;
case EFFECT_STOCKPILE: case EFFECT_STOCKPILE:
if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY)

View File

@ -60,10 +60,10 @@ void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId)
static bool8 ShouldSwitchIfAllBadMoves(void) static bool8 ShouldSwitchIfAllBadMoves(void)
{ {
if (gBattleResources->ai->switchMon) if (AI_DATA->shouldSwitchMon & gBitTable[gActiveBattler])
{ {
gBattleResources->ai->switchMon = 0; AI_DATA->shouldSwitchMon &= ~(gBitTable[gActiveBattler]);
*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = PARTY_SIZE; gBattleStruct->AI_monToSwitchIntoId[gActiveBattler] = AI_DATA->monToSwitchId[gActiveBattler];
BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SWITCH, 0); BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SWITCH, 0);
return TRUE; return TRUE;
} }
@ -142,11 +142,12 @@ static bool8 ShouldSwitchIfWonderGuard(void)
static bool8 FindMonThatAbsorbsOpponentsMove(void) static bool8 FindMonThatAbsorbsOpponentsMove(void)
{ {
u8 battlerIn1, battlerIn2; u8 battlerIn1, battlerIn2;
u16 absorbingTypeAbility; u8 numAbsorbingAbilities = 0;
u16 absorbingTypeAbilities[3]; // Array size is maximum number of absorbing abilities for a single type
s32 firstId; s32 firstId;
s32 lastId; // + 1 s32 lastId; // + 1
struct Pokemon *party; struct Pokemon *party;
s32 i; s32 i, j;
if (HasSuperEffectiveMoveAgainstOpponents(TRUE) && Random() % 3 != 0) if (HasSuperEffectiveMoveAgainstOpponents(TRUE) && Random() % 3 != 0)
return FALSE; return FALSE;
@ -171,17 +172,42 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void)
battlerIn2 = gActiveBattler; battlerIn2 = gActiveBattler;
} }
// Create an array of possible absorb abilities so the AI considers all of them
if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_FIRE) if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_FIRE)
absorbingTypeAbility = ABILITY_FLASH_FIRE; {
absorbingTypeAbilities[0] = ABILITY_FLASH_FIRE;
numAbsorbingAbilities = 1;
}
else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_WATER) else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_WATER)
absorbingTypeAbility = ABILITY_WATER_ABSORB; {
absorbingTypeAbilities[0] = ABILITY_WATER_ABSORB;
absorbingTypeAbilities[1] = ABILITY_STORM_DRAIN;
absorbingTypeAbilities[2] = ABILITY_DRY_SKIN;
numAbsorbingAbilities = 3;
}
else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_ELECTRIC) else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_ELECTRIC)
absorbingTypeAbility = ABILITY_VOLT_ABSORB; {
absorbingTypeAbilities[0] = ABILITY_VOLT_ABSORB;
absorbingTypeAbilities[1] = ABILITY_MOTOR_DRIVE;
absorbingTypeAbilities[2] = ABILITY_LIGHTNING_ROD;
numAbsorbingAbilities = 3;
}
else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_GRASS)
{
absorbingTypeAbilities[0] = ABILITY_SAP_SIPPER;
numAbsorbingAbilities = 1;
}
else else
{
return FALSE; return FALSE;
}
if (AI_DATA->abilities[gActiveBattler] == absorbingTypeAbility) // Check current mon for all absorbing abilities
return FALSE; for (i = 0; i < numAbsorbingAbilities; i++)
{
if (AI_DATA->abilities[gActiveBattler] == absorbingTypeAbilities[i])
return FALSE;
}
GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); GetAIPartyIndexes(gActiveBattler, &firstId, &lastId);
@ -208,15 +234,18 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void)
continue; continue;
monAbility = GetMonAbility(&party[i]); monAbility = GetMonAbility(&party[i]);
if (absorbingTypeAbility == monAbility && Random() & 1)
for (j = 0; j < numAbsorbingAbilities; j++)
{ {
// we found a mon. if (absorbingTypeAbilities[j] == monAbility && Random() & 1)
*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; {
BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SWITCH, 0); // we found a mon.
return TRUE; *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i;
BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0);
return TRUE;
}
} }
} }
return FALSE; return FALSE;
} }

View File

@ -2964,24 +2964,23 @@ bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility)
u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move) u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move)
{ {
if (defAbility == ABILITY_INNER_FOCUS if (((AI_DATA->abilities[battlerAtk] != ABILITY_MOLD_BREAKER && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS))
|| AI_GetHoldEffect(battlerDef) == HOLD_EFFECT_COVERT_CLOAK
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent goes first || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)) // Opponent goes first
{ {
return 0; // don't try to flinch return 0;
} }
else if ((gBattleMons[battlerDef].status1 & STATUS1_SLEEP) && !HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK) && !HasMoveEffect(battlerDef, EFFECT_SNORE)) else if ((atkAbility == ABILITY_SERENE_GRACE
{
return 0; // don't try to flinch sleeping pokemon
}
else if (atkAbility == ABILITY_SERENE_GRACE
|| gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS || gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|| gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|| ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)))
{ {
return 2; // good idea to flinch return 2; // good idea to flinch
} }
return 1; // decent idea to flinch
return 0; // don't try to flinch
} }
bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move)
@ -3000,15 +2999,16 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move)
bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move) bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move)
{ {
if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0) if (!gDisableStructs[battlerAtk].isFirstTurn
return FALSE; // don't lock attacker into fake out if can't switch out || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS
|| AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND
|| AI_GetHoldEffect(battlerDef) == HOLD_EFFECT_COVERT_CLOAK
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|| (AI_DATA->abilities[battlerAtk] != ABILITY_MOLD_BREAKER
&& (AI_DATA->abilities[battlerDef] == ABILITY_SHIELD_DUST || AI_DATA->abilities[battlerDef] == ABILITY_INNER_FOCUS)))
return FALSE;
if (gDisableStructs[battlerAtk].isFirstTurn return TRUE;
&& ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move)
&& !DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
return TRUE;
return FALSE;
} }
static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x)
@ -3676,7 +3676,8 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{ {
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PSN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS)
return; return;
if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20) if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20)
@ -3699,7 +3700,8 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{ {
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_BRN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS)
return; return;
if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove))
@ -3718,7 +3720,8 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{ {
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PAR || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS)
return; return;
if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove))
@ -3739,7 +3742,8 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{ {
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS)
return; return;
if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove))
@ -3757,7 +3761,8 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{ {
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_CONFUSION || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS)
return; return;
if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,160 +22,112 @@
#include "window.h" #include "window.h"
#include "constants/battle_anim.h" #include "constants/battle_anim.h"
#include "constants/songs.h" #include "constants/songs.h"
#include "constants/trainers.h"
#include "constants/rgb.h" #include "constants/rgb.h"
static void SafariHandleGetMonData(void); static void SafariHandleDrawTrainerPic(u32 battler);
static void SafariHandleGetRawMonData(void); static void SafariHandleSuccessBallThrowAnim(u32 battler);
static void SafariHandleSetMonData(void); static void SafariHandleBallThrowAnim(u32 battler);
static void SafariHandleSetRawMonData(void); static void SafariHandlePrintString(u32 battler);
static void SafariHandleLoadMonSprite(void); static void SafariHandlePrintSelectionString(u32 battler);
static void SafariHandleSwitchInAnim(void); static void SafariHandleChooseAction(u32 battler);
static void SafariHandleReturnMonToBall(void); static void SafariHandleChooseItem(u32 battler);
static void SafariHandleDrawTrainerPic(void); static void SafariHandleStatusIconUpdate(u32 battler);
static void SafariHandleTrainerSlide(void); static void SafariHandleFaintingCry(u32 battler);
static void SafariHandleTrainerSlideBack(void); static void SafariHandleIntroTrainerBallThrow(u32 battler);
static void SafariHandleFaintAnimation(void); static void SafariHandleBattleAnimation(u32 battler);
static void SafariHandlePaletteFade(void); static void SafariHandleEndLinkBattle(u32 battler);
static void SafariHandleSuccessBallThrowAnim(void);
static void SafariHandleBallThrowAnim(void);
static void SafariHandlePause(void);
static void SafariHandleMoveAnimation(void);
static void SafariHandlePrintString(void);
static void SafariHandlePrintSelectionString(void);
static void SafariHandleChooseAction(void);
static void SafariHandleYesNoBox(void);
static void SafariHandleChooseMove(void);
static void SafariHandleChooseItem(void);
static void SafariHandleChoosePokemon(void);
static void SafariHandleCmd23(void);
static void SafariHandleHealthBarUpdate(void);
static void SafariHandleExpUpdate(void);
static void SafariHandleStatusIconUpdate(void);
static void SafariHandleStatusAnimation(void);
static void SafariHandleStatusXor(void);
static void SafariHandleDataTransfer(void);
static void SafariHandleDMA3Transfer(void);
static void SafariHandlePlayBGM(void);
static void SafariHandleCmd32(void);
static void SafariHandleTwoReturnValues(void);
static void SafariHandleChosenMonReturnValue(void);
static void SafariHandleOneReturnValue(void);
static void SafariHandleOneReturnValue_Duplicate(void);
static void SafariHandleClearUnkVar(void);
static void SafariHandleSetUnkVar(void);
static void SafariHandleClearUnkFlag(void);
static void SafariHandleToggleUnkFlag(void);
static void SafariHandleHitAnimation(void);
static void SafariHandleCantSwitch(void);
static void SafariHandlePlaySE(void);
static void SafariHandlePlayFanfareOrBGM(void);
static void SafariHandleFaintingCry(void);
static void SafariHandleIntroSlide(void);
static void SafariHandleIntroTrainerBallThrow(void);
static void SafariHandleDrawPartyStatusSummary(void);
static void SafariHandleHidePartyStatusSummary(void);
static void SafariHandleEndBounceEffect(void);
static void SafariHandleSpriteInvisibility(void);
static void SafariHandleBattleAnimation(void);
static void SafariHandleLinkStandbyMsg(void);
static void SafariHandleResetActionMoveSelection(void);
static void SafariHandleEndLinkBattle(void);
static void SafariHandleBattleDebug(void);
static void SafariCmdEnd(void);
static void SafariBufferRunCommand(void); static void SafariBufferRunCommand(u32 battler);
static void SafariBufferExecCompleted(void); static void SafariBufferExecCompleted(u32 battler);
static void CompleteWhenChosePokeblock(void); static void CompleteWhenChosePokeblock(u32 battler);
static void (*const sSafariBufferCommands[CONTROLLER_CMDS_COUNT])(void) = static void (*const sSafariBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) =
{ {
[CONTROLLER_GETMONDATA] = SafariHandleGetMonData, [CONTROLLER_GETMONDATA] = BtlController_Empty,
[CONTROLLER_GETRAWMONDATA] = SafariHandleGetRawMonData, [CONTROLLER_GETRAWMONDATA] = BtlController_Empty,
[CONTROLLER_SETMONDATA] = SafariHandleSetMonData, [CONTROLLER_SETMONDATA] = BtlController_Empty,
[CONTROLLER_SETRAWMONDATA] = SafariHandleSetRawMonData, [CONTROLLER_SETRAWMONDATA] = BtlController_Empty,
[CONTROLLER_LOADMONSPRITE] = SafariHandleLoadMonSprite, [CONTROLLER_LOADMONSPRITE] = BtlController_Empty,
[CONTROLLER_SWITCHINANIM] = SafariHandleSwitchInAnim, [CONTROLLER_SWITCHINANIM] = BtlController_Empty,
[CONTROLLER_RETURNMONTOBALL] = SafariHandleReturnMonToBall, [CONTROLLER_RETURNMONTOBALL] = BtlController_Empty,
[CONTROLLER_DRAWTRAINERPIC] = SafariHandleDrawTrainerPic, [CONTROLLER_DRAWTRAINERPIC] = SafariHandleDrawTrainerPic,
[CONTROLLER_TRAINERSLIDE] = SafariHandleTrainerSlide, [CONTROLLER_TRAINERSLIDE] = BtlController_Empty,
[CONTROLLER_TRAINERSLIDEBACK] = SafariHandleTrainerSlideBack, [CONTROLLER_TRAINERSLIDEBACK] = BtlController_Empty,
[CONTROLLER_FAINTANIMATION] = SafariHandleFaintAnimation, [CONTROLLER_FAINTANIMATION] = BtlController_Empty,
[CONTROLLER_PALETTEFADE] = SafariHandlePaletteFade, [CONTROLLER_PALETTEFADE] = BtlController_Empty,
[CONTROLLER_SUCCESSBALLTHROWANIM] = SafariHandleSuccessBallThrowAnim, [CONTROLLER_SUCCESSBALLTHROWANIM] = SafariHandleSuccessBallThrowAnim,
[CONTROLLER_BALLTHROWANIM] = SafariHandleBallThrowAnim, [CONTROLLER_BALLTHROWANIM] = SafariHandleBallThrowAnim,
[CONTROLLER_PAUSE] = SafariHandlePause, [CONTROLLER_PAUSE] = BtlController_Empty,
[CONTROLLER_MOVEANIMATION] = SafariHandleMoveAnimation, [CONTROLLER_MOVEANIMATION] = BtlController_Empty,
[CONTROLLER_PRINTSTRING] = SafariHandlePrintString, [CONTROLLER_PRINTSTRING] = SafariHandlePrintString,
[CONTROLLER_PRINTSTRINGPLAYERONLY] = SafariHandlePrintSelectionString, [CONTROLLER_PRINTSTRINGPLAYERONLY] = SafariHandlePrintSelectionString,
[CONTROLLER_CHOOSEACTION] = SafariHandleChooseAction, [CONTROLLER_CHOOSEACTION] = SafariHandleChooseAction,
[CONTROLLER_YESNOBOX] = SafariHandleYesNoBox, [CONTROLLER_YESNOBOX] = BtlController_Empty,
[CONTROLLER_CHOOSEMOVE] = SafariHandleChooseMove, [CONTROLLER_CHOOSEMOVE] = BtlController_Empty,
[CONTROLLER_OPENBAG] = SafariHandleChooseItem, [CONTROLLER_OPENBAG] = SafariHandleChooseItem,
[CONTROLLER_CHOOSEPOKEMON] = SafariHandleChoosePokemon, [CONTROLLER_CHOOSEPOKEMON] = BtlController_Empty,
[CONTROLLER_23] = SafariHandleCmd23, [CONTROLLER_23] = BtlController_Empty,
[CONTROLLER_HEALTHBARUPDATE] = SafariHandleHealthBarUpdate, [CONTROLLER_HEALTHBARUPDATE] = BtlController_Empty,
[CONTROLLER_EXPUPDATE] = SafariHandleExpUpdate, [CONTROLLER_EXPUPDATE] = BtlController_Empty,
[CONTROLLER_STATUSICONUPDATE] = SafariHandleStatusIconUpdate, [CONTROLLER_STATUSICONUPDATE] = SafariHandleStatusIconUpdate,
[CONTROLLER_STATUSANIMATION] = SafariHandleStatusAnimation, [CONTROLLER_STATUSANIMATION] = BtlController_Empty,
[CONTROLLER_STATUSXOR] = SafariHandleStatusXor, [CONTROLLER_STATUSXOR] = BtlController_Empty,
[CONTROLLER_DATATRANSFER] = SafariHandleDataTransfer, [CONTROLLER_DATATRANSFER] = BtlController_Empty,
[CONTROLLER_DMA3TRANSFER] = SafariHandleDMA3Transfer, [CONTROLLER_DMA3TRANSFER] = BtlController_Empty,
[CONTROLLER_PLAYBGM] = SafariHandlePlayBGM, [CONTROLLER_PLAYBGM] = BtlController_Empty,
[CONTROLLER_32] = SafariHandleCmd32, [CONTROLLER_32] = BtlController_Empty,
[CONTROLLER_TWORETURNVALUES] = SafariHandleTwoReturnValues, [CONTROLLER_TWORETURNVALUES] = BtlController_Empty,
[CONTROLLER_CHOSENMONRETURNVALUE] = SafariHandleChosenMonReturnValue, [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty,
[CONTROLLER_ONERETURNVALUE] = SafariHandleOneReturnValue, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty,
[CONTROLLER_ONERETURNVALUE_DUPLICATE] = SafariHandleOneReturnValue_Duplicate, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty,
[CONTROLLER_CLEARUNKVAR] = SafariHandleClearUnkVar, [CONTROLLER_CLEARUNKVAR] = BtlController_Empty,
[CONTROLLER_SETUNKVAR] = SafariHandleSetUnkVar, [CONTROLLER_SETUNKVAR] = BtlController_Empty,
[CONTROLLER_CLEARUNKFLAG] = SafariHandleClearUnkFlag, [CONTROLLER_CLEARUNKFLAG] = BtlController_Empty,
[CONTROLLER_TOGGLEUNKFLAG] = SafariHandleToggleUnkFlag, [CONTROLLER_TOGGLEUNKFLAG] = BtlController_Empty,
[CONTROLLER_HITANIMATION] = SafariHandleHitAnimation, [CONTROLLER_HITANIMATION] = BtlController_Empty,
[CONTROLLER_CANTSWITCH] = SafariHandleCantSwitch, [CONTROLLER_CANTSWITCH] = BtlController_Empty,
[CONTROLLER_PLAYSE] = SafariHandlePlaySE, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE,
[CONTROLLER_PLAYFANFAREORBGM] = SafariHandlePlayFanfareOrBGM, [CONTROLLER_PLAYFANFAREORBGM] = BtlController_HandlePlayFanfareOrBGM,
[CONTROLLER_FAINTINGCRY] = SafariHandleFaintingCry, [CONTROLLER_FAINTINGCRY] = SafariHandleFaintingCry,
[CONTROLLER_INTROSLIDE] = SafariHandleIntroSlide, [CONTROLLER_INTROSLIDE] = BtlController_HandleIntroSlide,
[CONTROLLER_INTROTRAINERBALLTHROW] = SafariHandleIntroTrainerBallThrow, [CONTROLLER_INTROTRAINERBALLTHROW] = SafariHandleIntroTrainerBallThrow,
[CONTROLLER_DRAWPARTYSTATUSSUMMARY] = SafariHandleDrawPartyStatusSummary, [CONTROLLER_DRAWPARTYSTATUSSUMMARY] = BtlController_Empty,
[CONTROLLER_HIDEPARTYSTATUSSUMMARY] = SafariHandleHidePartyStatusSummary, [CONTROLLER_HIDEPARTYSTATUSSUMMARY] = BtlController_Empty,
[CONTROLLER_ENDBOUNCE] = SafariHandleEndBounceEffect, [CONTROLLER_ENDBOUNCE] = BtlController_Empty,
[CONTROLLER_SPRITEINVISIBILITY] = SafariHandleSpriteInvisibility, [CONTROLLER_SPRITEINVISIBILITY] = BtlController_Empty,
[CONTROLLER_BATTLEANIMATION] = SafariHandleBattleAnimation, [CONTROLLER_BATTLEANIMATION] = SafariHandleBattleAnimation,
[CONTROLLER_LINKSTANDBYMSG] = SafariHandleLinkStandbyMsg, [CONTROLLER_LINKSTANDBYMSG] = BtlController_Empty,
[CONTROLLER_RESETACTIONMOVESELECTION] = SafariHandleResetActionMoveSelection, [CONTROLLER_RESETACTIONMOVESELECTION] = BtlController_Empty,
[CONTROLLER_ENDLINKBATTLE] = SafariHandleEndLinkBattle, [CONTROLLER_ENDLINKBATTLE] = SafariHandleEndLinkBattle,
[CONTROLLER_DEBUGMENU] = SafariHandleBattleDebug, [CONTROLLER_DEBUGMENU] = BtlController_Empty,
[CONTROLLER_TERMINATOR_NOP] = SafariCmdEnd [CONTROLLER_TERMINATOR_NOP] = BtlController_TerminatorNop
}; };
static void SpriteCB_Null4(void) void SetControllerToSafari(u32 battler)
{ {
gBattlerControllerEndFuncs[battler] = SafariBufferExecCompleted;
gBattlerControllerFuncs[battler] = SafariBufferRunCommand;
} }
void SetControllerToSafari(void) static void SafariBufferRunCommand(u32 battler)
{ {
gBattlerControllerFuncs[gActiveBattler] = SafariBufferRunCommand; if (gBattleControllerExecFlags & gBitTable[battler])
}
static void SafariBufferRunCommand(void)
{
if (gBattleControllerExecFlags & gBitTable[gActiveBattler])
{ {
if (gBattleResources->bufferA[gActiveBattler][0] < ARRAY_COUNT(sSafariBufferCommands)) if (gBattleResources->bufferA[battler][0] < ARRAY_COUNT(sSafariBufferCommands))
sSafariBufferCommands[gBattleResources->bufferA[gActiveBattler][0]](); sSafariBufferCommands[gBattleResources->bufferA[battler][0]](battler);
else else
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
} }
} }
static void HandleInputChooseAction(void) static void HandleInputChooseAction(u32 battler)
{ {
if (JOY_NEW(A_BUTTON)) if (JOY_NEW(A_BUTTON))
{ {
PlaySE(SE_SELECT); PlaySE(SE_SELECT);
switch (gActionSelectionCursor[gActiveBattler]) switch (gActionSelectionCursor[battler])
{ {
case 0: case 0:
BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SAFARI_BALL, 0); BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SAFARI_BALL, 0);
@ -190,69 +142,57 @@ static void HandleInputChooseAction(void)
BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SAFARI_RUN, 0); BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_SAFARI_RUN, 0);
break; break;
} }
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
} }
else if (JOY_NEW(DPAD_LEFT)) else if (JOY_NEW(DPAD_LEFT))
{ {
if (gActionSelectionCursor[gActiveBattler] & 1) if (gActionSelectionCursor[battler] & 1)
{ {
PlaySE(SE_SELECT); PlaySE(SE_SELECT);
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); ActionSelectionDestroyCursorAt(gActionSelectionCursor[battler]);
gActionSelectionCursor[gActiveBattler] ^= 1; gActionSelectionCursor[battler] ^= 1;
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
} }
} }
else if (JOY_NEW(DPAD_RIGHT)) else if (JOY_NEW(DPAD_RIGHT))
{ {
if (!(gActionSelectionCursor[gActiveBattler] & 1)) if (!(gActionSelectionCursor[battler] & 1))
{ {
PlaySE(SE_SELECT); PlaySE(SE_SELECT);
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); ActionSelectionDestroyCursorAt(gActionSelectionCursor[battler]);
gActionSelectionCursor[gActiveBattler] ^= 1; gActionSelectionCursor[battler] ^= 1;
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
} }
} }
else if (JOY_NEW(DPAD_UP)) else if (JOY_NEW(DPAD_UP))
{ {
if (gActionSelectionCursor[gActiveBattler] & 2) if (gActionSelectionCursor[battler] & 2)
{ {
PlaySE(SE_SELECT); PlaySE(SE_SELECT);
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); ActionSelectionDestroyCursorAt(gActionSelectionCursor[battler]);
gActionSelectionCursor[gActiveBattler] ^= 2; gActionSelectionCursor[battler] ^= 2;
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
} }
} }
else if (JOY_NEW(DPAD_DOWN)) else if (JOY_NEW(DPAD_DOWN))
{ {
if (!(gActionSelectionCursor[gActiveBattler] & 2)) if (!(gActionSelectionCursor[battler] & 2))
{ {
PlaySE(SE_SELECT); PlaySE(SE_SELECT);
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]); ActionSelectionDestroyCursorAt(gActionSelectionCursor[battler]);
gActionSelectionCursor[gActiveBattler] ^= 2; gActionSelectionCursor[battler] ^= 2;
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
} }
} }
} }
static void CompleteOnBattlerSpriteCallbackDummy(void) static void Controller_WaitForHealthbox(u32 battler)
{ {
if (gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
} }
static void CompleteOnInactiveTextPrinter(void) static void SafariSetBattleEndCallbacks(u32 battler)
{
if (!IsTextPrinterActive(B_WIN_MSG))
SafariBufferExecCompleted();
}
static void CompleteOnHealthboxSpriteCallbackDummy(void)
{
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
SafariBufferExecCompleted();
}
static void SafariSetBattleEndCallbacks(void)
{ {
if (!gPaletteFade.active) if (!gPaletteFade.active)
{ {
@ -262,437 +202,141 @@ static void SafariSetBattleEndCallbacks(void)
} }
} }
static void CompleteOnSpecialAnimDone(void) static void SafariOpenPokeblockCase(u32 battler)
{
if (!gDoingBattleAnim || !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
SafariBufferExecCompleted();
}
static void SafariOpenPokeblockCase(void)
{ {
if (!gPaletteFade.active) if (!gPaletteFade.active)
{ {
gBattlerControllerFuncs[gActiveBattler] = CompleteWhenChosePokeblock; gBattlerControllerFuncs[battler] = CompleteWhenChosePokeblock;
FreeAllWindowBuffers(); FreeAllWindowBuffers();
OpenPokeblockCaseInBattle(); OpenPokeblockCaseInBattle();
} }
} }
static void CompleteWhenChosePokeblock(void) static void CompleteWhenChosePokeblock(u32 battler)
{ {
if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active) if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
{ {
BtlController_EmitOneReturnValue(BUFFER_B, gSpecialVar_ItemId); BtlController_EmitOneReturnValue(BUFFER_B, gSpecialVar_ItemId);
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
} }
} }
static void CompleteOnFinishedBattleAnimation(void) static void SafariBufferExecCompleted(u32 battler)
{ {
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animFromTableActive) gBattlerControllerFuncs[battler] = SafariBufferRunCommand;
SafariBufferExecCompleted();
}
static void SafariBufferExecCompleted(void)
{
gBattlerControllerFuncs[gActiveBattler] = SafariBufferRunCommand;
if (gBattleTypeFlags & BATTLE_TYPE_LINK) if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{ {
u8 playerId = GetMultiplayerId(); u8 playerId = GetMultiplayerId();
PrepareBufferDataTransferLink(2, 4, &playerId); PrepareBufferDataTransferLink(2, 4, &playerId);
gBattleResources->bufferA[gActiveBattler][0] = CONTROLLER_TERMINATOR_NOP; gBattleResources->bufferA[battler][0] = CONTROLLER_TERMINATOR_NOP;
} }
else else
{ {
gBattleControllerExecFlags &= ~gBitTable[gActiveBattler]; gBattleControllerExecFlags &= ~gBitTable[battler];
} }
} }
static void CompleteOnFinishedStatusAnimation(void) static void SafariHandleDrawTrainerPic(u32 battler)
{ {
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].statusAnimActive) u32 trainerPicId = gSaveBlock2Ptr->playerGender + TRAINER_BACK_PIC_BRENDAN;
SafariBufferExecCompleted();
BtlController_HandleDrawTrainerPic(battler, trainerPicId, FALSE,
80, 80 + 4 * (8 - gTrainerBackPicCoords[trainerPicId].size),
30);
} }
static void SafariHandleGetMonData(void) static void SafariHandleSuccessBallThrowAnim(u32 battler)
{ {
SafariBufferExecCompleted(); BtlController_HandleSuccessBallThrowAnim(battler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW_WITH_TRAINER, FALSE);
} }
static void SafariHandleGetRawMonData(void) static void SafariHandleBallThrowAnim(u32 battler)
{ {
SafariBufferExecCompleted(); BtlController_HandleBallThrowAnim(battler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW_WITH_TRAINER, FALSE);
} }
static void SafariHandleSetMonData(void) static void SafariHandlePrintString(u32 battler)
{ {
SafariBufferExecCompleted(); BtlController_HandlePrintString(battler, FALSE, FALSE);
} }
static void SafariHandleSetRawMonData(void) static void SafariHandlePrintSelectionString(u32 battler)
{ {
SafariBufferExecCompleted(); if (GetBattlerSide(battler) == B_SIDE_PLAYER)
} SafariHandlePrintString(battler);
static void SafariHandleLoadMonSprite(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleSwitchInAnim(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleReturnMonToBall(void)
{
SafariBufferExecCompleted();
}
#define sSpeedX data[0]
static void SafariHandleDrawTrainerPic(void)
{
DecompressTrainerBackPic(gSaveBlock2Ptr->playerGender, gActiveBattler);
SetMultiuseSpriteTemplateToTrainerBack(gSaveBlock2Ptr->playerGender, GetBattlerPosition(gActiveBattler));
gBattlerSpriteIds[gActiveBattler] = CreateSprite(
&gMultiuseSpriteTemplate,
80,
(8 - gTrainerBackPicCoords[gSaveBlock2Ptr->playerGender].size) * 4 + 80,
30);
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
gBattlerControllerFuncs[gActiveBattler] = CompleteOnBattlerSpriteCallbackDummy;
}
#undef sSpeedX
static void SafariHandleTrainerSlide(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleTrainerSlideBack(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleFaintAnimation(void)
{
SafariBufferExecCompleted();
}
static void SafariHandlePaletteFade(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleSuccessBallThrowAnim(void)
{
gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
gDoingBattleAnim = TRUE;
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW_WITH_TRAINER);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
}
static void SafariHandleBallThrowAnim(void)
{
u8 ballThrowCaseId = gBattleResources->bufferA[gActiveBattler][1];
gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId;
gDoingBattleAnim = TRUE;
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW_WITH_TRAINER);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
}
static void SafariHandlePause(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleMoveAnimation(void)
{
SafariBufferExecCompleted();
}
static void SafariHandlePrintString(void)
{
u16 *stringId;
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
stringId = (u16 *)(&gBattleResources->bufferA[gActiveBattler][2]);
BufferStringBattle(*stringId);
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter;
}
static void SafariHandlePrintSelectionString(void)
{
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
SafariHandlePrintString();
else else
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
} }
static void HandleChooseActionAfterDma3(void) static void HandleChooseActionAfterDma3(u32 battler)
{ {
if (!IsDma3ManagerBusyWithBgCopy()) if (!IsDma3ManagerBusyWithBgCopy())
{ {
gBattle_BG0_X = 0; gBattle_BG0_X = 0;
gBattle_BG0_Y = DISPLAY_HEIGHT; gBattle_BG0_Y = DISPLAY_HEIGHT;
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseAction; gBattlerControllerFuncs[battler] = HandleInputChooseAction;
} }
} }
static void SafariHandleChooseAction(void) static void SafariHandleChooseAction(u32 battler)
{ {
s32 i; s32 i;
gBattlerControllerFuncs[gActiveBattler] = HandleChooseActionAfterDma3; gBattlerControllerFuncs[battler] = HandleChooseActionAfterDma3;
BattlePutTextOnWindow(gText_SafariZoneMenu, B_WIN_ACTION_MENU); BattlePutTextOnWindow(gText_SafariZoneMenu, B_WIN_ACTION_MENU);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
ActionSelectionDestroyCursorAt(i); ActionSelectionDestroyCursorAt(i);
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2); BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2);
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT);
} }
static void SafariHandleYesNoBox(void) static void SafariHandleChooseItem(u32 battler)
{
SafariBufferExecCompleted();
}
static void SafariHandleChooseMove(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleChooseItem(void)
{ {
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gBattlerControllerFuncs[gActiveBattler] = SafariOpenPokeblockCase; gBattlerControllerFuncs[battler] = SafariOpenPokeblockCase;
gBattlerInMenuId = gActiveBattler; gBattlerInMenuId = battler;
} }
static void SafariHandleChoosePokemon(void) static void SafariHandleStatusIconUpdate(u32 battler)
{ {
SafariBufferExecCompleted(); UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_SAFARI_BALLS_TEXT);
SafariBufferExecCompleted(battler);
} }
static void SafariHandleCmd23(void) // All of the other controllers(except Wally's) use CRY_MODE_FAINT.
// Player is not a pokemon, so it can't really faint in the Safari anyway.
static void SafariHandleFaintingCry(u32 battler)
{ {
SafariBufferExecCompleted(); u16 species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES);
}
static void SafariHandleHealthBarUpdate(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleExpUpdate(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleStatusIconUpdate(void)
{
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], HEALTHBOX_SAFARI_BALLS_TEXT);
SafariBufferExecCompleted();
}
static void SafariHandleStatusAnimation(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleStatusXor(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleDataTransfer(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleDMA3Transfer(void)
{
SafariBufferExecCompleted();
}
static void SafariHandlePlayBGM(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleCmd32(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleTwoReturnValues(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleChosenMonReturnValue(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleOneReturnValue(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleOneReturnValue_Duplicate(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleClearUnkVar(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleSetUnkVar(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleClearUnkFlag(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleToggleUnkFlag(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleHitAnimation(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleCantSwitch(void)
{
SafariBufferExecCompleted();
}
static void SafariHandlePlaySE(void)
{
s8 pan;
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
pan = SOUND_PAN_ATTACKER;
else
pan = SOUND_PAN_TARGET;
PlaySE12WithPanning(gBattleResources->bufferA[gActiveBattler][1] | (gBattleResources->bufferA[gActiveBattler][2] << 8), pan);
SafariBufferExecCompleted();
}
static void SafariHandlePlayFanfareOrBGM(void)
{
if (gBattleResources->bufferA[gActiveBattler][3])
{
BattleStopLowHpSound();
PlayBGM(gBattleResources->bufferA[gActiveBattler][1] | (gBattleResources->bufferA[gActiveBattler][2] << 8));
}
else
{
PlayFanfare(gBattleResources->bufferA[gActiveBattler][1] | (gBattleResources->bufferA[gActiveBattler][2] << 8));
}
SafariBufferExecCompleted();
}
static void SafariHandleFaintingCry(void)
{
u16 species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES);
PlayCry_Normal(species, 25); PlayCry_Normal(species, 25);
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
SafariBufferExecCompleted(battler);
} }
static void SafariHandleIntroSlide(void) static void SafariHandleIntroTrainerBallThrow(u32 battler)
{ {
HandleIntroSlide(gBattleResources->bufferA[gActiveBattler][1]); UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_SAFARI_ALL_TEXT);
gIntroSlideFlags |= 1; StartHealthboxSlideIn(battler);
SafariBufferExecCompleted(); SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
gBattlerControllerFuncs[battler] = Controller_WaitForHealthbox;
} }
static void SafariHandleIntroTrainerBallThrow(void) static void SafariHandleBattleAnimation(u32 battler)
{ {
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], HEALTHBOX_SAFARI_ALL_TEXT); BtlController_HandleBattleAnimation(battler, TRUE, FALSE);
StartHealthboxSlideIn(gActiveBattler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler]);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnHealthboxSpriteCallbackDummy;
} }
static void SafariHandleDrawPartyStatusSummary(void) static void SafariHandleEndLinkBattle(u32 battler)
{ {
SafariBufferExecCompleted(); gBattleOutcome = gBattleResources->bufferA[battler][1];
}
static void SafariHandleHidePartyStatusSummary(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleEndBounceEffect(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleSpriteInvisibility(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleBattleAnimation(void)
{
u8 animationId = gBattleResources->bufferA[gActiveBattler][1];
u16 argument = gBattleResources->bufferA[gActiveBattler][2] | (gBattleResources->bufferA[gActiveBattler][3] << 8);
if (TryHandleLaunchBattleTableAnimation(gActiveBattler, gActiveBattler, gActiveBattler, animationId, argument))
SafariBufferExecCompleted();
else
gBattlerControllerFuncs[gActiveBattler] = CompleteOnFinishedBattleAnimation;
}
static void SafariHandleLinkStandbyMsg(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleResetActionMoveSelection(void)
{
SafariBufferExecCompleted();
}
static void SafariHandleEndLinkBattle(void)
{
gBattleOutcome = gBattleResources->bufferA[gActiveBattler][1];
FadeOutMapMusic(5); FadeOutMapMusic(5);
BeginFastPaletteFade(3); BeginFastPaletteFade(3);
SafariBufferExecCompleted(); SafariBufferExecCompleted(battler);
if ((gBattleTypeFlags & BATTLE_TYPE_LINK) && !(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER)) if ((gBattleTypeFlags & BATTLE_TYPE_LINK) && !(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER))
gBattlerControllerFuncs[gActiveBattler] = SafariSetBattleEndCallbacks; gBattlerControllerFuncs[battler] = SafariSetBattleEndCallbacks;
}
static void SafariHandleBattleDebug(void)
{
SafariBufferExecCompleted();
}
static void SafariCmdEnd(void)
{
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -157,8 +157,6 @@ static void BufferLastDomeWinnerName(void);
static void InitRandomTourneyTreeResults(void); static void InitRandomTourneyTreeResults(void);
static void InitDomeTrainers(void); static void InitDomeTrainers(void);
EWRAM_DATA u32 gPlayerPartyLostHP = 0; // never read
static EWRAM_DATA u32 sPlayerPartyMaxHP = 0; // never read
static EWRAM_DATA struct TourneyTreeInfoCard *sInfoCard = {0}; static EWRAM_DATA struct TourneyTreeInfoCard *sInfoCard = {0};
static EWRAM_DATA u8 *sTilemapBuffer = NULL; static EWRAM_DATA u8 *sTilemapBuffer = NULL;
@ -2544,9 +2542,6 @@ static void BufferDomeOpponentName(void)
static void InitDomeOpponentParty(void) static void InitDomeOpponentParty(void)
{ {
gPlayerPartyLostHP = 0;
sPlayerPartyMaxHP = GetMonData(&gPlayerParty[0], MON_DATA_MAX_HP, NULL);
sPlayerPartyMaxHP += GetMonData(&gPlayerParty[1], MON_DATA_MAX_HP, NULL);
CalculatePlayerPartyCount(); CalculatePlayerPartyCount();
CreateDomeOpponentMons(TrainerIdToTournamentId(gTrainerBattleOpponent_A)); CreateDomeOpponentMons(TrainerIdToTournamentId(gTrainerBattleOpponent_A));
} }

View File

@ -528,7 +528,7 @@ bool8 IsBattleSEPlaying(u8 battlerId)
if (IsSEPlaying()) if (IsSEPlaying())
{ {
gBattleSpritesDataPtr->healthBoxesData[battlerId].soundTimer++; gBattleSpritesDataPtr->healthBoxesData[battlerId].soundTimer++;
if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].soundTimer < 30) if (gBattleSpritesDataPtr->healthBoxesData[battlerId].soundTimer < 30)
return TRUE; return TRUE;
m4aMPlayStop(&gMPlayInfo_SE1); m4aMPlayStop(&gMPlayInfo_SE1);
@ -544,7 +544,7 @@ bool8 IsBattleSEPlaying(u8 battlerId)
return TRUE; return TRUE;
} }
static void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId, bool32 opponent) void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId)
{ {
u32 monsPersonality, currentPersonality, otId, currentOtId, species, paletteOffset, position; u32 monsPersonality, currentPersonality, otId, currentOtId, species, paletteOffset, position;
const void *lzPaletteData; const void *lzPaletteData;
@ -577,7 +577,7 @@ static void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId, bool32 op
} }
position = GetBattlerPosition(battlerId); position = GetBattlerPosition(battlerId);
if (opponent) if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
{ {
HandleLoadSpecialPokePic(TRUE, HandleLoadSpecialPokePic(TRUE,
gMonSpritesGfxPtr->sprites.ptr[position], gMonSpritesGfxPtr->sprites.ptr[position],
@ -609,16 +609,6 @@ static void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId, bool32 op
} }
} }
void BattleLoadOpponentMonSpriteGfx(struct Pokemon *mon, u8 battlerId)
{
BattleLoadMonSpriteGfx(mon, battlerId, TRUE);
}
void BattleLoadPlayerMonSpriteGfx(struct Pokemon *mon, u8 battlerId)
{
BattleLoadMonSpriteGfx(mon, battlerId, FALSE);
}
void BattleGfxSfxDummy2(u16 species) void BattleGfxSfxDummy2(u16 species)
{ {
} }
@ -642,10 +632,6 @@ void DecompressTrainerBackPic(u16 backPicId, u8 battlerId)
OBJ_PLTT_ID(battlerId), PLTT_SIZE_4BPP); OBJ_PLTT_ID(battlerId), PLTT_SIZE_4BPP);
} }
void BattleGfxSfxDummy3(u8 gender)
{
}
void FreeTrainerFrontPicPalette(u16 frontPicId) void FreeTrainerFrontPicPalette(u16 frontPicId)
{ {
FreeSpritePaletteByTag(gTrainerFrontPicPaletteTable[frontPicId].tag); FreeSpritePaletteByTag(gTrainerFrontPicPaletteTable[frontPicId].tag);
@ -968,12 +954,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite)
else else
{ {
if (!IsContest()) if (!IsContest())
{ BattleLoadMonSpriteGfx(&GetBattlerParty(battlerId)[gBattlerPartyIndexes[battlerId]], battlerId);
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[battlerId]], battlerId);
else
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battlerId]], battlerId);
}
} }
} }

View File

@ -251,11 +251,9 @@ void (*gPreBattleCallback1)(void);
void (*gBattleMainFunc)(void); void (*gBattleMainFunc)(void);
struct BattleResults gBattleResults; struct BattleResults gBattleResults;
u8 gLeveledUpInBattle; u8 gLeveledUpInBattle;
void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(void);
u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT]; u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
u8 gMultiUsePlayerCursor; u8 gMultiUsePlayerCursor;
u8 gNumberOfMovesToChoose; u8 gNumberOfMovesToChoose;
u8 gBattleControllerData[MAX_BATTLERS_COUNT]; // Used by the battle controllers to store misc sprite/task IDs for each battler
static const struct ScanlineEffectParams sIntroScanlineParams16Bit = static const struct ScanlineEffectParams sIntroScanlineParams16Bit =
{ {
@ -2743,8 +2741,6 @@ void SpriteCB_FaintOpponentMon(struct Sprite *sprite)
else else
species = sprite->sSpeciesId; species = sprite->sSpeciesId;
GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); // Unused return value.
if (species == SPECIES_UNOWN) if (species == SPECIES_UNOWN)
{ {
species = GetUnownSpeciesId(personality); species = GetUnownSpeciesId(personality);
@ -3006,7 +3002,7 @@ static void BattleMainCB1(void)
gBattleMainFunc(); gBattleMainFunc();
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
gBattlerControllerFuncs[gActiveBattler](); gBattlerControllerFuncs[gActiveBattler](gActiveBattler);
} }
static void BattleStartClearSetData(void) static void BattleStartClearSetData(void)

View File

@ -9974,13 +9974,13 @@ static void Cmd_various(void)
if (IsBattlerAlive(gActiveBattler)) if (IsBattlerAlive(gActiveBattler))
{ {
SetBattlerShadowSpriteCallback(gActiveBattler, gBattleMons[gActiveBattler].species); SetBattlerShadowSpriteCallback(gActiveBattler, gBattleMons[gActiveBattler].species);
BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); BattleLoadMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
} }
i = BATTLE_PARTNER(gActiveBattler); i = BATTLE_PARTNER(gActiveBattler);
if (IsBattlerAlive(i)) if (IsBattlerAlive(i))
{ {
SetBattlerShadowSpriteCallback(i, gBattleMons[i].species); SetBattlerShadowSpriteCallback(i, gBattleMons[i].species);
BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[i]], i); BattleLoadMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[i]], i);
} }
} }
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -1884,7 +1884,7 @@ u8 CheckMoveLimitations(u8 battlerId, u8 unusableMoves, u16 check)
else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battlerId].throatChopTimer && gBattleMoves[gBattleMons[battlerId].moves[i]].soundMove) else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battlerId].throatChopTimer && gBattleMoves[gBattleMons[battlerId].moves[i]].soundMove)
unusableMoves |= gBitTable[i]; unusableMoves |= gBitTable[i];
// Stuff Cheeks // Stuff Cheeks
else if (check & MOVE_LIMITATION_STUFF_CHEEKS && gBattleMons[battlerId].moves[i] == MOVE_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[gActiveBattler].item) != POCKET_BERRIES) else if (check & MOVE_LIMITATION_STUFF_CHEEKS && gBattleMons[battlerId].moves[i] == MOVE_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battlerId].item) != POCKET_BERRIES)
unusableMoves |= gBitTable[i]; unusableMoves |= gBitTable[i];
// Gorilla Tactics // Gorilla Tactics
else if (check & MOVE_LIMITATION_CHOICE_ITEM && GetBattlerAbility(battlerId) == ABILITY_GORILLA_TACTICS && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != gBattleMons[battlerId].moves[i]) else if (check & MOVE_LIMITATION_CHOICE_ITEM && GetBattlerAbility(battlerId) == ABILITY_GORILLA_TACTICS && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != gBattleMons[battlerId].moves[i])
@ -4879,7 +4879,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& gBattleResults.catchAttempts[gLastUsedBall - ITEM_ULTRA_BALL] >= 1 && gBattleResults.catchAttempts[gLastUsedBall - ITEM_ULTRA_BALL] >= 1
&& !gHasFetchedBall) && !gHasFetchedBall)
{ {
gBattleScripting.battler = battler; gBattleScripting.battler = gActiveBattler = battler;
BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedBall); BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedBall);
MarkBattlerForControllerExec(battler); MarkBattlerForControllerExec(battler);
gHasFetchedBall = TRUE; gHasFetchedBall = TRUE;
@ -10823,7 +10823,7 @@ void TrySaveExchangedItem(u8 battlerId, u16 stolenItem)
bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes) bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes)
{ {
bool32 ret = TRUE; bool32 ret = TRUE;
u32 holdEffect = GetBattlerHoldEffect(gActiveBattler, TRUE); u32 holdEffect = GetBattlerHoldEffect(battlerId, TRUE);
if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON)) if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON))
{ {
ret = FALSE; ret = FALSE;

View File

@ -187,7 +187,7 @@ static bool8 LoadBattlerSpriteGfx(u8 battler)
if (GetBattlerSide(battler) != B_SIDE_PLAYER) if (GetBattlerSide(battler) != B_SIDE_PLAYER)
{ {
if (!gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) if (!gBattleSpritesDataPtr->battlerData[battler].behindSubstitute)
BattleLoadOpponentMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[battler]], battler); BattleLoadMonSpriteGfx(&gEnemyParty[gBattlerPartyIndexes[battler]], battler);
else else
BattleLoadSubstituteOrMonSpriteGfx(battler, FALSE); BattleLoadSubstituteOrMonSpriteGfx(battler, FALSE);
} }
@ -196,7 +196,7 @@ static bool8 LoadBattlerSpriteGfx(u8 battler)
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) // Should be checking position, not battler. else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL && battler == B_POSITION_PLAYER_LEFT) // Should be checking position, not battler.
DecompressTrainerBackPic(TRAINER_BACK_PIC_WALLY, battler); DecompressTrainerBackPic(TRAINER_BACK_PIC_WALLY, battler);
else if (!gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) else if (!gBattleSpritesDataPtr->battlerData[battler].behindSubstitute)
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battler]], battler); BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battler]], battler);
else else
BattleLoadSubstituteOrMonSpriteGfx(battler, FALSE); BattleLoadSubstituteOrMonSpriteGfx(battler, FALSE);

View File

@ -37,6 +37,7 @@ gReservedSpritePaletteCount:
.include "link_rfu_2.o" .include "link_rfu_2.o"
.include "rtc.o" .include "rtc.o"
.include "battle_main.o" .include "battle_main.o"
.include "battle_controllers.o"
.include "random.o" .include "random.o"
.include "load_save.o" .include "load_save.o"
.include "berry_blender.o" .include "berry_blender.o"