Merge branch 'upcoming' into berryexpansion
This commit is contained in:
commit
a4b819ac41
17 changed files with 367 additions and 87 deletions
|
@ -8853,6 +8853,16 @@ BattleScript_ZeroToHeroActivates::
|
|||
waitmessage B_WAIT_TIME_LONG
|
||||
end3
|
||||
|
||||
BattleScript_HospitalityActivates::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_HOSPITALITYRESTORATION
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
|
||||
healthbarupdate BS_TARGET
|
||||
datahpupdate BS_TARGET
|
||||
end3
|
||||
|
||||
BattleScript_AttackWeakenedByStrongWinds::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
printstring STRINGID_ATTACKWEAKENEDBSTRONGWINDS
|
||||
|
@ -9249,6 +9259,7 @@ BattleScript_BattlerAbilityStatRaiseOnSwitchIn::
|
|||
waitanimation
|
||||
printstring STRINGID_BATTLERABILITYRAISEDSTAT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
copybyte gBattlerAttacker, sSAVED_BATTLER
|
||||
end3
|
||||
|
||||
BattleScript_ScriptingAbilityStatRaise::
|
||||
|
|
|
@ -336,7 +336,7 @@ struct AI_ThinkingStruct
|
|||
u16 moveConsidered;
|
||||
s32 score[MAX_MON_MOVES];
|
||||
u32 funcResult;
|
||||
u32 aiFlags;
|
||||
u32 aiFlags[MAX_BATTLERS_COUNT];
|
||||
u8 aiAction;
|
||||
u8 aiLogicId;
|
||||
struct AI_SavedBattleMon saved[MAX_BATTLERS_COUNT];
|
||||
|
|
|
@ -461,6 +461,7 @@ extern const u8 BattleScript_CudChewActivates[];
|
|||
extern const u8 BattleScript_SupremeOverlordActivates[];
|
||||
extern const u8 BattleScript_CostarActivates[];
|
||||
extern const u8 BattleScript_ZeroToHeroActivates[];
|
||||
extern const u8 BattleScript_HospitalityActivates[];
|
||||
extern const u8 BattleScript_ToxicDebrisActivates[];
|
||||
extern const u8 BattleScript_EarthEaterActivates[];
|
||||
extern const u8 BattleScript_MimicryActivates_End3[];
|
||||
|
|
|
@ -696,8 +696,9 @@
|
|||
#define STRINGID_SWAMPENVELOPEDSIDE 694
|
||||
#define STRINGID_THESWAMPDISAPPEARED 695
|
||||
#define STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE 696
|
||||
#define STRINGID_HOSPITALITYRESTORATION 697
|
||||
|
||||
#define BATTLESTRINGS_COUNT 697
|
||||
#define BATTLESTRINGS_COUNT 698
|
||||
|
||||
// This is the string id that gBattleStringsTable starts with.
|
||||
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "constants/hold_effects.h"
|
||||
#include "constants/moves.h"
|
||||
#include "constants/items.h"
|
||||
#include "constants/trainers.h"
|
||||
|
||||
#define AI_ACTION_DONE (1 << 0)
|
||||
#define AI_ACTION_FLEE (1 << 1)
|
||||
|
@ -139,36 +140,76 @@ static u32 GetWildAiFlags(void)
|
|||
return flags;
|
||||
}
|
||||
|
||||
static u32 GetAiFlags(u16 trainerId)
|
||||
{
|
||||
u32 flags = 0;
|
||||
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_HAS_AI) && !IsWildMonSmart())
|
||||
return 0;
|
||||
if (trainerId == 0xFFFF)
|
||||
{
|
||||
flags = GetWildAiFlags();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
flags = GetAiScriptsInRecordedBattle();
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
|
||||
flags = AI_FLAG_SAFARI;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER)
|
||||
flags = AI_FLAG_ROAMING;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
|
||||
flags = AI_FLAG_FIRST_BATTLE;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY)
|
||||
flags = GetAiScriptsInBattleFactory();
|
||||
else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE))
|
||||
flags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT;
|
||||
else
|
||||
flags = gTrainers[trainerId].aiFlags;
|
||||
}
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
flags |= AI_FLAG_DOUBLE_BATTLE;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void BattleAI_SetupFlags(void)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI
|
||||
|
||||
#if DEBUG_OVERWORLD_MENU == TRUE
|
||||
if (gIsDebugBattle)
|
||||
AI_THINKING_STRUCT->aiFlags = gDebugAIFlags;
|
||||
else
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags;
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
AI_THINKING_STRUCT->aiFlags = GetAiScriptsInRecordedBattle();
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
|
||||
AI_THINKING_STRUCT->aiFlags = AI_FLAG_SAFARI;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER)
|
||||
AI_THINKING_STRUCT->aiFlags = AI_FLAG_ROAMING;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
|
||||
AI_THINKING_STRUCT->aiFlags = AI_FLAG_FIRST_BATTLE;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY)
|
||||
AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory();
|
||||
else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE))
|
||||
AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
||||
AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags;
|
||||
|
||||
if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))
|
||||
{
|
||||
// smart wild AI
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF);
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF);
|
||||
}
|
||||
else
|
||||
AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags;
|
||||
|
||||
// check smart wild AI
|
||||
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)) && IsWildMonSmart())
|
||||
AI_THINKING_STRUCT->aiFlags |= GetWildAiFlags();
|
||||
|
||||
if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS) || gTrainers[gTrainerBattleOpponent_A].doubleBattle)
|
||||
AI_THINKING_STRUCT->aiFlags |= AI_FLAG_DOUBLE_BATTLE; // Act smart in doubles and don't attack your partner.
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(gTrainerBattleOpponent_A);
|
||||
if (gTrainerBattleOpponent_B != 0)
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(gTrainerBattleOpponent_B);
|
||||
else
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT];
|
||||
}
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE));
|
||||
}
|
||||
else
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player
|
||||
}
|
||||
}
|
||||
|
||||
// sBattler_AI set in ComputeBattleAiScores
|
||||
|
@ -176,11 +217,12 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
|||
{
|
||||
s32 i;
|
||||
u8 moveLimitations;
|
||||
u32 flags[MAX_BATTLERS_COUNT];
|
||||
|
||||
// Clear AI data but preserve the flags.
|
||||
u32 flags = AI_THINKING_STRUCT->aiFlags;
|
||||
memcpy(&flags[0], &AI_THINKING_STRUCT->aiFlags[0], sizeof(u32) * MAX_BATTLERS_COUNT);
|
||||
memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct));
|
||||
AI_THINKING_STRUCT->aiFlags = flags;
|
||||
memcpy(&AI_THINKING_STRUCT->aiFlags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT);
|
||||
|
||||
// Conditional score reset, unlike Ruby.
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
|
@ -251,7 +293,7 @@ static void CopyBattlerDataToAIParty(u32 bPosition, u32 side)
|
|||
void Ai_InitPartyStruct(void)
|
||||
{
|
||||
u32 i;
|
||||
bool32 isOmniscient = (AI_THINKING_STRUCT->aiFlags & AI_FLAG_OMNISCIENT);
|
||||
bool32 isOmniscient = (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT);
|
||||
struct Pokemon *mon;
|
||||
|
||||
AI_PARTY->count[B_SIDE_PLAYER] = gPlayerPartyCount;
|
||||
|
@ -433,13 +475,13 @@ static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle)
|
|||
if (CountUsablePartyMons(battler) > 0
|
||||
&& !IsBattlerTrapped(battler, 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))
|
||||
&& AI_THINKING_STRUCT->aiFlags[battler] & (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[battler].species) >= 310 // Mon is not weak.
|
||||
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2) // Mon has more than 50% of its HP
|
||||
{
|
||||
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93;
|
||||
s32 cap = AI_THINKING_STRUCT->aiFlags[battler] & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93;
|
||||
if (doubleBattle)
|
||||
{
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
|
@ -492,7 +534,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
|
|||
u8 consideredMoveArray[MAX_MON_MOVES];
|
||||
u32 numOfBestMoves;
|
||||
s32 i;
|
||||
u32 flags = AI_THINKING_STRUCT->aiFlags;
|
||||
u32 flags = AI_THINKING_STRUCT->aiFlags[battlerAi];
|
||||
|
||||
AI_DATA->partnerMove = 0; // no ally
|
||||
while (flags != 0)
|
||||
|
@ -577,7 +619,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
|
|||
AI_DATA->partnerMove = GetAllyChosenMove(battlerAi);
|
||||
AI_THINKING_STRUCT->aiLogicId = 0;
|
||||
AI_THINKING_STRUCT->movesetIndex = 0;
|
||||
flags = AI_THINKING_STRUCT->aiFlags;
|
||||
flags = AI_THINKING_STRUCT->aiFlags[sBattler_AI];
|
||||
|
||||
while (flags != 0)
|
||||
{
|
||||
|
@ -1017,7 +1059,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE))
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE))
|
||||
ADJUST_SCORE(-2);
|
||||
|
||||
if (effectiveness == AI_EFFECTIVENESS_x0)
|
||||
|
@ -1996,7 +2038,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
}
|
||||
}
|
||||
|
||||
/*if (AI_THINKING_STRUCT->aiFlags == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI
|
||||
/*if (AI_THINKING_STRUCT->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI
|
||||
&& IS_DOUBLE_BATTLE) //Make the regular AI know how to use Protect minimally in Doubles
|
||||
{
|
||||
u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move);
|
||||
|
@ -2803,7 +2845,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
switch (atkPartnerAbility)
|
||||
{
|
||||
case ABILITY_VOLT_ABSORB:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HP_AWARE))
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE))
|
||||
{
|
||||
RETURN_SCORE_MINUS(10);
|
||||
}
|
||||
|
@ -2824,7 +2866,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
break;
|
||||
case ABILITY_WATER_ABSORB:
|
||||
case ABILITY_DRY_SKIN:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HP_AWARE))
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE))
|
||||
{
|
||||
RETURN_SCORE_MINUS(10);
|
||||
}
|
||||
|
@ -3233,7 +3275,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
}
|
||||
|
||||
// check status move preference
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move) && effectiveness != AI_EFFECTIVENESS_x0)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move) && effectiveness != AI_EFFECTIVENESS_x0)
|
||||
ADJUST_SCORE(1);
|
||||
|
||||
// check thawing moves
|
||||
|
@ -3241,7 +3283,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
ADJUST_SCORE(10);
|
||||
|
||||
// check burn / frostbite
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING && AI_DATA->abilities[battlerAtk] == ABILITY_NATURAL_CURE)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && AI_DATA->abilities[battlerAtk] == ABILITY_NATURAL_CURE)
|
||||
{
|
||||
if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, BATTLE_CATEGORY_PHYSICAL, TRUE))
|
||||
|| (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, BATTLE_CATEGORY_SPECIAL, TRUE)))
|
||||
|
@ -3263,7 +3305,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
ADJUST_SCORE(2);
|
||||
case EFFECT_EXPLOSION:
|
||||
case EFFECT_MEMENTO:
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
|
||||
{
|
||||
if (aiData->hpPercents[battlerAtk] < 50 && AI_RandLessThan(128))
|
||||
ADJUST_SCORE(1);
|
||||
|
@ -3569,7 +3611,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
ADJUST_SCORE(5);
|
||||
if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_LIGHT_CLAY)
|
||||
ADJUST_SCORE(2);
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SCREENER)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SCREENER)
|
||||
ADJUST_SCORE(2);
|
||||
}
|
||||
break;
|
||||
|
@ -3611,7 +3653,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
ADJUST_SCORE(5);
|
||||
break;
|
||||
case EFFECT_MIST:
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SCREENER)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SCREENER)
|
||||
ADJUST_SCORE(2);
|
||||
break;
|
||||
case EFFECT_FOCUS_ENERGY:
|
||||
|
@ -4070,7 +4112,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
break;
|
||||
case STAT_DEF:
|
||||
case STAT_SPDEF:
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL)
|
||||
ADJUST_SCORE(1);
|
||||
break;
|
||||
}
|
||||
|
@ -4868,7 +4910,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
|| gBattleResults.battleTurnCounter != 0)
|
||||
return score;
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING
|
||||
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
|
||||
&& CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& GetMovePriority(battlerAtk, move) == 0)
|
||||
|
|
|
@ -38,10 +38,10 @@ static void InitializeSwitchinCandidate(struct Pokemon *mon)
|
|||
|
||||
static bool32 IsAceMon(u32 battler, u32 monPartyId)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_ACE_POKEMON
|
||||
&& !(gBattleStruct->forcedSwitch & gBitTable[battler])
|
||||
&& monPartyId == CalculateEnemyPartyCount()-1)
|
||||
return TRUE;
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON
|
||||
&& !(gBattleStruct->forcedSwitch & gBitTable[battler])
|
||||
&& monPartyId == CalculateEnemyPartyCount()-1)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
|
|||
u16 typeEffectiveness = UQ_4_12(1.0), aiMoveEffect; //baseline typing damage
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Won't bother configuring this for double battles
|
||||
|
@ -433,7 +433,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
|
|||
&& monAbility != ABILITY_SOUNDPROOF)
|
||||
switchMon = TRUE;
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)
|
||||
{
|
||||
//Yawn
|
||||
if (gStatuses3[battler] & STATUS3_YAWN
|
||||
|
@ -851,7 +851,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
|
|||
static bool32 ShouldSwitchIfEncored(u32 battler, bool32 emitResult)
|
||||
{
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// If not Encored or if no good switchin, don't switch
|
||||
|
@ -877,7 +877,7 @@ static bool32 AreAttackingStatsLowered(u32 battler, bool32 emitResult)
|
|||
s8 spAttackingStage = gBattleMons[battler].statStages[STAT_SPATK];
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Physical attacker
|
||||
|
@ -1015,7 +1015,7 @@ bool32 ShouldSwitch(u32 battler, bool32 emitResult)
|
|||
return TRUE;
|
||||
|
||||
//These Functions can prompt switch to generic pary members
|
||||
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE))
|
||||
if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE))
|
||||
return FALSE;
|
||||
if (ShouldSwitchIfAllBadMoves(battler, emitResult))
|
||||
return TRUE;
|
||||
|
@ -1939,7 +1939,7 @@ u8 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
|||
|
||||
// Split ideal mon decision between after previous mon KO'd (prioritize offensive options) and after switching active mon out (prioritize defensive options), and expand the scope of both.
|
||||
// Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer.
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_MON_CHOICES)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES)
|
||||
{
|
||||
bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchAfterMonKOd);
|
||||
return bestMonId;
|
||||
|
|
|
@ -404,7 +404,7 @@ bool32 BattlerHasAi(u32 battlerId)
|
|||
|
||||
bool32 IsAiBattlerAware(u32 battlerId)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_OMNISCIENT)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerId] & AI_FLAG_OMNISCIENT)
|
||||
return TRUE;
|
||||
|
||||
return BattlerHasAi(battlerId);
|
||||
|
@ -1290,7 +1290,7 @@ u32 AI_DecideHoldEffectForTurn(u32 battlerId)
|
|||
else
|
||||
holdEffect = GetBattlerHoldEffect(battlerId, FALSE);
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerId] & AI_FLAG_NEGATE_UNAWARE)
|
||||
return holdEffect;
|
||||
|
||||
if (gStatuses3[battlerId] & STATUS3_EMBARGO)
|
||||
|
@ -1341,7 +1341,7 @@ bool32 AI_IsBattlerGrounded(u32 battlerId)
|
|||
|
||||
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE)
|
||||
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
|
||||
return FALSE; // AI handicap flag: doesn't understand ability suppression concept
|
||||
|
||||
if (IsMoldBreakerTypeAbility(atkAbility) || gBattleMoves[move].ignoresTargetAbility)
|
||||
|
@ -1352,7 +1352,7 @@ bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move)
|
|||
|
||||
static inline bool32 AI_WeatherHasEffect(struct AiLogicData *aiData)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE)
|
||||
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
|
||||
return TRUE; // AI doesn't understand weather supression (handicap)
|
||||
|
||||
return aiData->weatherHasEffect; // weather damping abilities are announced
|
||||
|
@ -1437,7 +1437,7 @@ bool32 IsHazardMoveEffect(u32 moveEffect)
|
|||
|
||||
bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE)
|
||||
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
|
||||
return FALSE;
|
||||
|
||||
if (move == MOVE_SKY_DROP
|
||||
|
@ -1766,7 +1766,9 @@ u32 CountNegativeStatStages(u32 battlerId)
|
|||
|
||||
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4
|
||||
|
@ -1783,7 +1785,9 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
|||
|
||||
bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4
|
||||
|
@ -1800,7 +1804,9 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
|||
|
||||
bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
|
@ -1815,7 +1821,9 @@ bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
|||
|
||||
bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4
|
||||
|
@ -1831,7 +1839,9 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
|||
|
||||
bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4
|
||||
|
@ -1847,7 +1857,9 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
|||
|
||||
bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (defAbility != ABILITY_CONTRARY
|
||||
|
@ -1864,7 +1876,9 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
|||
|
||||
bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE
|
||||
|
@ -2969,7 +2983,7 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef]))
|
||||
return TRUE; // battler is taking secondary damage with low HP
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL)
|
||||
{
|
||||
if (!CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
return TRUE; // attacker goes first and opponent can't kill us
|
||||
|
@ -3553,7 +3567,7 @@ void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score)
|
|||
if (AI_DATA->hpPercents[battlerAtk] < 80 && AI_RandLessThan(128))
|
||||
return;
|
||||
|
||||
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return; // Damaging moves would get a score boost from AI_TryToFaint or PreferStrongestMove so we don't consider them here
|
||||
|
||||
switch (statId)
|
||||
|
@ -3627,8 +3641,8 @@ void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score)
|
|||
|
||||
void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
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)
|
||||
if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & 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;
|
||||
|
||||
if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20)
|
||||
|
@ -3636,7 +3650,7 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
|||
if (!HasDamagingMove(battlerDef))
|
||||
ADJUST_SCORE_PTR(2);
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT))
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT))
|
||||
ADJUST_SCORE_PTR(1); // stall tactic
|
||||
|
||||
if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK)
|
||||
|
@ -3651,8 +3665,8 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
|||
|
||||
void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
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)
|
||||
if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & 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;
|
||||
|
||||
if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove))
|
||||
|
@ -3671,8 +3685,8 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
|||
|
||||
void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
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)
|
||||
if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & 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;
|
||||
|
||||
if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove))
|
||||
|
@ -3693,8 +3707,8 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
|||
|
||||
void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
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)
|
||||
if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & 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;
|
||||
|
||||
if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove))
|
||||
|
@ -3712,8 +3726,8 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
|||
|
||||
void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
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)
|
||||
if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & 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;
|
||||
|
||||
if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)
|
||||
|
@ -3731,7 +3745,7 @@ void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score
|
|||
|
||||
void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return;
|
||||
|
||||
if (AI_CanGiveFrostbite(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove))
|
||||
|
|
|
@ -679,7 +679,7 @@ static void OpponentHandleChoosePokemon(u32 battler)
|
|||
if (IsValidForBattle(&gEnemyParty[chosenMonId])
|
||||
&& chosenMonId != gBattlerPartyIndexes[battler1]
|
||||
&& chosenMonId != gBattlerPartyIndexes[battler2]
|
||||
&& (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_ACE_POKEMON)
|
||||
&& (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON)
|
||||
|| chosenMonId != CalculateEnemyPartyCount() - 1
|
||||
|| CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle))
|
||||
{
|
||||
|
|
|
@ -1901,8 +1901,8 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data)
|
|||
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
|
||||
goto CASE_ITEM_STATUS;
|
||||
case LIST_ITEM_AI:
|
||||
data->modifyArrows.modifiedValPtr = &gBattleResources->ai->aiFlags;
|
||||
data->modifyArrows.currValue = GetBitfieldValue(gBattleResources->ai->aiFlags, data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
|
||||
data->modifyArrows.modifiedValPtr = &gBattleResources->ai->aiFlags[data->battlerId];
|
||||
data->modifyArrows.currValue = GetBitfieldValue(gBattleResources->ai->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
|
||||
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
|
||||
goto CASE_ITEM_STATUS;
|
||||
CASE_ITEM_STATUS:
|
||||
|
|
|
@ -833,9 +833,11 @@ static const u8 sText_HurtByTheSeaOfFire[] = _("{B_ATK_TEAM1} {B_ATK_NAME_WITH_P
|
|||
static const u8 sText_TheSeaOfFireDisappeared[] = _("The sea of fire around {B_ATK_TEAM2}\nteam disappeared!");
|
||||
static const u8 sText_SwampEnvelopedSide[] = _("A swamp enveloped\n{B_DEF_TEAM2} team!");
|
||||
static const u8 sText_TheSwampDisappeared[] = _("The swamp around {B_ATK_TEAM2}\nteam disappeared!");
|
||||
static const u8 sText_HospitalityRestoration[] = _("The {B_ATK_PARTNER_NAME} drank down all\nthe matcha that Sinistcha made!");
|
||||
|
||||
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
||||
{
|
||||
[STRINGID_HOSPITALITYRESTORATION - BATTLESTRINGS_TABLE_START] = sText_HospitalityRestoration,
|
||||
[STRINGID_THESWAMPDISAPPEARED - BATTLESTRINGS_TABLE_START] = sText_TheSwampDisappeared,
|
||||
[STRINGID_SWAMPENVELOPEDSIDE - BATTLESTRINGS_TABLE_START] = sText_SwampEnvelopedSide,
|
||||
[STRINGID_THESEAOFFIREDISAPPEARED - BATTLESTRINGS_TABLE_START] = sText_TheSeaOfFireDisappeared,
|
||||
|
|
|
@ -4314,6 +4314,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
u32 moveType, move;
|
||||
u32 side;
|
||||
u32 i, j;
|
||||
u32 partner;
|
||||
struct Pokemon *mon;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
|
||||
|
@ -4799,6 +4800,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& !(gBattleStruct->intrepidSwordBoost[GetBattlerSide(battler)] & gBitTable[gBattlerPartyIndexes[battler]]))
|
||||
{
|
||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||
gBattlerAttacker = battler;
|
||||
if (B_INTREPID_SWORD == GEN_9)
|
||||
gBattleStruct->intrepidSwordBoost[GetBattlerSide(battler)] |= gBitTable[gBattlerPartyIndexes[battler]];
|
||||
|
@ -4812,6 +4814,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& !(gBattleStruct->dauntlessShieldBoost[GetBattlerSide(battler)] & gBitTable[gBattlerPartyIndexes[battler]]))
|
||||
{
|
||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||
gBattlerAttacker = battler;
|
||||
if (B_DAUNTLESS_SHIELD == GEN_9)
|
||||
gBattleStruct->dauntlessShieldBoost[GetBattlerSide(battler)] |= gBitTable[gBattlerPartyIndexes[battler]];
|
||||
|
@ -4922,6 +4925,46 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_HOSPITALITY:
|
||||
partner = BATTLE_PARTNER(battler);
|
||||
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone && IsDoubleBattle() && gBattleMons[partner].hp < gBattleMons[partner].maxHP)
|
||||
{
|
||||
gBattlerTarget = partner;
|
||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
||||
gBattleMoveDamage = (GetNonDynamaxMaxHP(partner) / 4) * -1;
|
||||
BattleScriptPushCursorAndCallback(BattleScript_HospitalityActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_EMBODY_ASPECT_TEAL:
|
||||
case ABILITY_EMBODY_ASPECT_HEARTHFLAME:
|
||||
case ABILITY_EMBODY_ASPECT_WELLSPRING:
|
||||
case ABILITY_EMBODY_ASPECT_CORNERSTONE:
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone)
|
||||
{
|
||||
u32 stat = STAT_SPATK;
|
||||
|
||||
if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_TEAL)
|
||||
stat = STAT_SPATK;
|
||||
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME)
|
||||
stat = STAT_ATK;
|
||||
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_WELLSPRING)
|
||||
stat = STAT_SPDEF;
|
||||
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_CORNERSTONE)
|
||||
stat = STAT_DEF;
|
||||
|
||||
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL))
|
||||
break;
|
||||
|
||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||
gBattlerAttacker = battler;
|
||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
||||
SET_STATCHANGER(stat, 1, FALSE);
|
||||
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_ENDTURN: // 1
|
||||
|
|
|
@ -87,7 +87,7 @@ void RecordedBattle_Init(u8 mode)
|
|||
for (j = 0; j < BATTLER_RECORD_SIZE; j++)
|
||||
sBattleRecords[i][j] = 0xFF;
|
||||
sBattleFlags = gBattleTypeFlags;
|
||||
sAI_Scripts = gBattleResources->ai->aiFlags;
|
||||
sAI_Scripts = gBattleResources->ai->aiFlags[B_POSITION_OPPONENT_LEFT];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
ASSUME(B_PROTEAN_LIBERO == GEN_9);
|
||||
}
|
||||
|
||||
|
@ -45,3 +44,23 @@ SINGLE_BATTLE_TEST("Dauntless Shield raises Attack by one stage only once per ba
|
|||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dauntless Shield activates when it's no longer effected by Neutralizing Gas")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ZAMAZENTA) { Ability(ABILITY_DAUNTLESS_SHIELD); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
|
||||
MESSAGE("Neutralizing Gas filled the area!");
|
||||
MESSAGE("Weezing, that's enough! Come back!");
|
||||
MESSAGE("The effects of Neutralizing Gas wore off!");
|
||||
ABILITY_POPUP(opponent, ABILITY_DAUNTLESS_SHIELD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Zamazenta's Dauntless Shield raised its Defense!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
59
test/battle/ability/embody_aspect.c
Normal file
59
test/battle/ability/embody_aspect.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Embodoy Aspect raises a stat depending on the users form by one stage")
|
||||
{
|
||||
u16 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_TEAL; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_HEARTHFLAME; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_WELLSPRING; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_CORNERSTONE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ability);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
if (ability == ABILITY_EMBODY_ASPECT_TEAL)
|
||||
MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Atk!");
|
||||
else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME)
|
||||
MESSAGE("Foe Ogerpon's Embody Aspect raised its Attack!");
|
||||
else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING)
|
||||
MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Def!");
|
||||
else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE)
|
||||
MESSAGE("Foe Ogerpon's Embody Aspect raised its Defense!");
|
||||
} THEN {
|
||||
if (ability == ABILITY_EMBODY_ASPECT_TEAL)
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME)
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING)
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
|
||||
else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE)
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Embodoy Aspect activates when it's no longer effected by Neutralizing Gas")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_OGERPON_TEAL_MASK_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
|
||||
MESSAGE("Neutralizing Gas filled the area!");
|
||||
MESSAGE("Weezing, that's enough! Come back!");
|
||||
MESSAGE("The effects of Neutralizing Gas wore off!");
|
||||
ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Atk!");
|
||||
}
|
||||
}
|
70
test/battle/ability/hospitality.c
Normal file
70
test/battle/ability/hospitality.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hospitality user restores 25% of ally's health")
|
||||
{
|
||||
s16 health;
|
||||
|
||||
PARAMETRIZE { health = 75; }
|
||||
PARAMETRIZE { health = 100; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_POLTCHAGEIST) { Ability(ABILITY_HOSPITALITY); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(health); MaxHP(100); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
if (health == 75) {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY);
|
||||
MESSAGE("The Wobbuffet drank down all the matcha that Sinistcha made!");
|
||||
HP_BAR(playerRight, damage: -25);
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY);
|
||||
MESSAGE("The Wobbuffet drank down all the matcha that Sinistcha made!");
|
||||
HP_BAR(playerRight, damage: -25);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hospitality user restores 25% of ally's health on switch-in")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET)
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(75); MaxHP(100); }
|
||||
PLAYER(SPECIES_POLTCHAGEIST) { Ability(ABILITY_HOSPITALITY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { SWITCH(playerLeft, 2); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet, that's enough! Come back!");
|
||||
MESSAGE("Go! Ptchageist!");
|
||||
ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY);
|
||||
MESSAGE("The Wobbuffet drank down all the matcha that Sinistcha made!");
|
||||
HP_BAR(playerRight, damage: -25);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hospitality ignores Substitute")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_POLTCHAGEIST) { Ability(ABILITY_HOSPITALITY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_SUBSTITUTE); }
|
||||
TURN { SWITCH(playerLeft, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, playerRight);
|
||||
MESSAGE("Wobbuffet, that's enough! Come back!");
|
||||
MESSAGE("Go! Ptchageist!");
|
||||
ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY);
|
||||
MESSAGE("The Wobbuffet drank down all the matcha that Sinistcha made!");
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
ASSUME(B_INTREPID_SWORD == GEN_9);
|
||||
}
|
||||
|
||||
|
@ -45,3 +44,23 @@ SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage only once per batt
|
|||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Intrepid Sword activates when it's no longer effected by Neutralizing Gas")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
|
||||
MESSAGE("Neutralizing Gas filled the area!");
|
||||
MESSAGE("Weezing, that's enough! Come back!");
|
||||
MESSAGE("The effects of Neutralizing Gas wore off!");
|
||||
ABILITY_POPUP(opponent, ABILITY_INTREPID_SWORD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Zacian's Intrepid Sword raised its Attack!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ SINGLE_BATTLE_TEST("U-turn switches the user out if Wimp Out fails to activate")
|
|||
SINGLE_BATTLE_TEST("U-turn switches the user out after Ice Face activates")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_BEEDRILL);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_EISCUE) { Ability(ABILITY_ICE_FACE); }
|
||||
|
|
Loading…
Reference in a new issue