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

Small Ability Effect Move Block refactor #4635

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -8209,7 +8209,7 @@ BattleScript_DazzlingProtected::
attackstring
ppreduce
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
call BattleScript_AbilityPopUpScripting
printstring STRINGID_POKEMONCANNOTUSEMOVE
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
Expand Down
72 changes: 51 additions & 21 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4977,46 +4977,76 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITYEFFECT_MOVES_BLOCK: // 2
{
u16 moveTarget = GetBattlerMoveTargetType(battler, move);
u16 battlerAbility = GetBattlerAbility(battler);
u16 targetAbility = GetBattlerAbility(gBattlerTarget);

if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
|| (gLastUsedAbility == ABILITY_BULLETPROOF && gMovesInfo[move].ballisticMove))
switch (gLastUsedAbility)
{
case ABILITY_SOUNDPROOF:
if (gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
effect = 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should/can we get an enum to describe what precisely these effect numbers stand for? It's not very intuitive

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not feasible. They are used all across AbilityBattleEffects and can mean anything.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think we should streamline it. Out of scope for this PR of course, but it just makes it unnecessarily opaque to see what actually happens

break;
case ABILITY_BULLETPROOF:
if (gMovesInfo[move].ballisticMove)
effect = 1;
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
effect = 2;
break;
case ABILITY_GOOD_AS_GOLD:
if (IS_MOVE_STATUS(gCurrentMove)
&& !(moveTarget & MOVE_TARGET_USER)
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
effect = 3;
break;
}

if (!effect)
{
switch (GetBattlerAbility(BATTLE_PARTNER(battler)))
{
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
effect = 4;
break;
}
}

if (effect == 1)
{
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
gBattlescriptCurrInstr = BattleScript_SoundproofProtected;
effect = 1;
}
else if ((gLastUsedAbility == ABILITY_DAZZLING || gLastUsedAbility == ABILITY_QUEENLY_MAJESTY || gLastUsedAbility == ABILITY_ARMOR_TAIL || IsBattlerAlive(battler ^= BIT_FLANK))
&& (battlerAbility == ABILITY_DAZZLING || battlerAbility == ABILITY_QUEENLY_MAJESTY || battlerAbility == ABILITY_ARMOR_TAIL)
&& GetChosenMovePriority(gBattlerAttacker) > 0
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
else if (effect == 2 || effect == 4)
{
if (effect == 4)
gBattleScripting.battler = BATTLE_PARTNER(battler);
else
gBattleScripting.battler = battler;

if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
gBattlescriptCurrInstr = BattleScript_DazzlingProtected;
effect = 1;
}
else if (effect == 3)
{
gBattlescriptCurrInstr = BattleScript_GoodAsGoldActivates;
}
else if (GetChosenMovePriority(gBattlerAttacker) > 0
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && (targetAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
{
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
gBattlescriptCurrInstr = BattleScript_DarkTypePreventsPrankster;
effect = 1;
}
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_GOOD_AS_GOLD
&& IS_MOVE_STATUS(gCurrentMove)
&& !(moveTarget & MOVE_TARGET_USER)
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
{
gBattlescriptCurrInstr = BattleScript_GoodAsGoldActivates;
effect = 1;
}
break;
}
case ABILITYEFFECT_ABSORBING: // 3
Expand Down
52 changes: 52 additions & 0 deletions test/battle/ability/dazzling.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "global.h"
#include "test/battle.h"


ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority > 0);
}

DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect the user from priority moves")
{
u32 species, ability;

PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentLeft); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponentRight);
ABILITY_POPUP(opponentLeft, ability);
MESSAGE("Wobbuffet cannot use Quick Attack!");
}
}

DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect users partner from priority moves")
{
u32 species, ability;

PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponentRight);
ABILITY_POPUP(opponentLeft, ability);
MESSAGE("Wobbuffet cannot use Quick Attack!");
}
}
70 changes: 70 additions & 0 deletions test/battle/ability/good_as_gold.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "global.h"
#include "test/battle.h"


SINGLE_BATTLE_TEST("Good as Gold protects from status moves")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_TOXIC].category == DAMAGE_CATEGORY_STATUS);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
} WHEN {
TURN { MOVE(player, MOVE_TOXIC); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
MESSAGE("It doesn't affect Foe Gholdengo…");
}
}

SINGLE_BATTLE_TEST("Good as Gold doesn't protect the user from it's own moves")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_NASTY_PLOT].category == DAMAGE_CATEGORY_STATUS);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
} WHEN {
TURN { MOVE(opponent, MOVE_NASTY_PLOT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_NASTY_PLOT, opponent);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
MESSAGE("It doesn't affect Foe Gholdengo…");
}
}
}

SINGLE_BATTLE_TEST("Good as Gold doesn't protect from moves that target the field")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].category == DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
} WHEN {
TURN { MOVE(player, MOVE_STEALTH_ROCK); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
MESSAGE("It doesn't affect Foe Gholdengo…");
}
}
}

DOUBLE_BATTLE_TEST("Good as Gold protects from partner's status moves")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_HELPING_HAND].category == DAMAGE_CATEGORY_STATUS);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentRight, MOVE_HELPING_HAND); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, opponentRight);
ABILITY_POPUP(opponentLeft, ABILITY_GOOD_AS_GOLD);
MESSAGE("It doesn't affect Foe Gholdengo…");
}
}
Loading