Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added missing redirect abilities Gen 3-4 config #4920

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/config/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
#define B_WEATHER_FORMS GEN_LATEST // In Gen5+, Castform and Cherrim revert to their base form upon losing their respective ability. Cherrim needs Flower Gift to swap forms.
#define B_SYMBIOSIS_GEMS GEN_LATEST // In Gen7+, Symbiosis passes an item after a gem-boosted attack. Previously, items are passed before the gem-boosted attack hits, making the item effect apply.
#define B_ABSORBING_ABILITY_STRING GEN_LATEST // In Gen5+, the abilities that absorb moves of a certain type use a generic string for stat increases and decreases.
#define B_REDIRECT_ABILITY_IMMUNITY GEN_LATEST // In Gen5+, Pokémon with Lightning Rod/Storm Drain become immune to Electric/Water-type moves and increase their Sp. Attack by 1 stage on top of the redirecting effect.
#define B_LEAF_GUARD_PREVENTS_REST GEN_LATEST // In Gen5+, Leaf Guard prevents the use of Rest in harsh sunlight.
#define B_SNOW_WARNING GEN_LATEST // In Gen9+, Snow Warning will summon snow instead of hail.
#define B_TRANSISTOR_BOOST GEN_LATEST // In Gen9+, Transistor will only boost Electric-type moves by 1.3x as opposed to 1.5x.
Expand Down
25 changes: 20 additions & 5 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,19 +943,32 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& IsNonVolatileStatusMoveEffect(moveEffect))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_VOLT_ABSORB:
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_MOTOR_DRIVE:
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
RETURN_SCORE_MINUS(20);
break;
} // def ability checks

// target partner ability checks & not attacking partner
Expand Down Expand Up @@ -2820,7 +2833,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
break;
case ABILITY_LIGHTNING_ROD:
if (moveType == TYPE_ELECTRIC
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5
&& moveType == TYPE_ELECTRIC
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_SPECIAL)
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK))
{
Expand All @@ -2836,7 +2850,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
break; // handled in AI_HPAware
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5
&& moveType == TYPE_WATER
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_SPECIAL)
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK))
{
Expand Down Expand Up @@ -4266,7 +4281,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_ION_DELUGE:
if ((aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|| aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)
|| (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
&& gMovesInfo[predictedMove].type == TYPE_NORMAL)
ADJUST_SCORE(DECENT_EFFECT);
break;
Expand Down Expand Up @@ -4325,7 +4340,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
if (predictedMove != MOVE_NONE
&& (aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|| aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
|| (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)))
{
ADJUST_SCORE(DECENT_EFFECT);
}
Expand Down
17 changes: 13 additions & 4 deletions src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,25 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler, bool32 emitResult)
else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_WATER)
{
absorbingTypeAbilities[0] = ABILITY_WATER_ABSORB;
absorbingTypeAbilities[1] = ABILITY_STORM_DRAIN;
absorbingTypeAbilities[2] = ABILITY_DRY_SKIN;
absorbingTypeAbilities[1] = ABILITY_DRY_SKIN;
numAbsorbingAbilities = 2;
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
{
absorbingTypeAbilities[2] = ABILITY_STORM_DRAIN;
numAbsorbingAbilities++;
}
numAbsorbingAbilities = 3;
}
else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_ELECTRIC)
{
absorbingTypeAbilities[0] = ABILITY_VOLT_ABSORB;
absorbingTypeAbilities[1] = ABILITY_MOTOR_DRIVE;
absorbingTypeAbilities[2] = ABILITY_LIGHTNING_ROD;
numAbsorbingAbilities = 3;
numAbsorbingAbilities = 2;
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
{
absorbingTypeAbilities[2] = ABILITY_LIGHTNING_ROD;
numAbsorbingAbilities++;
}
}
else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_GRASS)
{
Expand Down
10 changes: 8 additions & 2 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,15 +385,21 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)

