diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index f41db18368..cfa3ccaf95 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -131,7 +131,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectMagnitude @ EFFECT_MAGNITUDE .4byte BattleScript_EffectBatonPass @ EFFECT_BATON_PASS .4byte BattleScript_EffectHit @ EFFECT_PURSUIT - .4byte BattleScript_EffectRapidSpin @ EFFECT_RAPID_SPIN + .4byte BattleScript_EffectHit @ EFFECT_UNUSED_109 .4byte BattleScript_EffectHit @ EFFECT_UNUSED_110 .4byte BattleScript_EffectCaptivate @ EFFECT_CAPTIVATE .4byte BattleScript_EffectMorningSun @ EFFECT_MORNING_SUN @@ -4821,28 +4821,6 @@ BattleScript_EffectBatonPass:: switchineffects BS_ATTACKER goto BattleScript_MoveEnd -BattleScript_EffectRapidSpin:: -.if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 - call BattleScript_EffectHit_Ret - jumpifhalfword CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveEnd - setmoveeffect MOVE_EFFECT_RAPIDSPIN | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN - seteffectsecondary - setstatchanger STAT_SPEED, 1, FALSE - statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_EffectRapidSpinEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectRapidSpinEnd - setgraphicalstatchangevalues - playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 - printfromtable gStatUpStringIds - waitmessage B_WAIT_TIME_LONG -BattleScript_EffectRapidSpinEnd:: - tryfaintmon BS_TARGET - moveendall - end -.else - setmoveeffect MOVE_EFFECT_RAPIDSPIN | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN - goto BattleScript_EffectHit -.endif - BattleScript_EffectArgFixedDamage:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 493659e3be..2e2c7833d0 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -110,7 +110,7 @@ #define EFFECT_MAGNITUDE 106 #define EFFECT_BATON_PASS 107 #define EFFECT_PURSUIT 108 -#define EFFECT_RAPID_SPIN 109 +#define EFFECT_UNUSED_109 109 #define EFFECT_UNUSED_110 110 #define EFFECT_CAPTIVATE 111 #define EFFECT_MORNING_SUN 112 diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 0759bf080d..2097f998df 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1666,13 +1666,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_HIT_ESCAPE: break; - case EFFECT_RAPID_SPIN: - if ((gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED) || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED)) - break; // check damage/accuracy - //Spin checks - if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY)) - ADJUST_SCORE(-6); - break; case EFFECT_BELLY_DRUM: if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) ADJUST_SCORE(-10); @@ -3682,7 +3675,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score case EFFECT_LEECH_SEED: if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || gStatuses3[battlerDef] & STATUS3_LEECHSEED - || HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) + || HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPIDSPIN, FALSE) || aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE || aiData->abilities[battlerDef] == ABILITY_MAGIC_GUARD) break; @@ -4086,46 +4079,30 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score else if (IsPredictedToUsePursuitableMove(battlerDef, battlerAtk) && !MoveWouldHitFirst(move, battlerAtk, battlerDef)) //Pursuit against fast U-Turn ADJUST_SCORE(3);*/ break; - case EFFECT_RAPID_SPIN: case EFFECT_DEFOG: - if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + || (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST))) { ADJUST_SCORE(3); - break; } - - switch (move) + else if (!(gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SPIKES)) //Don't blow away hazards if you set them up { - case MOVE_DEFOG: - if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)) + if (isDoubleBattle) { - ADJUST_SCORE(3); + if (IsHazardMoveEffect(gBattleMoves[aiData->partnerMove].effect) // Partner is going to set up hazards + && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk), move) == AI_IS_SLOWER) // Partner going first + break; // Don't use Defog if partner is going to set up hazards } - else if (!(gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SPIKES)) //Don't blow away hazards if you set them up - { - if (isDoubleBattle) - { - if (IsHazardMoveEffect(gBattleMoves[aiData->partnerMove].effect) // Partner is going to set up hazards - && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk), move) == AI_IS_SLOWER) // Partner going first - break; // Don't use Defog if partner is going to set up hazards - } - // check defog lowering evasion - if (ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - { - if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 - || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef])) - ADJUST_SCORE(2); // encourage lowering evasion if they are evasive or we have a move with low accuracy - else - ADJUST_SCORE(1); - } + // check defog lowering evasion + if (ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + { + if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 + || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef])) + ADJUST_SCORE(2); // encourage lowering evasion if they are evasive or we have a move with low accuracy + else + ADJUST_SCORE(1); } - break; - case MOVE_RAPID_SPIN: - case MOVE_MORTAL_SPIN: - if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED) - ADJUST_SCORE(3); - break; } break; case EFFECT_TORMENT: @@ -4771,6 +4748,17 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) ADJUST_SCORE(3); break; + case MOVE_EFFECT_RAPIDSPIN: + if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED)) + { + ADJUST_SCORE(3); + break; + } + //Spin checks + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY)) + ADJUST_SCORE(-6); + break; } } else // consider move effects that hinder the target @@ -4922,7 +4910,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score } break; case MOVE_EFFECT_WRAP: - if (!HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) && !IsBattlerTrapped(battlerDef, TRUE) && ShouldTrap(battlerAtk, battlerDef, move)) + if (!HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPIDSPIN, FALSE) && !IsBattlerTrapped(battlerDef, TRUE) && ShouldTrap(battlerAtk, battlerDef, move)) ADJUST_SCORE(5); break; } diff --git a/src/battle_tv.c b/src/battle_tv.c index 3829eedcc9..b2053b665a 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -191,7 +191,6 @@ static const u16 sPoints_MoveEffect[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_MAGNITUDE] = 1, [EFFECT_BATON_PASS] = 7, [EFFECT_PURSUIT] = 2, - [EFFECT_RAPID_SPIN] = 2, [EFFECT_ARG_FIXED_DAMAGE] = 1, [EFFECT_MORNING_SUN] = 4, [EFFECT_SYNTHESIS] = 4, @@ -1276,6 +1275,8 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) // various cases add/remove points if (gBattleMoves[arg2].recoil > 0) baseFromEffect++; // recoil moves + if (MoveHasMoveEffect(arg2, MOVE_EFFECT_RAPIDSPIN, FALSE)) + baseFromEffect++; if (MoveHasMoveEffect(arg2, MOVE_EFFECT_SP_ATK_TWO_DOWN, FALSE) || MoveHasMoveEffect(arg2, MOVE_EFFECT_ATK_DEF_DOWN, FALSE)) baseFromEffect += 2; // Overheat etc & Superpower diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 0202cbc878..2ac03860b9 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -3860,12 +3860,8 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = [MOVE_RAPID_SPIN] = { - #if B_UPDATED_MOVE_DATA >= GEN_8 - .power = 50, - #else - .power = 20, - #endif - .effect = EFFECT_RAPID_SPIN, + .effect = EFFECT_HIT, + .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 50 : 20, .type = TYPE_NORMAL, .accuracy = 100, .pp = 40, @@ -3873,6 +3869,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = BATTLE_CATEGORY_PHYSICAL, .makesContact = TRUE, + ADDITIONAL_EFFECTS( + PRIMARY_EFFECT_SELF(MOVE_EFFECT_RAPIDSPIN) + #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 + , SECONDARY_EFFECT_SELF(MOVE_EFFECT_SPD_PLUS_1, 100) + #endif + ), }, [MOVE_SWEET_SCENT] = diff --git a/test/battle/move_effect/mortal_spin.c b/test/battle/move_effect/mortal_spin.c index 57256d92c9..24ee320cc3 100644 --- a/test/battle/move_effect/mortal_spin.c +++ b/test/battle/move_effect/mortal_spin.c @@ -3,20 +3,22 @@ ASSUMPTIONS { - ASSUME(MoveHasMoveEffect(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPIDSPIN, FALSE) == TRUE); + ASSUME(MoveHasMoveEffectSelf(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE); ASSUME(MoveHasMoveEffect(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, FALSE) == TRUE); } -SINGLE_BATTLE_TEST("Mortal Spin blows away hazards and poisons foe") +SINGLE_BATTLE_TEST("Mortal Spin blows away Wrap, hazards and poisons foe") { GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(opponent, MOVE_WRAP); } TURN { MOVE(opponent, MOVE_STEALTH_ROCK); MOVE(player, MOVE_MORTAL_SPIN); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_MORTAL_SPIN, player); + MESSAGE("Wobbuffet got free of Foe Wobbuffet's Wrap!"); MESSAGE("Wobbuffet blew away Stealth Rock!"); MESSAGE("Foe Wobbuffet was poisoned!"); STATUS_ICON(opponent, poison: TRUE); diff --git a/test/battle/move_effect/rapid_spin.c b/test/battle/move_effect/rapid_spin.c new file mode 100644 index 0000000000..af1c96d7f4 --- /dev/null +++ b/test/battle/move_effect/rapid_spin.c @@ -0,0 +1,31 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE); + #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 + ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_SPD_PLUS_1) == TRUE); + #endif +} + +SINGLE_BATTLE_TEST("Rapin Spin blows away Wrap, hazards and raises Speed (Gen 8+)") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_WRAP); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); MOVE(player, MOVE_RAPID_SPIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAPID_SPIN, player); + MESSAGE("Wobbuffet got free of Foe Wobbuffet's Wrap!"); + MESSAGE("Wobbuffet blew away Stealth Rock!"); + #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Speed rose!"); + #endif + } +} +