Use dedicated functions for Mud/Water Sport (#7248)

This commit is contained in:
Alex 2025-07-02 09:08:12 +02:00 committed by GitHub
parent 92b4b7f0a0
commit e503f97f32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 108 additions and 53 deletions

View File

@ -54,7 +54,6 @@ enum {
ABILITYEFFECT_ATK_SYNCHRONIZE,
ABILITYEFFECT_MOVE_END_OTHER,
ABILITYEFFECT_NEUTRALIZINGGAS,
ABILITYEFFECT_FIELD_SPORT, // Only used if B_SPORT_TURNS >= GEN_6
ABILITYEFFECT_ON_WEATHER,
ABILITYEFFECT_ON_TERRAIN,
ABILITYEFFECT_SWITCH_IN_TERRAIN,
@ -63,10 +62,6 @@ enum {
ABILITYEFFECT_SWITCH_IN_STATUSES,
};
// Special cases
#define ABILITYEFFECT_MUD_SPORT 252 // Only used if B_SPORT_TURNS >= GEN_6
#define ABILITYEFFECT_WATER_SPORT 253 // Only used if B_SPORT_TURNS >= GEN_6
// For the first argument of ItemBattleEffects, to deteremine which block of item effects to try
enum ItemCaseId
{

View File

@ -167,7 +167,9 @@ enum VolatileFlags
F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \
F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE)
F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE)
/* Use within a macro to get the maximum allowed value for a volatile. Requires _typeBitSize and debug parameters as input. */
#define GET_VOLATILE_MAXIMUM(_typeBitSize, ...) INVOKE_WITH_B(GET_VOLATILE_MAXIMUM_, _typeBitSize)

View File

@ -2050,13 +2050,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case EFFECT_MUD_SPORT:
if (gFieldStatuses & STATUS_FIELD_MUDSPORT
|| gStatuses4[battlerAtk] & STATUS4_MUD_SPORT
|| gBattleMons[battlerAtk].volatiles.mudSport
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;
case EFFECT_WATER_SPORT:
if (gFieldStatuses & STATUS_FIELD_WATERSPORT
|| gStatuses4[battlerAtk] & STATUS4_WATER_SPORT
|| gBattleMons[battlerAtk].volatiles.waterSport
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;

View File

@ -169,8 +169,6 @@ enum
enum
{
LIST_STATUS4_ELECTRIFIED,
LIST_STATUS4_MUD_SPORT,
LIST_STATUS4_WATER_SPORT,
LIST_STATUS4_SALT_CURE,
LIST_STATUS4_SYRUP_BOMB,
LIST_STATUS4_GLAIVE_RUSH,
@ -348,8 +346,6 @@ static const u8 sText_LaserFocus[] = _("Laser Focus");
static const u8 sText_PowerTrick[] = _("Power Trick");
static const u8 sText_SkyDropped[] = _("Sky Dropped");
static const u8 sText_Electrified[] = _("Electrified");
static const u8 sText_MudSport[] = _("Mud Sport");
static const u8 sText_WaterSport[] = _("Water Sport");
static const u8 sText_InfiniteConfusion[] = _("Infinite Confusion");
static const u8 sText_SaltCure[] = _("Salt Cure");
static const u8 sText_SyrupBomb[] = _("Syrup Bomb");
@ -548,6 +544,8 @@ static const struct ListMenuItem sVolatileStatusListItems[] =
{COMPOUND_STRING("Foresight"), VOLATILE_FORESIGHT},
{COMPOUND_STRING("DragonCheer"), VOLATILE_DRAGON_CHEER},
{COMPOUND_STRING("FocusEnergy"), VOLATILE_FOCUS_ENERGY},
{COMPOUND_STRING("MudSport"), VOLATILE_MUD_SPORT},
{COMPOUND_STRING("WaterSport"), VOLATILE_WATER_SPORT},
};
static const struct ListMenuItem sStatus3ListItems[] =
@ -580,8 +578,6 @@ static const struct ListMenuItem sStatus3ListItems[] =
static const struct ListMenuItem sStatus4ListItems[] =
{
{sText_Electrified, LIST_STATUS4_ELECTRIFIED},
{sText_MudSport, LIST_STATUS4_MUD_SPORT},
{sText_WaterSport, LIST_STATUS4_WATER_SPORT},
{sText_SaltCure, LIST_STATUS4_SALT_CURE},
{sText_SyrupBomb, LIST_STATUS4_SYRUP_BOMB},
{sText_GlaiveRush, LIST_STATUS4_GLAIVE_RUSH},

View File

@ -3156,7 +3156,7 @@ void SwitchInClearSetData(u32 battler)
gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED
| STATUS3_GASTRO_ACID | STATUS3_EMBARGO | STATUS3_TELEKINESIS | STATUS3_MAGNET_RISE | STATUS3_HEAL_BLOCK
| STATUS3_AQUA_RING | STATUS3_POWER_TRICK);
gStatuses4[battler] &= (STATUS4_MUD_SPORT | STATUS4_WATER_SPORT | STATUS4_INFINITE_CONFUSION);
gStatuses4[battler] &= STATUS4_INFINITE_CONFUSION;
for (i = 0; i < gBattlersCount; i++)
{
if (!IsBattlerAlly(battler, i)

View File

@ -15393,9 +15393,9 @@ static void Cmd_settypebasedhalvers(void)
}
else
{
if (!(gStatuses4[gBattlerAttacker] & STATUS4_MUD_SPORT))
if (!gBattleMons[gBattlerAttacker].volatiles.waterSport)
{
gStatuses4[gBattlerAttacker] |= STATUS4_MUD_SPORT;
gBattleMons[gBattlerAttacker].volatiles.waterSport = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_ELECTRIC;
worked = TRUE;
}
@ -15415,9 +15415,9 @@ static void Cmd_settypebasedhalvers(void)
}
else
{
if (!(gStatuses4[gBattlerAttacker] & STATUS4_WATER_SPORT))
if (!gBattleMons[gBattlerAttacker].volatiles.mudSport)
{
gStatuses4[gBattlerAttacker] |= STATUS4_WATER_SPORT;
gBattleMons[gBattlerAttacker].volatiles.mudSport = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_FIRE;
worked = TRUE;
}

View File

@ -5199,35 +5199,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
}
break;
case ABILITYEFFECT_FIELD_SPORT:
switch (gLastUsedAbility)
{
case ABILITYEFFECT_MUD_SPORT:
for (i = 0; i < gBattlersCount; i++)
{
if (gStatuses4[i] & STATUS4_MUD_SPORT)
effect = i + 1;
}
break;
case ABILITYEFFECT_WATER_SPORT:
for (i = 0; i < gBattlersCount; i++)
{
if (gStatuses4[i] & STATUS4_WATER_SPORT)
effect = i + 1;
}
break;
default:
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ability)
{
gLastUsedAbility = ability;
effect = i + 1;
}
}
break;
}
break;
case ABILITYEFFECT_ON_WEATHER: // For ability effects that activate when the battle weather changes.
gLastUsedAbility = GetBattlerAbility(battler);
switch (gLastUsedAbility)
@ -7933,6 +7904,40 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter)
return basePower;
}
static inline u32 IsFieldMudSportAffected(u32 moveType)
{
if (moveType == TYPE_ELECTRIC && (gFieldStatuses & STATUS_FIELD_MUDSPORT))
return TRUE;
if (B_SPORT_TURNS < GEN_6)
{
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleMons[battler].volatiles.mudSport)
return TRUE;
}
}
return FALSE;
}
static inline u32 IsFieldWaterSportAffected(u32 moveType)
{
if (moveType == TYPE_FIRE && (gFieldStatuses & STATUS_FIELD_WATERSPORT))
return TRUE;
if (B_SPORT_TURNS < GEN_6)
{
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleMons[battler].volatiles.waterSport)
return TRUE;
}
}
return FALSE;
}
static inline u32 CalcMoveBasePower(struct DamageContext *ctx)
{
u32 battlerAtk = ctx->battlerAtk;
@ -8268,12 +8273,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5)));
if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && moveType == TYPE_PSYCHIC)
modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5)));
if (moveType == TYPE_ELECTRIC && ((gFieldStatuses & STATUS_FIELD_MUDSPORT)
|| AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, ABILITYEFFECT_MUD_SPORT, 0)))
if (IsFieldMudSportAffected(ctx->moveType))
modifier = uq4_12_multiply(modifier, UQ_4_12(B_SPORT_DMG_REDUCTION >= GEN_5 ? 0.33 : 0.5));
if (moveType == TYPE_FIRE && ((gFieldStatuses & STATUS_FIELD_WATERSPORT)
|| AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, ABILITYEFFECT_WATER_SPORT, 0)))
if (IsFieldWaterSportAffected(ctx->moveType))
modifier = uq4_12_multiply(modifier, UQ_4_12(B_SPORT_DMG_REDUCTION >= GEN_5 ? 0.33 : 0.5));
// attacker's abilities

