Add Struggle tests, weakness berry tests and prevent Struggle from activating Silk Scarf and Chilan Berry (#7880)

This commit is contained in:
Raymond Dodge 2025-10-08 10:03:20 -04:00 committed by GitHub
parent 4d12c35eb3
commit c455665115
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 291 additions and 5 deletions

View File

@ -5862,11 +5862,11 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState
enum ItemHoldEffect holdEffect;
enum Gimmick gimmick = GetActiveGimmick(battler);
if (move == MOVE_STRUGGLE)
return TYPE_NORMAL;
if (state == MON_IN_BATTLE)
{
if (moveEffect == EFFECT_STRUGGLE)
return TYPE_MYSTERY;
species = gBattleMons[battler].species;
heldItem = gBattleMons[battler].item;
holdEffect = GetBattlerHoldEffect(battler, TRUE);
@ -6119,8 +6119,7 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler)
&& GetBattleMoveType(move) == GetItemSecondaryId(heldItem)
&& effect != EFFECT_PLEDGE
&& effect != EFFECT_OHKO
&& effect != EFFECT_SHEER_COLD
&& effect != EFFECT_STRUGGLE)
&& effect != EFFECT_SHEER_COLD)
{
gSpecialStatuses[battler].gemParam = GetBattlerHoldEffectParam(battler);
gSpecialStatuses[battler].gemBoost = TRUE;

View File

@ -153,3 +153,23 @@ SINGLE_BATTLE_TEST("Color Change changes the type to Normal when a Pokemon is hi
MESSAGE("The opposing Kecleon's Color Change made it the Normal type!");
}
}
SINGLE_BATTLE_TEST("Color Change does not change the type to Normal when a Pokemon is hit by Struggle")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_SOAK); }
TURN { MOVE(player, MOVE_STRUGGLE); }
TURN { }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SOAK, player);
MESSAGE("The opposing Kecleon transformed into the Water type!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("The opposing Kecleon's Color Change made it the Normal type!");
}
}
}

View File

@ -54,3 +54,19 @@ SINGLE_BATTLE_TEST("Protean changes the type of the user only once per switch in
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent);
}
}
SINGLE_BATTLE_TEST("Protean does not change the user's type when using Struggle")
{
GIVEN {
PLAYER(SPECIES_REGIROCK);
OPPONENT(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); }
} WHEN {
TURN { MOVE(opponent, MOVE_STRUGGLE); }
} SCENE {
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_PROTEAN);
MESSAGE("The opposing Greninja transformed into the Normal type!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent);
}
}

View File

