Added weather accuracy move flags (#6857)

This commit is contained in:
Eduardo Quezada 2025-05-16 01:58:40 -04:00 committed by GitHub
parent 0ea1ebe8de
commit 3056909286
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 134 additions and 77 deletions

View File

@ -171,6 +171,9 @@ bool32 HasSubstituteIgnoringMove(u32 battler);
bool32 HasHighCritRatioMove(u32 battler);
bool32 HasMagicCoatAffectedMove(u32 battler);
bool32 HasSnatchAffectedMove(u32 battler);
bool32 HasMoveThatAlwaysHitsInRain(u32 battler);
bool32 HasMoveThatHas50AccuracyInSun(u32 battler);
bool32 HasMoveThatAlwaysHitsInHailSnow(u32 battler);
bool32 IsHazardClearingMove(u32 move);
bool32 IsSubstituteEffect(enum BattleMoveEffects effect);

View File

@ -124,7 +124,6 @@ enum BattleMoveEffects
EFFECT_EARTHQUAKE,
EFFECT_FUTURE_SIGHT,
EFFECT_SOLAR_BEAM,
EFFECT_THUNDER,
EFFECT_TELEPORT,
EFFECT_BEAT_UP,
EFFECT_SEMI_INVULNERABLE,
@ -337,8 +336,6 @@ enum BattleMoveEffects
EFFECT_FILLET_AWAY,
EFFECT_IVY_CUDGEL,
EFFECT_FICKLE_BEAM,
EFFECT_BLIZZARD,
EFFECT_RAIN_ALWAYS_HIT, // Unlike EFFECT_THUNDER, it doesn't get its accuracy reduced under sun.
EFFECT_SHED_TAIL,
EFFECT_UPPER_HAND,
EFFECT_DRAGON_CHEER,

View File

@ -113,6 +113,9 @@ struct MoveInfo
bool32 ignoresSubstitute:1;
bool32 forcePressure:1;
bool32 cantUseTwice:1;
bool32 alwaysHitsInRain:1;
bool32 accuracy50InSun:1;
bool32 alwaysHitsInHailSnow:1;
// Ban flags
bool32 gravityBanned:1;
bool32 mirrorMoveBanned:1;
@ -129,7 +132,7 @@ struct MoveInfo
bool32 sketchBanned:1;
//Other
bool32 validApprenticeMove:1;
u32 padding:10;
u32 padding:7;
// end of word
union {
@ -389,6 +392,21 @@ static inline bool32 MoveCantBeUsedTwice(u32 moveId)
return gMovesInfo[SanitizeMoveId(moveId)].cantUseTwice;
}
static inline bool32 MoveAlwaysHitsInRain(u32 moveId)
{
return gMovesInfo[SanitizeMoveId(moveId)].alwaysHitsInRain;
}
static inline bool32 MoveHas50AccuracyInSun(u32 moveId)
{
return gMovesInfo[SanitizeMoveId(moveId)].accuracy50InSun;
}
static inline bool32 MoveAlwaysHitsInHailSnow(u32 moveId)
{
return gMovesInfo[SanitizeMoveId(moveId)].alwaysHitsInHailSnow;
}
static inline bool32 IsMoveGravityBanned(u32 moveId)
{
return gMovesInfo[SanitizeMoveId(moveId)].gravityBanned;

View File

@ -4101,7 +4101,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(WEAK_EFFECT);
if (HasMoveWithType(battlerDef, TYPE_WATER) || HasMoveWithType(BATTLE_PARTNER(battlerDef), TYPE_WATER))
ADJUST_SCORE(WEAK_EFFECT);
if (HasMoveEffect(battlerDef, EFFECT_THUNDER) || HasMoveEffect(BATTLE_PARTNER(battlerDef), EFFECT_THUNDER))
if (HasMoveThatHas50AccuracyInSun(battlerDef) || HasMoveThatHas50AccuracyInSun(BATTLE_PARTNER(battlerDef)))
ADJUST_SCORE(WEAK_EFFECT);
}
break;

View File

@ -1639,13 +1639,12 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move)
// discouraged from hitting
weather = AI_GetWeather();
if ((weather & B_WEATHER_SUN) && effect == EFFECT_THUNDER)
if ((weather & B_WEATHER_SUN) && MoveHas50AccuracyInSun(move))
return FALSE;
// increased accuracy but don't always hit
if ((weather & B_WEATHER_RAIN) && effect == EFFECT_THUNDER)
if ((weather & B_WEATHER_RAIN) && MoveAlwaysHitsInRain(move))
return TRUE;
if ((weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && effect == EFFECT_BLIZZARD)
if ((weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && MoveAlwaysHitsInHailSnow(move))
return TRUE;
if (B_MINIMIZE_DMG_ACC >= GEN_6 && (gStatuses3[battlerDef] & STATUS3_MINIMIZED) && MoveIncreasesPowerToMinimizedTargets(move))
return TRUE;
@ -1722,7 +1721,7 @@ bool32 ShouldSetHail(u32 battler, u32 ability, enum ItemHoldEffect holdEffect)
|| ability == ABILITY_OVERCOAT
|| holdEffect == HOLD_EFFECT_SAFETY_GOGGLES
|| IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
|| HasMoveEffect(battler, EFFECT_BLIZZARD)
|| HasMoveThatAlwaysHitsInHailSnow(battler)
|| HasMoveEffect(battler, EFFECT_AURORA_VEIL)
|| HasMoveEffect(battler, EFFECT_WEATHER_BALL))
{
@ -1743,7 +1742,7 @@ bool32 ShouldSetRain(u32 battlerAtk, u32 atkAbility, enum ItemHoldEffect holdEff
|| atkAbility == ABILITY_HYDRATION
|| atkAbility == ABILITY_RAIN_DISH
|| atkAbility == ABILITY_DRY_SKIN
|| HasMoveEffect(battlerAtk, EFFECT_THUNDER)
|| HasMoveThatAlwaysHitsInRain(battlerAtk)
|| HasMoveEffect(battlerAtk, EFFECT_WEATHER_BALL)
|| HasMoveWithType(battlerAtk, TYPE_WATER)))
{
@ -1789,7 +1788,7 @@ bool32 ShouldSetSnow(u32 battler, u32 ability, enum ItemHoldEffect holdEffect)
|| ability == ABILITY_FORECAST
|| ability == ABILITY_SLUSH_RUSH
|| IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
|| HasMoveEffect(battler, EFFECT_BLIZZARD)
|| HasMoveThatAlwaysHitsInHailSnow(battler)
|| HasMoveEffect(battler, EFFECT_AURORA_VEIL)
|| HasMoveEffect(battler, EFFECT_WEATHER_BALL))
{
@ -2653,6 +2652,42 @@ bool32 HasSnatchAffectedMove(u32 battler)
return FALSE;
}
bool32 HasMoveThatAlwaysHitsInRain(u32 battler)
{
s32 i;
u16 *moves = GetMovesArray(battler);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveAlwaysHitsInRain(moves[i]))
return TRUE;
}
return FALSE;
}
bool32 HasMoveThatHas50AccuracyInSun(u32 battler)
{
s32 i;
u16 *moves = GetMovesArray(battler);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveHas50AccuracyInSun(moves[i]))
return TRUE;
}
return FALSE;
}
bool32 HasMoveThatAlwaysHitsInHailSnow(u32 battler)
{
s32 i;
u16 *moves = GetMovesArray(battler);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveAlwaysHitsInHailSnow(moves[i]))
return TRUE;
}
return FALSE;
}
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move)
{
switch (GetMoveEffect(move))

View File

@ -4044,8 +4044,9 @@ static bool32 IsDomeRareMove(u32 move)
return TRUE;
}
static bool32 IsDomeComboMoveEffect(enum BattleMoveEffects effect)
static bool32 IsDomeComboMove(u32 move)
{
enum BattleMoveEffects effect = GetMoveEffect(move);
switch(effect)
{
// Weather moves
@ -4064,8 +4065,6 @@ static bool32 IsDomeComboMoveEffect(enum BattleMoveEffects effect)
case EFFECT_MORNING_SUN:
case EFFECT_MOONLIGHT:
case EFFECT_SHORE_UP:
case EFFECT_THUNDER:
case EFFECT_BLIZZARD:
case EFFECT_SOLAR_BEAM:
case EFFECT_GROWTH:
case EFFECT_AURORA_VEIL:
@ -4119,8 +4118,15 @@ static bool32 IsDomeComboMoveEffect(enum BattleMoveEffects effect)
case EFFECT_ROAR:
return TRUE;
default:
return FALSE;
break;
}
if (MoveAlwaysHitsInRain(move))
return TRUE;
else if (MoveAlwaysHitsInHailSnow(move))
return TRUE;
return FALSE;
}
// allocatedArray below needs to be large enough to hold stat totals for each mon, or totals of each type of move points
@ -4307,7 +4313,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
switch (k)
{
case MOVE_POINTS_COMBO:
allocatedArray[k] = IsDomeComboMoveEffect(effect) ? 1 : 0;
allocatedArray[k] = IsDomeComboMove(move) ? 1 : 0;
break;
case MOVE_POINTS_STAT_RAISE:
allocatedArray[k] = IsStatRaisingEffect(effect) ? 1 : 0;

View File

@ -1552,10 +1552,9 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler)
if (!effect && HasWeatherEffect())
{
if ((moveEffect == EFFECT_THUNDER || moveEffect == EFFECT_RAIN_ALWAYS_HIT)
&& IsBattlerWeatherAffected(battler, B_WEATHER_RAIN))
if (MoveAlwaysHitsInRain(move) && IsBattlerWeatherAffected(battler, B_WEATHER_RAIN))
effect = TRUE;
else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && moveEffect == EFFECT_BLIZZARD)
else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && MoveAlwaysHitsInHailSnow(move))
effect = TRUE;
if (effect)
@ -1600,7 +1599,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
moveAcc = GetMoveAccuracy(move);
// Check Thunder and Hurricane on sunny weather.
if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && GetMoveEffect(move) == EFFECT_THUNDER)
if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && MoveHas50AccuracyInSun(move))
moveAcc = 50;
// Check Wonder Skin.
if (defAbility == ABILITY_WONDER_SKIN && IsBattleMoveStatus(move) && moveAcc > 50)

