rework incoming surviability

This commit is contained in:
DizzyEggg 2023-07-18 11:36:09 +02:00
commit 1bd4f9c7a8
6 changed files with 82 additions and 33 deletions

View File

@ -168,7 +168,7 @@ bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove
bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move); bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move);
// party logic // party logic
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon); s32 AI_CalcPartyMonBestMoveDamage(u32 battlerAtk, u32 battlerDef, struct Pokemon *attackerMon, struct Pokemon *targetMon);
s32 CountUsablePartyMons(u8 battlerId); s32 CountUsablePartyMons(u8 battlerId);
bool32 IsPartyFullyHealedExceptBattler(u8 battler); bool32 IsPartyFullyHealedExceptBattler(u8 battler);
bool32 PartyHasMoveSplit(u8 battlerId, u8 split); bool32 PartyHasMoveSplit(u8 battlerId, u8 split);

View File

@ -28,6 +28,7 @@ static bool8 ShouldUseItem(void);
static bool32 AiExpectsToFaintPlayer(void); static bool32 AiExpectsToFaintPlayer(void);
static bool32 AI_ShouldHeal(u32 healAmount); static bool32 AI_ShouldHeal(u32 healAmount);
static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount); static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount);
static bool32 IsAiPartyMonOHKOBy(u32 battlerAtk, struct Pokemon *aiMon);
static bool32 IsAceMon(u32 battlerId, u32 monPartyId) static bool32 IsAceMon(u32 battlerId, u32 monPartyId)
{ {
@ -753,6 +754,8 @@ void AI_TrySwitchOrUseItem(void)
{ {
if (GetMonData(&party[monToSwitchId], MON_DATA_HP) == 0) if (GetMonData(&party[monToSwitchId], MON_DATA_HP) == 0)
continue; continue;
if (GetMonData(&party[monToSwitchId], MON_DATA_SPECIES) == SPECIES_NONE)
continue;
if (monToSwitchId == gBattlerPartyIndexes[battlerIn1]) if (monToSwitchId == gBattlerPartyIndexes[battlerIn1])
continue; continue;
if (monToSwitchId == gBattlerPartyIndexes[battlerIn2]) if (monToSwitchId == gBattlerPartyIndexes[battlerIn2])
@ -793,6 +796,8 @@ static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u
{ {
if (invalidMons & gBitTable[i]) if (invalidMons & gBitTable[i])
continue; continue;
if (IsAiPartyMonOHKOBy(BATTLE_OPPOSITE(gActiveBattler), &party[i]))
continue;
for (j = 0; j < MAX_MON_MOVES; j++) for (j = 0; j < MAX_MON_MOVES; j++)
{ {
@ -837,6 +842,9 @@ static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId,
u8 defType1 = gSpeciesInfo[species].types[0]; u8 defType1 = gSpeciesInfo[species].types[0];
u8 defType2 = gSpeciesInfo[species].types[1]; u8 defType2 = gSpeciesInfo[species].types[1];
if (IsAiPartyMonOHKOBy(opposingBattler, &party[i]))
continue;
typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType1))); typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType1)));
if (atkType2 != atkType1) if (atkType2 != atkType1)
typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType1))); typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType1)));
@ -881,7 +889,7 @@ static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId,
static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler) static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler)
{ {
int i, j; int i, j;
int bestDmg = 0; int dmg, bestDmg = 0;
int bestMonId = PARTY_SIZE; int bestMonId = PARTY_SIZE;
gMoveResultFlags = 0; gMoveResultFlags = 0;
@ -890,21 +898,16 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
{ {
if (gBitTable[i] & invalidMons) if (gBitTable[i] & invalidMons)
continue; continue;
if (IsAiPartyMonOHKOBy(opposingBattler, &party[i]))
continue;
for (j = 0; j < MAX_MON_MOVES; j++) dmg = AI_CalcPartyMonBestMoveDamage(gActiveBattler, opposingBattler, &party[i], NULL);
{
u32 move = GetMonData(&party[i], MON_DATA_MOVE1 + j);
if (move != MOVE_NONE && gBattleMoves[move].power != 0)
{
s32 dmg = AI_CalcPartyMonDamage(move, gActiveBattler, opposingBattler, &party[i]);
if (bestDmg < dmg) if (bestDmg < dmg)
{ {
bestDmg = dmg; bestDmg = dmg;
bestMonId = i; bestMonId = i;
} }
} }
}
}
return bestMonId; return bestMonId;
} }
@ -912,7 +915,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
u8 GetMostSuitableMonToSwitchInto(void) u8 GetMostSuitableMonToSwitchInto(void)
{ {
u32 opposingBattler = 0; u32 opposingBattler = 0;
u32 bestMonId = 0; u32 bestMonId = PARTY_SIZE;
u8 battlerIn1 = 0, battlerIn2 = 0; u8 battlerIn1 = 0, battlerIn2 = 0;
s32 firstId = 0; s32 firstId = 0;
s32 lastId = 0; // + 1 s32 lastId = 0; // + 1
@ -1155,3 +1158,20 @@ static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount)
} }
return FALSE; return FALSE;
} }
static bool32 IsAiPartyMonOHKOBy(u32 battlerAtk, struct Pokemon *aiMon)
{
struct BattlePokemon *battleMon;
s32 hp = GetMonData(aiMon, MON_DATA_HP);
s32 bestDmg = AI_CalcPartyMonBestMoveDamage(battlerAtk, gActiveBattler, NULL, aiMon);
switch (GetNoOfHitsToKO(bestDmg, hp))
{
case 1:
return TRUE;
case 2: // TODO: Compare speeds, if AI mon is faster allow 2 turns
return TRUE;
}
return FALSE;
}

