MoveInfo rearrangement and flag optimisation (#4096)

This commit is contained in:
Eduardo Quezada D'Ottone 2024-02-27 09:32:54 -03:00 committed by GitHub
commit 918a0be312
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
65 changed files with 317 additions and 496 deletions

View File

@ -8552,7 +8552,7 @@ BattleScript_GooeyActivates::
waitstate
call BattleScript_AbilityPopUp
swapattackerwithtarget @ for defiant, mirror armor
seteffectsecondary
seteffectsecondary MOVE_EFFECT_SPD_MINUS_1
swapattackerwithtarget
return

View File

@ -54,8 +54,10 @@ struct __attribute__((packed, aligned(2))) BattleMoveEffect
const u8 *battleScript;
u16 battleTvScore:3;
u16 encourageEncore:1;
u16 twoTurnEffect:1;
u16 semiInvulnerableEffect:1;
u16 flags:11; // coming soon...
u16 usesProtectCounter:1;
u16 padding:9;
};
#define GET_MOVE_BATTLESCRIPT(move) gBattleMoveEffects[gMovesInfo[move].effect].battleScript
@ -612,7 +614,6 @@ struct BattleStruct
u32 expValue;
u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share
u8 expGetterMonId;
u8 additionalEffectsCounter:2;
u8 expOrderId:3;
u8 expGetterBattlerId:2;
u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed.
@ -736,6 +737,7 @@ struct BattleStruct
u8 forcedSwitch:4; // For each battler
u8 blunderPolicy:1; // should blunder policy activate
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 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.

View File

@ -201,7 +201,8 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move);
bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId);
bool32 IsPartnerMonFromSameTrainer(u32 battler);
u8 GetCategoryBasedOnStats(u32 battler);
bool32 TestSheerForceFlag(u32 battler, u16 move);
bool32 MoveIsAffectedBySheerForce(u16 move);
bool32 TestIfSheerForceAffected(u32 battler, u16 move);
void TryRestoreHeldItems(void);
bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item);
void TrySaveExchangedItem(u32 battler, u16 stolenItem);
@ -222,11 +223,11 @@ void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon);
void RecalcBattlerStats(u32 battler, struct Pokemon *mon);
bool32 IsAlly(u32 battlerAtk, u32 battlerDef);
bool32 IsGen6ExpShareEnabled(void);
bool32 MoveHasMoveEffect(u32 move, u32 moveEffect);
bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance);
bool32 MoveHasMoveEffectSelf(u32 move, u32 moveEffect);
bool32 MoveHasMoveEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
bool32 MoveHasChargeTurnMoveEffect(u32 move);
bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect);
bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance);
bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect);
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
bool32 CanSleep(u32 battler);
bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget);

View File

@ -451,44 +451,40 @@ struct MoveInfo
const u8 *name;
const u8 *description;
u16 effect;
u8 power;
u8 type:5;
u8 category:3;
u16 type:5;
u16 category:2;
u16 power:9; // up to 511
u16 accuracy:7;
u16 recoil:7;
u16 criticalHitStage:2;
u8 padding:6; // coming soon...
u8 numAdditionalEffects:2; // limited to 3 - don't want to get too crazy
u16 target:9;
u8 pp;
u16 target;
s8 priority;
union {
u8 effect;
u8 powerOverride;
} zMove;
s32 priority:4;
u32 recoil:7;
u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit.
u32 criticalHitStage:2;
u32 alwaysCriticalHit:1;
// 14 bits left to complete this word - continues into flags
// Flags
u32 makesContact:1;
u32 ignoresProtect:1;
u32 magicCoatAffected:1;
u32 snatchAffected:1;
u32 mirrorMoveBanned:1;
u32 ignoresKingsRock:1;
u32 alwaysCriticalHit:1;
u32 twoTurnMove:1;
u32 punchingMove:1;
u32 sheerForceBoost:1;
u32 bitingMove:1;
u32 pulseMove:1;
u32 soundMove:1;
u32 ballisticMove:1;
u32 protectionMove:1;
u32 powderMove:1;
u32 danceMove:1;
u32 windMove:1;
u32 slicingMove:1;
u32 slicingMove:1; // end of word
u32 healingMove:1;
u32 minimizeDoubleDamage:1;
u32 ignoresTargetAbility:1;
u32 ignoresTargetDefenseEvasionStages:1;
@ -499,11 +495,12 @@ struct MoveInfo
u32 ignoreTypeIfFlyingAndUngrounded:1;
u32 thawsUser:1;
u32 ignoresSubstitute:1;
u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit.
u32 forcePressure:1;
u32 cantUseTwice:1;
// Ban flags
u32 gravityBanned:1;
u32 healingMove:1;
u32 mirrorMoveBanned:1;
u32 meFirstBanned:1;
u32 mimicBanned:1;
u32 metronomeBanned:1;
@ -516,10 +513,10 @@ struct MoveInfo
u32 skyBattleBanned:1;
u32 sketchBanned:1;
u32 argument; // also coming soon
u32 argument;
// primary/secondary effects
const struct AdditionalEffect *additionalEffects;
uintptr_t additionalEffects;
// contest parameters
u8 contestEffect;
@ -529,15 +526,23 @@ struct MoveInfo
};
#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(...) ((min(ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ )), 15)) << 28) + (uintptr_t)(EFFECTS_ARR( __VA_ARGS__ ))
// Retrieve a move's additional effects and the count thereof
#define GET_ADDITIONAL_EFFECTS(move) (void *)(gMovesInfo[move].additionalEffects & 0x8FFFFFF)
#define GET_ADDITIONAL_EFFECT_COUNT(move) (gMovesInfo[move].additionalEffects >> 28)
#define GET_ADDITIONAL_EFFECTS_AND_COUNT(move, _count, _effects) u32 _count = GET_ADDITIONAL_EFFECT_COUNT(move); const struct AdditionalEffect *_effects = GET_ADDITIONAL_EFFECTS(move)
// 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, }
struct AdditionalEffect
{
u16 moveEffect;
u8 self:1;
u8 onlyIfTargetRaisedStats:1;
u8 onChargeTurnOnly:1;
u8 chance; // 0% = effect certain, primary effect
u16 moveEffect;
};
struct Ability

View File

@ -2507,8 +2507,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (instructedMove == MOVE_NONE
|| gMovesInfo[instructedMove].instructBanned
|| gMovesInfo[instructedMove].twoTurnMove
|| MoveHasMoveEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE)
|| MoveHasAdditionalEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE)
|| IsZMove(instructedMove)
|| (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF)
|| gBattleMons[battlerDef].status2 & STATUS2_MULTIPLETURNS
@ -3229,6 +3228,9 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
// additional effects
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
s32 score = 0;
u32 predictedMove = aiData->predictedMoves[battlerDef];
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
@ -4458,19 +4460,19 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
} // move effect checks
// 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
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &gMovesInfo[move].additionalEffects[i]))
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &additionalEffects[i]))
continue;
// 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 twoStageStatId = STAT_CHANGE_ATK_2 + 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 + 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_1:
@ -4521,7 +4523,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
}
else // consider move effects that hinder the target
{
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
switch (additionalEffects[i].moveEffect)
{
case MOVE_EFFECT_FLINCH:
score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move);
@ -4805,11 +4807,13 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_HIT:
{
// TEMPORARY - should applied to all moves regardless of EFFECT
// 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_SPIKES:
@ -4819,6 +4823,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
break;
}
}
}
default:
break;
}
@ -4859,11 +4864,13 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_HIT:
{
// TEMPORARY - should applied to all moves regardless of EFFECT
// 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:
if (Random() & 1)
@ -4873,6 +4880,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
}
}
}
default:
break;
}