View File

@ -902,7 +902,6 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3)
switch (GetMoveEffect(move))
{
case EFFECT_WEATHER_BALL:
case EFFECT_THUNDER:
points += 3;
break;
case EFFECT_SOLAR_BEAM:
@ -912,6 +911,9 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3)
break;
}
if (MoveAlwaysHitsInRain(move))
points += 3;
movePoints->points[atkSide][gBattlerPartyIndexes[gBattlerAttacker] * 4 + arg2] += points;
break;
}

View File

@ -792,12 +792,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.twoTurnEffect = TRUE,
},
[EFFECT_THUNDER] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 1,
},
[EFFECT_TELEPORT] =
{
.battleScript = BattleScript_EffectTeleport,
@ -2146,18 +2140,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_BLIZZARD] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 1,
},
[EFFECT_RAIN_ALWAYS_HIT] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_SHED_TAIL] =
{
.battleScript = BattleScript_EffectShedTail,

View File

@ -1613,7 +1613,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
#else
"storm that may freeze it."),
#endif
.effect = B_BLIZZARD_HAIL >= GEN_4 ? EFFECT_BLIZZARD : EFFECT_HIT,
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_6 ? 110 : 120,
.type = TYPE_ICE,
.accuracy = 70,
@ -1622,6 +1622,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.windMove = TRUE,
.alwaysHitsInHailSnow = B_BLIZZARD_HAIL >= GEN_4,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE,
.chance = 10,
@ -2321,7 +2322,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"A lightning attack that may\n"
"cause paralysis."),
.effect = EFFECT_THUNDER,
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_6 ? 110 : 120,
.type = TYPE_ELECTRIC,
.accuracy = 70,
@ -2330,6 +2331,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.damagesAirborne = TRUE,
.alwaysHitsInRain = TRUE,
.accuracy50InSun = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_PARALYSIS,
.chance = 30,
@ -13786,7 +13789,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"Traps the foe in a fierce\n"
"wind. May cause confusion."),
.effect = EFFECT_THUNDER,
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_6 ? 110 : 120,
.type = TYPE_FLYING,
.accuracy = 70,
@ -13796,6 +13799,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.category = DAMAGE_CATEGORY_SPECIAL,
.windMove = TRUE,
.damagesAirborne = TRUE,
.alwaysHitsInRain = TRUE,
.accuracy50InSun = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_CONFUSION,
.chance = 30,
@ -19473,7 +19478,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"Hits with brutal, cold winds.\n"
"May lower the foe's Speed."),
.effect = EFFECT_RAIN_ALWAYS_HIT,
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_9 ? 100 : 95,
.type = TYPE_FLYING,
.accuracy = 80,
@ -19482,6 +19487,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.windMove = TRUE,
.alwaysHitsInRain = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_SPD_MINUS_1,
.chance = 30,
@ -19495,7 +19501,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"Hits with a brutal tempest.\n"
"May inflict paralysis."),
.effect = EFFECT_RAIN_ALWAYS_HIT,
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_9 ? 100 : 95,
.type = TYPE_ELECTRIC,
.accuracy = 80,
@ -19504,6 +19510,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.windMove = TRUE,
.alwaysHitsInRain = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_PARALYSIS,
.chance = 20,
@ -19517,7 +19524,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"Hits with brutally hot sand.\n"
"May inflict a burn."),
.effect = EFFECT_RAIN_ALWAYS_HIT,
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_9 ? 100 : 95,
.type = TYPE_GROUND,
.accuracy = 80,
@ -19526,6 +19533,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.windMove = TRUE,
.alwaysHitsInRain = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_BURN,
.chance = 20,

