AdditionalEffects storage tweak

Uses some macro and bitwise trickery to store additional effects and the count thereof in a single word
This commit is contained in:
Nephrite 2024-02-01 15:19:10 +09:00
parent 086375ab13
commit 8a8d181654
7 changed files with 98 additions and 62 deletions

View File

@ -615,7 +615,6 @@ struct BattleStruct
u32 expValue; u32 expValue;
u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share
u8 expGetterMonId; u8 expGetterMonId;
u8 additionalEffectsCounter:2;
u8 expOrderId:3; u8 expOrderId:3;
u8 expGetterBattlerId:2; u8 expGetterBattlerId:2;
u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed. u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed.
@ -737,6 +736,7 @@ struct BattleStruct
u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler
u8 blunderPolicy:1; // should blunder policy activate u8 blunderPolicy:1; // should blunder policy activate
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
u8 ballSpriteIds[2]; // item gfx, window gfx u8 ballSpriteIds[2]; // item gfx, window gfx
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.

View File

@ -463,10 +463,9 @@ struct MoveInfo
s32 priority:4; s32 priority:4;
u32 recoil:7; u32 recoil:7;
u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit. u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit.
u32 criticalHitStage:2; u32 criticalHitStage:2;
u32 alwaysCriticalHit:1; u32 alwaysCriticalHit:1;
u32 numAdditionalEffects:2; // limited to 3 - don't want to get too crazy
// Flags // Flags
u32 makesContact:1; u32 makesContact:1;
@ -514,7 +513,7 @@ struct MoveInfo
u32 argument; u32 argument;
// primary/secondary effects // primary/secondary effects
const struct AdditionalEffect *additionalEffects; uintptr_t additionalEffects;
// contest parameters // contest parameters
u8 contestEffect; u8 contestEffect;
@ -524,7 +523,12 @@ struct MoveInfo
}; };
#define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__} #define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__}
#define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ )) #define ADDITIONAL_EFFECTS(...) ((ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ )) % 0xF) << 28) + (uintptr_t)(EFFECTS_ARR( __VA_ARGS__ ))
// Retrieve a move's additional effects and the count thereof
#define GET_ADDITIONAL_EFFECTS_AND_COUNT(move, _count, _effects) u32 _count = GET_ADDITIONAL_EFFECTS_COUNT(move); const struct AdditionalEffect *_effects = GET_ADDITIONAL_EFFECTS(move)
#define GET_ADDITIONAL_EFFECTS(move) (void *)(gMovesInfo[move].additionalEffects & 0x8FFFFFF)
#define GET_ADDITIONAL_EFFECTS_COUNT(move) (gMovesInfo[move].additionalEffects >> 28)
// Just a hack to make a move boosted by Sheer Force despite having no secondary effects affected // Just a hack to make a move boosted by Sheer Force despite having no secondary effects affected
#define SHEER_FORCE_HACK { .moveEffect = 0, .chance = 100, } #define SHEER_FORCE_HACK { .moveEffect = 0, .chance = 100, }

View File

@ -3201,6 +3201,9 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex; u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex]; u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
// additional effects
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
s32 score = 0; s32 score = 0;
u32 predictedMove = aiData->predictedMoves[battlerDef]; u32 predictedMove = aiData->predictedMoves[battlerDef];
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove); u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
@ -4427,19 +4430,19 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
} // move effect checks } // move effect checks
// check move additional effects that are likely to happen // check move additional effects that are likely to happen
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) for (i = 0; i < additionalEffectsCount; i++)
{ {
// Only consider effects with a guaranteed chance to happen // Only consider effects with a guaranteed chance to happen
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &gMovesInfo[move].additionalEffects[i])) if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &additionalEffects[i]))
continue; continue;
// Consider move effects that target self // Consider move effects that target self
if (gMovesInfo[move].additionalEffects[i].self) if (additionalEffects[i].self)
{ {
u32 oneStageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1; u32 oneStageStatId = STAT_CHANGE_ATK + additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
u32 twoStageStatId = STAT_CHANGE_ATK_2 + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1; u32 twoStageStatId = STAT_CHANGE_ATK_2 + additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_SPD_PLUS_2: case MOVE_EFFECT_SPD_PLUS_2:
case MOVE_EFFECT_SPD_PLUS_1: case MOVE_EFFECT_SPD_PLUS_1:
@ -4490,7 +4493,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
} }
else // consider move effects that hinder the target else // consider move effects that hinder the target
{ {
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_FLINCH: case MOVE_EFFECT_FLINCH:
score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move); score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move);
@ -4768,11 +4771,13 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
break; break;
case EFFECT_HIT: case EFFECT_HIT:
{
// TEMPORARY - should applied to all moves regardless of EFFECT // TEMPORARY - should applied to all moves regardless of EFFECT
// Consider move effects // Consider move effects
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
for (i = 0; i < additionalEffectsCount; i++)
{ {
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_STEALTH_ROCK: case MOVE_EFFECT_STEALTH_ROCK:
case MOVE_EFFECT_SPIKES: case MOVE_EFFECT_SPIKES:
@ -4782,6 +4787,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
break; break;
} }
} }
}
default: default:
break; break;
} }
@ -4823,11 +4829,13 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
break; break;
case EFFECT_HIT: case EFFECT_HIT:
{
// TEMPORARY - should applied to all moves regardless of EFFECT // TEMPORARY - should applied to all moves regardless of EFFECT
// Consider move effects // Consider move effects
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
for (i = 0; i < additionalEffectsCount; i++)
{ {
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_ALL_STATS_UP: case MOVE_EFFECT_ALL_STATS_UP:
if (Random() & 1) if (Random() & 1)
@ -4837,6 +4845,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break; break;
} }
} }
}
default: default:
break; break;
} }