View File

@ -519,6 +519,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
u32 i;
u32 abilityDef = AI_DATA->abilities[battlerDef];
u32 abilityAtk = AI_DATA->abilities[battlerAtk];
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
switch (gMovesInfo[move].effect)
{
@ -533,12 +534,12 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
}
// check ADDITIONAL_EFFECTS
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
for (i = 0; i < additionalEffectsCount; i++)
{
// 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:
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK))
@ -568,7 +569,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
}
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_TOXIC:
@ -602,7 +603,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
case MOVE_EFFECT_SP_DEF_MINUS_1:
case MOVE_EFFECT_ACC_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;
break;
case MOVE_EFFECT_ATK_MINUS_2:
@ -612,7 +613,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
case MOVE_EFFECT_SP_DEF_MINUS_2:
case MOVE_EFFECT_ACC_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;
break;
}
@ -642,9 +643,12 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
return TRUE;
break;
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_DEF_MINUS_1:
@ -656,16 +660,17 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
case MOVE_EFFECT_DEF_SPDEF_DOWN:
case MOVE_EFFECT_SP_DEF_MINUS_1:
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)))
return TRUE;
break;
case MOVE_EFFECT_RECHARGE:
return gMovesInfo[move].additionalEffects[i].self;
return additionalEffects[i].self;
}
}
break;
}
}
return FALSE;
}
@ -1716,7 +1721,7 @@ bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect)
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
&& MoveHasMoveEffect(moves[i], moveEffect))
&& MoveHasAdditionalEffect(moves[i], moveEffect))
return TRUE;
}
@ -1747,7 +1752,7 @@ bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
&& gMovesInfo[moves[i]].effect != exception
&& MoveHasMoveEffect(moves[i], moveEffect))
&& MoveHasAdditionalEffect(moves[i], moveEffect))
return TRUE;
}
@ -1843,8 +1848,8 @@ bool32 IsTrappingMove(u32 move)
//case EFFECT_NO_RETREAT: // TODO
return TRUE;
default:
return MoveHasMoveEffect(move, MOVE_EFFECT_PREVENT_ESCAPE)
|| MoveHasMoveEffect(move, MOVE_EFFECT_WRAP);
return MoveHasAdditionalEffect(move, MOVE_EFFECT_PREVENT_ESCAPE)
|| MoveHasAdditionalEffect(move, MOVE_EFFECT_WRAP);
}
}
@ -2738,7 +2743,7 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move)
bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move)
{
if ((!gDisableStructs[battlerAtk].isFirstTurn && MoveHasMoveEffectWithChance(move, MOVE_EFFECT_FLINCH, 100))
if ((!gDisableStructs[battlerAtk].isFirstTurn && MoveHasAdditionalEffectWithChance(move, MOVE_EFFECT_FLINCH, 100))
|| AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS
|| AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK

View File

@ -4059,7 +4059,7 @@ static bool32 IsDomeStatusMoveEffect(u32 move)
case EFFECT_CURSE:
return TRUE;
default:
return MoveHasMoveEffect(move, MOVE_EFFECT_WRAP);
return MoveHasAdditionalEffect(move, MOVE_EFFECT_WRAP);
}
}
@ -4388,7 +4388,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
allocatedArray[k] = (gMovesInfo[move].pp <= 5) ? 1 : 0;
break;
case MOVE_POINTS_EFFECT:
allocatedArray[k] = gMovesInfo[move].sheerForceBoost;
allocatedArray[k] = MoveIsAffectedBySheerForce(move);
break;
}
}

View File