switch (battlerDefAbility)
{
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_VOLT_ABSORB:
case ABILITY_MOTOR_DRIVE:
case ABILITY_LIGHTNING_ROD:
if (moveType == TYPE_ELECTRIC)
return TRUE;
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER)
return TRUE;
break;
Expand Down
2 changes: 1 addition & 1 deletion src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -16350,7 +16350,7 @@ void BS_JumpIfEmergencyExited(void)
void BS_JumpIfRod(void)
{
NATIVE_ARGS(const u8 *jumpInstr);
if (IsElectricAbilityAffected(ABILITY_LIGHTNING_ROD))
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_6 && IsElectricAbilityAffected(ABILITY_LIGHTNING_ROD))
AsparagusEduardo marked this conversation as resolved.
Show resolved Hide resolved
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
Expand Down
4 changes: 2 additions & 2 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5080,11 +5080,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
effect = 2, statId = STAT_SPEED;
break;
case ABILITY_LIGHTNING_ROD:
if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS)
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS)
effect = 2, statId = STAT_SPATK;
break;
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER)
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_WATER)
effect = 2, statId = STAT_SPATK;
break;
case ABILITY_SAP_SIPPER:
Expand Down
73 changes: 73 additions & 0 deletions test/battle/ability/lightning_rod.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "global.h"
#include "test/battle.h"

SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the Sp. Attack [Gen5+]")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
} WHEN {
TURN { MOVE(player, MOVE_THUNDERBOLT); MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
HP_BAR(opponent);
};
ABILITY_POPUP(opponent, ABILITY_LIGHTNING_ROD);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Raichu's Sp. Atk rose!");
} else {
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_LIGHTNING_ROD);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Raichu's Sp. Atk rose!");
};
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
HP_BAR(opponent);
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
}
}

DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to target the Pokémon with this Ability.")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentRight);
MOVE(playerRight, MOVE_THUNDERBOLT, target: opponentRight);
MOVE(opponentLeft, MOVE_CELEBRATE);
MOVE(opponentRight, MOVE_CELEBRATE);
}
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
NONE_OF {
HP_BAR(opponentLeft);
HP_BAR(opponentRight);
};
ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("Foe Raichu's Sp. Atk rose!");
ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("Foe Raichu's Sp. Atk rose!");
} else {
NONE_OF {
HP_BAR(opponentRight);
};
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, playerLeft);
HP_BAR(opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, playerRight);
HP_BAR(opponentLeft);
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
}
}
73 changes: 73 additions & 0 deletions test/battle/ability/storm_drain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "global.h"
#include "test/battle.h"

SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. Attack [Gen5+]")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GASTRODON_EAST_SEA) { Ability(ABILITY_STORM_DRAIN); }
} WHEN {
TURN { MOVE(player, MOVE_WATER_GUN); MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent);
};
ABILITY_POPUP(opponent, ABILITY_STORM_DRAIN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
} else {
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_STORM_DRAIN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
};
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent);
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
}
}

DOUBLE_BATTLE_TEST("Storm Drain forces single-target Water-type moves to target the Pokémon with this Ability.")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GASTRODON_EAST_SEA) { Ability(ABILITY_STORM_DRAIN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight);
MOVE(playerRight, MOVE_WATER_GUN, target: opponentRight);
MOVE(opponentLeft, MOVE_CELEBRATE);
MOVE(opponentRight, MOVE_CELEBRATE);
}
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
NONE_OF {
HP_BAR(opponentLeft);
HP_BAR(opponentRight);
};
ABILITY_POPUP(opponentLeft, ABILITY_STORM_DRAIN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
ABILITY_POPUP(opponentLeft, ABILITY_STORM_DRAIN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
} else {
NONE_OF {
HP_BAR(opponentRight);
};
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
HP_BAR(opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerRight);
HP_BAR(opponentLeft);
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
}
}
2 changes: 1 addition & 1 deletion test/battle/move_effect/ion_deluge.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ WILD_BATTLE_TEST("Ion Deluge works the same way as always when used by a mon wit
NONE_OF {
ABILITY_POPUP(opponent, ability);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Wild Zebstrika's Sp.Atk rose!");
MESSAGE("Wild Zebstrika's Sp. Atk rose!");
MESSAGE("Wild Zebstrika's Speed rose!");
}
MESSAGE("A deluge of ions showers the battlefield!");
Expand Down
3 changes: 2 additions & 1 deletion test/battle/move_effect_secondary/dire_claw.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ SINGLE_BATTLE_TEST("Dire Claw cannot poison/paralyze/cause to fall asleep pokemo
u8 statusAnim;
u16 species, ability;
u32 rng;
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; }
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; }
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_JOLTEON; ability = ABILITY_VOLT_ABSORB; }
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_ELECTIVIRE; ability = ABILITY_MOTOR_DRIVE; }
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = MOVE_EFFECT_POISON; species = SPECIES_ZANGOOSE; ability = ABILITY_IMMUNITY; }
Expand Down
Loading