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

Add newer generation Heal Bell interactions with Soundproof #4732

Merged
merged 4 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions include/config/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
#define B_ALLY_SWITCH_FAIL_CHANCE GEN_LATEST // In Gen9, using Ally Switch consecutively decreases the chance of success for each consecutive use.
#define B_SKETCH_BANS GEN_LATEST // In Gen9+, Sketch is unable to copy more moves than in previous generations.
#define B_KNOCK_OFF_REMOVAL GEN_LATEST // In Gen5+, Knock Off removes the foe's item instead of rendering it unusable.
#define B_HEAL_BELL_SOUNDPROOF GEN_LATEST // In Gen5, Heal Bell affects all mons with Soundproof. In Gen6-8 it affects inactive mons, but not battlers. In Gen9 it always affects the user.

// Ability settings
#define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters.
Expand Down
33 changes: 28 additions & 5 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2954,19 +2954,42 @@ bool32 IsWakeupTurn(u32 battler)
bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
{
struct Pokemon *party;
u32 i;
u32 i, battlerOnField1, battlerOnField2;

if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
party = gPlayerParty;
else
party = gEnemyParty;

for (i = 0; i < PARTY_SIZE; i++)
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
if (checkSoundproof && GetMonAbility(&party[i]) == ABILITY_SOUNDPROOF)
continue;
battlerOnField1 = gBattlerPartyIndexes[battlerId];
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))];
// Check partner's status
if ((GetMonData(&party[battlerOnField2], MON_DATA_STATUS) != STATUS1_NONE)
&& (GetBattlerAbility(battlerOnField2) != ABILITY_SOUNDPROOF
Copy link
Collaborator

@AlexOn1ine AlexOn1ine Jun 7, 2024

Choose a reason for hiding this comment

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

I would make 2 bools for those things since they are checked twice and would make the code a little bit cleaner

You could go even as far as making a bool for the whole soundproof condition or at least part of it.

Copy link
Author

Choose a reason for hiding this comment

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

Sadly these aren't checked twice, it's a different battler in each case.

|| B_HEAL_BELL_SOUNDPROOF == GEN_5 || !checkSoundproof))
return TRUE;
}
else // In singles there's only one battlerId by side.
{
battlerOnField1 = gBattlerPartyIndexes[battlerId];
battlerOnField2 = gBattlerPartyIndexes[battlerId];
}

if (GetMonData(&party[i], MON_DATA_STATUS) != STATUS1_NONE)
// Check attacker's status
if ((GetMonData(&party[battlerOnField1], MON_DATA_STATUS) != STATUS1_NONE)
&& (GetBattlerAbility(battlerOnField1) != ABILITY_SOUNDPROOF || !checkSoundproof
|| B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_9))
return TRUE;

// Check inactive party mons' status
for (i = 0; i < PARTY_SIZE; i++)
{
if ((!checkSoundproof || B_HEAL_BELL_SOUNDPROOF >= GEN_5
|| GetMonAbility(&party[i]) != ABILITY_SOUNDPROOF)
&& i != battlerOnField1 && i != battlerOnField2
&& GetMonData(&party[i], MON_DATA_STATUS) != STATUS1_NONE)
return TRUE;
}

Expand Down
20 changes: 15 additions & 5 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -13178,7 +13178,8 @@ static void Cmd_healpartystatus(void)

gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_BELL;