@ -1370,7 +1370,7 @@ static void Cmd_attackcanceler(void)
gHitMarker |= HITMARKER_OBEYS;
// Check if no available target present on the field or if Sky Battles ban the move
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
&& (!gMovesInfo[gCurrentMove].twoTurnMove || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
&& (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
|| (IsMoveNotAllowedInSkyBattles(gCurrentMove)))
{
if (gMovesInfo[gCurrentMove].effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling.
@ -1378,7 +1378,7 @@ static void Cmd_attackcanceler(void)
else
gBattlescriptCurrInstr = BattleScript_FailedFromAtkString;
if (!gMovesInfo[gCurrentMove].twoTurnMove || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
if (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
CancelMultiTurnMoves(gBattlerAttacker);
return;
}
@ -1457,7 +1457,7 @@ static void Cmd_attackcanceler(void)
}
else if (IsBattlerProtected(gBattlerTarget, gCurrentMove)
&& (gCurrentMove != MOVE_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
&& ((!gMovesInfo[gCurrentMove].twoTurnMove || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
&& (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
&& gMovesInfo[gCurrentMove].effect != EFFECT_SUCKER_PUNCH
&& gMovesInfo[gCurrentMove].effect != EFFECT_UPPER_HAND)
{
@ -2749,13 +2749,13 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem)
#define INCREMENT_RESET_RETURN \
{ \
gBattlescriptCurrInstr++; \
gBattleScripting.moveEffect = 0; \
gBattleScripting.moveEffect = 0; \
return; \
}
#define RESET_RETURN \
{ \
gBattleScripting.moveEffect = 0; \
gBattleScripting.moveEffect = 0; \
return; \
}
@ -2768,6 +2768,10 @@ void SetMoveEffect(bool32 primary, bool32 certain)
u16 battlerAbility;
bool8 activateAfterFaint = FALSE;
// NULL move effect
if (gBattleScripting.moveEffect == 0)
return;
if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_1ST_HIT
&& gBattleMons[gBattlerTarget].hp != 0
&& IsFinalStrikeEffect(gBattleScripting.moveEffect))
@ -2827,7 +2831,10 @@ void SetMoveEffect(bool32 primary, bool32 certain)
&& !primary && gBattleScripting.moveEffect <= MOVE_EFFECT_CONFUSION)
INCREMENT_RESET_RETURN
if (TestSheerForceFlag(gBattlerAttacker, gCurrentMove) && !primary && gBattleScripting.moveEffect != MOVE_EFFECT_CHARGING)
if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT)
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& !primary
&& gBattleScripting.moveEffect != MOVE_EFFECT_CHARGING)
INCREMENT_RESET_RETURN
if (gBattleMons[gEffectBattler].hp == 0 && !activateAfterFaint)
@ -3306,12 +3313,14 @@ void SetMoveEffect(bool32 primary, bool32 certain)
case MOVE_EFFECT_ACC_MINUS_1:
case MOVE_EFFECT_EVS_MINUS_1:
flags = affectsUser;
if (mirrorArmorReflected && !affectsUser)
flags |= STAT_CHANGE_ALLOW_PTR;
if (mirrorArmorReflected)
flags |= (STAT_CHANGE_ALLOW_PTR * !affectsUser);
else
flags |= STAT_CHANGE_UPDATE_MOVE_EFFECT;
if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE,
gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1,
flags | STAT_CHANGE_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1))
flags, gBattlescriptCurrInstr + 1))
{
if (!mirrorArmorReflected)
gBattlescriptCurrInstr++;
@ -3823,34 +3832,47 @@ void SetMoveEffect(bool32 primary, bool32 certain)
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)
{
CMD_ARGS();
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;
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
u32 percentChance, i = gBattleStruct->additionalEffectsCounter;
const u8 *currentPtr = gBattlescriptCurrInstr;
const struct AdditionalEffect *additionalEffect = &gMovesInfo[gCurrentMove].additionalEffects[gBattleStruct->additionalEffectsCounter];
// Check additional effect flags
// self-targeting move effects cannot occur multiple times per turn
// 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)
// Various checks for if this move effect can be applied this turn
if (CanApplyAdditionalEffect(&additionalEffects[i]))
{
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
if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + gBattleStruct->additionalEffectsCounter, percentChance))
if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + (i % 3), percentChance))
{
gBattleScripting.moveEffect = additionalEffect->moveEffect | (MOVE_EFFECT_AFFECTS_USER * (additionalEffect->self));
gBattleScripting.moveEffect = additionalEffects[i].moveEffect | (MOVE_EFFECT_AFFECTS_USER * (additionalEffects[i].self));
SetMoveEffect(
percentChance == 0, // a primary effect
@ -3865,7 +3887,7 @@ static void Cmd_setadditionaleffects(void)
// Call setadditionaleffects again in the case of a move with multiple effects
gBattleStruct->additionalEffectsCounter++;
if (gMovesInfo[gCurrentMove].numAdditionalEffects > gBattleStruct->additionalEffectsCounter)
if (additionalEffectsCount > gBattleStruct->additionalEffectsCounter)
gBattleScripting.moveEffect = MOVE_EFFECT_CONTINUE;
else
gBattleScripting.moveEffect = gBattleStruct->additionalEffectsCounter = 0;
@ -5761,7 +5783,7 @@ static void Cmd_moveend(void)
&& GetBattlerSide(gBattlerTarget) != GetBattlerSide(gBattlerAttacker)
&& gProtectStructs[gBattlerTarget].physicalDmg
&& gProtectStructs[gBattlerTarget].physicalBattlerId == gBattlerAttacker
&& !TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
{
gProtectStructs[gBattlerTarget].shellTrap = TRUE;
// Change move order in double battles, so the hit mon with shell trap moves immediately after being hit.
@ -5992,7 +6014,7 @@ static void Cmd_moveend(void)
case MOVEEND_EJECT_BUTTON:
if (gMovesInfo[gCurrentMove].effect != EFFECT_HIT_SWITCH_TARGET
&& IsBattlerAlive(gBattlerAttacker)
&& !TestSheerForceFlag(gBattlerAttacker, gCurrentMove)
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER || (gBattleTypeFlags & BATTLE_TYPE_TRAINER)))
{
// Since we check if battler was damaged, we don't need to check move result.
@ -6025,7 +6047,7 @@ static void Cmd_moveend(void)
case MOVEEND_RED_CARD:
if ((gMovesInfo[gCurrentMove].effect != EFFECT_HIT_SWITCH_TARGET || gBattleStruct->hitSwitchTargetFailed)
&& IsBattlerAlive(gBattlerAttacker)
&& !TestSheerForceFlag(gBattlerAttacker, gCurrentMove)
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_GUARD_DOG)
{
// Since we check if battler was damaged, we don't need to check move result.
@ -6095,7 +6117,7 @@ static void Cmd_moveend(void)
if (IsBattlerAlive(gBattlerAttacker)
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]) // But not knocked off
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)) // Pickpocket doesn't activate for sheer force
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) // Pickpocket doesn't activate for sheer force
&& IsMoveMakingContact(gCurrentMove, gBattlerAttacker) // Pickpocket requires contact
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked
{
@ -6224,7 +6246,7 @@ static void Cmd_moveend(void)
*(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3;
if (B_RAMPAGE_CANCELLING >= GEN_5
&& MoveHasMoveEffectSelf(gCurrentMove, MOVE_EFFECT_THRASH) // If we're rampaging
&& MoveHasAdditionalEffectSelf(gCurrentMove, MOVE_EFFECT_THRASH) // If we're rampaging
&& (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) // And it is unusable
&& (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
@ -9678,8 +9700,10 @@ static void Cmd_various(void)
{
VARIOUS_ARGS(const u8 *failInstr);
u16 move = gLastPrintedMoves[gBattlerTarget];
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || MoveHasMoveEffectSelf(move, MOVE_EFFECT_RECHARGE)
|| gMovesInfo[move].instructBanned || gMovesInfo[move].twoTurnMove || IsDynamaxed(gBattlerTarget))
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || MoveHasAdditionalEffectSelf(move, MOVE_EFFECT_RECHARGE)
|| gMovesInfo[move].instructBanned
|| gBattleMoveEffects[gMovesInfo[move].effect].twoTurnEffect
|| IsDynamaxed(gBattlerTarget))
{
gBattlescriptCurrInstr = cmd->failInstr;
}
@ -10760,7 +10784,8 @@ static void TryResetProtectUseCounter(u32 battler)
{
u32 lastMove = gLastResultingMoves[battler];
if (lastMove == MOVE_UNAVAILABLE
|| (!gMovesInfo[lastMove].protectionMove && (B_ALLY_SWITCH_FAIL_CHANCE >= GEN_9 && gMovesInfo[lastMove].effect != EFFECT_ALLY_SWITCH)))
|| (!gBattleMoveEffects[gMovesInfo[lastMove].effect].usesProtectCounter
&& (B_ALLY_SWITCH_FAIL_CHANCE >= GEN_9 && gMovesInfo[lastMove].effect != EFFECT_ALLY_SWITCH)))
gDisableStructs[battler].protectUses = 0;
}
@ -11730,7 +11755,7 @@ static void Cmd_twoturnmoveschargestringandanimation(void)
CMD_ARGS(const u8 *animationThenStringPtr);
gBattleScripting.savedStringId = LOHALF(gMovesInfo[gCurrentMove].argument);
if (B_UPDATED_MOVE_DATA < GEN_5 || MoveHasChargeTurnMoveEffect(gCurrentMove))
if (B_UPDATED_MOVE_DATA < GEN_5 || MoveHasChargeTurnAdditionalEffect(gCurrentMove))
gBattlescriptCurrInstr = cmd->animationThenStringPtr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
@ -12741,7 +12766,7 @@ static void Cmd_settypetorandomresistance(void)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gMovesInfo[gLastLandedMoves[gBattlerAttacker]].twoTurnMove
else if (gBattleMoveEffects[gMovesInfo[gLastLandedMoves[gBattlerAttacker]].effect].twoTurnEffect
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
{
gBattlescriptCurrInstr = cmd->failInstr;
@ -12857,7 +12882,7 @@ static void Cmd_trychoosesleeptalkmove(void)
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].sleepTalkBanned
|| gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].twoTurnMove)
|| gBattleMoveEffects[gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].effect].twoTurnEffect)
{
unusableMovesBits |= gBitTable[i];
}
@ -13709,7 +13734,7 @@ static bool32 CheckIfCanFireTwoTurnMoveNow(u8 battler, bool8 checkChargeTurnEffe
return FALSE;
// If this move has charge turn effects, it must charge, activate them, then try to fire
if (checkChargeTurnEffects && MoveHasChargeTurnMoveEffect(gCurrentMove))
if (checkChargeTurnEffects && MoveHasChargeTurnAdditionalEffect(gCurrentMove))
return FALSE;
// Insert custom conditions here
@ -15731,12 +15756,13 @@ static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 byIntimidate)
static bool8 CanBurnHitThaw(u16 move)
{
u8 i;
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, additionalEffectsCount, additionalEffects);
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;
}
}