View File

@ -2,3 +2,33 @@
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Mud Sport (Move Effect) test titles")
SINGLE_BATTLE_TEST("Mud Sport reduces the damage of Electric Type moves by 67% (Gen5+)")
{
s16 playerDmg[2];
s16 opponentDmg[2];
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SHOCK_WAVE); MOVE(opponent, MOVE_SHOCK_WAVE); }
TURN { MOVE(player, MOVE_MUD_SPORT); }
TURN { MOVE(player, MOVE_SHOCK_WAVE); MOVE(opponent, MOVE_SHOCK_WAVE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, player);
HP_BAR(opponent, captureDamage: &opponentDmg[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, opponent);
HP_BAR(player, captureDamage: &playerDmg[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MUD_SPORT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, player);
HP_BAR(opponent, captureDamage: &opponentDmg[1]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, opponent);
HP_BAR(player, captureDamage: &playerDmg[1]);
} THEN {
EXPECT_MUL_EQ(opponentDmg[0], Q_4_12(0.33), opponentDmg[1]);
EXPECT_MUL_EQ(playerDmg[0], Q_4_12(0.33), playerDmg[1]);
}
}

View File

@ -2,3 +2,33 @@
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Water Sport (Move Effect) test titles")
SINGLE_BATTLE_TEST("Water Sport reduces the damage of Fire Type moves by 67% (Gen5+)")
{
s16 playerDmg[2];
s16 opponentDmg[2];
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FIRE_PLEDGE); MOVE(opponent, MOVE_FIRE_PLEDGE); }
TURN { MOVE(player, MOVE_WATER_SPORT); }
TURN { MOVE(player, MOVE_FIRE_PLEDGE); MOVE(opponent, MOVE_FIRE_PLEDGE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PLEDGE, player);
HP_BAR(opponent, captureDamage: &opponentDmg[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PLEDGE, opponent);
HP_BAR(player, captureDamage: &playerDmg[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_SPORT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PLEDGE, player);
HP_BAR(opponent, captureDamage: &opponentDmg[1]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PLEDGE, opponent);
HP_BAR(player, captureDamage: &playerDmg[1]);
} THEN {
EXPECT_MUL_EQ(opponentDmg[0], Q_4_12(0.33), opponentDmg[1]);
EXPECT_MUL_EQ(playerDmg[0], Q_4_12(0.33), playerDmg[1]);
}
}