diff --git a/asm/macros/battle_ai_script.inc b/asm/macros/battle_ai_script.inc index 5b6d3b6db..8531c7a20 100644 --- a/asm/macros/battle_ai_script.inc +++ b/asm/macros/battle_ai_script.inc @@ -678,6 +678,11 @@ .byte \battler2 .endm + .macro is_wakeup_turn battler:req + .byte 0x78 + .byte \battler + .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 5398a6c3d..5a43eeb8a 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -1096,9 +1096,9 @@ AI_CheckViability: if_effect EFFECT_COUNTER, AI_CV_Counter if_effect EFFECT_ENCORE, AI_CV_Encore if_effect EFFECT_PAIN_SPLIT, AI_CV_PainSplit - if_effect EFFECT_SNORE, AI_CV_Snore if_effect EFFECT_LOCK_ON, AI_CV_LockOn if_effect EFFECT_SLEEP_TALK, AI_CV_SleepTalk + if_effect EFFECT_SNORE, AI_CV_SleepTalk if_effect EFFECT_DESTINY_BOND, AI_CV_DestinyBond if_effect EFFECT_FLAIL, AI_CV_Flail if_effect EFFECT_HEAL_BELL, AI_CV_HealBell @@ -2387,10 +2387,6 @@ AI_CV_PainSplit_ScoreDown1: AI_CV_PainSplit_End: end -AI_CV_Snore: - score +2 - end - AI_CV_LockOn: if_random_less_than 128, AI_CV_LockOn_End score +2 @@ -2399,6 +2395,8 @@ AI_CV_LockOn_End: end AI_CV_SleepTalk: + is_wakeup_turn AI_USER + if_equal 1, Score_Minus5 if_status AI_USER, STATUS1_SLEEP, Score_Plus10 score -5 end diff --git a/include/battle.h b/include/battle.h index a36f2aead..1d690a7fd 100644 --- a/include/battle.h +++ b/include/battle.h @@ -229,7 +229,7 @@ struct WishFutureKnock struct AI_SavedBattleMon { u8 ability; - u16 moves[4]; + u16 moves[MAX_MON_MOVES]; u16 heldItem; u16 species; }; @@ -249,17 +249,15 @@ struct AI_ThinkingStruct bool8 switchMon; // Because all available moves have no/little effect. }; -struct UsedMoves -{ - u16 moves[MAX_MON_MOVES]; - u16 unknown[MAX_MON_MOVES]; -}; +#define AI_MOVE_HISTORY_COUNT 3 struct BattleHistory { - struct UsedMoves usedMoves[MAX_BATTLERS_COUNT]; u8 abilities[MAX_BATTLERS_COUNT]; u8 itemEffects[MAX_BATTLERS_COUNT]; + u16 usedMoves[MAX_BATTLERS_COUNT][MAX_MON_MOVES]; + u16 moveHistory[MAX_BATTLERS_COUNT][AI_MOVE_HISTORY_COUNT]; // 3 last used moves for each battler + u8 moveHistoryIndex[MAX_BATTLERS_COUNT]; u16 trainerItems[MAX_BATTLERS_COUNT]; u8 itemsNo; }; diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h index 04d580a84..bd990d77a 100644 --- a/include/battle_ai_script_commands.h +++ b/include/battle_ai_script_commands.h @@ -17,7 +17,8 @@ u8 BattleAI_ChooseMoveOrAction(void); bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); bool32 IsBattlerAIControlled(u32 battlerId); void ClearBattlerMoveHistory(u8 battlerId); -void RecordMoveBattle(u8 battlerId, u32 move); +void RecordLastUsedMoveBy(u32 battlerId, u32 move); +void RecordKnownMove(u8 battlerId, u32 move); void RecordAbilityBattle(u8 battlerId, u8 abilityId); void ClearBattlerAbilityHistory(u8 battlerId); void RecordItemEffectBattle(u8 battlerId, u8 itemEffect); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 7e081c764..f40e7a382 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -178,6 +178,7 @@ static void Cmd_get_move_split_from_result(void); static void Cmd_get_considered_move_split(void); static void Cmd_get_considered_move_target(void); static void Cmd_compare_speeds(void); +static void Cmd_is_wakeup_turn(void); // ewram EWRAM_DATA const u8 *gAIScriptPtr = NULL; @@ -308,6 +309,7 @@ static const BattleAICmdFunc sBattleAICmdTable[] = Cmd_get_considered_move_split, // 0x75 Cmd_get_considered_move_target, // 0x76 Cmd_compare_speeds, // 0x77 + Cmd_is_wakeup_turn, // 0x78 }; static const u16 sDiscouragedPowerfulMoveEffects[] = @@ -463,7 +465,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) for (i = 0; i < MAX_MON_MOVES; i++) { - u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler].moves[i]; + u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; if (gBattleMoves[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) return TRUE; if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAI, opposingBattler, TRUE) == 1) @@ -735,7 +737,7 @@ static void BattleAI_DoAIProcessing(void) static void RecordLastUsedMoveByTarget(void) { - RecordMoveBattle(gBattlerTarget, gLastMoves[gBattlerTarget]); + RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]); } bool32 IsBattlerAIControlled(u32 battlerId) @@ -756,23 +758,30 @@ bool32 IsBattlerAIControlled(u32 battlerId) void ClearBattlerMoveHistory(u8 battlerId) { - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - BATTLE_HISTORY->usedMoves[battlerId].moves[i] = MOVE_NONE; + memset(BATTLE_HISTORY->usedMoves[battlerId], 0, sizeof(BATTLE_HISTORY->usedMoves[battlerId])); + memset(BATTLE_HISTORY->moveHistory[battlerId], 0, sizeof(BATTLE_HISTORY->moveHistory[battlerId])); + BATTLE_HISTORY->moveHistoryIndex[battlerId] = 0; } -void RecordMoveBattle(u8 battlerId, u32 move) +void RecordLastUsedMoveBy(u32 battlerId, u32 move) +{ + u8 *index = &BATTLE_HISTORY->moveHistoryIndex[battlerId]; + + if (++(*index) >= AI_MOVE_HISTORY_COUNT) + *index = 0; + BATTLE_HISTORY->moveHistory[battlerId][*index] = move; +} + +void RecordKnownMove(u8 battlerId, u32 move) { s32 i; - for (i = 0; i < MAX_MON_MOVES; i++) { - if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] == move) + if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) break; - if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] == MOVE_NONE) + if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) { - BATTLE_HISTORY->usedMoves[battlerId].moves[i] = move; + BATTLE_HISTORY->usedMoves[battlerId][i] = move; break; } } @@ -835,7 +844,7 @@ static void SetBattlerData(u8 battlerId) for (i = 0; i < 4; i++) { - if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] == 0) + if (BATTLE_HISTORY->usedMoves[battlerId][i] == 0) gBattleMons[battlerId].moves[i] = 0; } @@ -2020,7 +2029,7 @@ static void Cmd_if_has_move(void) case AI_TARGET_PARTNER: for (i = 0; i < MAX_MON_MOVES; i++) { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget].moves[i] == *movePtr) + if (BATTLE_HISTORY->usedMoves[gBattlerTarget][i] == *movePtr) break; } if (i == MAX_MON_MOVES) @@ -2054,7 +2063,7 @@ static void Cmd_if_doesnt_have_move(void) case AI_TARGET_PARTNER: for (i = 0; i < MAX_MON_MOVES; i++) { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget].moves[i] == *movePtr) + if (BATTLE_HISTORY->usedMoves[gBattlerTarget][i] == *movePtr) break; } if (i != MAX_MON_MOVES) @@ -2087,7 +2096,7 @@ static void Cmd_if_has_move_with_effect(void) case AI_TARGET_PARTNER: for (i = 0; i < MAX_MON_MOVES; i++) { - if (gBattleMons[gBattlerTarget].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBattlerTarget].moves[i]].effect == gAIScriptPtr[2]) + if (gBattleMons[gBattlerTarget].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBattlerTarget][i]].effect == gAIScriptPtr[2]) break; } if (i == MAX_MON_MOVES) @@ -2120,7 +2129,7 @@ static void Cmd_if_doesnt_have_move_with_effect(void) case AI_TARGET_PARTNER: for (i = 0; i < MAX_MON_MOVES; i++) { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget].moves[i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBattlerTarget].moves[i]].effect == gAIScriptPtr[2]) + if (BATTLE_HISTORY->usedMoves[gBattlerTarget][i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBattlerTarget][i]].effect == gAIScriptPtr[2]) break; } if (i != MAX_MON_MOVES) @@ -2516,7 +2525,7 @@ static void Cmd_if_has_no_attacking_moves(void) { for (i = 0; i < 4; i++) { - if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[battlerId].moves[i]].power != 0) + if (BATTLE_HISTORY->usedMoves[battlerId][i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[battlerId][i]].power != 0) break; } } @@ -2590,7 +2599,7 @@ static bool32 HasMoveWithSplit(u32 battler, u32 split) if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler))) moves = gBattleMons[battler].moves; else - moves = gBattleResources->battleHistory->usedMoves[battler].moves; + moves = gBattleResources->battleHistory->usedMoves[battler]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2629,7 +2638,7 @@ static bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) if (IsBattlerAIControlled(attacker)) moves = gBattleMons[attacker].moves; else - moves = gBattleResources->battleHistory->usedMoves[attacker].moves; + moves = gBattleResources->battleHistory->usedMoves[attacker]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2661,7 +2670,7 @@ static void Cmd_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; + u16 *moves = gBattleResources->battleHistory->usedMoves[gBattlerTarget]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2694,7 +2703,7 @@ static void Cmd_if_has_move_with_type(void) if (IsBattlerAIControlled(battler)) moves = gBattleMons[battler].moves; else - moves = BATTLE_HISTORY->usedMoves[battler].moves; + moves = BATTLE_HISTORY->usedMoves[battler]; for (i = 0; i < 4; i++) { @@ -2721,7 +2730,7 @@ static void Cmd_if_has_move_with_flag(void) if (IsBattlerAIControlled(battler)) moves = gBattleMons[battler].moves; else - moves = BATTLE_HISTORY->usedMoves[battler].moves; + moves = BATTLE_HISTORY->usedMoves[battler]; flag = T1_READ_32(gAIScriptPtr + 2); for (i = 0; i < 4; i++) @@ -2744,7 +2753,7 @@ static void Cmd_if_no_move_used(void) { for (i = 0; i < 4; i++) { - if (BATTLE_HISTORY->usedMoves[battler].moves[i] != 0 && BATTLE_HISTORY->usedMoves[battler].moves[i] != 0xFFFF) + if (BATTLE_HISTORY->usedMoves[battler][i] != 0 && BATTLE_HISTORY->usedMoves[battler][i] != 0xFFFF) { gAIScriptPtr += 6; return; @@ -2826,3 +2835,26 @@ static void Cmd_compare_speeds(void) AI_THINKING_STRUCT->funcResult = GetWhoStrikesFirst(battler1, battler2, TRUE); gAIScriptPtr += 3; } + +static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) +{ + s32 i, index = BATTLE_HISTORY->moveHistoryIndex[battlerId]; + for (i = 0; i < x; i++) + { + if (--index < 0) + index = AI_MOVE_HISTORY_COUNT - 1; + } + return BATTLE_HISTORY->moveHistory[battlerId][index]; +} + +static void Cmd_is_wakeup_turn(void) +{ + u32 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); + // Check if rest was used 2 turns ago + if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && FindMoveUsedXTurnsAgo(battler, 2) == MOVE_REST) + AI_THINKING_STRUCT->funcResult = TRUE; + else + AI_THINKING_STRUCT->funcResult = FALSE; + + gAIScriptPtr += 2; +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 962a7fdc6..54412d8df 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -4781,6 +4781,7 @@ static void Cmd_moveend(void) gHitMarker &= ~(HITMARKER_NO_PPDEDUCT); } } + RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove); gBattleScripting.moveendState++; break; case MOVEEND_LIFE_ORB: diff --git a/src/battle_util.c b/src/battle_util.c index 48057afa0..53cdbe10d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2860,7 +2860,7 @@ static u8 ForewarnChooseMove(u32 battler) gBattlerTarget = data[bestId].battlerId; PREPARE_MOVE_BUFFER(gBattleTextBuff1, data[bestId].moveId) - RecordMoveBattle(gBattlerTarget, data[bestId].moveId); + RecordKnownMove(gBattlerTarget, data[bestId].moveId); free(data); }