Review fixes

Added more move effect considerations to AI; redid way it calculates secondaryEffectChance; misc fixes
This commit is contained in:
Nephrite 2023-12-29 12:04:42 +09:00
parent 417a02c95e
commit 7c38056da7
8 changed files with 203 additions and 171 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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;