View File

@ -4,7 +4,6 @@
ASSUMPTIONS
{
ASSUME(MoveHasAdditionalEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
ASSUME(GetMoveAccuracy(MOVE_BLIZZARD) == 70);
}
#if B_USE_FROSTBITE == TRUE
@ -60,21 +59,6 @@ SINGLE_BATTLE_TEST("Freeze cannot be inflicted in Sunlight")
}
}
SINGLE_BATTLE_TEST("Blizzard bypasses accuracy checks in Hail and Snow")
{
u32 move;
PARAMETRIZE { move = MOVE_HAIL; }
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, move); MOVE(player, MOVE_BLIZZARD); }
} SCENE {
NOT MESSAGE("Wobbuffet's attack missed!");
}
}
#if B_STATUS_TYPE_IMMUNITY > GEN_1
#if B_USE_FROSTBITE == TRUE
SINGLE_BATTLE_TEST("Freezing Glare should frostbite Psychic-types")

View File

@ -3,8 +3,9 @@
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_HURRICANE) == EFFECT_THUNDER);
ASSUME(GetMoveAccuracy(MOVE_HURRICANE) == 70);
ASSUME(MoveAlwaysHitsInRain(MOVE_HURRICANE) == TRUE);
ASSUME(MoveHas50AccuracyInSun(MOVE_HURRICANE) == TRUE);
}
SINGLE_BATTLE_TEST("Hurricane's accuracy is lowered to 50% in Sunlight")

