Adds RNG tags and tests for Moody and Starf Berry (#6718)
This commit is contained in:
parent
d2a4b5ef84
commit
fadf472157
@ -311,6 +311,8 @@ bool32 IsMoveEffectRemoveSpeciesType(u32 move, u32 moveEffect, u32 argument);
|
||||
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
||||
bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 MoodyCantRaiseStat(u32 stat);
|
||||
bool32 MoodyCantLowerStat(u32 stat);
|
||||
|
||||
bool32 CanBeSlept(u32 battler, u32 ability, enum SleepClauseBlock isBlockedBySleepClause);
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
|
||||
@ -12,6 +12,7 @@ enum GenConfigTag
|
||||
GEN_CONFIG_GALE_WINGS,
|
||||
GEN_CONFIG_HEAL_BELL_SOUNDPROOF,
|
||||
GEN_CONFIG_TELEPORT_BEHAVIOR,
|
||||
GEN_CONFIG_MOODY_STATS,
|
||||
GEN_CONFIG_COUNT
|
||||
};
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
|
||||
[GEN_CONFIG_GALE_WINGS] = B_GALE_WINGS,
|
||||
[GEN_CONFIG_HEAL_BELL_SOUNDPROOF] = B_HEAL_BELL_SOUNDPROOF,
|
||||
[GEN_CONFIG_TELEPORT_BEHAVIOR] = B_TELEPORT_BEHAVIOR,
|
||||
[GEN_CONFIG_MOODY_STATS] = B_MOODY_ACC_EVASION,
|
||||
};
|
||||
|
||||
#if TESTING
|
||||
|
||||
@ -146,11 +146,14 @@ enum RandomTag
|
||||
RNG_INFATUATION,
|
||||
RNG_LOADED_DICE,
|
||||
RNG_METRONOME,
|
||||
RNG_MOODY_INCREASE,
|
||||
RNG_MOODY_DECREASE,
|
||||
RNG_PARALYSIS,
|
||||
RNG_PICKUP,
|
||||
RNG_POISON_POINT,
|
||||
RNG_POISON_TOUCH,
|
||||
RNG_RAMPAGE_TURNS,
|
||||
RNG_RANDOM_STAT_UP,
|
||||
RNG_SECONDARY_EFFECT,
|
||||
RNG_SECONDARY_EFFECT_2,
|
||||
RNG_SECONDARY_EFFECT_3,
|
||||
|
||||
@ -1604,6 +1604,18 @@ u32 GetBattlerAffectionHearts(u32 battler)
|
||||
return GetMonAffectionHearts(&party[gBattlerPartyIndexes[battler]]);
|
||||
}
|
||||
|
||||
// gBattlerAttacker is the battler that's trying to raise their stats and due to limitations of RandomUniformExcept, cannot be an argument
|
||||
bool32 MoodyCantRaiseStat(u32 stat)
|
||||
{
|
||||
return CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_EQUAL);
|
||||
}
|
||||
|
||||
// gBattlerAttacker is the battler that's trying to lower their stats and due to limitations of RandomUniformExcept, cannot be an argument
|
||||
bool32 MoodyCantLowerStat(u32 stat)
|
||||
{
|
||||
return stat == GET_STAT_BUFF_ID(gBattleScripting.statChanger) || CompareStat(gBattlerAttacker, stat, MIN_STAT_STAGE, CMP_EQUAL);
|
||||
}
|
||||
|
||||
void TryToRevertMimicryAndFlags(void)
|
||||
{
|
||||
u32 i;
|
||||
@ -5469,7 +5481,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (gDisableStructs[battler].isFirstTurn != 2)
|
||||
{
|
||||
u32 validToRaise = 0, validToLower = 0;
|
||||
u32 statsNum = B_MOODY_ACC_EVASION >= GEN_8 ? NUM_STATS : NUM_BATTLE_STATS;
|
||||
u32 statsNum = GetGenConfig(GEN_CONFIG_MOODY_STATS) >= GEN_8 ? NUM_STATS : NUM_BATTLE_STATS;
|
||||
|
||||
for (i = STAT_ATK; i < statsNum; i++)
|
||||
{
|
||||
@ -5479,29 +5491,21 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
validToRaise |= 1u << i;
|
||||
}
|
||||
|
||||
if (validToLower != 0 || validToRaise != 0) // Can lower one stat, or can raise one stat
|
||||
gBattleScripting.statChanger = gBattleScripting.savedStatChanger = 0; // for raising and lowering stat respectively
|
||||
if (validToRaise) // Find stat to raise
|
||||
{
|
||||
gBattleScripting.statChanger = gBattleScripting.savedStatChanger = 0; // for raising and lowering stat respectively
|
||||
if (validToRaise != 0) // Find stat to raise
|
||||
{
|
||||
do
|
||||
{
|
||||
i = (Random() % statsNum) + STAT_ATK;
|
||||
} while (!(validToRaise & (1u << i)));
|
||||
SET_STATCHANGER(i, 2, FALSE);
|
||||
validToLower &= ~(1u << i); // Can't lower the same stat as raising.
|
||||
}
|
||||
if (validToLower != 0) // Find stat to lower
|
||||
{
|
||||
do
|
||||
{
|
||||
i = (Random() % statsNum) + STAT_ATK;
|
||||
} while (!(validToLower & (1u << i)));
|
||||
SET_STATCHANGER2(gBattleScripting.savedStatChanger, i, 1, TRUE);
|
||||
}
|
||||
BattleScriptPushCursorAndCallback(BattleScript_MoodyActivates);
|
||||
effect++;
|
||||
i = RandomUniformExcept(RNG_MOODY_INCREASE, STAT_ATK, statsNum - 1, MoodyCantRaiseStat);
|
||||
SET_STATCHANGER(i, 2, FALSE);
|
||||
validToLower &= ~(1u << i); // Can't lower the same stat as raising.
|
||||
}
|
||||
if (validToLower) // Find stat to lower
|
||||
{
|
||||
// MoodyCantLowerStat already checks that both stats are different
|
||||
i = RandomUniformExcept(RNG_MOODY_DECREASE, STAT_ATK, statsNum - 1, MoodyCantLowerStat);
|
||||
SET_STATCHANGER2(gBattleScripting.savedStatChanger, i, 1, TRUE);
|
||||
}
|
||||
BattleScriptPushCursorAndCallback(BattleScript_MoodyActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_TRUANT:
|
||||
@ -6976,23 +6980,24 @@ static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, u32 statId, enum
|
||||
|
||||
static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, enum ItemCaseId caseID)
|
||||
{
|
||||
s32 i;
|
||||
s32 stat;
|
||||
u16 stringId;
|
||||
|
||||
for (i = 0; i < NUM_STATS - 1; i++)
|
||||
for (stat = STAT_ATK; stat < NUM_STATS; stat++)
|
||||
{
|
||||
if (CompareStat(battler, STAT_ATK + i, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
break;
|
||||
}
|
||||
if (i != NUM_STATS - 1 && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId))
|
||||
if (stat != NUM_STATS && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId))
|
||||
{
|
||||
u16 battlerAbility = GetBattlerAbility(battler);
|
||||
do
|
||||
{
|
||||
i = Random() % (NUM_STATS - 1);
|
||||
} while (!CompareStat(battler, STAT_ATK + i, MAX_STAT_STAGE, CMP_LESS_THAN));
|
||||
u32 savedAttacker = gBattlerAttacker;
|
||||
// MoodyCantRaiseStat requires that the battler is set to gBattlerAttacker
|
||||
gBattlerAttacker = battler;
|
||||
stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantRaiseStat);
|
||||
gBattlerAttacker = savedAttacker;
|
||||
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, i + 1);
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, stat);
|
||||
stringId = (battlerAbility == ABILITY_CONTRARY) ? STRINGID_STATFELL : STRINGID_STATROSE;
|
||||
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
|
||||
gBattleTextBuff2[1] = B_BUFF_STRING;
|
||||
@ -7004,11 +7009,11 @@ static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, enum ItemCa
|
||||
gBattleTextBuff2[7] = EOS;
|
||||
gEffectBattler = battler;
|
||||
if (battlerAbility == ABILITY_RIPEN)
|
||||
SET_STATCHANGER(i + 1, 4, FALSE);
|
||||
SET_STATCHANGER(stat, 4, FALSE);
|
||||
else
|
||||
SET_STATCHANGER(i + 1, 2, FALSE);
|
||||
SET_STATCHANGER(stat, 2, FALSE);
|
||||
|
||||
gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + i + 1;
|
||||
gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + stat;
|
||||
gBattleScripting.animArg2 = 0;
|
||||
if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL)
|
||||
{
|
||||
|
||||
76
test/battle/ability/moody.c
Normal file
76
test/battle/ability/moody.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Moody randomly raises the user's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages")
|
||||
{
|
||||
u32 config, statsNum;
|
||||
|
||||
PARAMETRIZE { config = GEN_8; statsNum = NUM_STATS; }
|
||||
PARAMETRIZE { config = GEN_7; statsNum = NUM_BATTLE_STATS; }
|
||||
|
||||
// HP is not included
|
||||
PASSES_RANDOMLY(1, statsNum - 1, RNG_MOODY_INCREASE);
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_MOODY_STATS, config);
|
||||
PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_MOODY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_MOODY);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Octillery's Attack sharply rose!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Moody randomly lowers the user's Attack, Defense, Sp. Atk, Sp. Def, or Speed by one stage")
|
||||
{
|
||||
u32 config, statsNum;
|
||||
|
||||
PARAMETRIZE { config = GEN_8; statsNum = NUM_STATS; }
|
||||
PARAMETRIZE { config = GEN_7; statsNum = NUM_BATTLE_STATS; }
|
||||
|
||||
// One stat becomes unavailable due to it already increasing
|
||||
PASSES_RANDOMLY(1, statsNum - 2, RNG_MOODY_DECREASE);
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_MOODY_STATS, config);
|
||||
PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_MOODY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_MOODY);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Octillery's Attack fell!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Moody randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages and lowers a different stat by one stage")
|
||||
{
|
||||
u32 config, statsNum;
|
||||
|
||||
PARAMETRIZE { config = GEN_8; statsNum = NUM_STATS; }
|
||||
PARAMETRIZE { config = GEN_7; statsNum = NUM_BATTLE_STATS; }
|
||||
|
||||
PASSES_RANDOMLY(statsNum - 1, statsNum - 1, RNG_MOODY_DECREASE);
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_MOODY_STATS, config);
|
||||
PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_MOODY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_MOODY);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
for (int stat = STAT_ATK; stat < statsNum; stat++)
|
||||
EXPECT_NE(player->statStages[stat], DEFAULT_STAT_STAGE + 1); // Both raised and lowered
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,101 @@ ASSUMPTIONS
|
||||
ASSUME(gItemsInfo[ITEM_STARF_BERRY].holdEffect == HOLD_EFFECT_RANDOM_STAT_UP);
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages when the holder's HP drop to 1/4 or below")
|
||||
TO_DO_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages when the holder's HP drop to 1/2 or below if it has Gluttony")
|
||||
TO_DO_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by four stages when the holder's HP drop to 1/4 or below if it has Riped")
|
||||
SINGLE_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages")
|
||||
{
|
||||
PASSES_RANDOMLY(1, 5, RNG_RANDOM_STAT_UP);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_STARF_BERRY); HP(100); MaxHP(400); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Using Starf Berry, the Attack of Wobbuffet sharply rose!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages when the holder's HP drop to 1/4 or below")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_STARF_BERRY); HP(101); MaxHP(400); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
int boostedStats = 0;
|
||||
EXPECT_EQ(player->item, ITEM_NONE);
|
||||
EXPECT_LE(player->hp * 4, player->maxHP);
|
||||
for (int stat = STAT_ATK; stat < NUM_STATS; stat++)
|
||||
{
|
||||
if (player->statStages[stat] == DEFAULT_STAT_STAGE + 2)
|
||||
boostedStats++;
|
||||
else
|
||||
EXPECT_EQ(player->statStages[stat], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
EXPECT_EQ(boostedStats, 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by two stages when the holder's HP drop to 1/2 or below if it has Gluttony")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_STARF_BERRY); HP(201); MaxHP(400); Ability(ABILITY_GLUTTONY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
int boostedStats = 0;
|
||||
EXPECT_EQ(player->item, ITEM_NONE);
|
||||
EXPECT_LE(player->hp * 2, player->maxHP);
|
||||
for (int stat = STAT_ATK; stat < NUM_STATS; stat++)
|
||||
{
|
||||
if (player->statStages[stat] == DEFAULT_STAT_STAGE + 2)
|
||||
boostedStats++;
|
||||
else
|
||||
EXPECT_EQ(player->statStages[stat], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
EXPECT_EQ(boostedStats, 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Starf Berry randomly raises the holder's Attack, Defense, Sp. Atk, Sp. Def, or Speed by four stages when the holder's HP drop to 1/4 or below if it has Ripen")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_FLAPPLE) { Item(ITEM_STARF_BERRY); HP(101); MaxHP(400); Ability(ABILITY_RIPEN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player);
|
||||
ABILITY_POPUP(player, ABILITY_RIPEN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
int boostedStats = 0;
|
||||
EXPECT_EQ(player->item, ITEM_NONE);
|
||||
EXPECT_LE(player->hp * 4, player->maxHP);
|
||||
for (int stat = STAT_ATK; stat < NUM_STATS; stat++)
|
||||
{
|
||||
if (player->statStages[stat] == DEFAULT_STAT_STAGE + 4)
|
||||
boostedStats++;
|
||||
else
|
||||
EXPECT_EQ(player->statStages[stat], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
EXPECT_EQ(boostedStats, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user