Additional effects tweak (#7392)

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
Nephrite 2025-08-01 19:13:23 +03:00 committed by GitHub
parent 0b44093a8e
commit 73fd567520
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 46 additions and 62 deletions

View File

@ -40,7 +40,6 @@ Let's look at an example:
.target = MOVE_TARGET_SELECTED,
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.sheerForceBoost = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_PARALYSIS,
.chance = 10,
@ -140,7 +139,18 @@ If you look at the example [here](#srcdatamoves_infoh), you can see that Thunder
All additional effects with a defined chance (even 100%) are treated as "secondary effects". This means that they are nullified by Sheer Force, blocked by Shield Dust or the Covert Cloak, and have their chance modified by Serene Grace. Additional effects without a chance field (effectively setting it to 0) are treated as "primary effects", which means that they cannot be blocked by the aforementioned items and abilities and their chance to occur cannot be modified; they will *always* happen.
Each move can have up to 15 additional effects, allowing you to construct monstrosities like this:
Depending on the move effect, it is possible to also set a `multistring` value. For example:
```
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring = B_MSG_WRAPPED_MAGMA_STORM,
}),
```
For Magma Storm, we not only want the wrapping move effect, we want to give it a unique string when it activates. The index is an enum defined in `battle_string_ids.h` and it corresponds to an entry (for this move effect) in the `gWrappedStringIds` list in battle_message.c. For custom strings, you need to add an enum and an entry respectively. For new custom move effects, you will have to add a new set of enums and a new table of strings.
Each move can have up to 3 additional effects, allowing you to construct monstrosities like this:
```
[MOVE_POUND] =
{
@ -165,13 +175,6 @@ Each move can have up to 15 additional effects, allowing you to construct monstr
},{
.moveEffect = MOVE_EFFECT_FLINCH,
.chance = 30,
},{
.moveEffect = MOVE_EFFECT_ALL_STATS_UP,
.chance = 40,
.self = TRUE,
},{
.moveEffect = MOVE_EFFECT_DEF_MINUS_2,
.chance = 50,
}),
.makesContact = TRUE,
.ignoresKingsRock = B_UPDATED_MOVE_FLAGS == GEN_4,

View File

@ -202,8 +202,8 @@ bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 HasThawingMove(u32 battler);
bool32 IsStatRaisingEffect(enum BattleMoveEffects effect);
bool32 IsStatLoweringEffect(enum BattleMoveEffects effect);
bool32 IsSelfStatLoweringEffect(enum MoveEffects effect);
bool32 IsSelfStatRaisingEffect(enum MoveEffects effect);
bool32 IsSelfStatLoweringEffect(enum MoveEffect effect);
bool32 IsSelfStatRaisingEffect(enum MoveEffect effect);
bool32 IsSwitchOutEffect(enum BattleMoveEffects effect);
bool32 IsChaseEffect(enum BattleMoveEffects effect);
bool32 IsAttackBoostMoveEffect(enum BattleMoveEffects effect);

View File

@ -357,7 +357,7 @@ bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, u32 ability);
bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects secondaryMoveEffect, enum FunctionCallOption option);
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffect secondaryMoveEffect, enum FunctionCallOption option);
bool32 CanBeConfused(u32 battler);
bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag);
u32 GetBattlerAffectionHearts(u32 battler);

View File

@ -392,7 +392,7 @@ enum BattleWeather
#define B_WEATHER_LOW_LIGHT (B_WEATHER_FOG | B_WEATHER_ICY_ANY | B_WEATHER_RAIN | B_WEATHER_SANDSTORM)
#define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS)
enum __attribute__((packed)) MoveEffects
enum __attribute__((packed)) MoveEffect
{
MOVE_EFFECT_NONE,
MOVE_EFFECT_SLEEP,

View File

@ -1167,8 +1167,7 @@ enum StartingStatusStringID
};
// gWrappedStringIds
// These correspond in order to sTrappingMoves!
enum WrappedStringID
enum __attribute__((packed)) WrappedStringID
{
B_MSG_WRAPPED_BIND,
B_MSG_WRAPPED_WRAP,

View File

@ -4,6 +4,7 @@
#include "contest_effect.h"
#include "constants/battle.h"
#include "constants/battle_move_effects.h"
#include "constants/battle_string_ids.h"
#include "constants/moves.h"
// For defining EFFECT_HIT etc. with battle TV scores and flags etc.
@ -21,21 +22,17 @@ struct __attribute__((packed, aligned(2))) BattleMoveEffect
#define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__}
#define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ ))
enum SheerForceBoost
{
SHEER_FORCE_AUTO_BOOST, // This is the default state when a move has a move effect with a chance
SHEER_FORCE_BOOST, // If a move effect doesn't have an effect with a chance this can force a boost
SHEER_FORCE_NO_BOOST, // Prevents a Sheer Force boost
};
struct AdditionalEffect
{
enum MoveEffects moveEffect;
enum MoveEffect moveEffect;
u8 self:1;
u8 onlyIfTargetRaisedStats:1;
u8 onChargeTurnOnly:1;
u8 sheerForceBoost:2; // Handles edge cases for Sheer Force
u8 padding:3;
u8 sheerForceOverride:1; // Handles edge cases for Sheer Force - if TRUE, boosts when it shouldn't, or doesn't boost when it should
u8 padding:4;
union PACKED {
enum WrappedStringID wrapped;
} multistring;
u8 chance; // 0% = effect certain, primary effect
};

View File

@ -2673,7 +2673,7 @@ bool32 IsStatLoweringEffect(enum BattleMoveEffects effect)
}
}
bool32 IsSelfStatLoweringEffect(enum MoveEffects effect)
bool32 IsSelfStatLoweringEffect(enum MoveEffect effect)
{
// Self stat lowering moves like Overheart, Superpower etc.
switch (effect)
@ -2701,7 +2701,7 @@ bool32 IsSelfStatLoweringEffect(enum MoveEffects effect)
}
}
bool32 IsSelfStatRaisingEffect(enum MoveEffects effect)
bool32 IsSelfStatRaisingEffect(enum MoveEffect effect)
{
// Self stat lowering moves like Power Up Punch or Charge Beam
switch (effect)

View File

@ -288,20 +288,6 @@ static const s32 sExperienceScalingFactors[] =
159767,
};
static const u16 sTrappingMoves[NUM_TRAPPING_MOVES] =
{
MOVE_BIND,
MOVE_WRAP,
MOVE_FIRE_SPIN,
MOVE_CLAMP,
MOVE_WHIRLPOOL,
MOVE_SAND_TOMB,
MOVE_MAGMA_STORM,
MOVE_INFESTATION,
MOVE_SNAP_TRAP,
MOVE_THUNDER_CAGE
};
static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 64, 80, 100, 120 };
enum GiveCaughtMonStates
@ -2900,7 +2886,7 @@ static inline bool32 TrySetLightScreen(u32 battler)
return FALSE;
}
static void SetNonVolatileStatusCondition(u32 effectBattler, enum MoveEffects effect, enum StatusTrigger trigger)
static void SetNonVolatileStatusCondition(u32 effectBattler, enum MoveEffect effect, enum StatusTrigger trigger)
{
gEffectBattler = effectBattler;
@ -3187,12 +3173,6 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_MoveEffectWrap;
for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattleCommunication[MULTISTRING_CHOOSER] < NUM_TRAPPING_MOVES; gBattleCommunication[MULTISTRING_CHOOSER]++)
{
if (sTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove)
break;
}
}
break;
case MOVE_EFFECT_ATK_PLUS_1:
@ -4123,6 +4103,7 @@ static void Cmd_setadditionaleffects(void)
if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + gBattleStruct->additionalEffectsCounter, percentChance))
{
gBattleScripting.moveEffect = additionalEffect->moveEffect;
gBattleCommunication[MULTISTRING_CHOOSER] = *((u8 *) &additionalEffect->multistring);
SetMoveEffect(
gBattlerAttacker,

View File

@ -768,7 +768,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3)
for (i = 0; i < GetMoveAdditionalEffectCount(move); i++)
{
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
switch ((enum MoveEffects)additionalEffect->moveEffect)
switch ((enum MoveEffect)additionalEffect->moveEffect)
{
case MOVE_EFFECT_ATK_PLUS_1:
case MOVE_EFFECT_DEF_PLUS_1:

View File

@ -5625,7 +5625,7 @@ bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef)
return FALSE;
}
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects effect, enum FunctionCallOption option)
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffect effect, enum FunctionCallOption option)
{
const u8 *battleScript = NULL;
u32 sideBattler = ABILITY_NONE;
@ -11044,12 +11044,7 @@ bool32 MoveIsAffectedBySheerForce(u32 move)
for (i = 0; i < numAdditionalEffects; i++)
{
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
if (additionalEffect->sheerForceBoost == SHEER_FORCE_NO_BOOST)
continue;
if (additionalEffect->chance > 0)
return TRUE;
if (additionalEffect->sheerForceBoost == SHEER_FORCE_BOOST)
if ((additionalEffect->chance > 0) != additionalEffect->sheerForceOverride)
return TRUE;
}
return FALSE;

View File

@ -631,6 +631,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.ignoresKingsRock = B_UPDATED_MOVE_FLAGS < GEN_3,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_BIND,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_TOUGH,
@ -1018,6 +1019,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.makesContact = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_WRAP,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_TOUGH,
@ -2255,6 +2257,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.ignoresKingsRock = B_UPDATED_MOVE_FLAGS < GEN_3,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_FIRE_SPIN,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_BEAUTY,
@ -3428,6 +3431,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.ignoresKingsRock = B_UPDATED_MOVE_FLAGS < GEN_3,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_CLAMP,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_TOUGH,
@ -6639,6 +6643,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.damagesUnderwater = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_WHIRLPOOL,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_BEAUTY,
@ -8670,6 +8675,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.category = DAMAGE_CATEGORY_PHYSICAL,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_SAND_TOMB,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_SMART,
@ -11990,6 +11996,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.category = DAMAGE_CATEGORY_SPECIAL,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_MAGMA_STORM,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_TOUGH,
@ -15612,6 +15619,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.makesContact = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_INFESTATION,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_SMART,
@ -16003,7 +16011,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.soundMove = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_REMOVE_STATUS,
.sheerForceBoost = SHEER_FORCE_BOOST,
.sheerForceOverride = TRUE,
}),
.contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING,
.contestCategory = CONTEST_CATEGORY_BEAUTY,
@ -17270,7 +17278,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_FLINCH,
.chance = 30,
.sheerForceBoost = SHEER_FORCE_NO_BOOST,
.sheerForceOverride = TRUE,
}),
.battleAnimScript = gBattleAnimMove_FloatyFall,
},
@ -17953,6 +17961,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_SNAP_TRAP,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_TOUGH,
@ -18935,6 +18944,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.metronomeBanned = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_WRAP,
.multistring.wrapped = B_MSG_WRAPPED_THUNDER_CAGE,
}),
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_COOL,
@ -19202,7 +19212,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.makesContact = TRUE,
.slicingMove = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.sheerForceBoost = SHEER_FORCE_BOOST,
.sheerForceOverride = TRUE,
}),
.battleAnimScript = gBattleAnimMove_StoneAxe,
},
@ -19527,7 +19537,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.makesContact = TRUE,
.slicingMove = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.sheerForceBoost = SHEER_FORCE_BOOST,
.sheerForceOverride = TRUE,
}),
.battleAnimScript = gBattleAnimMove_CeaselessEdge,
},
@ -20837,7 +20847,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.moveEffect = MOVE_EFFECT_SP_ATK_PLUS_1,
.self = TRUE,
.onChargeTurnOnly = TRUE,
.sheerForceBoost = SHEER_FORCE_BOOST,
.sheerForceOverride = TRUE,
}),
.battleAnimScript = gBattleAnimMove_ElectroShot,
},
@ -21113,7 +21123,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_TOXIC,
.chance = 50,
.sheerForceBoost = SHEER_FORCE_BOOST,
}),
.battleAnimScript = gBattleAnimMove_MalignantChain,
},