Fix Forewarn edge cases and random selection (#9049)

This commit is contained in:
GGbond 2026-01-29 20:54:28 +08:00 committed by GitHub
parent dd21d8fae4
commit 4198a5cb85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 118 additions and 6 deletions

View File

@ -167,6 +167,7 @@ enum RandomTag
RNG_QUICK_DRAW,
RNG_QUICK_CLAW,
RNG_TRACE,
RNG_FOREWARN,
RNG_FICKLE_BEAM,
RNG_AI_ABILITY,
RNG_AI_SWITCH_HASBADODDS,

View File

@ -3335,12 +3335,43 @@ static void ForewarnChooseMove(u32 battler)
}
}
for (bestId = 0, i = 1; i < count; i++)
if (count == 0)
{
if (data[i].power > data[bestId].power)
bestId = i;
else if (data[i].power == data[bestId].power && Random() & 1)
Free(data);
return;
}
u32 tieCount = 1;
u8 bestPower = data[0].power;
bestId = 0;
for (i = 1; i < count; i++)
{
if (data[i].power > bestPower)
{
bestPower = data[i].power;
bestId = i;
tieCount = 1;
}
else if (data[i].power == bestPower)
{
tieCount++;
}
}
if (tieCount > 1)
{
u32 tieIndex = RandomUniform(RNG_FOREWARN, 0, tieCount - 1);
for (i = 0, bestId = 0; i < count; i++)
{
if (data[i].power != bestPower)
continue;
if (tieIndex-- == 0)
{
bestId = i;
break;
}
}
}
gEffectBattler = data[bestId].battler;
@ -4155,7 +4186,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
return effect; // Note: It returns effect as to not record the ability if Frisk does not activate.
case ABILITY_FOREWARN:
if (!gSpecialStatuses[battler].switchInAbilityDone)
if (!gSpecialStatuses[battler].switchInAbilityDone && !IsOpposingSideEmpty(battler))
{
ForewarnChooseMove(battler);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_FOREWARN;

View File

@ -1,4 +1,84 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Forewarn (Ability) test titles")
DOUBLE_BATTLE_TEST("Forewarn warns about the highest power move among all opposing battlers")
{
GIVEN {
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_ZUBAT) { Moves(MOVE_CRUNCH, MOVE_CELEBRATE); }
OPPONENT(SPECIES_EXCADRILL) { Moves(MOVE_FISSURE, MOVE_CELEBRATE); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
MESSAGE("Forewarn alerted Musharna to the opposing Excadrill's Fissure!");
}
}
SINGLE_BATTLE_TEST("Forewarn randomly chooses between same-power moves on one opponent")
{
PASSES_RANDOMLY(1, 3, RNG_FOREWARN);
GIVEN {
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_POUND));
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_SCRATCH));
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
OPPONENT(SPECIES_ZUBAT) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_CELEBRATE); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(player, ABILITY_FOREWARN);
MESSAGE("Forewarn alerted Musharna to the opposing Zubat's Tackle!");
}
}
DOUBLE_BATTLE_TEST("Forewarn randomly chooses between opponents with same-power moves")
{
PASSES_RANDOMLY(1, 4, RNG_FOREWARN);
GIVEN {
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_POUND));
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_SCRATCH));
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_QUICK_ATTACK));
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_ZUBAT) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_PECK, MOVE_CELEBRATE); }
OPPONENT(SPECIES_EXCADRILL) { Moves(MOVE_SCRATCH, MOVE_QUICK_ATTACK, MOVE_ABSORB, MOVE_CELEBRATE); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
MESSAGE("Forewarn alerted Musharna to the opposing Zubat's Tackle!");
}
}
DOUBLE_BATTLE_TEST("Forewarn does not trigger if a mon switches in while the opposing field is empty")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE);
ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
OPPONENT(SPECIES_WYNAUT) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_TREECKO);
OPPONENT(SPECIES_TORCHIC);
} WHEN {
TURN {
MOVE(opponentRight, MOVE_HEALING_WISH);
MOVE(playerLeft, MOVE_U_TURN, target: opponentLeft);
SEND_OUT(playerLeft, 2);
SEND_OUT(opponentLeft, 2);
SEND_OUT(opponentRight, 3);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft);
HP_BAR(opponentLeft);
NOT ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
MESSAGE("2 sent out Treecko!");
MESSAGE("2 sent out Torchic!");
NOT ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
}
}