New AI command for using priority moves in death situatiions

This commit is contained in:
DizzyEggg 2019-02-16 14:54:17 +01:00
parent c1f9032989
commit a001faeced
7 changed files with 101 additions and 17 deletions

View File

@ -615,6 +615,11 @@
.4byte \ptr
.endm
.macro if_ai_can_go_down ptr:req
.byte 0x6C
.4byte \ptr
.endm
@ useful script macros
.macro if_has_physical_move battler:req, ptr:req
if_has_move_with_split \battler, SPLIT_PHYSICAL, \ptr

View File

@ -886,11 +886,25 @@ Score_Plus5:
Score_Plus10:
score +10
end
@ omae wa mou shindeiru
@ Basically a scenario where the players mon is faster, able to hit and able to OHKO
@ In which, it would be best to use a priority move to deal any damage
AI_CheckIfAlreadyDead:
if_status2 AI_TARGET, STATUS2_RECHARGE | STATUS2_BIDE, AI_Ret
if_ai_can_go_down AI_CheckIfAlreadyDeadPriorities
end
AI_CheckIfAlreadyDeadPriorities:
if_target_faster Score_Minus1
if_random_less_than 126, AI_Ret
score +1
end
AI_CheckViability:
if_target_is_ally AI_Ret
call_if_always_hit AI_CV_AlwaysHit
call_if_move_flag FLAG_HIGH_CRIT, AI_CV_HighCrit
call AI_CheckIfAlreadyDead
if_effect EFFECT_HIT, AI_CV_Hit
if_effect EFFECT_SLEEP, AI_CV_Sleep
if_effect EFFECT_ABSORB, AI_CV_Absorb

View File

@ -69,7 +69,8 @@ u8 IsRunningFromBattleImpossible(void);
void sub_803BDA0(u8 battlerId);
void SwapTurnOrder(u8 id1, u8 id2);
u32 GetBattlerTotalSpeedStat(u8 battlerId);
s8 GetMovePriority(u8 battlerId);
s8 GetChosenMovePriority(u32 battlerId);
s8 GetMovePriority(u32 battlerId, u16 move);
u8 GetWhoStrikesFirst(u8 battlerId1, u8 battlerId2, bool8 ignoreChosenMoves);
void RunBattleScriptCommands_PopCallbacksStack(void);
void RunBattleScriptCommands(void);

View File

@ -93,7 +93,7 @@ static void BattleAICmd_get_how_powerful_move_is(void);
static void BattleAICmd_get_last_used_battler_move(void);
static void BattleAICmd_if_equal_(void);
static void BattleAICmd_if_not_equal_(void);
static void BattleAICmd_if_user_goes(void);
void BattleAICmd_if_user_goes(void);
static void BattleAICmd_if_user_doesnt_go(void);
static void BattleAICmd_nullsub_2A(void);
static void BattleAICmd_nullsub_2B(void);
@ -161,6 +161,7 @@ static void BattleAICmd_if_cant_use_last_resort(void);
static void BattleAICmd_if_has_move_with_split(void);
static void BattleAICmd_if_has_no_move_with_split(void);
static void BattleAICmd_if_physical_moves_unusable(void);
static void BattleAICmd_if_ai_can_go_down(void);
// ewram
EWRAM_DATA const u8 *gAIScriptPtr = NULL;
@ -279,6 +280,7 @@ static const BattleAICmdFunc sBattleAICmdTable[] =
BattleAICmd_if_has_move_with_split, // 0x69
BattleAICmd_if_has_no_move_with_split, // 0x6A
BattleAICmd_if_physical_moves_unusable, // 0x6B
BattleAICmd_if_ai_can_go_down, // 0x6C
};
static const u16 sDiscouragedPowerfulMoveEffects[] =
@ -1434,20 +1436,56 @@ static void BattleAICmd_if_not_equal_(void) // Same as if_not_equal.
gAIScriptPtr += 6;
}
static void BattleAICmd_if_user_goes(void)
void BattleAICmd_if_user_goes(void)
{
if (GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == gAIScriptPtr[1])
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
u32 fasterAI = 0, fasterPlayer = 0, i;
s8 prioAI, prioPlayer;
// Check move priorities first.
prioAI = GetMovePriority(sBattler_AI, AI_THINKING_STRUCT->moveConsidered);
SaveBattlerData(gBattlerTarget);
SetBattlerData(gBattlerTarget);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (gBattleMons[gBattlerTarget].moves[i] == 0 || gBattleMons[gBattlerTarget].moves[i] == 0xFFFF)
continue;
prioPlayer = GetMovePriority(gBattlerTarget, gBattleMons[gBattlerTarget].moves[i]);
if (prioAI > prioPlayer)
fasterAI++;
else if (prioPlayer > prioAI)
fasterPlayer++;
}
RestoreBattlerData(gBattlerTarget);
if (fasterAI > fasterPlayer)
{
if (gAIScriptPtr[1] == 0)
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
}
else if (fasterAI < fasterPlayer)
{
if (gAIScriptPtr[1] == 1)
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
}
else
gAIScriptPtr += 6;
{
// Priorities are the same(at least comparing to moves the AI is aware of), decide by speed.
if (GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == gAIScriptPtr[1])
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
}
}
static void BattleAICmd_if_user_doesnt_go(void)
{
if (GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) != gAIScriptPtr[1])
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
// To be changed. Not needed since the above does the same.
gAIScriptPtr += 6;
}
static void BattleAICmd_nullsub_2A(void)
@ -2622,3 +2660,23 @@ static void BattleAICmd_if_physical_moves_unusable(void)
else
gAIScriptPtr += 7;
}
// Check if target has means to faint ai mon.
static void BattleAICmd_if_ai_can_go_down(void)
{
s32 i, dmg;
u32 unusable = CheckMoveLimitations(gBattlerTarget, 0, 0xFF & ~MOVE_LIMITATION_PP);
u16 *moves = gBattleResources->battleHistory->usedMoves[gBattlerTarget].moves;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i])
&& AI_CalcDamage(moves[i], gBattlerTarget, sBattler_AI) >= gBattleMons[sBattler_AI].hp)
{
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
return;
}
}
gAIScriptPtr += 5;
}

View File

@ -4328,9 +4328,8 @@ u32 GetBattlerTotalSpeedStat(u8 battlerId)
return speed;
}
s8 GetMovePriority(u8 battlerId)
s8 GetChosenMovePriority(u32 battlerId)
{
s8 priority;
u16 move;
if (gProtectStructs[battlerId].noValidMoves)
@ -4338,6 +4337,13 @@ s8 GetMovePriority(u8 battlerId)
else
move = gBattleMons[battlerId].moves[*(gBattleStruct->chosenMovePositions + battlerId)];
return GetMovePriority(battlerId, move);
}
s8 GetMovePriority(u32 battlerId, u16 move)
{
s8 priority;
priority = gBattleMoves[move].priority;
if (GetBattlerAbility(battlerId) == ABILITY_GALE_WINGS
&& gBattleMoves[move].type == TYPE_FLYING
@ -4397,9 +4403,9 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
if (!ignoreChosenMoves)
{
if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE)
priority1 = GetMovePriority(battler1);
priority1 = GetChosenMovePriority(battler1);
if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE)
priority2 = GetMovePriority(battler2);
priority2 = GetChosenMovePriority(battler2);
}
if (priority1 == priority2)

View File

@ -902,7 +902,7 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move)
else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_QUICK_GUARD
&& GetMovePriority(gBattlerAttacker) > 0)
&& GetChosenMovePriority(gBattlerAttacker) > 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD
&& gBattleMoves[move].power == 0)

View File

@ -2345,7 +2345,7 @@ u8 AtkCanceller_UnableToUseMove2(void)
case CANCELLER_PSYCHIC_TERRAIN:
if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN
&& IsBattlerGrounded(gBattlerAttacker)
&& GetMovePriority(gBattlerAttacker) > 0
&& GetChosenMovePriority(gBattlerAttacker) > 0
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
{
CancelMultiTurnMoves(gBattlerAttacker);
@ -2989,7 +2989,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
else if ((gLastUsedAbility == ABILITY_DAZZLING
|| (IsBattlerAlive(battler ^= BIT_FLANK) && GetBattlerAbility(battler) == ABILITY_DAZZLING)
)
&& GetMovePriority(battler) > 0
&& GetChosenMovePriority(battler) > 0
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
{
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)