@ -26,6 +26,34 @@ SINGLE_BATTLE_TEST("Gem is consumed when it corresponds to the type of a move")
}
}
SINGLE_BATTLE_TEST("Gem is not consumed when using Struggle", s16 damage)
{
u32 item = 0;
PARAMETRIZE { item = ITEM_NONE; }
PARAMETRIZE { item = ITEM_NORMAL_GEM; }
GIVEN {
if (item != ITEM_NONE) {
ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_GEMS);
ASSUME(GetItemSecondaryId(item) == GetMoveType(MOVE_STRUGGLE));
}
PLAYER(SPECIES_WOBBUFFET) { Item(item); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_STRUGGLE); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("The Normal Gem strengthened Wobbuffet's power!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}
SINGLE_BATTLE_TEST("Gem boost is only applied once")
{
s16 boostedHit;

View File

@ -53,3 +53,27 @@ SINGLE_BATTLE_TEST("Type-enhancing items increase the base power of moves by 20%
}
}
}
SINGLE_BATTLE_TEST("Type-enhancing items do not increase the power of Struggle", s16 damage)
{
u32 item = 0;
PARAMETRIZE { item = ITEM_NONE; }
PARAMETRIZE { item = ITEM_SILK_SCARF; }
GIVEN {
if (item != ITEM_NONE) {
ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_TYPE_POWER);
ASSUME(GetItemSecondaryId(item) == GetMoveType(MOVE_STRUGGLE));
}
PLAYER(SPECIES_WOBBUFFET) { Item(item); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_STRUGGLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}

View File

@ -0,0 +1,124 @@
#include "global.h"
#include "test/battle.h"
static const u16 sMoveItemTable[][4] =
{
{ TYPE_NORMAL, MOVE_SCRATCH, ITEM_CHILAN_BERRY, SPECIES_WOBBUFFET },
{ TYPE_FIGHTING, MOVE_KARATE_CHOP, ITEM_CHOPLE_BERRY, SPECIES_RAMPARDOS },
{ TYPE_FLYING, MOVE_WING_ATTACK, ITEM_COBA_BERRY, SPECIES_HARIYAMA },
{ TYPE_POISON, MOVE_POISON_STING, ITEM_KEBIA_BERRY, SPECIES_GOGOAT },
{ TYPE_GROUND, MOVE_MUD_SHOT, ITEM_SHUCA_BERRY, SPECIES_RAMPARDOS },
{ TYPE_ROCK, MOVE_ROCK_THROW, ITEM_CHARTI_BERRY, SPECIES_CORVISQUIRE },
{ TYPE_BUG, MOVE_BUG_BITE, ITEM_TANGA_BERRY, SPECIES_WOBBUFFET },
{ TYPE_GHOST, MOVE_SHADOW_PUNCH, ITEM_KASIB_BERRY, SPECIES_WOBBUFFET },
{ TYPE_STEEL, MOVE_METAL_CLAW, ITEM_BABIRI_BERRY, SPECIES_RAMPARDOS },
{ TYPE_FIRE, MOVE_EMBER, ITEM_OCCA_BERRY, SPECIES_GOGOAT },
{ TYPE_WATER, MOVE_WATER_GUN, ITEM_PASSHO_BERRY, SPECIES_RAMPARDOS },
{ TYPE_GRASS, MOVE_VINE_WHIP, ITEM_RINDO_BERRY, SPECIES_RAMPARDOS },
{ TYPE_ELECTRIC, MOVE_THUNDER_SHOCK, ITEM_WACAN_BERRY, SPECIES_CORVISQUIRE },
{ TYPE_PSYCHIC, MOVE_CONFUSION, ITEM_PAYAPA_BERRY, SPECIES_HARIYAMA },
{ TYPE_ICE, MOVE_AURORA_BEAM, ITEM_YACHE_BERRY, SPECIES_DRAGONAIR },
{ TYPE_DRAGON, MOVE_DRAGON_BREATH, ITEM_HABAN_BERRY, SPECIES_DRAGONAIR },
{ TYPE_DARK, MOVE_BITE, ITEM_COLBUR_BERRY, SPECIES_WOBBUFFET },
{ TYPE_FAIRY, MOVE_DISARMING_VOICE, ITEM_ROSELI_BERRY, SPECIES_DRAGONAIR },
};
SINGLE_BATTLE_TEST("Weakness berries decrease the base power of moves by half", s16 damage)
{
u32 move = 0, item = 0, type = 0, defender = 0;
for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++)
{
PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; defender = sMoveItemTable[j][3]; item = ITEM_NONE; }
PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; defender = sMoveItemTable[j][3]; item = sMoveItemTable[j][2]; }
}
GIVEN {
ASSUME(GetMovePower(move) > 0);
ASSUME(GetMoveType(move) == type);
ASSUME(GetSpeciesType(defender, 0) == GetSpeciesType(defender, 1));
if (type != TYPE_NORMAL) {
ASSUME(gTypeEffectivenessTable[type][GetSpeciesType(defender, 0)] > UQ_4_12(1.0));
}
if (item != ITEM_NONE) {
ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_RESIST_BERRY);
ASSUME(GetItemHoldEffectParam(item) == type);
}
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(defender) { Item(item); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
if (1 == i % 2) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
}
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++) {
EXPECT_MUL_EQ(results[j*2].damage, Q_4_12(0.5), results[(j*2)+1].damage);
}
}
}
SINGLE_BATTLE_TEST("Weakness berries do not activate unless a move is super effective", s16 damage)
{
u32 move = 0, item = 0, type = 0, defender = 0;
for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++)
{
if (TYPE_NORMAL == type)
{
// ITEM_CHILAN_BERRY activates without a weakness
}
else if (TYPE_FAIRY == type)
{
PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; item = sMoveItemTable[j][2]; defender = SPECIES_WOBBUFFET; }
}
else
{
PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; item = sMoveItemTable[j][2]; defender = SPECIES_SABLEYE; }
}
}
GIVEN {
ASSUME(GetMovePower(move) > 0);
ASSUME(uq4_12_multiply(gTypeEffectivenessTable[type][GetSpeciesType(defender, 0)],
gTypeEffectivenessTable[type][GetSpeciesType(defender, 1)]) <= UQ_4_12(1.0));
ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_RESIST_BERRY);
ASSUME(GetItemHoldEffectParam(item) == type);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(defender) { Item(item); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
}
}
SINGLE_BATTLE_TEST("Weakness berries do not decrease the power of Struggle", s16 damage)
{
u32 item = 0;
PARAMETRIZE { item = ITEM_NONE; }
PARAMETRIZE { item = ITEM_CHILAN_BERRY; }
GIVEN {
if (item != ITEM_NONE) {
ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_RESIST_BERRY);
ASSUME(GetItemHoldEffectParam(item) == TYPE_NORMAL);
}
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(item); }
} WHEN {
TURN { MOVE(player, MOVE_STRUGGLE); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
MESSAGE("The Chilan Berry weakened the damage to the opposing Wobbuffet!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}

View File

@ -0,0 +1,75 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("Struggle deals recoil 1/4 of damage dealt (Gen 2-3)")
SINGLE_BATTLE_TEST("Struggle deals recoil 1/4 of user's hp (Gen 4+)")
{
ASSUME(GetMoveEffect(MOVE_STRUGGLE) == EFFECT_STRUGGLE);
s16 recoil;
u32 atkStat = 0;
u32 hpStat = 0;
PARAMETRIZE { atkStat = 100; hpStat = 200; }
PARAMETRIZE { atkStat = 50; hpStat = 200; }
PARAMETRIZE { atkStat = 100; hpStat = 300; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { MaxHP(hpStat); HP(hpStat); Attack(atkStat); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_STRUGGLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
HP_BAR(player, captureDamage: &recoil);
} THEN {
EXPECT_MUL_EQ(hpStat, Q_4_12(0.25), recoil);
}
}
SINGLE_BATTLE_TEST("Struggle can hit ghost types")
{
ASSUME(GetSpeciesType(SPECIES_DRIFBLIM, 0) == TYPE_GHOST);
s16 damage;
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_DRIFBLIM);
} WHEN {
TURN { MOVE(player, MOVE_STRUGGLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
HP_BAR(opponent, captureDamage: &damage);
} THEN {
EXPECT_NE(0, damage);
}
}
SINGLE_BATTLE_TEST("Struggle does not receive normal-type STAB")
{
// Compare with Cut, which does receive normal-type STAB
ASSUME(GetSpeciesType(SPECIES_ZANGOOSE, 0) == GetMoveType(MOVE_STRUGGLE));
ASSUME(GetMovePower(MOVE_CUT) == GetMovePower(MOVE_STRUGGLE));
ASSUME(GetMoveCategory(MOVE_CUT) == GetMoveCategory(MOVE_STRUGGLE));
ASSUME(GetMoveType(MOVE_CUT) == GetMoveType(MOVE_STRUGGLE));
s16 cutDamage;
s16 struggleDamage;
GIVEN {
PLAYER(SPECIES_ZANGOOSE);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CUT); }
TURN { MOVE(player, MOVE_STRUGGLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CUT, player);
HP_BAR(opponent, captureDamage: &cutDamage);
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player);
HP_BAR(opponent, captureDamage: &struggleDamage);
} THEN {
EXPECT_MUL_EQ(struggleDamage, Q_4_12(1.5), cutDamage);
}
}