if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF)
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF
|| B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_9)
{
gBattleMons[gBattlerAttacker].status1 = 0;
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
Expand All @@ -13194,7 +13195,7 @@ static void Cmd_healpartystatus(void)
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& !(gAbsentBattlerFlags & gBitTable[battler]))
{
if (GetBattlerAbility(battler) != ABILITY_SOUNDPROOF)
if (GetBattlerAbility(battler) != ABILITY_SOUNDPROOF || B_HEAL_BELL_SOUNDPROOF == GEN_5)
{
gBattleMons[battler].status1 = 0;
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
Expand All @@ -13217,11 +13218,20 @@ static void Cmd_healpartystatus(void)
{
u16 ability;

if (gBattlerPartyIndexes[gBattlerAttacker] == i)
if (B_HEAL_BELL_SOUNDPROOF == GEN_5
|| (i == gBattlerPartyIndexes[gBattlerAttacker] && B_HEAL_BELL_SOUNDPROOF >= GEN_9))
ability = ABILITY_NONE;
else if (B_HEAL_BELL_SOUNDPROOF > GEN_5
&& i != gBattlerPartyIndexes[gBattlerAttacker]
&& !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattlerPartyIndexes[battler] == i
&& !(gAbsentBattlerFlags & gBitTable[battler])))
Sneed69 marked this conversation as resolved.
Show resolved Hide resolved
ability = ABILITY_NONE;
else if (gBattlerPartyIndexes[gBattlerAttacker] == i)
ability = GetBattlerAbility(gBattlerAttacker);
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattlerPartyIndexes[battler] == i
&& !(gAbsentBattlerFlags & gBitTable[battler]))
&& gBattlerPartyIndexes[battler] == i
&& !(gAbsentBattlerFlags & gBitTable[battler]))
Sneed69 marked this conversation as resolved.
Show resolved Hide resolved
ability = GetBattlerAbility(battler);
else
ability = GetAbilityBySpecies(species, abilityNum);
Expand Down
21 changes: 21 additions & 0 deletions test/battle/ai_check_viability.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,24 @@ AI_SINGLE_BATTLE_TEST("AI chooses moves with secondary effect that have a 100% c
TURN { EXPECT_MOVES(opponent, MOVE_OCTAZOOKA); }
}
}

AI_SINGLE_BATTLE_TEST("AI chooses moves that cure inactive party members")
{
u32 status;

PARAMETRIZE { status = STATUS1_NONE; }
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }

GIVEN {
ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_REGIROCK) { Moves(MOVE_BODY_PRESS, MOVE_HEAL_BELL); }
OPPONENT(SPECIES_REGICE) { Status1(status); }
} WHEN {
if (status == STATUS1_NONE)
TURN { EXPECT_MOVE(opponent, MOVE_BODY_PRESS); }
else
TURN { EXPECT_MOVE(opponent, MOVE_HEAL_BELL, target: opponent); }
}
}
102 changes: 102 additions & 0 deletions test/battle/move_effect/heal_bell.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "global.h"
#include "test/battle.h"

ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL);
ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL);
}

DOUBLE_BATTLE_TEST("Heal Bell cures the entire party")
{
u32 move;

PARAMETRIZE { move = MOVE_HEAL_BELL; }
PARAMETRIZE { move = MOVE_AROMATHERAPY; }

GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
OPPONENT(SPECIES_WYNAUT);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerLeft, move, target: playerLeft); }
TURN { SWITCH(playerLeft, 2); SWITCH(playerRight, 3); }
} SCENE {
int i;

ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
NOT MESSAGE("Wobbuffet is hurt by poison!");
for (i = 0; i < 6; i++)
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_STATUS), STATUS1_NONE);
}
}

DOUBLE_BATTLE_TEST("Heal Bell does not cure soundproof partners")
{
u32 ability;

PARAMETRIZE { ability = ABILITY_SCRAPPY; }
PARAMETRIZE { ability = ABILITY_SOUNDPROOF; }

ASSUME(B_HEAL_BELL_SOUNDPROOF != GEN_5);

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_EXPLOUD) { Ability(ability); Status1(STATUS1_POISON); }
OPPONENT(SPECIES_WYNAUT);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerLeft, MOVE_HEAL_BELL, target: playerLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BELL, playerLeft);
if (ability == ABILITY_SOUNDPROOF) {
MESSAGE("Exploud is hurt by poison!");
} else {
NOT MESSAGE("Exploud is hurt by poison!");
}
}
}

SINGLE_BATTLE_TEST("Heal Bell cures inactive soundproof Pokemon")
{
u32 ability;

PARAMETRIZE { ability = ABILITY_SCRAPPY; }
PARAMETRIZE { ability = ABILITY_SOUNDPROOF; }

ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_5);

GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_EXPLOUD) { Ability(ability); Status1(STATUS1_POISON); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(player, MOVE_HEAL_BELL, target: player); }
TURN { SWITCH(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BELL, player);
SEND_IN_MESSAGE("Exploud");
NOT MESSAGE("Exploud is hurt by poison!");
}
}


SINGLE_BATTLE_TEST("Heal Bell cures a soundproof user")
{
ASSUME(B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_9);

GIVEN {
PLAYER(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); Status1(STATUS1_POISON); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(player, MOVE_HEAL_BELL, target: player); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BELL, player);
NOT MESSAGE("Exploud is hurt by poison!");
}
}
Loading