diff --git a/docs/tutorials/how_to_new_move.md b/docs/tutorials/how_to_new_move.md index e4289f4c58..442e2b28c9 100644 --- a/docs/tutorials/how_to_new_move.md +++ b/docs/tutorials/how_to_new_move.md @@ -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, diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index ec8c250fd2..f5af4acb33 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -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); diff --git a/include/battle_util.h b/include/battle_util.h index 272ccf3d1e..95efdd9922 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -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); diff --git a/include/constants/battle.h b/include/constants/battle.h index de4b3f40ba..5faa91ad7e 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -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, diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 57cf6f7021..df7b5e6232 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -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, diff --git a/include/move.h b/include/move.h index fa89ec3cf3..61483e402e 100644 --- a/include/move.h +++ b/include/move.h @@ -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 }; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dc766c9ee8..b4e0cbaaf4 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -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) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d7ccf40f53..e615c9d2d1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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, diff --git a/src/battle_tv.c b/src/battle_tv.c index dbcb9fb101..e23712beab 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -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: diff --git a/src/battle_util.c b/src/battle_util.c index cd33223a6e..ce82a997cc 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -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; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index adab4af3cc..4edf88f17a 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -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, },