View File

@ -517,6 +517,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
u32 i; u32 i;
u32 abilityDef = AI_DATA->abilities[battlerDef]; u32 abilityDef = AI_DATA->abilities[battlerDef];
u32 abilityAtk = AI_DATA->abilities[battlerAtk]; u32 abilityAtk = AI_DATA->abilities[battlerAtk];
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
switch (gMovesInfo[move].effect) switch (gMovesInfo[move].effect)
{ {
@ -531,12 +532,12 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
} }
// check ADDITIONAL_EFFECTS // check ADDITIONAL_EFFECTS
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) for (i = 0; i < additionalEffectsCount; i++)
{ {
// Consider move effects that target self // Consider move effects that target self
if (gMovesInfo[move].additionalEffects[i].self) if (additionalEffects[i].self)
{ {
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_ATK_PLUS_1: case MOVE_EFFECT_ATK_PLUS_1:
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK)) if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK))
@ -566,7 +567,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
} }
else // consider move effects that hinder the target else // consider move effects that hinder the target
{ {
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_POISON: case MOVE_EFFECT_POISON:
case MOVE_EFFECT_TOXIC: case MOVE_EFFECT_TOXIC:
@ -600,7 +601,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_SP_DEF_MINUS_1:
case MOVE_EFFECT_ACC_MINUS_1: case MOVE_EFFECT_ACC_MINUS_1:
case MOVE_EFFECT_EVS_MINUS_1: case MOVE_EFFECT_EVS_MINUS_1:
if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1)
return TRUE; return TRUE;
break; break;
case MOVE_EFFECT_ATK_MINUS_2: case MOVE_EFFECT_ATK_MINUS_2:
@ -610,7 +611,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
case MOVE_EFFECT_SP_DEF_MINUS_2: case MOVE_EFFECT_SP_DEF_MINUS_2:
case MOVE_EFFECT_ACC_MINUS_2: case MOVE_EFFECT_ACC_MINUS_2:
case MOVE_EFFECT_EVS_MINUS_2: case MOVE_EFFECT_EVS_MINUS_2:
if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1) if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1)
return TRUE; return TRUE;
break; break;
} }
@ -640,9 +641,12 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
return TRUE; return TRUE;
break; break;
default: default:
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) {
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
for (i = 0; i < additionalEffectsCount; i++)
{ {
switch (gMovesInfo[move].additionalEffects[i].moveEffect) switch (additionalEffects[i].moveEffect)
{ {
case MOVE_EFFECT_ATK_MINUS_1: case MOVE_EFFECT_ATK_MINUS_1:
case MOVE_EFFECT_DEF_MINUS_1: case MOVE_EFFECT_DEF_MINUS_1:
@ -654,16 +658,17 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
case MOVE_EFFECT_DEF_SPDEF_DOWN: case MOVE_EFFECT_DEF_SPDEF_DOWN:
case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_SP_DEF_MINUS_1:
case MOVE_EFFECT_SP_DEF_MINUS_2: case MOVE_EFFECT_SP_DEF_MINUS_2:
if ((gMovesInfo[move].additionalEffects[i].self && GetBattlerAbility(battlerAtk) != ABILITY_CONTRARY) if ((additionalEffects[i].self && GetBattlerAbility(battlerAtk) != ABILITY_CONTRARY)
|| (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !IsMoldBreakerTypeAbility(abilityAtk))) || (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !IsMoldBreakerTypeAbility(abilityAtk)))
return TRUE; return TRUE;
break; break;
case MOVE_EFFECT_RECHARGE: case MOVE_EFFECT_RECHARGE:
return gMovesInfo[move].additionalEffects[i].self; return additionalEffects[i].self;
} }
} }
break; break;
} }
}
return FALSE; return FALSE;
} }

