diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 832c231401..6d13889553 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -64,9 +64,6 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move); u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move); bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove); -u32 AI_CalcSecondaryEffectChance(u32 battler, u32 secondaryEffectChance); -bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef); -u32 AI_ShouldSetUpHazards(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef); // stat stage checks bool32 AnyStatIsRaised(u32 battlerId); @@ -104,6 +101,7 @@ bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensiv bool32 HasMoveWithCategory(u32 battler, u32 category); bool32 HasMoveWithType(u32 battler, u32 type); bool32 HasMoveEffect(u32 battlerId, u32 moveEffect); +bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument); bool32 HasMoveWithMoveEffect(u32 battlerId, u32 moveEffect, u32 effectHitOnly); bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); bool32 IsAromaVeilProtectedMove(u32 move); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index a4e8a166ed..88ffbf32b3 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -48,7 +48,6 @@ u32 IsAbilityStatusProtected(u32 battler); bool32 TryResetBattlerStatChanges(u8 battler); bool32 CanCamouflage(u8 battlerId); u16 GetNaturePowerMove(void); -u16 GetSecretPowerMoveEffect(void); void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); u32 GetHighestStatId(u32 battlerId); diff --git a/include/battle_util.h b/include/battle_util.h index 9f23c934af..936f773d99 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -221,7 +221,6 @@ void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon); void RecalcBattlerStats(u32 battler, struct Pokemon *mon); bool32 IsAlly(u32 battlerAtk, u32 battlerDef); bool32 IsGen6ExpShareEnabled(void); -bool32 MoveEffectIsGuaranteed(u32 secondaryEffectChance); bool32 MoveHasMoveEffect(u32 move, u32 moveEffect, bool32 effectHitOnly); bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance); bool32 MoveHasMoveEffectSelf(u32 move, u32 moveEffect); @@ -252,7 +251,8 @@ void RemoveConfusionStatus(u32 battler); u8 GetBattlerGender(u32 battler); bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2); bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2); -u32 CalcSecondaryEffectChance(u32 battler, const struct AdditionalEffect *additionalEffect); +u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); +bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); u8 GetBattlerType(u32 battler, u8 typeIndex); bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon); bool8 IsMonBannedFromSkyBattles(u16 species); diff --git a/include/config/battle.h b/include/config/battle.h index 7e0f05a819..287cbd992b 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -192,7 +192,7 @@ #define B_THUNDERSTORM_TERRAIN TRUE // If TRUE, overworld Thunderstorm generates Rain and Electric Terrain as in Gen 8. #define B_FOG_TERRAIN TRUE // If TRUE, overworld Fog generates Misty Terrain as in Gen 8. #define B_TERRAIN_TYPE_BOOST GEN_LATEST // In Gen8, damage is boosted by 30% instead of 50%. -#define B_SECRET_POWER_EFFECT GEN_LATEST // Secret Power's effects change depending on terrain and generation. See GetSecretPowerMoveEffect. +#define B_SECRET_POWER_EFFECT GEN_LATEST // Secret Power's effects change depending on terrain and generation. See MOVE_EFFECT_SECRET_POWER. #define B_SECRET_POWER_ANIMATION GEN_LATEST // Secret Power's animations change depending on terrain and generation. #define B_NATURE_POWER_MOVES GEN_LATEST // Nature Power calls different moves depending on terrain and generation. See sNaturePowerMoves. #define B_CAMOUFLAGE_TYPES GEN_LATEST // Camouflage changes the user to different types depending on terrain and generation. See sTerrainToType. diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 25aa3d153f..ccba1d2c48 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -50,6 +50,10 @@ static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle); +static bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef); +static s32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); + static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = { @@ -2665,6 +2669,51 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } +static s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle) +{ + if (isDoubleBattle) + return min(CountPositiveStatStages(battlerDef) + CountPositiveStatStages(BATTLE_PARTNER(battlerDef)), 7); + else + return min(CountPositiveStatStages(battlerDef), 4); +} + +static bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) +{ + u8 i; + // Want to copy positive stat changes + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerDef].statStages[i] > gBattleMons[battlerAtk].statStages[i]) + { + switch (i) + { + case STAT_ATK: + return (HasMoveWithCategory(battlerAtk, BATTLE_CATEGORY_PHYSICAL)); + case STAT_SPATK: + return (HasMoveWithCategory(battlerAtk, BATTLE_CATEGORY_SPECIAL)); + case STAT_ACC: + case STAT_EVASION: + case STAT_SPEED: + return TRUE; + case STAT_DEF: + case STAT_SPDEF: + return (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL); + } + } + } + + return FALSE; +} + +//TODO - track entire opponent party data to determine hazard effectiveness +static s32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0) + return 0; + + return 2 * gDisableStructs[battlerAtk].isFirstTurn; +} + // double battle logic static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { @@ -3487,13 +3536,15 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score ADJUST_SCORE(-3); break; } + score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle); break; case EFFECT_ROAR: - if (aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF || aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) + if ((gBattleMoves[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF) || aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) { ADJUST_SCORE(-3); break; } + score += AI_TryToClearStats(battlerAtk, battlerDef, FALSE); break; case EFFECT_MULTI_HIT: case EFFECT_TRIPLE_KICK: @@ -3840,7 +3891,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score case EFFECT_STEALTH_ROCK: case EFFECT_STICKY_WEB: case EFFECT_TOXIC_SPIKES: - score += AI_ShouldSetUpHazards(aiData, battlerAtk, battlerDef); + score += AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData); break; case EFFECT_FORESIGHT: if (aiData->abilities[battlerAtk] == ABILITY_SCRAPPY || aiData->abilities[battlerAtk] == ABILITY_MINDS_EYE) @@ -4672,7 +4723,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score for (i = 0; i < gBattleMoves[move].numAdditionalEffects; i++) { // Only consider effects with a guaranteed chance to happen - if (!MoveEffectIsGuaranteed(AI_CalcSecondaryEffectChance(battlerAtk, gBattleMoves[move].additionalEffects[i].chance))) + if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &gBattleMoves[move].additionalEffects[i])) continue; // Consider move effects that target self @@ -4689,6 +4740,8 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score case MOVE_EFFECT_DEF_PLUS_1: case MOVE_EFFECT_SP_ATK_PLUS_1: case MOVE_EFFECT_SP_DEF_PLUS_1: + case MOVE_EFFECT_ACC_PLUS_1: + case MOVE_EFFECT_EVS_PLUS_1: IncreaseStatUpScore( battlerAtk, battlerDef, @@ -4696,7 +4749,25 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score &score ); break; + case MOVE_EFFECT_ATK_PLUS_2: + case MOVE_EFFECT_DEF_PLUS_2: + case MOVE_EFFECT_SP_ATK_PLUS_2: + case MOVE_EFFECT_SP_DEF_PLUS_2: + case MOVE_EFFECT_ACC_PLUS_2: + case MOVE_EFFECT_EVS_PLUS_2: + IncreaseStatUpScore( + battlerAtk, + battlerDef, + STAT_ATK + gBattleMoves[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_2, + &score + ); + break; // Effects that lower stat(s) - only need to consider Contrary + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_V_CREATE: case MOVE_EFFECT_DEF_SPDEF_DOWN: case MOVE_EFFECT_ATK_DEF_DOWN: @@ -4714,6 +4785,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move); break; case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_2: if (!ShouldLowerSpeed(battlerAtk, battlerDef, aiData->abilities[battlerDef])) break; case MOVE_EFFECT_ATK_MINUS_1: @@ -4725,11 +4797,20 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score if (aiData->abilities[battlerDef] != ABILITY_CONTRARY) ADJUST_SCORE(2); break; + case MOVE_EFFECT_ATK_MINUS_2: + case MOVE_EFFECT_DEF_MINUS_2: + case MOVE_EFFECT_SP_ATK_MINUS_2: + case MOVE_EFFECT_SP_DEF_MINUS_2: + case MOVE_EFFECT_ACC_MINUS_2: + case MOVE_EFFECT_EVS_MINUS_2: + if (aiData->abilities[battlerDef] != ABILITY_CONTRARY) + ADJUST_SCORE(3); + break; case MOVE_EFFECT_POISON: IncreasePoisonScore(battlerAtk, battlerDef, move, &score); break; case MOVE_EFFECT_CLEAR_SMOG: - score += min(CountPositiveStatStages(battlerDef), 4); + score += AI_TryToClearStats(battlerAtk, battlerDef, FALSE); break; case MOVE_EFFECT_SPECTRAL_THIEF: score += AI_ShouldCopyStatChanges(battlerAtk, battlerDef); @@ -4822,7 +4903,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score break; case MOVE_EFFECT_STEALTH_ROCK: case MOVE_EFFECT_SPIKES: - score += AI_ShouldSetUpHazards(aiData, battlerAtk, battlerDef); + score += AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData); break; case MOVE_EFFECT_FEINT: if (gBattleMoves[predictedMove].effect == EFFECT_PROTECT) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0a1b70d6c3..d05eebeddc 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -845,7 +845,6 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 u32 abilityDef = AI_DATA->abilities[battlerDef]; u32 abilityAtk = AI_DATA->abilities[battlerAtk]; - switch (gBattleMoves[move].effect) { case EFFECT_HIT_ESCAPE: @@ -1968,6 +1967,22 @@ bool32 HasMoveEffect(u32 battlerId, u32 effect) return FALSE; } +bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gBattleMoves[moves[i]].effect == effect + && (gBattleMoves[moves[i]].argument & argument)) + return TRUE; + } + + return FALSE; +} + bool32 HasMoveWithMoveEffect(u32 battlerId, u32 moveEffect, u32 effectHitOnly) { s32 i; @@ -3667,8 +3682,7 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) ADJUST_SCORE_PTR(1); // stall tactic - if ((HasMoveEffect(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_PSN_ANY) + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY) || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) || AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS) ADJUST_SCORE_PTR(2); @@ -3692,10 +3706,8 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) ADJUST_SCORE_PTR(2); // burning the target to stay alive is cool } - if ((HasMoveEffect(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_BURN) - || (HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_BURN)) + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN) + || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN)) ADJUST_SCORE_PTR(1); } } @@ -3712,8 +3724,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) u32 defSpeed = AI_DATA->speedStats[battlerDef]; if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe - || (HasMoveEffect(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_PARALYSIS) + || HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS) || HasMoveWithMoveEffect(battlerAtk, MOVE_EFFECT_FLINCH, TRUE) // filter out Fake Out || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) @@ -3738,10 +3749,8 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) ADJUST_SCORE_PTR(1); - if ((HasMoveEffect(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_SLEEP) - || (HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_SLEEP)) + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP) + || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP)) ADJUST_SCORE_PTR(1); } @@ -3778,10 +3787,8 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score ADJUST_SCORE_PTR(2); // frostbiting the target to stay alive is cool } - if ((HasMoveEffect(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_FROSTBITE) - || (HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS) - && gBattleMoves[move].argument & STATUS1_FROSTBITE)) + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE) + || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE)) ADJUST_SCORE_PTR(1); } } @@ -3830,49 +3837,4 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove) bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId) { return (gBattleMons[battlerId].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerId] == ABILITY_COMATOSE; -} - -u32 AI_CalcSecondaryEffectChance(u32 battler, u32 secondaryEffectChance) -{ - if (AI_DATA->abilities[battler] == ABILITY_SERENE_GRACE) - secondaryEffectChance *= 2; - - return secondaryEffectChance; -} - -bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) -{ - u8 i; - // Want to copy positive stat changes - for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) - { - if (gBattleMons[battlerDef].statStages[i] > gBattleMons[battlerAtk].statStages[i]) - { - switch (i) - { - case STAT_ATK: - return (HasMoveWithCategory(battlerAtk, BATTLE_CATEGORY_PHYSICAL)); - case STAT_SPATK: - return (HasMoveWithCategory(battlerAtk, BATTLE_CATEGORY_SPECIAL)); - case STAT_ACC: - case STAT_EVASION: - case STAT_SPEED: - return TRUE; - case STAT_DEF: - case STAT_SPDEF: - return (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL); - } - } - } - - return FALSE; -} - -//TODO - track entire opponent party data to determine hazard effectiveness -u32 AI_ShouldSetUpHazards(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef) -{ - if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0) - return 0; - - return 2 * gDisableStructs[battlerAtk].isFirstTurn; -} +} \ No newline at end of file diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index bec54dbec6..52640ab992 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -976,7 +976,6 @@ static const u16 sFinalStrikeOnlyEffects[] = MOVE_EFFECT_STEAL_ITEM, MOVE_EFFECT_BURN_UP, MOVE_EFFECT_DOUBLE_SHOCK, - MOVE_EFFECT_SECRET_POWER, MOVE_EFFECT_SMACK_DOWN, MOVE_EFFECT_REMOVE_STATUS, MOVE_EFFECT_RECOIL_HP_25, @@ -3696,7 +3695,86 @@ void SetMoveEffect(bool32 primary, u32 certain) } break; case MOVE_EFFECT_SECRET_POWER: - gBattleScripting.moveEffect = GetSecretPowerMoveEffect(); + if (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) + { + switch (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) + { + case STATUS_FIELD_MISTY_TERRAIN: + gBattleScripting.moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; + break; + case STATUS_FIELD_GRASSY_TERRAIN: + gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; + break; + case STATUS_FIELD_ELECTRIC_TERRAIN: + gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + break; + case STATUS_FIELD_PSYCHIC_TERRAIN: + gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1; + break; + default: + gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + break; + } + } + else + { + switch (gBattleTerrain) + { + case BATTLE_TERRAIN_GRASS: + gBattleScripting.moveEffect = (B_SECRET_POWER_EFFECT >= GEN_4 ? MOVE_EFFECT_SLEEP : MOVE_EFFECT_POISON); + break; + case BATTLE_TERRAIN_UNDERWATER: + gBattleScripting.moveEffect = (B_SECRET_POWER_EFFECT >= GEN_6 ? MOVE_EFFECT_ATK_MINUS_1 : MOVE_EFFECT_DEF_MINUS_1); + break; + case BATTLE_TERRAIN_POND: + gBattleScripting.moveEffect = (B_SECRET_POWER_EFFECT >= GEN_4 ? MOVE_EFFECT_ATK_MINUS_1 : MOVE_EFFECT_SPD_MINUS_1); + break; + case BATTLE_TERRAIN_MOUNTAIN: + if (B_SECRET_POWER_EFFECT >= GEN_5) + gBattleScripting.moveEffect = MOVE_EFFECT_ACC_MINUS_1; + else if (B_SECRET_POWER_EFFECT >= GEN_4) + gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; + else + gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; + break; + case BATTLE_TERRAIN_PUDDLE: + gBattleScripting.moveEffect = (B_SECRET_POWER_EFFECT >= GEN_5 ? MOVE_EFFECT_SPD_MINUS_1 : MOVE_EFFECT_ACC_MINUS_1); + break; + case BATTLE_TERRAIN_LONG_GRASS: + gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; + break; + case BATTLE_TERRAIN_SAND: + gBattleScripting.moveEffect = MOVE_EFFECT_ACC_MINUS_1; + break; + case BATTLE_TERRAIN_WATER: + gBattleScripting.moveEffect = MOVE_EFFECT_ATK_MINUS_1; + break; + case BATTLE_TERRAIN_CAVE: + case BATTLE_TERRAIN_BURIAL_GROUND: + case BATTLE_TERRAIN_SPACE: + gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; + break; + case BATTLE_TERRAIN_SOARING: + case BATTLE_TERRAIN_SKY_PILLAR: + case BATTLE_TERRAIN_MARSH: + case BATTLE_TERRAIN_SWAMP: + gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1; + break; + case BATTLE_TERRAIN_SNOW: + case BATTLE_TERRAIN_ICE: + gBattleScripting.moveEffect = (B_USE_FROSTBITE == TRUE ? MOVE_EFFECT_FROSTBITE : MOVE_EFFECT_FREEZE); + break; + case BATTLE_TERRAIN_VOLCANO: + gBattleScripting.moveEffect = MOVE_EFFECT_BURN; + break; + case BATTLE_TERRAIN_ULTRA_SPACE: + gBattleScripting.moveEffect = MOVE_EFFECT_DEF_MINUS_1; + break; + default: + gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + break; + } + } SetMoveEffect(FALSE, 0); break; } @@ -3735,6 +3813,7 @@ static void Cmd_seteffectwithchance(void) { u32 percentChance = CalcSecondaryEffectChance( gBattlerAttacker, + GetBattlerAbility(gBattlerAttacker), &gBattleMoves[gCurrentMove].additionalEffects[gBattleStruct->additionalEffectsCounter] ); @@ -14352,93 +14431,6 @@ static void Cmd_unused0xe4(void) { } -u16 GetSecretPowerMoveEffect(void) -{ - u16 moveEffect; - u32 fieldTerrain = gFieldStatuses & STATUS_FIELD_TERRAIN_ANY; - if (fieldTerrain) - { - switch (fieldTerrain) - { - case STATUS_FIELD_MISTY_TERRAIN: - moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; - break; - case STATUS_FIELD_GRASSY_TERRAIN: - moveEffect = MOVE_EFFECT_SLEEP; - break; - case STATUS_FIELD_ELECTRIC_TERRAIN: - moveEffect = MOVE_EFFECT_PARALYSIS; - break; - case STATUS_FIELD_PSYCHIC_TERRAIN: - moveEffect = MOVE_EFFECT_SPD_MINUS_1; - break; - default: - moveEffect = MOVE_EFFECT_PARALYSIS; - break; - } - } - else - { - switch (gBattleTerrain) - { - case BATTLE_TERRAIN_GRASS: - moveEffect = (B_SECRET_POWER_EFFECT >= GEN_4 ? MOVE_EFFECT_SLEEP : MOVE_EFFECT_POISON); - break; - case BATTLE_TERRAIN_UNDERWATER: - moveEffect = (B_SECRET_POWER_EFFECT >= GEN_6 ? MOVE_EFFECT_ATK_MINUS_1 : MOVE_EFFECT_DEF_MINUS_1); - break; - case BATTLE_TERRAIN_POND: - moveEffect = (B_SECRET_POWER_EFFECT >= GEN_4 ? MOVE_EFFECT_ATK_MINUS_1 : MOVE_EFFECT_SPD_MINUS_1); - break; - case BATTLE_TERRAIN_MOUNTAIN: - if (B_SECRET_POWER_EFFECT >= GEN_5) - moveEffect = MOVE_EFFECT_ACC_MINUS_1; - else if (B_SECRET_POWER_EFFECT >= GEN_4) - moveEffect = MOVE_EFFECT_FLINCH; - else - moveEffect = MOVE_EFFECT_CONFUSION; - break; - case BATTLE_TERRAIN_PUDDLE: - moveEffect = (B_SECRET_POWER_EFFECT >= GEN_5 ? MOVE_EFFECT_SPD_MINUS_1 : MOVE_EFFECT_ACC_MINUS_1); - break; - case BATTLE_TERRAIN_LONG_GRASS: - moveEffect = MOVE_EFFECT_SLEEP; - break; - case BATTLE_TERRAIN_SAND: - moveEffect = MOVE_EFFECT_ACC_MINUS_1; - break; - case BATTLE_TERRAIN_WATER: - moveEffect = MOVE_EFFECT_ATK_MINUS_1; - break; - case BATTLE_TERRAIN_CAVE: - case BATTLE_TERRAIN_BURIAL_GROUND: - case BATTLE_TERRAIN_SPACE: - moveEffect = MOVE_EFFECT_FLINCH; - break; - case BATTLE_TERRAIN_SOARING: - case BATTLE_TERRAIN_SKY_PILLAR: - case BATTLE_TERRAIN_MARSH: - case BATTLE_TERRAIN_SWAMP: - moveEffect = MOVE_EFFECT_SPD_MINUS_1; - break; - case BATTLE_TERRAIN_SNOW: - case BATTLE_TERRAIN_ICE: - moveEffect = (B_USE_FROSTBITE == TRUE ? MOVE_EFFECT_FROSTBITE : MOVE_EFFECT_FREEZE); - break; - case BATTLE_TERRAIN_VOLCANO: - moveEffect = MOVE_EFFECT_BURN; - break; - case BATTLE_TERRAIN_ULTRA_SPACE: - moveEffect = MOVE_EFFECT_DEF_MINUS_1; - break; - default: - moveEffect = MOVE_EFFECT_PARALYSIS; - break; - } - } - return moveEffect; -} - static void Cmd_pickup(void) { CMD_ARGS(); diff --git a/src/battle_util.c b/src/battle_util.c index 2c255385ea..4599a817f3 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -11381,9 +11381,9 @@ bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2) return (gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS && gender1 == gender2); } -u32 CalcSecondaryEffectChance(u32 battler, const struct AdditionalEffect *additionalEffect) +u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect) { - bool8 hasSereneGrace = (GetBattlerAbility(battler) == ABILITY_SERENE_GRACE); + bool8 hasSereneGrace = (battlerAbility == ABILITY_SERENE_GRACE); bool8 hasRainbow = (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_RAINBOW) != 0; u16 secondaryEffectChance = additionalEffect->chance; @@ -11398,6 +11398,11 @@ u32 CalcSecondaryEffectChance(u32 battler, const struct AdditionalEffect *additi return secondaryEffectChance; } +bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect) +{ + return additionalEffect->chance == 0 || CalcSecondaryEffectChance(battler, battlerAbility, additionalEffect) >= 100; +} + bool32 IsAlly(u32 battlerAtk, u32 battlerDef) { return (GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)); @@ -11412,11 +11417,6 @@ bool32 IsGen6ExpShareEnabled(void) #endif } -bool32 MoveEffectIsGuaranteed(u32 secondaryEffectChance) -{ - return secondaryEffectChance == 0 || secondaryEffectChance >= 100; -} - bool32 MoveHasMoveEffect(u32 move, u32 moveEffect, bool32 effectHitOnly) { u8 i;