View File

@ -942,15 +942,15 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3)
// Various cases to add/remove points
if (gMovesInfo[arg2].recoil > 0)
baseFromEffect++; // Recoil moves
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_RAPID_SPIN))
if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_RAPID_SPIN))
baseFromEffect++;
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_SP_ATK_TWO_DOWN) || MoveHasMoveEffect(arg2, MOVE_EFFECT_ATK_DEF_DOWN))
if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_SP_ATK_TWO_DOWN) || MoveHasAdditionalEffect(arg2, MOVE_EFFECT_ATK_DEF_DOWN))
baseFromEffect += 2; // Overheat, Superpower, etc.
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_STEAL_ITEM))
if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_STEAL_ITEM))
baseFromEffect += 3;
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_WRAP) || MoveHasMoveEffectSelf(arg2, MOVE_EFFECT_THRASH))
if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_WRAP) || MoveHasAdditionalEffectSelf(arg2, MOVE_EFFECT_THRASH))
baseFromEffect += 3;
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_RECHARGE))
if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_RECHARGE))
baseFromEffect += 4;
movePoints->points[atkSide][gBattlerPartyIndexes[gBattlerAttacker] * 4 + arg1] += baseFromEffect;

View File

@ -3445,7 +3445,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
case CANCELLER_THAW: // move thawing
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE)
{
if (!(MoveHasMoveEffectSelfArg(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE)))
if (!(MoveHasAdditionalEffectSelfArg(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE)))
{
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE;
BattleScriptPushCursor();
@ -3456,7 +3456,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
}
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && gMovesInfo[gCurrentMove].thawsUser)
{
if (!(MoveHasMoveEffectSelfArg(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE)))
if (!(MoveHasAdditionalEffectSelfArg(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE)))
{
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FROSTBITE;
BattleScriptPushCursor();
@ -5172,7 +5172,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& IsBattlerAlive(battler)
&& HadMoreThanHalfHpNowHasLess(battler)
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{
gEffectBattler = battler;
@ -5190,7 +5190,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
// Had more than half of hp before, now has less
&& HadMoreThanHalfHpNowHasLess(battler)
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
&& CountUsablePartyMons(battler) > 0
@ -5320,7 +5320,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& IsMoveMakingContact(move, gBattlerAttacker))
{
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_GooeyActivates;
@ -5621,7 +5620,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1) // Activates after all hits from a multi-hit move.
&& IsBattlerAlive(gBattlerTarget)
&& HadMoreThanHalfHpNowHasLess(gBattlerTarget)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)))
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)))
{
gBattlerAttacker = gBattlerTarget;
BattleScriptPushCursor();
@ -5686,7 +5685,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& RandomWeighted(RNG_STENCH, 9, 1)
&& TARGET_TURN_DAMAGED
&& !MoveHasMoveEffect(gCurrentMove, MOVE_EFFECT_FLINCH))
&& !MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH))
{
gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH;
BattleScriptPushCursor();
@ -7649,7 +7648,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_LIFE_ORB:
if (IsBattlerAlive(gBattlerAttacker)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
&& !gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
@ -8851,7 +8850,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
modifier = uq4_12_multiply(modifier, UQ_4_12(1.2));
break;
case ABILITY_SHEER_FORCE:
if (gMovesInfo[move].sheerForceBoost)
if (MoveIsAffectedBySheerForce(move))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
break;
case ABILITY_SAND_FORCE:
@ -10807,12 +10806,9 @@ bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
return ret;
}
bool32 TestSheerForceFlag(u32 battler, u16 move)
bool32 TestIfSheerForceAffected(u32 battler, u16 move)
{
if (GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && gMovesInfo[move].sheerForceBoost)
return TRUE;
else
return FALSE;
return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
}
// This function is the body of "jumpifstat", but can be used dynamically in a function
@ -11082,56 +11078,50 @@ bool32 IsGen6ExpShareEnabled(void)
return FlagGet(I_EXP_SHARE_FLAG);
}
bool32 MoveHasMoveEffect(u32 move, u32 moveEffect)
{
u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
{
if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect
&& gMovesInfo[move].additionalEffects[i].self == FALSE)
return TRUE;
}
#define R_CHECK_MOVE_EFFECT(...) RECURSIVELY(R_FOR_EACH(CHECK_MOVE_EFFECT, __VA_ARGS__))
#define CHECK_MOVE_EFFECT(_condition) && effects[i]._condition
/* Quick way of checking if a move has move effects with match a few
comma-separated conditions. Each condition has to check a field of AdditionalEffect. */
#define RETURN_HAS_MOVE_ADDITIONAL_EFFECT(condition1, ...) \
u32 i; \
GET_ADDITIONAL_EFFECTS_AND_COUNT(move, count, effects); \
for (i = 0; i < count; i++) \
{ \
if (effects[i].condition1 R_CHECK_MOVE_EFFECT(__VA_ARGS__)) \
return TRUE; \
} \
return FALSE;
bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect)
{
RETURN_HAS_MOVE_ADDITIONAL_EFFECT(moveEffect == moveEffect, self == FALSE)
}
bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance)
bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance)
{
u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
{
if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect
&& gMovesInfo[move].additionalEffects[i].chance == chance)
return TRUE;
}
return FALSE;
RETURN_HAS_MOVE_ADDITIONAL_EFFECT(moveEffect == moveEffect, chance == chance)
}
bool32 MoveHasMoveEffectSelf(u32 move, u32 moveEffect)
bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect)
{
u32 i;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
{
if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect
&& gMovesInfo[move].additionalEffects[i].self == TRUE)
return TRUE;
}
return FALSE;
RETURN_HAS_MOVE_ADDITIONAL_EFFECT(moveEffect == moveEffect, self == TRUE)
}
bool32 MoveHasMoveEffectSelfArg(u32 move, u32 moveEffect, u32 argument)
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument)
{
return (gMovesInfo[move].argument == argument) && MoveHasMoveEffectSelf(move, moveEffect);
return (gMovesInfo[move].argument == argument) && MoveHasAdditionalEffectSelf(move, moveEffect);
}
bool32 MoveHasChargeTurnMoveEffect(u32 move)
bool32 MoveHasChargeTurnAdditionalEffect(u32 move)
{
u8 i = 0;
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
{
if (gMovesInfo[move].additionalEffects[i].onChargeTurnOnly)
return TRUE;
}
return FALSE;
RETURN_HAS_MOVE_ADDITIONAL_EFFECT(onChargeTurnOnly == TRUE)
}
bool32 MoveIsAffectedBySheerForce(u16 move)
{
RETURN_HAS_MOVE_ADDITIONAL_EFFECT(chance > 0)
}
bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon)

View File

