AI switch mons if all moves are not usable

This commit is contained in:
DizzyEggg 2019-06-11 10:45:12 +02:00
parent 30bd85a58a
commit 272fa07799
5 changed files with 56 additions and 15 deletions

View File

@ -249,6 +249,7 @@ struct AI_ThinkingStruct
u8 aiLogicId;
u8 simulatedRNG[4];
struct AI_SavedBattleMon saved[4];
bool8 switchMon; // Because all available moves have no/little effect.
};
struct UsedMoves

View File

@ -5,6 +5,7 @@
// 0 - 3 are move idx
#define AI_CHOICE_FLEE 4
#define AI_CHOICE_WATCH 5
#define AI_CHOICE_SWITCH 7
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef);
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon);

View File

@ -54,6 +54,7 @@ static void RecordLastUsedMoveByTarget(void);
static void BattleAI_DoAIProcessing(void);
static void AIStackPushVar(const u8 *);
static bool8 AIStackPop(void);
static s32 CountUsablePartyMons(u8 battlerId);
static void BattleAICmd_if_random_less_than(void);
static void BattleAICmd_if_random_greater_than(void);
@ -448,6 +449,28 @@ static u8 ChooseMoveOrAction_Singles(void)
if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH)
return AI_CHOICE_WATCH;
// Consider switching if all moves are worthless to use.
if (AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_PREFER_BATON_PASS)
&& CountUsablePartyMons(sBattler_AI) >= 1
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2
&& !(gBattleTypeFlags & BATTLE_TYPE_PALACE))
{
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY) ? 95 : 93;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (AI_THINKING_STRUCT->score[i] > cap)
break;
}
gActiveBattler = sBattler_AI;
if (i == MAX_MON_MOVES && GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
{
AI_THINKING_STRUCT->switchMon = TRUE;
return AI_CHOICE_SWITCH;
}
}
numOfBestMoves = 1;
currentMoveArray[0] = AI_THINKING_STRUCT->score[0];
consideredMoveArray[0] = 0;
@ -1422,19 +1445,10 @@ static void BattleAICmd_nullsub_2B(void)
{
}
static void BattleAICmd_count_usable_party_mons(void)
static s32 CountUsablePartyMons(u8 battlerId)
{
u8 battlerId;
u8 battlerOnField1, battlerOnField2;
s32 battlerOnField1, battlerOnField2, i, ret;
struct Pokemon *party;
s32 i;
AI_THINKING_STRUCT->funcResult = 0;
if (gAIScriptPtr[1] == AI_USER)
battlerId = sBattler_AI;
else
battlerId = gBattlerTarget;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
party = gPlayerParty;
@ -1443,10 +1457,8 @@ static void BattleAICmd_count_usable_party_mons(void)
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
u32 position;
battlerOnField1 = gBattlerPartyIndexes[battlerId];
position = GetBattlerPosition(battlerId) ^ BIT_FLANK;
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(position)];
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(GetBattlerPosition(battlerId) ^ BIT_FLANK)];
}
else // In singles there's only one battlerId by side.
{
@ -1454,6 +1466,7 @@ static void BattleAICmd_count_usable_party_mons(void)
battlerOnField2 = gBattlerPartyIndexes[battlerId];
}
ret = 0;
for (i = 0; i < PARTY_SIZE; i++)
{
if (i != battlerOnField1 && i != battlerOnField2
@ -1461,10 +1474,16 @@ static void BattleAICmd_count_usable_party_mons(void)
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
{
AI_THINKING_STRUCT->funcResult++;
ret++;
}
}
return ret;
}
static void BattleAICmd_count_usable_party_mons(void)
{
AI_THINKING_STRUCT->funcResult = CountUsablePartyMons(BattleAI_GetWantedBattler(gAIScriptPtr[1]));
gAIScriptPtr += 2;
}

View File

@ -37,6 +37,21 @@ void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId)
}
}
static bool8 ShouldSwitchIfAllBadMoves(void)
{
if (gBattleResources->ai->switchMon)
{
gBattleResources->ai->switchMon = 0;
*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = PARTY_SIZE;
BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0);
return TRUE;
}
else
{
return FALSE;
}
}
static bool8 ShouldSwitchIfPerishSong(void)
{
if (gStatuses3[gActiveBattler] & STATUS3_PERISH_SONG
@ -474,6 +489,8 @@ static bool8 ShouldSwitch(void)
if (availableToSwitch == 0)
return FALSE;
if (ShouldSwitchIfAllBadMoves())
return TRUE;
if (ShouldSwitchIfPerishSong())
return TRUE;
if (ShouldSwitchIfWonderGuard())

View File

@ -1551,6 +1551,9 @@ static void OpponentHandleChooseMove(void)
case AI_CHOICE_FLEE:
BtlController_EmitTwoReturnValues(1, B_ACTION_RUN, 0);
break;
case AI_CHOICE_SWITCH:
BtlController_EmitTwoReturnValues(1, 10, 0xFFFF);
break;
case 6:
BtlController_EmitTwoReturnValues(1, 15, gBattlerTarget);
break;