diff --git a/asm/macros/battle_ai_script.inc b/asm/macros/battle_ai_script.inc index 1abc94b19..9e467686a 100644 --- a/asm/macros/battle_ai_script.inc +++ b/asm/macros/battle_ai_script.inc @@ -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 diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index b103cd78f..48d247260 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -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 diff --git a/include/battle_main.h b/include/battle_main.h index 583b0ae39..b72ec7195 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -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); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index d73857ee8..bd194e15c 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -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; +} diff --git a/src/battle_main.c b/src/battle_main.c index 7a4bb2541..b4d80beb1 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -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) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index adc13bae6..d3be76bf6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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) diff --git a/src/battle_util.c b/src/battle_util.c index 3024652b2..dadd4f701 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -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)