@ -384,6 +384,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
{
.battleScript = BattleScript_EffectTwoTurnsAttack,
.battleTvScore = 3,
.twoTurnEffect = TRUE,
},
[EFFECT_SUBSTITUTE] =
@ -569,6 +570,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleScript = BattleScript_EffectProtect,
.battleTvScore = 5,
.encourageEncore = TRUE,
.usesProtectCounter = TRUE,
},
[EFFECT_SPIKES] =
@ -603,6 +605,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleScript = BattleScript_EffectEndure,
.battleTvScore = 3,
.encourageEncore = TRUE,
.usesProtectCounter = TRUE,
},
[EFFECT_ROLLOUT] =
@ -765,6 +768,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
{
.battleScript = BattleScript_EffectTwoTurnsAttack,
.battleTvScore = 1,
.twoTurnEffect = TRUE,
},
[EFFECT_THUNDER] =
@ -789,6 +793,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
{
.battleScript = BattleScript_EffectTwoTurnsAttack,
.battleTvScore = 3,
.twoTurnEffect = TRUE,
.semiInvulnerableEffect = TRUE,
},
@ -1791,6 +1796,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
{
.battleScript = BattleScript_EffectGeomancy,
.battleTvScore = 0, // TODO: Assign points
.twoTurnEffect = TRUE,
},
[EFFECT_FAIRY_LOCK] =
@ -1993,6 +1999,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
{
.battleScript = BattleScript_EffectSkyDrop,
.battleTvScore = 0, // TODO: Assign points
.twoTurnEffect = TRUE,
.semiInvulnerableEffect = TRUE,
},

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@ SINGLE_BATTLE_TEST("Contrary raises stats after using a move which would normall
PARAMETRIZE { ability = ABILITY_CONTRARY; }
PARAMETRIZE { ability = ABILITY_TANGLED_FEET; }
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
ASSUME(gMovesInfo[MOVE_OVERHEAT].category == DAMAGE_CATEGORY_SPECIAL);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SPINDA) { Ability(ability); }

View File

@ -9,7 +9,7 @@ SINGLE_BATTLE_TEST("Corrosion can poison or badly poison a Pokemon regardless of
PARAMETRIZE { species = SPECIES_BELDUM; }
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_TWINEEDLE, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_TWINEEDLE, MOVE_EFFECT_POISON) == TRUE);
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
OPPONENT(species);
} WHEN {
@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Corrosion can poison or badly poison a Steel type with a sta
SINGLE_BATTLE_TEST("Corrosion does not effect poison type damaging moves if the target is immune to it")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_SLUDGE_BOMB, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_SLUDGE_BOMB, MOVE_EFFECT_POISON) == TRUE);
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
OPPONENT(SPECIES_BELDUM);
} WHEN {

View File

@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("Hyper Cutter is ignored by Mold Breaker")
SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Attack stage reduction from moves used by the user")
{
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_SUPERPOWER, MOVE_EFFECT_ATK_DEF_DOWN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_SUPERPOWER, MOVE_EFFECT_ATK_DEF_DOWN) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); }
} WHEN {
@ -117,7 +117,7 @@ SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Spectral Thief from resetting p
{
GIVEN {
ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2);
ASSUME(MoveHasMoveEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF));
ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); }
} WHEN {

View File

@ -4,7 +4,7 @@
SINGLE_BATTLE_TEST("Immunity prevents Poison Sting poison")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_IMMUNITY); }
} WHEN {

View File

@ -174,7 +174,7 @@ SINGLE_BATTLE_TEST("Keen Eye & Gen9+ Illuminate don't prevent Spectral Thief fro
GIVEN {
ASSUME(gMovesInfo[MOVE_HONE_CLAWS].effect == EFFECT_ATTACK_ACCURACY_UP);
ASSUME(MoveHasMoveEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {

View File

@ -198,7 +198,6 @@ DOUBLE_BATTLE_TEST("Mirror Armor lowers Speed of the partner Pokemon after Court
SINGLE_BATTLE_TEST("Mirror Armor reflects Tangling Hair speed drop")
{
KNOWN_FAILING;
GIVEN {
PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); }
OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }

View File

@ -44,7 +44,7 @@ SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the opponent")
SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user")
{
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_PETAL_DANCE, MOVE_EFFECT_THRASH));
ASSUME(MoveHasAdditionalEffectSelf(MOVE_PETAL_DANCE, MOVE_EFFECT_THRASH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
} WHEN {

View File

@ -4,7 +4,7 @@
SINGLE_BATTLE_TEST("Pastel Veil prevents Poison Sting poison")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_PONYTA_GALARIAN) { Ability(ABILITY_PASTEL_VEIL); }
} WHEN {
@ -18,7 +18,7 @@ SINGLE_BATTLE_TEST("Pastel Veil prevents Poison Sting poison")
DOUBLE_BATTLE_TEST("Pastel Veil prevents Poison Sting poison on partner")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_PONYTA_GALARIAN) { Ability(ABILITY_PASTEL_VEIL); }

View File

@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Purifying Salt grants immunity to status effects")
ASSUME(gMovesInfo[MOVE_HYPNOSIS].effect == EFFECT_SLEEP);
ASSUME(gMovesInfo[MOVE_THUNDER_WAVE].effect == EFFECT_PARALYZE);
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
ASSUME(MoveHasMoveEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_PURIFYING_SALT); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -1,6 +1,12 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(MoveIsAffectedBySheerForce(MOVE_ELECTRO_SHOT) == TRUE);
}
SINGLE_BATTLE_TEST("Sheer Force boosts power, but removes secondary effects of moves", s16 damage)
{
s32 j;
@ -8,7 +14,7 @@ SINGLE_BATTLE_TEST("Sheer Force boosts power, but removes secondary effects of m
for (j = 1; j < MOVES_COUNT; j++)
{
if (gMovesInfo[j].sheerForceBoost
if (MoveIsAffectedBySheerForce(j)
//&& gMovesInfo[j].effect != EFFECT_ORDER_UP
&& gMovesInfo[j].effect != EFFECT_AURA_WHEEL
&& gMovesInfo[j].effect != EFFECT_PLACEHOLDER)

View File

@ -13,13 +13,13 @@ SINGLE_BATTLE_TEST("Shield Dust blocks secondary effects")
PARAMETRIZE { move = MOVE_PSYCHIC_NOISE; }
GIVEN {
ASSUME(MoveHasMoveEffectWithChance(MOVE_NUZZLE, MOVE_EFFECT_PARALYSIS, 100) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_INFERNO, MOVE_EFFECT_BURN, 100) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, 100) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_ROCK_TOMB, MOVE_EFFECT_SPD_MINUS_1, 100) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_SPIRIT_SHACKLE, MOVE_EFFECT_PREVENT_ESCAPE, 100) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_NUZZLE, MOVE_EFFECT_PARALYSIS, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_INFERNO, MOVE_EFFECT_BURN, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_ROCK_TOMB, MOVE_EFFECT_SPD_MINUS_1, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SPIRIT_SHACKLE, MOVE_EFFECT_PREVENT_ESCAPE, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE, 100) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); }
} WHEN {
@ -49,11 +49,11 @@ SINGLE_BATTLE_TEST("Shield Dust does not block primary effects")
PARAMETRIZE { move = MOVE_PAY_DAY; }
GIVEN {
ASSUME(MoveHasMoveEffectWithChance(MOVE_INFESTATION, MOVE_EFFECT_WRAP, 0) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH, 0) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY, 0) == TRUE);
ASSUME(MoveHasMoveEffectWithChance(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_INFESTATION, MOVE_EFFECT_WRAP, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); }
} WHEN {
@ -93,10 +93,10 @@ SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary o
PARAMETRIZE { move = MOVE_METEOR_ASSAULT; }
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); }
} WHEN {

View File

@ -35,7 +35,7 @@ DOUBLE_BATTLE_TEST("Stench only triggers if target takes damage")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
ASSUME(MoveHasMoveEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_GRIMER) { Ability(ABILITY_STENCH); }
@ -59,7 +59,7 @@ DOUBLE_BATTLE_TEST("Stench doesn't trigger if partner uses a move")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
ASSUME(MoveHasMoveEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
PLAYER(SPECIES_WOBBUFFET) { Speed(20); }
PLAYER(SPECIES_WYNAUT) { Speed(10); }
OPPONENT(SPECIES_GRIMER) { Speed(100); Ability(ABILITY_STENCH); }

View File

@ -81,7 +81,7 @@ AI_SINGLE_BATTLE_TEST("AI will not use Throat Chop if opposing mon has a better
ASSUME(gMovesInfo[MOVE_THROAT_CHOP].power == 80);
ASSUME(gMovesInfo[MOVE_DISARMING_VOICE].power == 40);
ASSUME(gMovesInfo[MOVE_FLAME_BURST].power == 70);
ASSUME(MoveHasMoveEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_REGIROCK) { Speed(15); Moves(MOVE_DISARMING_VOICE, MOVE_FLAME_BURST); };
OPPONENT(SPECIES_WOBBUFFET) { Speed(20); Moves(MOVE_THROAT_CHOP, MOVE_PSYCHIC_FANGS); }
@ -95,7 +95,7 @@ AI_SINGLE_BATTLE_TEST("AI will not use Throat Chop if opposing mon has a better
AI_SINGLE_BATTLE_TEST("AI will select Throat Chop if the sound move is the best damaging move from opposing mon")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE);
ASSUME(gMovesInfo[MOVE_PSYCHIC_FANGS].power == 85);
ASSUME(gMovesInfo[MOVE_THROAT_CHOP].power == 80);
ASSUME(gMovesInfo[MOVE_FLAME_BURST].power == 70);

View File

@ -4,7 +4,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_BODY_SLAM, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_BODY_SLAM, MOVE_EFFECT_PARALYSIS) == TRUE);
}
AI_SINGLE_BATTLE_TEST("AI sees increased base power of Facade")
@ -82,7 +82,7 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Grav Apple")
GIVEN {
ASSUME(gMovesInfo[MOVE_GRAV_APPLE].effect == EFFECT_GRAV_APPLE);
ASSUME(gMovesInfo[MOVE_GRAV_APPLE].power == gMovesInfo[MOVE_DRUM_BEATING].power);
ASSUME(MoveHasMoveEffect(MOVE_DRUM_BEATING, MOVE_EFFECT_SPD_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_DRUM_BEATING, MOVE_EFFECT_SPD_MINUS_1) == TRUE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET) { HP(81); Speed(20); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(10); Moves(MOVE_DRUM_BEATING, MOVE_GRAV_APPLE); }
@ -179,8 +179,8 @@ AI_SINGLE_BATTLE_TEST("AI chooses moves with secondary effect that have a 100% c
PARAMETRIZE { ability = ABILITY_SERENE_GRACE; }
GIVEN {
ASSUME(MoveHasMoveEffectWithChance(MOVE_SHADOW_BALL, MOVE_EFFECT_SP_DEF_MINUS_1, 20));
ASSUME(MoveHasMoveEffectWithChance(MOVE_OCTAZOOKA, MOVE_EFFECT_ACC_MINUS_1, 50));
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SHADOW_BALL, MOVE_EFFECT_SP_DEF_MINUS_1, 20));
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_OCTAZOOKA, MOVE_EFFECT_ACC_MINUS_1, 50));
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_REGICE);
OPPONENT(SPECIES_REGIROCK) { Ability(ability); Moves(MOVE_SHADOW_BALL, MOVE_OCTAZOOKA); }