View File

@ -3,8 +3,8 @@
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_THUNDER) == EFFECT_THUNDER);
ASSUME(GetMoveAccuracy(MOVE_THUNDER) == 70);
ASSUME(MoveHas50AccuracyInSun(MOVE_HURRICANE) == TRUE);
}
SINGLE_BATTLE_TEST("Thunder's accuracy is lowered to 50% in Sunlight")
@ -19,16 +19,3 @@ SINGLE_BATTLE_TEST("Thunder's accuracy is lowered to 50% in Sunlight")
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER, opponent);
}
}
SINGLE_BATTLE_TEST("Thunder bypasses accuracy checks in Rain")
{
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_RAIN_DANCE); MOVE(player, MOVE_THUNDER); }
} SCENE {
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
}
}

View File

@ -0,0 +1,19 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Blizzard bypasses accuracy checks in Hail and Snow")
{
u32 move;
PARAMETRIZE { move = MOVE_HAIL; }
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
GIVEN {
ASSUME(GetMoveAccuracy(MOVE_BLIZZARD) == 70);
ASSUME(MoveAlwaysHitsInHailSnow(MOVE_BLIZZARD));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, move); MOVE(player, MOVE_BLIZZARD); }
} SCENE {
NOT MESSAGE("Wobbuffet's attack missed!");
}
}

View File

@ -0,0 +1,16 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Thunder bypasses accuracy checks in Rain")
{
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
GIVEN {
ASSUME(MoveAlwaysHitsInRain(MOVE_THUNDER) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_RAIN_DANCE); MOVE(player, MOVE_THUNDER); }
} SCENE {
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
}
}