View File

@ -3369,24 +3369,40 @@ bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move)
} }
// party logic // party logic
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon) s32 AI_CalcPartyMonBestMoveDamage(u32 battlerAtk, u32 battlerDef, struct Pokemon *attackerMon, struct Pokemon *targetMon)
{ {
s32 dmg; s32 bestDmg, dmg;
u32 i; u32 i, move;
u8 effectiveness; u8 effectiveness;
struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT); struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT);
for (i = 0; i < MAX_BATTLERS_COUNT; i++) for (i = 0; i < MAX_BATTLERS_COUNT; i++)
battleMons[i] = gBattleMons[i]; battleMons[i] = gBattleMons[i];
PokemonToBattleMon(mon, &gBattleMons[battlerAtk]); if (attackerMon != NULL)
PokemonToBattleMon(attackerMon, &gBattleMons[battlerAtk]);
if (targetMon != NULL)
PokemonToBattleMon(targetMon, &gBattleMons[battlerDef]);
for (bestDmg = 0, i = 0; i < MAX_MON_MOVES; i++)
{
if (BattlerHasAi(battlerAtk))
move = GetMonData(attackerMon, MON_DATA_MOVE1 + i);
else
move = AI_PARTY->mons[GET_BATTLER_SIDE2(battlerAtk)][gBattlerPartyIndexes[battlerAtk]].moves[i];
if (move != MOVE_NONE && gBattleMoves[move].power != 0)
{
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE); dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE);
if (dmg > bestDmg)
bestDmg = dmg;
}
}
for (i = 0; i < MAX_BATTLERS_COUNT; i++) for (i = 0; i < MAX_BATTLERS_COUNT; i++)
gBattleMons[i] = battleMons[i]; gBattleMons[i] = battleMons[i];
Free(battleMons); Free(battleMons);
return dmg; return dmg;
} }

View File