View File

@ -22,7 +22,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers to set up a powerful Status over fainting a ta
AI_SINGLE_BATTLE_TEST("AI will try to do damage on target instead of setting up hazards if target has a way to remove them")
{
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK);
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_POWERFUL_STATUS | AI_FLAG_OMNISCIENT);

View File

@ -3,7 +3,7 @@
SINGLE_BATTLE_TEST("Shaymin-Sky reverts to Shaymin-Land when frozen or frostbitten")
{
ASSUME(MoveHasMoveEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE));
ASSUME(MoveHasAdditionalEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE));
GIVEN {
PLAYER(SPECIES_SHAYMIN_SKY);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -109,7 +109,7 @@ SINGLE_BATTLE_TEST("Air Balloon pops before it can be stolen with Thief or Covet
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
ASSUME(MoveHasMoveEffect(move, MOVE_EFFECT_STEAL_ITEM) == TRUE);
ASSUME(MoveHasAdditionalEffect(move, MOVE_EFFECT_STEAL_ITEM) == TRUE);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_AIR_BALLOON); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -72,12 +72,12 @@ SINGLE_BATTLE_TEST("Clear Amulet prevents secondary effects that reduce stats")
PARAMETRIZE { move = MOVE_MUD_SLAP; }
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_AURORA_BEAM, MOVE_EFFECT_ATK_MINUS_1) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_ROCK_SMASH, MOVE_EFFECT_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_BUBBLE_BEAM, MOVE_EFFECT_SPD_MINUS_1) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_SNARL, MOVE_EFFECT_SP_ATK_MINUS_1) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_PSYCHIC, MOVE_EFFECT_SP_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_MUD_SLAP, MOVE_EFFECT_ACC_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_AURORA_BEAM, MOVE_EFFECT_ATK_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_ROCK_SMASH, MOVE_EFFECT_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_BUBBLE_BEAM, MOVE_EFFECT_SPD_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_SNARL, MOVE_EFFECT_SP_ATK_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_PSYCHIC, MOVE_EFFECT_SP_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_MUD_SLAP, MOVE_EFFECT_ACC_MINUS_1) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); };
} WHEN {

View File

@ -170,7 +170,7 @@ SINGLE_BATTLE_TEST("Red Card does not activate if stolen by a move")
bool32 activate;
PARAMETRIZE { item = ITEM_NONE; activate = FALSE; }
PARAMETRIZE { item = ITEM_POTION; activate = TRUE; }
ASSUME(MoveHasMoveEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE);
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); }

View File

@ -135,7 +135,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if it is knocked off o
KNOWN_FAILING; // Knock off fails, Thief is fine
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE);
ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF);
PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_WOBBUFFET);
@ -190,7 +190,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if Pickpocket steals i
{
KNOWN_FAILING; // White Herb is activated
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN));
ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN));
PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {

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")
{
u32 move;
PARAMETRIZE { move = MOVE_THUNDER_SHOCK; }
PARAMETRIZE { move = MOVE_DISCHARGE; }
PARAMETRIZE { move = MOVE_NUZZLE; }
ASSUME(MoveHasMoveEffect(move, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(0 < gMovesInfo[move].additionalEffects[0].chance && gMovesInfo[move].additionalEffects[0].chance <= 100);
PASSES_RANDOMLY(gMovesInfo[move].additionalEffects[0].chance, 100, RNG_SECONDARY_EFFECT);
u32 move, chance;
PARAMETRIZE { move = MOVE_THUNDER_SHOCK; chance = 10; }
PARAMETRIZE { move = MOVE_DISCHARGE; chance = 30; }
PARAMETRIZE { move = MOVE_NUZZLE; chance = 100; }
ASSUME(MoveHasAdditionalEffect(move, MOVE_EFFECT_PARALYSIS) == TRUE);
PASSES_RANDOMLY(chance, 100, RNG_SECONDARY_EFFECT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_AURA_WHEEL, MOVE_EFFECT_SPD_PLUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_AURA_WHEEL, MOVE_EFFECT_SPD_PLUS_1) == TRUE);
ASSUME(gMovesInfo[MOVE_AURA_WHEEL].effect == EFFECT_AURA_WHEEL);
}

View File

@ -4,7 +4,7 @@
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_AXE_KICK].effect == EFFECT_RECOIL_IF_MISS);
ASSUME(MoveHasMoveEffect(MOVE_AXE_KICK, MOVE_EFFECT_CONFUSION) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_AXE_KICK, MOVE_EFFECT_CONFUSION) == TRUE);
}
SINGLE_BATTLE_TEST("Axe Kick confuses the target")

