Skip to content

Commit

Permalink
Use 9th roll instead of average in AI calcs (rh-hideout#4679)
Browse files Browse the repository at this point in the history
* Use 9th roll instead of average in AI calcs

* damage_roll

* duke suggestion
  • Loading branch information
AlexOn1ine authored Jun 2, 2024
1 parent 240b69d commit 4eda5f6
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 12 deletions.
5 changes: 3 additions & 2 deletions include/battle_ai_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)

// Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt.
#define MAX_ROLL_PERCENTAGE DMG_ROLL_PERCENT_HI
#define MAX_ROLL_PERCENTAGE DMG_ROLL_PERCENT_HI
#define MIN_ROLL_PERCENTAGE DMG_ROLL_PERCENT_LO
#define DMG_ROLL_PERCENTAGE ((MAX_ROLL_PERCENTAGE + MIN_ROLL_PERCENTAGE + 1) / 2) // Controls the damage roll the AI sees for the default roll. By default the 9th roll is seen

enum
{
DMG_ROLL_LOWEST,
DMG_ROLL_AVERAGE,
DMG_ROLL_DEFAULT,
DMG_ROLL_HIGHEST,
};

Expand Down
2 changes: 1 addition & 1 deletion src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3
else if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_LOWEST);
else
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_AVERAGE);
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_DEFAULT);
aiData->moveAccuracy[battlerAtk][battlerDef][i] = Ai_SetMoveAccuracy(aiData, battlerAtk, battlerDef, move);
}
aiData->simulatedDmg[battlerAtk][battlerDef][i] = dmg;
Expand Down
4 changes: 2 additions & 2 deletions src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0)
{
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j);
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_AVERAGE);
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_DEFAULT);
if (bestDmg < dmg)
{
bestDmg = dmg;
Expand Down Expand Up @@ -1840,7 +1840,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,

// Only do damage calc if switching after KO, don't need it otherwise and saves ~0.02s per turn
if (isSwitchAfterKO && aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0)
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_AVERAGE);
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_DEFAULT);

// Check for Baton Pass; hitsToKO requirements mean mon can boost and BP without dying whether it's slower or not
if (aiMove == MOVE_BATON_PASS && ((hitsToKOAI > hitsToKOAIThreshold + 1 && AI_DATA->switchinCandidate.battleMon.speed < playerMonSpeed) || (hitsToKOAI > hitsToKOAIThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed)))
Expand Down
14 changes: 7 additions & 7 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,9 +391,9 @@ static inline s32 HighestRollDmg(s32 dmg)
return dmg;
}

static inline s32 AverageDmg(s32 dmg)
static inline s32 DmgRoll(s32 dmg)
{
dmg = (dmg * (MIN_ROLL_PERCENTAGE + MAX_ROLL_PERCENTAGE)) / 2;
dmg *= DMG_ROLL_PERCENTAGE;
dmg /= 100;
return dmg;
}
Expand Down Expand Up @@ -566,17 +566,17 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
u32 critChance = GetCritHitChance(critChanceIndex);
// With critChance getting closer to 1, dmg gets closer to critDmg.
if (dmgRoll == DMG_ROLL_AVERAGE)
dmg = AverageDmg((critDmg + normalDmg * (critChance - 1)) / (critChance));
if (dmgRoll == DMG_ROLL_DEFAULT)
dmg = DmgRoll((critDmg + normalDmg * (critChance - 1)) / (critChance));
else if (dmgRoll == DMG_ROLL_HIGHEST)
dmg = HighestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance));
else
dmg = LowestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance)); // Default to lowest roll
}
else
{
if (dmgRoll == DMG_ROLL_AVERAGE)
dmg = AverageDmg(normalDmg);
if (dmgRoll == DMG_ROLL_DEFAULT)
dmg = DmgRoll(normalDmg);
else if (dmgRoll == DMG_ROLL_HIGHEST)
dmg = HighestRollDmg(normalDmg);
else
Expand Down Expand Up @@ -3763,7 +3763,7 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove)
else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove))
return FALSE;

if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE, DMG_ROLL_AVERAGE) >= gBattleMons[battlerDef].hp)
if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE, DMG_ROLL_DEFAULT) >= gBattleMons[battlerDef].hp)
return FALSE; // don't waste damaging z move if can otherwise faint target

return TRUE;
Expand Down

0 comments on commit 4eda5f6

Please sign in to comment.