diff --git a/include/battle_util.h b/include/battle_util.h index 5e86fc615a..81a3466bda 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -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 { diff --git a/include/constants/battle.h b/include/constants/battle.h index a3af32bb4a..2ebf99ebce 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -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) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 3a43503719..78693b1950 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -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; diff --git a/src/battle_debug.c b/src/battle_debug.c index 8282dcadbb..b91ca4b5e4 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -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}, diff --git a/src/battle_main.c b/src/battle_main.c index 4427093e30..b0f2392231 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -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) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 61cdfc65e6..1a0e933383 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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; } diff --git a/src/battle_util.c b/src/battle_util.c index c4a957a40d..60fdf39b65 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -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 diff --git a/test/battle/move_effect/mud_sport.c b/test/battle/move_effect/mud_sport.c index 143bbe1447..ff483699b4 100644 --- a/test/battle/move_effect/mud_sport.c +++ b/test/battle/move_effect/mud_sport.c @@ -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]); + } +} diff --git a/test/battle/move_effect/water_sport.c b/test/battle/move_effect/water_sport.c index f7521c1fcc..cf4ec929c3 100644 --- a/test/battle/move_effect/water_sport.c +++ b/test/battle/move_effect/water_sport.c @@ -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]); + } +}