View File

@ -5,7 +5,7 @@ ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS);
ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].argument == STATUS1_PSN_ANY);
ASSUME(MoveHasMoveEffect(MOVE_BARB_BARRAGE, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_BARB_BARRAGE, MOVE_EFFECT_POISON) == TRUE);
}
SINGLE_BATTLE_TEST("Barb Barrage inflicts poison")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_BUG_BITE, MOVE_EFFECT_BUG_BITE));
ASSUME(MoveHasAdditionalEffect(MOVE_BUG_BITE, MOVE_EFFECT_BUG_BITE));
ASSUME(gMovesInfo[MOVE_BUG_BITE].pp == 20);
}

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_EMBER, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_EMBER, MOVE_EFFECT_BURN) == TRUE);
}
SINGLE_BATTLE_TEST("Ember inflicts burn")
@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Ember cannot burn a Fire-type Pokémon")
DOUBLE_BATTLE_TEST("Lava Plume inflicts burn to all adjacent battlers")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_LAVA_PLUME, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_LAVA_PLUME, MOVE_EFFECT_BURN) == TRUE);
ASSUME(gMovesInfo[MOVE_LAVA_PLUME].target == MOVE_TARGET_FOES_AND_ALLY);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
@ -68,7 +68,7 @@ SINGLE_BATTLE_TEST("Matcha Gotcha inflicts burn 20% of the time")
{
PASSES_RANDOMLY(20, 100, RNG_SECONDARY_EFFECT);
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_MATCHA_GOTCHA, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_MATCHA_GOTCHA, MOVE_EFFECT_BURN) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Matcha Gotcha inflicts burn 20% of the time")
DOUBLE_BATTLE_TEST("Matcha Gatcha can burn both targets")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_MATCHA_GOTCHA, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_MATCHA_GOTCHA, MOVE_EFFECT_BURN) == TRUE);
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -110,7 +110,7 @@ SINGLE_BATTLE_TEST("Scald shouldn't burn a Water-type Pokémon")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[0] == TYPE_WATER);
ASSUME(MoveHasMoveEffect(MOVE_SCALD, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_SCALD, MOVE_EFFECT_BURN) == TRUE);
ASSUME(gMovesInfo[MOVE_SCALD].type == TYPE_WATER);
PLAYER(SPECIES_SQUIRTLE);
OPPONENT(SPECIES_SQUIRTLE);

View File

@ -4,7 +4,7 @@
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE);
ASSUME(MoveHasMoveEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE);
ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE);
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE);
ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE);
}

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_CLANGING_SCALES, MOVE_EFFECT_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_CLANGING_SCALES, MOVE_EFFECT_DEF_MINUS_1) == TRUE);
}
DOUBLE_BATTLE_TEST("Clanging Scales lowers defense by one stage if it hits both targets")

View File

@ -9,7 +9,7 @@ SINGLE_BATTLE_TEST("Alluring Voice confuses the target if the target raised a st
PARAMETRIZE { move = MOVE_SWORDS_DANCE; }
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_ALLURING_VOICE, MOVE_EFFECT_CONFUSION));
ASSUME(MoveHasAdditionalEffect(MOVE_ALLURING_VOICE, MOVE_EFFECT_CONFUSION));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Alluring Voice confuses the target if the target raised a st
SINGLE_BATTLE_TEST("Alluring Voice confuse effect is removed if it is Sheer Force boosted")
{
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_ALLURING_VOICE, MOVE_EFFECT_CONFUSION));
ASSUME(MoveHasAdditionalEffect(MOVE_ALLURING_VOICE, MOVE_EFFECT_CONFUSION));
PLAYER(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_DIRE_CLAW, MOVE_EFFECT_DIRE_CLAW) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_DIRE_CLAW, MOVE_EFFECT_DIRE_CLAW) == TRUE);
}
SINGLE_BATTLE_TEST("Dire Claw can inflict poison, paralysis or sleep")

View File

@ -4,7 +4,7 @@
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE);
ASSUME(MoveHasMoveEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE);
ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE);
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC);
ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC);
}

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_HEADBUTT, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_HEADBUTT, MOVE_EFFECT_FLINCH) == TRUE);
}
SINGLE_BATTLE_TEST("Headbutt flinches the target if attacker is faster")

View File

@ -3,12 +3,12 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_THUNDER_FANG, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_THUNDER_FANG, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_ICE_FANG, MOVE_EFFECT_FREEZE) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_ICE_FANG, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_FIRE_FANG, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_FIRE_FANG, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THUNDER_FANG, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THUNDER_FANG, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_ICE_FANG, MOVE_EFFECT_FREEZE) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_ICE_FANG, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_FIRE_FANG, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_FIRE_FANG, MOVE_EFFECT_FLINCH) == TRUE);
}
SINGLE_BATTLE_TEST("Thunder, Ice and Fire Fang inflict status 10% of the time")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
ASSUME(gMovesInfo[MOVE_BLIZZARD].accuracy == 70);
}
@ -75,7 +75,7 @@ SINGLE_BATTLE_TEST("Freezing Glare shouldn't freeze Psychic-types")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_ARTICUNO_GALARIAN].types[0] == TYPE_PSYCHIC);
ASSUME(MoveHasMoveEffect(MOVE_FREEZING_GLARE, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_FREEZING_GLARE, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
ASSUME(gMovesInfo[MOVE_FREEZING_GLARE].type == TYPE_PSYCHIC);
PLAYER(SPECIES_ARTICUNO_GALARIAN);
OPPONENT(SPECIES_ARTICUNO_GALARIAN);

View File

@ -3,8 +3,8 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_STONE_AXE, MOVE_EFFECT_STEALTH_ROCK) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_CEASELESS_EDGE, MOVE_EFFECT_SPIKES) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_STONE_AXE, MOVE_EFFECT_STEALTH_ROCK) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_CEASELESS_EDGE, MOVE_EFFECT_SPIKES) == TRUE);
}
SINGLE_BATTLE_TEST("Stone Axe / Ceaseless Edge set up hazards after hitting the target")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH) == TRUE);
}
SINGLE_BATTLE_TEST("Jaw Lock traps both opponents")

View File