@ -1688,7 +1688,6 @@ static void OpponentHandleChoosePokemon(void)
else if (*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) == PARTY_SIZE) else if (*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) == PARTY_SIZE)
{ {
chosenMonId = GetMostSuitableMonToSwitchInto(); chosenMonId = GetMostSuitableMonToSwitchInto();
if (chosenMonId == PARTY_SIZE) if (chosenMonId == PARTY_SIZE)
{ {
s32 battler1, battler2, firstId, lastId; s32 battler1, battler2, firstId, lastId;
@ -1702,7 +1701,6 @@ static void OpponentHandleChoosePokemon(void)
battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
pokemonInBattle = 2; pokemonInBattle = 2;
} }
GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); GetAIPartyIndexes(gActiveBattler, &firstId, &lastId);
@ -1710,6 +1708,7 @@ static void OpponentHandleChoosePokemon(void)
for (chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--) for (chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--)
{ {
if (GetMonData(&gEnemyParty[chosenMonId], MON_DATA_HP) != 0 if (GetMonData(&gEnemyParty[chosenMonId], MON_DATA_HP) != 0
&& GetMonData(&gEnemyParty[chosenMonId], MON_DATA_SPECIES) != SPECIES_NONE
&& chosenMonId != gBattlerPartyIndexes[battler1] && chosenMonId != gBattlerPartyIndexes[battler1]
&& chosenMonId != gBattlerPartyIndexes[battler2] && chosenMonId != gBattlerPartyIndexes[battler2]
&& (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_ACE_POKEMON) && (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_ACE_POKEMON)

View File

@ -3366,25 +3366,39 @@ static const struct TrainerMonItemCustomMoves sParty_Drake[] = {
static const struct TrainerMonItemCustomMoves sParty_Roxanne1[] = { static const struct TrainerMonItemCustomMoves sParty_Roxanne1[] = {
{ {
.iv = 100, .iv = 46,
.lvl = 12, .lvl = 46,
.species = SPECIES_GEODUDE, .species = SPECIES_SKARMORY,
.heldItem = ITEM_NONE, .heldItem = ITEM_NONE,
.moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_ROCK_THROW, MOVE_ROCK_TOMB} .moves = {MOVE_SPIKES, MOVE_TOXIC, MOVE_WHIRLWIND, MOVE_ROOST}
}, },
{ {
.iv = 100, .iv = 100,
.lvl = 12, .lvl = 46,
.species = SPECIES_GEODUDE, .species = SPECIES_TROPIUS,
.heldItem = ITEM_NONE, .heldItem = ITEM_NONE,
.moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_ROCK_THROW, MOVE_ROCK_TOMB} .moves = {MOVE_LEAF_TORNADO, MOVE_BODY_SLAM, MOVE_PROTECT, MOVE_ROOST}
},
{
.iv = 47,
.lvl = 47,
.species = SPECIES_HAWLUCHA,
.heldItem = ITEM_ORAN_BERRY,
.moves = {MOVE_SUPERPOWER, MOVE_ACROBATICS, MOVE_U_TURN, MOVE_ROOST}
},
{
.iv = 47,
.lvl = 47,
.species = SPECIES_MANTINE,
.heldItem = ITEM_ORAN_BERRY,
.moves = {MOVE_CONFUSE_RAY, MOVE_WATER_PULSE, MOVE_AIR_SLASH, MOVE_ROOST}
}, },
{ {
.iv = 200, .iv = 200,
.lvl = 15, .lvl = 48,
.species = SPECIES_NOSEPASS, .species = SPECIES_ALTARIA,
.heldItem = ITEM_ORAN_BERRY, .heldItem = ITEM_ORAN_BERRY,
.moves = {MOVE_BLOCK, MOVE_HARDEN, MOVE_TACKLE, MOVE_ROCK_TOMB} .moves = {MOVE_DRAGON_PULSE, MOVE_TOXIC, MOVE_COTTON_GUARD, MOVE_ROOST}
} }
}; };

View File

@ -3189,7 +3189,7 @@ const struct Trainer gTrainers[] = {
.trainerName = _("ROXANNE"), .trainerName = _("ROXANNE"),
.items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE}, .items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE},
.doubleBattle = FALSE, .doubleBattle = FALSE,
.aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY,
.party = ITEM_CUSTOM_MOVES(sParty_Roxanne1), .party = ITEM_CUSTOM_MOVES(sParty_Roxanne1),
}, },