View File

@ -3820,34 +3820,47 @@ void SetMoveEffect(bool32 primary, bool32 certain)
gBattleScripting.moveEffect = 0; gBattleScripting.moveEffect = 0;
} }
static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additionalEffect)
{
// Self-targeting move effects only apply after the last mon has been hit
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
if (additionalEffect->self
&& (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY)
&& GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT)
return FALSE;
// Certain move effects only apply if the target raised stats this turn (e.g. Burning Jealousy)
if (additionalEffect->onlyIfTargetRaisedStats && !gProtectStructs[gBattlerTarget].statRaised)
return FALSE;
// Certain additional effects only apply on a two-turn move's charge turn
if (additionalEffect->onChargeTurnOnly != gProtectStructs[gBattlerAttacker].chargingTurn)
return FALSE;
return TRUE;
}
static void Cmd_setadditionaleffects(void) static void Cmd_setadditionaleffects(void)
{ {
CMD_ARGS(); CMD_ARGS();
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
{ {
if (gMovesInfo[gCurrentMove].numAdditionalEffects > gBattleStruct->additionalEffectsCounter) GET_ADDITIONAL_EFFECTS_AND_COUNT(gCurrentMove, additionalEffectsCount, additionalEffects);
if (additionalEffectsCount > gBattleStruct->additionalEffectsCounter)
{ {
u32 percentChance; u32 percentChance, i = gBattleStruct->additionalEffectsCounter;
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
const u8 *currentPtr = gBattlescriptCurrInstr; const u8 *currentPtr = gBattlescriptCurrInstr;
const struct AdditionalEffect *additionalEffect = &gMovesInfo[gCurrentMove].additionalEffects[gBattleStruct->additionalEffectsCounter];
// Check additional effect flags // Various checks for if this move effect can be applied this turn
// self-targeting move effects cannot occur multiple times per turn if (CanApplyAdditionalEffect(&additionalEffects[i]))
// only occur on the last setmoveeffect when there are multiple targets
if (!(gMovesInfo[gCurrentMove].additionalEffects[gBattleStruct->additionalEffectsCounter].self
&& (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY)
&& GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT)
&& !(additionalEffect->onlyIfTargetRaisedStats && !gProtectStructs[gBattlerTarget].statRaised)
&& additionalEffect->onChargeTurnOnly == gProtectStructs[gBattlerAttacker].chargingTurn)
{ {
percentChance = CalcSecondaryEffectChance(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), additionalEffect); percentChance = CalcSecondaryEffectChance(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), &additionalEffects[i]);
// Activate effect if it's primary (chance == 0) or if RNGesus says so // Activate effect if it's primary (chance == 0) or if RNGesus says so
if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + gBattleStruct->additionalEffectsCounter, percentChance)) if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + i, percentChance))
{ {
gBattleScripting.moveEffect = additionalEffect->moveEffect | (MOVE_EFFECT_AFFECTS_USER * (additionalEffect->self)); gBattleScripting.moveEffect = additionalEffects[i].moveEffect | (MOVE_EFFECT_AFFECTS_USER * (additionalEffects[i].self));
SetMoveEffect( SetMoveEffect(
percentChance == 0, // a primary effect percentChance == 0, // a primary effect
@ -3862,7 +3875,7 @@ static void Cmd_setadditionaleffects(void)
// Call setadditionaleffects again in the case of a move with multiple effects // Call setadditionaleffects again in the case of a move with multiple effects
gBattleStruct->additionalEffectsCounter++; gBattleStruct->additionalEffectsCounter++;
if (gMovesInfo[gCurrentMove].numAdditionalEffects > gBattleStruct->additionalEffectsCounter) if (additionalEffectsCount > gBattleStruct->additionalEffectsCounter)
gBattleScripting.moveEffect = MOVE_EFFECT_CONTINUE; gBattleScripting.moveEffect = MOVE_EFFECT_CONTINUE;
else else
gBattleScripting.moveEffect = gBattleStruct->additionalEffectsCounter = 0; gBattleScripting.moveEffect = gBattleStruct->additionalEffectsCounter = 0;
@ -15677,12 +15690,13 @@ static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 byIntimidate)
static bool8 CanBurnHitThaw(u16 move) static bool8 CanBurnHitThaw(u16 move)
{ {
u8 i; u8 i;
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
if (B_BURN_HIT_THAW >= GEN_6) if (B_BURN_HIT_THAW >= GEN_6)
{ {
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) for (i = 0; i < additionalEffectsCount; i++)
{ {
if (gMovesInfo[move].additionalEffects[i].moveEffect == MOVE_EFFECT_BURN) if (additionalEffects[i].moveEffect == MOVE_EFFECT_BURN)
return TRUE; return TRUE;
} }
} }

View File

@ -10691,9 +10691,11 @@ bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
bool32 MoveIsAffectedBySheerForce(u16 move) bool32 MoveIsAffectedBySheerForce(u16 move)
{ {
u32 i; u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
for (i = 0; i < additionalEffectsCount; i++)
{ {
if (gMovesInfo[move].additionalEffects[i].chance > 0) if (additionalEffects[i].chance > 0)
return TRUE; return TRUE;
} }
@ -10975,10 +10977,11 @@ bool32 IsGen6ExpShareEnabled(void)
bool32 MoveHasMoveEffect(u32 move, u32 moveEffect) bool32 MoveHasMoveEffect(u32 move, u32 moveEffect)
{ {
u32 i; u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) GET_ADDITIONAL_EFFECTS_AND_COUNT(move, count, effects);
for (i = 0; i < count; i++)
{ {
if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect if (effects[i].moveEffect == moveEffect && effects[i].self == FALSE)
&& gMovesInfo[move].additionalEffects[i].self == FALSE)
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -10987,10 +10990,11 @@ bool32 MoveHasMoveEffect(u32 move, u32 moveEffect)
bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance) bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance)
{ {
u32 i; u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) GET_ADDITIONAL_EFFECTS_AND_COUNT(move, count, effects);
for (i = 0; i < count; i++)
{ {
if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect if (effects[i].moveEffect == moveEffect && effects[i].chance == chance)
&& gMovesInfo[move].additionalEffects[i].chance == chance)
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -10999,10 +11003,11 @@ bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance)
bool32 MoveHasMoveEffectSelf(u32 move, u32 moveEffect) bool32 MoveHasMoveEffectSelf(u32 move, u32 moveEffect)
{ {
u32 i; u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) GET_ADDITIONAL_EFFECTS_AND_COUNT(move, count, effects);
for (i = 0; i < count; i++)
{ {
if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect if (effects[i].moveEffect == moveEffect && effects[i].self == TRUE)
&& gMovesInfo[move].additionalEffects[i].self == TRUE)
return TRUE; return TRUE;
} }
return FALSE; return FALSE;

View File

@ -23,13 +23,12 @@ SINGLE_BATTLE_TEST("Accuracy controls the proportion of misses")
SINGLE_BATTLE_TEST("AdditionalEffect.chance controls the proportion of secondary effects") SINGLE_BATTLE_TEST("AdditionalEffect.chance controls the proportion of secondary effects")
{ {
u32 move; u32 move, chance;
PARAMETRIZE { move = MOVE_THUNDER_SHOCK; } PARAMETRIZE { move = MOVE_THUNDER_SHOCK; chance = 10; }
PARAMETRIZE { move = MOVE_DISCHARGE; } PARAMETRIZE { move = MOVE_DISCHARGE; chance = 30; }
PARAMETRIZE { move = MOVE_NUZZLE; } PARAMETRIZE { move = MOVE_NUZZLE; chance = 100; }
ASSUME(MoveHasMoveEffect(move, MOVE_EFFECT_PARALYSIS) == TRUE); ASSUME(MoveHasMoveEffectWithChance(move, MOVE_EFFECT_PARALYSIS, chance) == TRUE);
ASSUME(0 < gMovesInfo[move].additionalEffects[0].chance && gMovesInfo[move].additionalEffects[0].chance <= 100); PASSES_RANDOMLY(chance, 100, RNG_SECONDARY_EFFECT);
PASSES_RANDOMLY(gMovesInfo[move].additionalEffects[0].chance, 100, RNG_SECONDARY_EFFECT);
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);