Fixes Helping Hand boosts not stacking with each other (#7775)

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
PhallenTree 2025-09-22 19:00:34 +01:00 committed by GitHub
parent dae8aea26c
commit 5fad32decc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 129 additions and 8 deletions

View File

@ -141,7 +141,6 @@ struct ProtectStruct
{
u32 protected:7; // 126 protect options
u32 noValidMoves:1;
u32 helpingHand:1;
u32 bounceMove:1;
u32 stealMove:1;
u32 nonVolatileStatusImmobility:1;
@ -163,13 +162,14 @@ struct ProtectStruct
u32 shellTrap:1;
u32 eatMirrorHerb:1;
u32 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
// End of 32-bit bitfield
u16 usedAllySwitch:1;
// End of 32-bit bitfield
u32 helpingHand:3;
u16 lashOutAffected:1;
u16 assuranceDoubled:1;
u16 myceliumMight:1;
u16 laggingTail:1;
u16 padding:11;
u16 padding:9;
// End of 16-bit bitfield
u16 physicalDmg;
u16 specialDmg;

View File

@ -3325,7 +3325,7 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].quash = FALSE;
gProtectStructs[battler].noValidMoves = FALSE;
gProtectStructs[battler].helpingHand = FALSE;
gProtectStructs[battler].helpingHand = 0;
gProtectStructs[battler].bounceMove = FALSE;
gProtectStructs[battler].stealMove = FALSE;
gProtectStructs[battler].nonVolatileStatusImmobility = FALSE;

View File

@ -12760,10 +12760,9 @@ static void Cmd_trysethelpinghand(void)
if (IsDoubleBattle()
&& !(gAbsentBattlerFlags & (1u << gBattlerTarget))
&& !gProtectStructs[gBattlerAttacker].helpingHand
&& !gProtectStructs[gBattlerTarget].helpingHand)
&& gCurrentTurnActionNumber < GetBattlerTurnOrderNum(gBattlerTarget))
{
gProtectStructs[gBattlerTarget].helpingHand = TRUE;
gProtectStructs[gBattlerTarget].helpingHand++;
gBattlescriptCurrInstr = cmd->nextInstr;
}
else

View File

@ -8329,8 +8329,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
}
// various effects
if (gProtectStructs[battlerAtk].helpingHand)
for (u32 i = 0; i < gProtectStructs[battlerAtk].helpingHand; i++)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.5));
if (gSpecialStatuses[battlerAtk].gemBoost)
modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(gSpecialStatuses[battlerAtk].gemParam)));
if (gBattleMons[battlerAtk].volatiles.charge && moveType == TYPE_ELECTRIC)

View File

@ -1,4 +1,125 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_HELPING_HAND) == EFFECT_HELPING_HAND);
}
SINGLE_BATTLE_TEST("Helping Hand fails in a Single Battle")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_HELPING_HAND); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, player);
MESSAGE("But it failed!");
}
}
DOUBLE_BATTLE_TEST("Helping Hand fails if ally already acted")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_HELPING_HAND, target: playerRight); MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, playerLeft);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, playerRight);
}
}
DOUBLE_BATTLE_TEST("Helping Hand boosts the power of attacking moves by 50%", s16 damage)
{
bool32 useHelpingHand;
PARAMETRIZE { useHelpingHand = FALSE; }
PARAMETRIZE { useHelpingHand = TRUE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (useHelpingHand)
TURN { MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft); MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
else
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}
DOUBLE_BATTLE_TEST("Helping Hand still boosts moves used due to Instruct", s16 damage)
{
bool32 useHelpingHand;
PARAMETRIZE { useHelpingHand = FALSE; }
PARAMETRIZE { useHelpingHand = TRUE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (useHelpingHand)
{
TURN { MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft);
MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft);
MOVE(opponentLeft, MOVE_INSTRUCT, target: playerLeft); }
}
else
{
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft);
MOVE(opponentLeft, MOVE_INSTRUCT, target: playerLeft); }
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}
DOUBLE_BATTLE_TEST("Helping Hand boosts the power of attacking moves by 125% if Instructed into using it again", s16 damage)
{
bool32 useHelpingHandTwice;
PARAMETRIZE { useHelpingHandTwice = FALSE; }
PARAMETRIZE { useHelpingHandTwice = TRUE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (useHelpingHandTwice)
TURN { MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft);
MOVE(opponentLeft, MOVE_INSTRUCT, target: playerRight);
MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
else
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.25), results[1].damage);
}
}
TO_DO_BATTLE_TEST("TODO: Write Helping Hand (Move Effect) test titles")