Helping Hand logic (#7504)
This commit is contained in:
parent
b4826b446c
commit
260b12337e
@ -160,6 +160,7 @@ bool32 AI_IsDamagedByRecoil(u32 battler);
|
||||
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);
|
||||
u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef);
|
||||
u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext);
|
||||
u32 GetBestNoOfHitsToKO(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext);
|
||||
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext);
|
||||
uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef);
|
||||
u16 *GetMovesArray(u32 battler);
|
||||
|
||||
@ -211,7 +211,7 @@ static u64 GetAiFlags(u16 trainerId)
|
||||
flags = GetTrainerAIFlagsFromId(trainerId);
|
||||
}
|
||||
|
||||
if (IsDoubleBattle())
|
||||
if (IsDoubleBattle() && flags != 0)
|
||||
{
|
||||
flags |= AI_FLAG_DOUBLE_BATTLE;
|
||||
}
|
||||
@ -2042,7 +2042,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)
|
||||
|| (aiData->partnerMove != MOVE_NONE && IsBattleMoveStatus(aiData->partnerMove))
|
||||
|| gBattleStruct->monToSwitchIntoId[BATTLE_PARTNER(battlerAtk)] != PARTY_SIZE) //Partner is switching out.
|
||||
ADJUST_SCORE(-10);
|
||||
ADJUST_SCORE(-20);
|
||||
break;
|
||||
case EFFECT_TRICK:
|
||||
case EFFECT_KNOCK_OFF:
|
||||
@ -3030,6 +3030,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetBattleMoveType(move);
|
||||
|
||||
bool32 hasTwoOpponents = HasTwoOpponents(battlerAtk);
|
||||
bool32 hasPartner = HasPartner(battlerAtk);
|
||||
u32 friendlyFireThreshold = GetFriendlyFireKOThreshold(battlerAtk);
|
||||
u32 noOfHitsToKOPartner = GetNoOfHitsToKOBattler(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING);
|
||||
@ -3088,8 +3089,54 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
switch (effect)
|
||||
{
|
||||
case EFFECT_HELPING_HAND:
|
||||
if (!hasPartner || !HasDamagingMove(battlerAtkPartner))
|
||||
ADJUST_SCORE(-20);
|
||||
if (!hasPartner
|
||||
|| !HasDamagingMove(battlerAtkPartner)
|
||||
|| (aiData->partnerMove != MOVE_NONE && IsBattleMoveStatus(aiData->partnerMove)))
|
||||
{
|
||||
ADJUST_SCORE(WORST_EFFECT);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 ownHitsToKOFoe1 = GetBestNoOfHitsToKO(battlerAtk, FOE(battlerAtk), AI_ATTACKING);
|
||||
u32 partnerHitsToKOFoe1 = GetBestNoOfHitsToKO(battlerAtkPartner, FOE(battlerAtk), AI_ATTACKING);
|
||||
u32 ownHitsToKOFoe2 = GetBestNoOfHitsToKO(battlerAtk, FOE(battlerAtkPartner), AI_ATTACKING);
|
||||
u32 partnerHitsToKOFoe2 = GetBestNoOfHitsToKO(battlerAtkPartner, FOE(battlerAtkPartner), AI_ATTACKING);
|
||||
|
||||
if (hasTwoOpponents)
|
||||
{
|
||||
// Might be about to die
|
||||
if (CanTargetFaintAi(FOE(battlerAtk), battlerAtk) && CanTargetFaintAi(FOE(battlerAtkPartner), battlerAtk)
|
||||
&& AI_IsSlower(battlerAtk, FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)
|
||||
&& AI_IsSlower(battlerAtk, FOE(battlerAtkPartner), move, predictedMove, DONT_CONSIDER_PRIORITY))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
|
||||
if (ownHitsToKOFoe1 > partnerHitsToKOFoe1 && partnerHitsToKOFoe1 > 1
|
||||
&& ownHitsToKOFoe2 > partnerHitsToKOFoe2 && partnerHitsToKOFoe2 > 1)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
}
|
||||
else if (IsBattlerAlive(FOE(battlerAtk)))
|
||||
{
|
||||
// Might be about to die
|
||||
if (CanTargetFaintAi(FOE(battlerAtk), battlerAtk)
|
||||
&& AI_IsSlower(battlerAtk, FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
|
||||
if (ownHitsToKOFoe1 > partnerHitsToKOFoe1 && partnerHitsToKOFoe1 > 1)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
}
|
||||
else if (IsBattlerAlive(FOE(battlerAtkPartner)))
|
||||
{
|
||||
// Might be about to die
|
||||
if (CanTargetFaintAi(FOE(battlerAtkPartner), battlerAtk)
|
||||
&& AI_IsSlower(battlerAtk, FOE(battlerAtkPartner), move, predictedMove, DONT_CONSIDER_PRIORITY))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
|
||||
if (ownHitsToKOFoe2 > partnerHitsToKOFoe2 && partnerHitsToKOFoe2 > 1)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case EFFECT_PERISH_SONG:
|
||||
if (aiData->partnerMove != 0 && HasTrappingMoveEffect(battlerAtkPartner))
|
||||
|
||||
@ -1252,6 +1252,29 @@ u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum D
|
||||
return GetNoOfHitsToKOBattlerDmg(AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, gAiLogicData), battlerDef);
|
||||
}
|
||||
|
||||
u32 GetBestNoOfHitsToKO(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext)
|
||||
{
|
||||
u32 result = 100;
|
||||
u32 tempResult = 0;
|
||||
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
s32 moveIndex;
|
||||
u16 *moves = GetMovesArray(battlerAtk);
|
||||
u32 moveLimitations = aiData->moveLimitations[battlerAtk];
|
||||
|
||||
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
|
||||
{
|
||||
if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations))
|
||||
continue;
|
||||
|
||||
tempResult = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, moveIndex, calcContext);
|
||||
if (tempResult != 0 && tempResult < result)
|
||||
result = tempResult;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext)
|
||||
{
|
||||
int bestDmg = AI_GetDamage(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, calcContext, gAiLogicData);
|
||||
|
||||
@ -595,6 +595,43 @@ AI_DOUBLE_BATTLE_TEST("AI uses Trick Room intelligently")
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Helping Hand if it's about to die")
|
||||
{
|
||||
u32 hp;
|
||||
|
||||
PARAMETRIZE { hp = 1; }
|
||||
PARAMETRIZE { hp = 500; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_HELPING_HAND) == EFFECT_HELPING_HAND);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(hp); Moves(MOVE_HELPING_HAND, MOVE_MUDDY_WATER); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_MUDDY_WATER); }
|
||||
} WHEN {
|
||||
if (hp == 1)
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_HELPING_HAND); }
|
||||
else
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_HELPING_HAND); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Helping Hand if the ally does notably more damage")
|
||||
{
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_HELPING_HAND) == EFFECT_HELPING_HAND);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HELPING_HAND, MOVE_MUD_SLAP); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_MUDDY_WATER); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_HELPING_HAND); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Tailwind")
|
||||
{
|
||||
u32 speed1, speed2, speed3, speed4;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user