@ -3,8 +3,8 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_MAKE_IT_RAIN, MOVE_EFFECT_PAYDAY));
ASSUME(MoveHasMoveEffectSelf(MOVE_MAKE_IT_RAIN, MOVE_EFFECT_SP_ATK_MINUS_1));
ASSUME(MoveHasAdditionalEffect(MOVE_MAKE_IT_RAIN, MOVE_EFFECT_PAYDAY));
ASSUME(MoveHasAdditionalEffectSelf(MOVE_MAKE_IT_RAIN, MOVE_EFFECT_SP_ATK_MINUS_1));
}
SINGLE_BATTLE_TEST("Make It Rain lowers special attack by one stage")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_THUNDER_SHOCK, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THUNDER_SHOCK, MOVE_EFFECT_PARALYSIS) == TRUE);
}
SINGLE_BATTLE_TEST("Thunder Shock inflicts paralysis")
@ -48,7 +48,7 @@ SINGLE_BATTLE_TEST("Body Slam shouldn't paralyze Normal-types")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_TAUROS].types[0] == TYPE_NORMAL);
ASSUME(MoveHasMoveEffect(MOVE_BODY_SLAM, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_BODY_SLAM, MOVE_EFFECT_PARALYSIS) == TRUE);
ASSUME(gMovesInfo[MOVE_BODY_SLAM].type == TYPE_NORMAL);
PLAYER(SPECIES_TAUROS);
OPPONENT(SPECIES_TAUROS);

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY));
ASSUME(MoveHasAdditionalEffect(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY));
}
SINGLE_BATTLE_TEST("Pay Day Scatters coins around after it hits - singles")

View File

@ -38,7 +38,7 @@ DOUBLE_BATTLE_TEST("Rainbow doubles the chance of secondary move effects")
{
PASSES_RANDOMLY(20, 100, RNG_SECONDARY_EFFECT);
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_EMBER, MOVE_EFFECT_BURN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_EMBER, MOVE_EFFECT_BURN) == TRUE);
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
PLAYER(SPECIES_WYNAUT) { Speed(3); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(8); }
@ -59,7 +59,7 @@ DOUBLE_BATTLE_TEST("Rainbow flinch chance does not stack with Serene Grace")
{
PASSES_RANDOMLY(60, 100, RNG_SECONDARY_EFFECT);
GIVEN {
ASSUME(MoveHasMoveEffect(MOVE_BITE, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_BITE, MOVE_EFFECT_FLINCH) == TRUE);
PLAYER(SPECIES_TOGEPI) { Speed(8); Ability(ABILITY_SERENE_GRACE); }
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(4); }

View File

@ -3,8 +3,8 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_TWINEEDLE, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_TWINEEDLE, MOVE_EFFECT_POISON) == TRUE);
}
SINGLE_BATTLE_TEST("Poison Sting inflicts poison")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE));
ASSUME(MoveHasAdditionalEffect(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE));
ASSUME(gMovesInfo[MOVE_RECOVER].effect == EFFECT_RESTORE_HP);
}

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_THRASH, MOVE_EFFECT_THRASH) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_THRASH, MOVE_EFFECT_THRASH) == TRUE);
}
SINGLE_BATTLE_TEST("Thrash lasts for 2 or 3 turns")

View File

@ -3,12 +3,12 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
#if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_SPD_PLUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_SPD_PLUS_1) == TRUE);
#endif
ASSUME(MoveHasMoveEffectSelf(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON) == TRUE);
}
SINGLE_BATTLE_TEST("Rapin Spin blows away Wrap, hazards and raises Speed (Gen 8+)")

View File

@ -68,7 +68,7 @@ SINGLE_BATTLE_TEST("Flare Blitz deals 33% of recoil damage to the user and can b
GIVEN {
ASSUME(gMovesInfo[MOVE_FLARE_BLITZ].recoil == 33);
ASSUME(gMovesInfo[MOVE_FLARE_BLITZ].argument == STATUS1_BURN);
ASSUME(MoveHasAdditionalEffect(MOVE_FLARE_BLITZ, MOVE_EFFECT_BURN));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -4,7 +4,7 @@
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_RELIC_SONG].effect == EFFECT_RELIC_SONG);
ASSUME(MoveHasMoveEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP) == TRUE);
}
SINGLE_BATTLE_TEST("Relic Song has a 10% chance to put the target to sleep")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_TWO_DOWN));
ASSUME(MoveHasAdditionalEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_TWO_DOWN));
}
SINGLE_BATTLE_TEST("Overheat drops Sp. Atk by 2 stages - singles")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_SPIN_OUT, MOVE_EFFECT_SPD_MINUS_2) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_SPIN_OUT, MOVE_EFFECT_SPD_MINUS_2) == TRUE);
}
SINGLE_BATTLE_TEST("Spin Out lowers speed by 2 stages")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE);
}
SINGLE_BATTLE_TEST("Throat Chop prevents the usage of sound moves")

View File

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_TRI_ATTACK, MOVE_EFFECT_TRI_ATTACK) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_TRI_ATTACK, MOVE_EFFECT_TRI_ATTACK) == TRUE);
}
SINGLE_BATTLE_TEST("Tri Attack can inflict paralysis, burn or freeze")

View File

@ -3,8 +3,8 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffect(MOVE_TRIPLE_ARROWS, MOVE_EFFECT_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_TRIPLE_ARROWS, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_TRIPLE_ARROWS, MOVE_EFFECT_DEF_MINUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_TRIPLE_ARROWS, MOVE_EFFECT_FLINCH) == TRUE);
}
SINGLE_BATTLE_TEST("Triple Arrows may lower Defense by one stage")

View File

@ -5,7 +5,7 @@ ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_RAZOR_WIND].effect == EFFECT_TWO_TURNS_ATTACK);
ASSUME(gMovesInfo[MOVE_SKULL_BASH].effect == EFFECT_TWO_TURNS_ATTACK);
ASSUME(MoveHasMoveEffectSelf(MOVE_SKULL_BASH, MOVE_EFFECT_DEF_PLUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_SKULL_BASH, MOVE_EFFECT_DEF_PLUS_1) == TRUE);
ASSUME(gMovesInfo[MOVE_SKY_ATTACK].effect == EFFECT_TWO_TURNS_ATTACK);
// Solar Beam - check for sun
@ -17,7 +17,7 @@ ASSUMPTIONS
// Electro shot - check for rain
ASSUME(HIHALF(gMovesInfo[MOVE_ELECTRO_SHOT].argument) == B_WEATHER_RAIN);
ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].effect == EFFECT_TWO_TURNS_ATTACK);
ASSUME(MoveHasMoveEffectSelf(MOVE_ELECTRO_SHOT, MOVE_EFFECT_SP_ATK_PLUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_ELECTRO_SHOT, MOVE_EFFECT_SP_ATK_PLUS_1) == TRUE);
}
SINGLE_BATTLE_TEST("Razor Wind needs a charging turn")

View File

@ -5,7 +5,7 @@ ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_UPPER_HAND].effect == EFFECT_UPPER_HAND);
ASSUME(gMovesInfo[MOVE_UPPER_HAND].priority == 3);
ASSUME(MoveHasMoveEffect(MOVE_UPPER_HAND, MOVE_EFFECT_FLINCH) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_UPPER_HAND, MOVE_EFFECT_FLINCH) == TRUE);
}
SINGLE_BATTLE_TEST("Upper Hand succeeds if the target is using a priority attacking move and causes it to flinch")
@ -104,7 +104,7 @@ SINGLE_BATTLE_TEST("Upper Hand is boosted by Sheer Force")
GIVEN {
ASSUME(gMovesInfo[MOVE_EXTREME_SPEED].category == DAMAGE_CATEGORY_PHYSICAL);
ASSUME(gMovesInfo[MOVE_EXTREME_SPEED].priority == 2);
ASSUME(gMovesInfo[MOVE_UPPER_HAND].sheerForceBoost == TRUE);
ASSUME(MoveIsAffectedBySheerForce(MOVE_UPPER_HAND) == TRUE);
PLAYER(SPECIES_HARIYAMA) { Ability(ABILITY_SHEER_FORCE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {