Remove redundant bit for Throat Spray (#6593)

This commit is contained in:
Alex 2025-04-13 16:22:04 +02:00 committed by GitHub
parent 6a70f4f390
commit caa878002a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 111 additions and 15 deletions

View File

@ -146,7 +146,7 @@ struct ProtectStruct
u32 stealMove:1;
u32 prlzImmobility:1;
u32 confusionSelfDmg:1;
u32 targetAffected:1;
u32 touchedProtectLike:1;
u32 chargingTurn:1;
u32 fleeType:2; // 0: Normal, 1: FLEE_ITEM, 2: FLEE_ABILITY
u32 usedImprisonedMove:1;
@ -164,7 +164,6 @@ struct ProtectStruct
u32 statRaised:1;
u32 usedCustapBerry:1; // also quick claw
// End of 32-bit bitfield
u16 touchedProtectLike:1;
u16 disableEjectPack:1;
u16 statFell:1;
u16 pranksterElevated:1;
@ -175,7 +174,7 @@ struct ProtectStruct
u16 eatMirrorHerb:1;
u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
u16 usedAllySwitch:1;
u16 padding:4;
u16 padding:5;
// End of 16-bit bitfield
u16 physicalDmg;
u16 specialDmg;

View File

@ -3286,7 +3286,6 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].stealMove = FALSE;
gProtectStructs[battler].prlzImmobility = FALSE;
gProtectStructs[battler].confusionSelfDmg = FALSE;
gProtectStructs[battler].targetAffected = FALSE;
gProtectStructs[battler].chargingTurn = FALSE;
gProtectStructs[battler].fleeType = 0;
gProtectStructs[battler].usedImprisonedMove = FALSE;

View File

@ -1155,12 +1155,11 @@ bool32 IsMoveNotAllowedInSkyBattles(u32 move)
u32 NumAffectedSpreadMoveTargets(void)
{
u32 targetCount = 1;
u32 targetCount = 0;
if (!IsDoubleSpreadMove())
return targetCount;
targetCount = 0;
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT))
@ -7113,10 +7112,6 @@ static void Cmd_moveend(void)
case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon.
{
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
// Set a flag if move hits either target (for throat spray that can't check damage)
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
gProtectStructs[gBattlerAttacker].targetAffected = TRUE;
gBattleStruct->battlerState[gBattlerAttacker].targetsDone[gBattlerTarget] = TRUE;
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
@ -7566,7 +7561,6 @@ static void Cmd_moveend(void)
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
// #endif
}
gProtectStructs[gBattlerAttacker].targetAffected = FALSE;
gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
gBattleStruct->ateBoost[gBattlerAttacker] = FALSE;
gStatuses3[gBattlerAttacker] &= ~STATUS3_ME_FIRST;

View File

@ -65,6 +65,7 @@ static u32 GetFlingPowerFromItemId(u32 itemId);
static void SetRandomMultiHitCounter();
static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item);
static bool32 CanBeInfinitelyConfused(u32 battler);
static bool32 IsAnyTargetAffected(u32 battlerAtk);
ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12(u32 percent);
ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12_Floored(u32 percent);
@ -4801,8 +4802,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
case ABILITY_IMPOSTER:
{
u32 diagonalBattler = BATTLE_OPPOSITE(battler);
if (IsDoubleBattle())
u32 diagonalBattler = BATTLE_OPPOSITE(battler);
if (IsDoubleBattle())
diagonalBattler = BATTLE_PARTNER(diagonalBattler);
if (IsBattlerAlive(diagonalBattler)
&& !(gBattleMons[diagonalBattler].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))
@ -8213,9 +8214,9 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
}
break;
case HOLD_EFFECT_THROAT_SPRAY: // Does NOT need to be a damaging move
if (gProtectStructs[gBattlerAttacker].targetAffected
if (IsSoundMove(gCurrentMove)
&& IsBattlerAlive(gBattlerAttacker)
&& IsSoundMove(gCurrentMove)
&& IsAnyTargetAffected(gBattlerAttacker)
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end
{
@ -12408,3 +12409,16 @@ bool32 HasWeatherEffect(void)
return TRUE;
}
static bool32 IsAnyTargetAffected(u32 battlerAtk)
{
for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++)
{
if (battlerAtk == battlerDef)
continue;
if (!(gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT))
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,90 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(ItemId_GetHoldEffect(ITEM_THROAT_SPRAY) == HOLD_EFFECT_THROAT_SPRAY);
ASSUME(IsSoundMove(MOVE_HYPER_VOICE) == TRUE);
}
DOUBLE_BATTLE_TEST("Throat Spray activates after both hits of a spread move")
{
s16 firstHit, secondHit;
GIVEN {
ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_THROAT_SPRAY); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_HYPER_VOICE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, playerLeft);
HP_BAR(opponentLeft, captureDamage: &firstHit);
HP_BAR(opponentRight, captureDamage: &secondHit);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft);
} THEN {
EXPECT_EQ(firstHit, secondHit);
}
}
SINGLE_BATTLE_TEST("Throat Spray increases Sp. Atk by one stage")
{
s16 normalHit;
s16 boostedHit;
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_THROAT_SPRAY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_HYPER_VOICE); }
TURN { MOVE(player, MOVE_HYPER_VOICE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, player);
HP_BAR(opponent, captureDamage: &normalHit);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, player);
HP_BAR(opponent, captureDamage: &boostedHit);
} THEN {
EXPECT_MUL_EQ(normalHit, Q_4_12(1.5), boostedHit);
}
}
SINGLE_BATTLE_TEST("Throat Spray activates when a sound move is used")
{
u32 move;
PARAMETRIZE { move = MOVE_SWIFT; }
PARAMETRIZE { move = MOVE_HYPER_VOICE; }
GIVEN {
ASSUME(IsSoundMove(MOVE_SWIFT) != IsSoundMove(MOVE_HYPER_VOICE));
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_THROAT_SPRAY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
if (move == MOVE_HYPER_VOICE)
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
else
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
}
}
SINGLE_BATTLE_TEST("Throat Spray does not activate if move fails")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_THROAT_SPRAY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_HYPER_VOICE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
}
}
}