From 3977b66c91370fff6f49ee73af564a9b18bcf252 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 19 Jan 2025 22:45:26 +0100 Subject: [PATCH 1/5] Remove redundant line in Cmd_setcharge (#6053) --- src/battle_script_commands.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 42b1b86c84..554ec7b6c5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -14146,7 +14146,6 @@ static void Cmd_setcharge(void) gDisableStructs[battler].chargeTimer = 2; else gDisableStructs[battler].chargeTimer = 0; - gBattlescriptCurrInstr++; gBattlescriptCurrInstr = cmd->nextInstr; } From 4bcb07a6a79e8ea53ade8a84e591181be3b566f8 Mon Sep 17 00:00:00 2001 From: kittenchilly Date: Mon, 20 Jan 2025 02:49:20 -0600 Subject: [PATCH 2/5] Add Clodsire second frame and fixed Grookey backsprite + overworld (#6047) --- graphics/pokemon/clodsire/anim_front.png | Bin 0 -> 1448 bytes graphics/pokemon/clodsire/back.png | Bin 539 -> 813 bytes graphics/pokemon/clodsire/front.png | Bin 698 -> 0 bytes graphics/pokemon/clodsire/normal.pal | 28 ++++++++++---------- graphics/pokemon/clodsire/shiny.pal | 26 +++++++++--------- graphics/pokemon/grookey/back.png | Bin 591 -> 949 bytes graphics/pokemon/grookey/overworld.png | Bin 783 -> 653 bytes src/data/graphics/pokemon.h | 2 +- src/data/pokemon_graphics/front_pic_anims.h | 2 +- test/battle/trainer_control.h | 2 +- 10 files changed, 30 insertions(+), 30 deletions(-) create mode 100644 graphics/pokemon/clodsire/anim_front.png delete mode 100755 graphics/pokemon/clodsire/front.png diff --git a/graphics/pokemon/clodsire/anim_front.png b/graphics/pokemon/clodsire/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..1630189f6256f7e51ea054c5dad5cf9a373475f0 GIT binary patch literal 1448 zcmV;Z1y}lsP)EX>4Tx04R}tkv&MmP!xqvQ$>-AiUma+GE{M}AS&W0RV;#q(pG5I!Q`cX(4-+r zad8w}3l9D)RvlcNb#-tR1i>E=cfm=~MM}IcDYS_3!sC6MchBLy`v9R9ommw-Ug1L@2GEN!iJ5vVxtM}yece+x)m@lpdH4NU-AdMEfKMczW4d7xZxGLH zS~}-_;vg$X3h_DdxIq^re&o9B@*C&8!vfC?8mYuQagbQdx3Jv8tYE0b)5IY~)hJ&` zyR2~D;;fb`tZ`5N!a!DANphXmFrrvO3~`8%Q9%(USP0Xukzyi2=MfM8kmHY&OD0zl zj2sInLxtq{!T;d*Y|Y%%q?;6o0PQcf{V@V`>;m?2VCv|gHO6-NRH&ECFF9z`x$*x2I#*9y4KveHO_JR0HkPE%QwKm zAuyV!>~)WKcec*$-=4<&egKIYaPmqaX}L zXInu*l>h(RO+t_WL2YLq%|mNj?lA<>-u(PL@x&8PJTVL>;w$x>V_B9@8A8p3W%1qz zj2m+A=4qO0`LfL0=KZ>^*9;GX=T@Ew39+6NJPmHu88N3UuJmU?h%v!0;R*l~IR&)Q z0VScUDC*5bVa(Yyh!6s;N(}%x66`5trW`=-F(koHZ4knkd?X1Vrw@`qC$=d%R)uhW z^)4S4f;Aw2rvQc-6P)v~LFm9anSwQM5dzXqBM~?x!Ps{lJR{TOAa}b2{M0GD-?Rlo zNu&bs`*H$E`cSHomlkyf16QdASS5kJlx|6Sit1vLDZDUR04HGv`T}_U<9KP;ggF7& zN)9ms*!0@&O-kX8-oWC5yxZHs)cSD(R=>+4;976h?33Q!n1EI5M-@Ook-y}QGDrF_ z3IpyNeFX#loX=iuNW&j!?xcp}(CQ~3Os3jFS)M0@dBg5NLRSTgUxxNR!209sOt5_o z@S=rTw6_vk?#zWZlBthMkXjxu);kR(K)U0eJeqLpLt=qXAkUHj<^qs}gJ1ZDuPpw} zz{RuX)_;UC;#cw~o_OMkzls=tso(ay1pQR|w%rBn+Q_)w21Iq_p8#$aVdsId`Sw#l z6nVIS32giER5>F>9+&~}XB^zkUIF4+IS_y;L>lkVS*>eIV9yUWb)6~z42@H$XfP8OGaTu@)M+YGTb`-&sz^z?h z5K%TD4#JKzfV|>mCbGjo z`_T|!DtL2I0l9%P60_r@Ec66Ul?NeEO~2MJxV?g3mH&J#z_}3t!ea-aYCrV)QAZ{L zRvce9Fz(IZAkdK{c#(0{E@)dI+5FSH7l7c7@zNpY!w%4P4}7cce9twY^nloT>4egJ zXb8obv1e;3x&1)yp9!LYVN9R#x*rEsveB#fx$ld2WH$ppdYZUInWyc zIEg`fX`+p8zjptDmO<;A+$IF0_FX;7=H)@0001;w}I>c00D++LqkwWLqi~Na&Km7Y-IodD3N`UJxIe) z6opSyMUje%1w|Y(RB^B%D&i!IHxu2nOID)F5Td`@ik3v1n9K z)7#GaAAdXLs{-})+S%Fp7r~sbs=bGU^Bh4Br98zyAP^zu_>zdfUZoIA0)m`X;i~ty z)W}r8s#riK0!rmIG86{&nec;p8rCzRAA!!WBIv*wra%Ctx*ILX4nJPMu9{?YJYhPz(atAd^LOJ0g#AX4+DU=aQJVq zBOqOr7=WW&fE57WRJRWv0>pr{LK$$v9;7wI3Giv6asY@2c;g801K>>cJj`x|Zh#Yk zs{sY*R_FsbN8$l`pjn~P14FAopR3*&wFeU*jle`f9^@)ZT*{5Z3VbB`kva gDjV+X?EKyQ07XVH0SXOlKL7v#07*qoM6N<$f);CXxc~qF delta 526 zcmV+p0`dK=2Ac$s7=Hu<00013M{Ml?000McNliru=K~KDI2I*+|DON=02g#cSaefw zW^{L9a%BKVOhiylM<8}(av(DOV1ZP1_ zK>z@;j|==^1poj5Fi=cXMVQc_N<&(IbdPIcd@d*~5D*Zco`1#7w5lj1Ab)?IS5l1sUjW#OR%*Jei9-%6AKGZi7)Zx*p7IB_Mam8%kh7{WU;v9 ze6wt1p61W%YkwlMnMGK5ZLRt?71eu9ap`XdxLCf1aK4ula~yy zEeCj?Vql;{1jtV{uy?;^U+R+7HP|Xo!T-=7H6V8|74Rql!N5;>$ywwN*EEP=k;AC1 Q00000Ne4wvM6N<$f*$(PK>z>% diff --git a/graphics/pokemon/clodsire/front.png b/graphics/pokemon/clodsire/front.png deleted file mode 100755 index 2722b7eb7013fd0338a58bb7644911bca78f9d73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 698 zcmV;r0!96aP)G1 z6F4dg5`!23000+sMObuGZ)S9NVRB^vM@&RePDdbiWpW@hE;Mn4q~QPn00?w&PDe*f zL^A*Y002sWDIWj;00d`2O+f$vv5yPP{gc2H@u->b~C% z6$6d;AO9Wz8lUdCu**LVs5)PuYji()bms#ipoU>I>F(FK0v6a0Ba=5r70j?kY$0!) ze=nVBeVr>+eCq&{>o4fn(x>BFLoO@c)tJgsYCNal+d3t=R)y$+LgamSLR(I(sL_27 zv?|JOTGSrw1oIW4!z!t%ga)_vJrF9nKP?CR$=DIxo gLqxc00D++LqkwWLqi~Na&Km7Y-IodD3N`UJxIe) z6opSyMUje%1w|Y(RB^B%D&i##;c<-vK~i0>F#}0p0@DPa41&L&yvW3joQQh3eZ3OeG)| zG;2k~6$6@tAs{Z+PzeHAE+N99N0OK)fFQV_NGYYqV}YAxKk?mbDUR0uh&l!*4Fg3XV5`lF1**1;C*` z6Y}Y-9|45$2`GB^4)Cn60MZ(+0ld;j%yMq6u9~ZaSNc2{jsdL`eqNvg$OoWaG#(|W z`XF2AWngJyybkn#Gq9gD0b~YtkI(`Lfp7TP1yBzl8xrBwt)d*#21J?BK48;B+630` zy%dCiJqxY@L$oab4m~vOI`~>!SPc&&dTvD}T$mX7vxYkIx-e=J{Mz~YJWU3u?r!Xr z#_|@{25hNs+yvb|!15NNsme_2C+z!k@6JLY;Crv02;nJ5Fi}HSxa}2D{-GUl@PY%@D7NE0Li!vOfbI#8h0OW+3qO+3Wn5zv}E>wBq}9;T>gmOMz` zf9nKbMrK(^^IdJxbfGN^ey(;<>#)$a1s}VDhlup?)C905G>Guh^f0pkkQU$*;MZz1 z>H}EB8^GJy2K=}Q&;tq^6(XXW+q(z-9yjbE1wFul${t)unqaC9tLi#Y52=BfQmdPb zQHwzwHJ;qf1aAGy>1+dfkAH}y+$bUBR{28SLg#B}fxELvJc0*h3WXdA^d2V?&;*2&MNm&JGh0000< KMNUMnLSTaW=HQ0_ diff --git a/graphics/pokemon/grookey/overworld.png b/graphics/pokemon/grookey/overworld.png index 2fb83529569e83109c93a2b68fb969b4f40655c7..928fd09bc4cf26c72773cf4577e24222ecf28645 100644 GIT binary patch delta 581 zcmV-L0=oT=28{)f7#0Wv0001UMu)cm0004VQb$4nuFf3kks&{S3rR#lR9J=WmQi5*}QA8n?TGV$A*EEd6f_yb%=a?h=(J;{E zqsIyR@gRr20D~icnMc&&%uHB-@ckE#?ft+3dA6>3pF@DihTspl2$&7QJ3QCDZ;7!0gKi6u$-ztiU5@WFVD08OG|=M?JPgX_-`d1I^#sN<0z z-3=Ja54f6t9PsAQGkkDE5K@W|#FS?B4Cem7To&@axRa;N$O57KLJ(StSKH@V!BnN!36TrUwin0bbCEi`L`LM_1A8jkg4{>FG| zMF}npURzaEI_w757G{kX1(GlqkPTw<3jfCVX^Jf*K1dNZ@LhBS{m%HNdv%IWu~sZy T;?sSU00000NkvXXu0mjfQu!TC delta 712 zcmV;(0yq7Q1&;=h7zqRe0002CwraMKEORd5$C^`N36J&1>FEyJ5T3{Qe(f-(3)dl1`dkiMgxY>llXGXl-0lK5B~w)z9+ho z(@<`}w2*oB)E<~IVYPw~WFTWFH8y|C0Oi@yns11tt{g_u1jjX0xvHX_blXeeYCWIA( zA(nbb$!%?JHNnVgUn>TfwE=atvZfm#Rt%)bgl*%n4IYP8*~ryJS@~tb;Cz2|^aAW8 zGlaRiRV1Ppdy~O&@&AAfd~)OrRPu!T!HJonZl#OG$~7=ybuXIU@9XGV(mQB8qK|3j z$Zq@sSO^v|moBGRhgew5*RYrs^>rYv!9?jh*-ab@ub{8?Wf(-HM{njqTqbg~^SL;6 zPpIY5Ub0ot>`#BeJ*;=QtuTL!R_>*45$k{bcf~@2=#tR3+Si3Rc4f8CpCbm$JC5D9 zPDU`e!m*x(oX$)#%W{)MA3DC75WVGvJv*BY5G0Pw2;% z`Xk_y5GNz>5pQq*g#~orygpw{_q-$>2Id{E8z>=lx>htF{Os6*b*6(l uhB Date: Mon, 20 Jan 2025 10:45:14 -0500 Subject: [PATCH 3/5] Fix Entrainment AI scoring bug (#6056) --- src/battle_ai_main.c | 12 ++++++++---- test/battle/move_effect/entrainment.c | 13 +++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index ea8a4bb91f..25700f670e 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -2952,7 +2952,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_ENTRAINMENT: if (partnerHasBadAbility && IsAbilityOfRating(aiData->abilities[battlerAtk], 0)) { - RETURN_SCORE_PLUS(WEAK_EFFECT); + RETURN_SCORE_PLUS(DECENT_EFFECT); } break; case EFFECT_SOAK: @@ -4061,9 +4061,13 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_ENTRAINMENT: if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) break; - else if ((IsAbilityOfRating(aiData->abilities[battlerDef], 5) || gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating <= 0) - && (aiData->abilities[battlerDef] != aiData->abilities[battlerAtk] && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID))) - ADJUST_SCORE(DECENT_EFFECT); + if (aiData->abilities[battlerDef] != aiData->abilities[battlerAtk] && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID)) + { + if (gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating <= 0) + ADJUST_SCORE(DECENT_EFFECT); + else if (IsAbilityOfRating(aiData->abilities[battlerDef], 5) && gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating <= 3) + ADJUST_SCORE(WEAK_EFFECT); + } break; case EFFECT_IMPRISON: if (predictedMove != MOVE_NONE && HasMove(battlerAtk, predictedMove)) diff --git a/test/battle/move_effect/entrainment.c b/test/battle/move_effect/entrainment.c index b43f6dcbc1..cccae86759 100644 --- a/test/battle/move_effect/entrainment.c +++ b/test/battle/move_effect/entrainment.c @@ -1,6 +1,19 @@ #include "global.h" #include "test/battle.h" +AI_DOUBLE_BATTLE_TEST("AI prefers Entrainment'ing good abilities onto partner with bad ability") +{ + GIVEN { + AI_FLAGS(AI_FLAG_SMART_TRAINER); + PLAYER(SPECIES_QUAXWELL) { Level(18); Ability(ABILITY_TORRENT); Moves(MOVE_WATER_GUN); }; + PLAYER(SPECIES_CORPHISH) { Level(18); Moves(MOVE_WATER_GUN); }; + OPPONENT(SPECIES_SMEARGLE) { Level(17); Ability(ABILITY_TECHNICIAN); Moves(MOVE_AERIAL_ACE, MOVE_ENTRAINMENT, MOVE_FLAME_WHEEL, MOVE_MAGICAL_LEAF); } + OPPONENT(SPECIES_ARCHEN) { Level(17); Ability(ABILITY_DEFEATIST); Moves(MOVE_DUAL_WINGBEAT, MOVE_ROCK_TOMB); } + } WHEN { + TURN { EXPECT_MOVE(opponentLeft, MOVE_ENTRAINMENT); EXPECT_MOVE(opponentRight, MOVE_DUAL_WINGBEAT); MOVE(playerLeft, MOVE_WATER_GUN); MOVE(playerRight, MOVE_WATER_GUN); } + } +} + TO_DO_BATTLE_TEST("Entrainment changes the target's Ability to match the user's"); TO_DO_BATTLE_TEST("Entrainment fails if the user's ability has cantBeCopied flag"); TO_DO_BATTLE_TEST("Entrainment fails if the targets's ability has cantBeOverwritten flag"); From b1831daa98c8f6a72529059ec5f285df93c5a04d Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:15:25 +0100 Subject: [PATCH 4/5] Adds static assert for DamageCalculationData (#6063) --- include/battle_util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/battle_util.h b/include/battle_util.h index 1eacdaa03d..dba6299dee 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -152,6 +152,7 @@ struct DamageCalculationData u32 updateFlags:1; u32 padding:2; }; +STATIC_ASSERT(sizeof(struct DamageCalculationData) <= 4, StructExceedsFourBytes); void HandleAction_ThrowBall(void); bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move); From b2f2a8c9fb8c7d00ceceb485ef2bd1fcc38a8070 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:43:54 +0100 Subject: [PATCH 5/5] Fixes Rapid Spin / Toxic Debris interaction (#6023) Co-authored-by: Bassoonian --- docs/tutorials/how_to_new_move.md | 2 - include/constants/battle.h | 107 +++++++++--------- include/constants/battle_move_effects.h | 1 + include/constants/battle_script_commands.h | 1 + src/battle_ai_main.c | 15 +-- src/battle_ai_switch_items.c | 2 +- src/battle_ai_util.c | 2 +- src/battle_script_commands.c | 15 ++- src/battle_tv.c | 2 +- src/data/battle_move_effects.h | 6 + src/data/moves_info.h | 16 +-- test/battle/ability/shield_dust.c | 2 +- test/battle/ai/ai_powerful_status.c | 2 +- test/battle/hold_effect/covert_cloak.c | 2 +- .../rapid_spin.c | 32 ++++-- 15 files changed, 114 insertions(+), 93 deletions(-) rename test/battle/{move_effect_secondary => move_effect}/rapid_spin.c (65%) diff --git a/docs/tutorials/how_to_new_move.md b/docs/tutorials/how_to_new_move.md index e3a2eb0a12..e4289f4c58 100644 --- a/docs/tutorials/how_to_new_move.md +++ b/docs/tutorials/how_to_new_move.md @@ -169,8 +169,6 @@ Each move can have up to 15 additional effects, allowing you to construct monstr .moveEffect = MOVE_EFFECT_ALL_STATS_UP, .chance = 40, .self = TRUE, - },{ - .moveEffect = MOVE_EFFECT_RAPID_SPIN, },{ .moveEffect = MOVE_EFFECT_DEF_MINUS_2, .chance = 50, diff --git a/include/constants/battle.h b/include/constants/battle.h index bdabd816d5..865f5ce886 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -364,61 +364,60 @@ #define MOVE_EFFECT_PREVENT_ESCAPE 33 #define MOVE_EFFECT_NIGHTMARE 34 #define MOVE_EFFECT_ALL_STATS_UP 35 -#define MOVE_EFFECT_RAPID_SPIN 36 -#define MOVE_EFFECT_REMOVE_STATUS 37 -#define MOVE_EFFECT_ATK_DEF_DOWN 38 -#define MOVE_EFFECT_ATK_PLUS_2 39 -#define MOVE_EFFECT_DEF_PLUS_2 40 -#define MOVE_EFFECT_SPD_PLUS_2 41 -#define MOVE_EFFECT_SP_ATK_PLUS_2 42 -#define MOVE_EFFECT_SP_DEF_PLUS_2 43 -#define MOVE_EFFECT_ACC_PLUS_2 44 -#define MOVE_EFFECT_EVS_PLUS_2 45 -#define MOVE_EFFECT_ATK_MINUS_2 46 -#define MOVE_EFFECT_DEF_MINUS_2 47 -#define MOVE_EFFECT_SPD_MINUS_2 48 -#define MOVE_EFFECT_SP_ATK_MINUS_2 49 -#define MOVE_EFFECT_SP_DEF_MINUS_2 50 -#define MOVE_EFFECT_ACC_MINUS_2 51 -#define MOVE_EFFECT_EVS_MINUS_2 52 -#define MOVE_EFFECT_SCALE_SHOT 53 -#define MOVE_EFFECT_THRASH 54 -#define MOVE_EFFECT_KNOCK_OFF 55 -#define MOVE_EFFECT_DEF_SPDEF_DOWN 56 -#define MOVE_EFFECT_CLEAR_SMOG 57 -#define MOVE_EFFECT_SMACK_DOWN 58 -#define MOVE_EFFECT_FLAME_BURST 59 -#define MOVE_EFFECT_FEINT 60 -#define MOVE_EFFECT_SPECTRAL_THIEF 61 -#define MOVE_EFFECT_V_CREATE 62 -#define MOVE_EFFECT_HAPPY_HOUR 63 -#define MOVE_EFFECT_CORE_ENFORCER 64 -#define MOVE_EFFECT_THROAT_CHOP 65 -#define MOVE_EFFECT_INCINERATE 66 -#define MOVE_EFFECT_BUG_BITE 67 -#define MOVE_EFFECT_RECOIL_HP_25 68 -#define MOVE_EFFECT_TRAP_BOTH 69 -#define MOVE_EFFECT_ROUND 70 -#define MOVE_EFFECT_STOCKPILE_WORE_OFF 71 -#define MOVE_EFFECT_DIRE_CLAW 72 -#define MOVE_EFFECT_STEALTH_ROCK 73 -#define MOVE_EFFECT_SPIKES 74 -#define MOVE_EFFECT_SYRUP_BOMB 75 -#define MOVE_EFFECT_FLORAL_HEALING 76 -#define MOVE_EFFECT_SECRET_POWER 77 -#define MOVE_EFFECT_PSYCHIC_NOISE 78 -#define MOVE_EFFECT_TERA_BLAST 79 -#define MOVE_EFFECT_ORDER_UP 80 -#define MOVE_EFFECT_ION_DELUGE 81 -#define MOVE_EFFECT_AROMATHERAPY 82 // No functionality yet -#define MOVE_EFFECT_HAZE 83 -#define MOVE_EFFECT_LEECH_SEED 84 -#define MOVE_EFFECT_REFLECT 85 -#define MOVE_EFFECT_LIGHT_SCREEN 86 -#define MOVE_EFFECT_SALT_CURE 87 -#define MOVE_EFFECT_EERIE_SPELL 88 +#define MOVE_EFFECT_REMOVE_STATUS 36 +#define MOVE_EFFECT_ATK_DEF_DOWN 37 +#define MOVE_EFFECT_ATK_PLUS_2 38 +#define MOVE_EFFECT_DEF_PLUS_2 39 +#define MOVE_EFFECT_SPD_PLUS_2 40 +#define MOVE_EFFECT_SP_ATK_PLUS_2 41 +#define MOVE_EFFECT_SP_DEF_PLUS_2 42 +#define MOVE_EFFECT_ACC_PLUS_2 43 +#define MOVE_EFFECT_EVS_PLUS_2 44 +#define MOVE_EFFECT_ATK_MINUS_2 45 +#define MOVE_EFFECT_DEF_MINUS_2 46 +#define MOVE_EFFECT_SPD_MINUS_2 47 +#define MOVE_EFFECT_SP_ATK_MINUS_2 48 +#define MOVE_EFFECT_SP_DEF_MINUS_2 49 +#define MOVE_EFFECT_ACC_MINUS_2 50 +#define MOVE_EFFECT_EVS_MINUS_2 51 +#define MOVE_EFFECT_SCALE_SHOT 52 +#define MOVE_EFFECT_THRASH 53 +#define MOVE_EFFECT_KNOCK_OFF 54 +#define MOVE_EFFECT_DEF_SPDEF_DOWN 55 +#define MOVE_EFFECT_CLEAR_SMOG 56 +#define MOVE_EFFECT_SMACK_DOWN 57 +#define MOVE_EFFECT_FLAME_BURST 58 +#define MOVE_EFFECT_FEINT 59 +#define MOVE_EFFECT_SPECTRAL_THIEF 60 +#define MOVE_EFFECT_V_CREATE 61 +#define MOVE_EFFECT_HAPPY_HOUR 62 +#define MOVE_EFFECT_CORE_ENFORCER 63 +#define MOVE_EFFECT_THROAT_CHOP 64 +#define MOVE_EFFECT_INCINERATE 65 +#define MOVE_EFFECT_BUG_BITE 66 +#define MOVE_EFFECT_RECOIL_HP_25 67 +#define MOVE_EFFECT_TRAP_BOTH 68 +#define MOVE_EFFECT_ROUND 69 +#define MOVE_EFFECT_STOCKPILE_WORE_OFF 70 +#define MOVE_EFFECT_DIRE_CLAW 71 +#define MOVE_EFFECT_STEALTH_ROCK 72 +#define MOVE_EFFECT_SPIKES 73 +#define MOVE_EFFECT_SYRUP_BOMB 74 +#define MOVE_EFFECT_FLORAL_HEALING 75 +#define MOVE_EFFECT_SECRET_POWER 76 +#define MOVE_EFFECT_PSYCHIC_NOISE 77 +#define MOVE_EFFECT_TERA_BLAST 78 +#define MOVE_EFFECT_ORDER_UP 79 +#define MOVE_EFFECT_ION_DELUGE 80 +#define MOVE_EFFECT_AROMATHERAPY 81 // No functionality yet +#define MOVE_EFFECT_HAZE 82 +#define MOVE_EFFECT_LEECH_SEED 83 +#define MOVE_EFFECT_REFLECT 84 +#define MOVE_EFFECT_LIGHT_SCREEN 85 +#define MOVE_EFFECT_SALT_CURE 86 +#define MOVE_EFFECT_EERIE_SPELL 87 -#define NUM_MOVE_EFFECTS 89 +#define NUM_MOVE_EFFECTS 88 #define MOVE_EFFECT_AFFECTS_USER 0x2000 #define MOVE_EFFECT_CERTAIN 0x4000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index d0e4839bce..b32b7a3837 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -348,6 +348,7 @@ enum { EFFECT_GUARDIAN_OF_ALOLA, EFFECT_SHELL_SIDE_ARM, EFFECT_ORDER_UP, + EFFECT_RAPID_SPIN, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index c4797e94ae..20858c2365 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -286,6 +286,7 @@ enum MoveEndEffects MOVEEND_MULTIHIT_MOVE, MOVEEND_DEFROST, MOVEEND_RECOIL, + MOVEEND_RAPID_SPIN, MOVEEND_ITEM_EFFECTS_ATTACKER, MOVEEND_MAGICIAN, // Occurs after final multi-hit strike, and after other items/abilities would activate MOVEEND_RED_CARD, // Red Card triggers before Eject Pack diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 25700f670e..59695bc0e6 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -3502,7 +3502,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_LEECH_SEED: if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || gStatuses3[battlerDef] & STATUS3_LEECHSEED - || HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) + || HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) || aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE || aiData->abilities[battlerDef] == ABILITY_MAGIC_GUARD) break; @@ -4418,6 +4418,12 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) || gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & STATUS1_ANY) ADJUST_SCORE(GOOD_EFFECT); break; + case EFFECT_RAPID_SPIN: + if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED)) + ADJUST_SCORE(GOOD_EFFECT); + break; + } // move effect checks // check move additional effects that are likely to happen @@ -4460,11 +4466,6 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case MOVE_EFFECT_EVS_PLUS_2: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_EVASION)); break; - case MOVE_EFFECT_RAPID_SPIN: - if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) - || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED)) - ADJUST_SCORE(GOOD_EFFECT); - break; } } else @@ -4659,7 +4660,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case MOVE_EFFECT_WRAP: - if (!HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) + if (!HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) ADJUST_SCORE(BEST_EFFECT); break; case MOVE_EFFECT_SALT_CURE: diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index db0070da8e..23d96dedfe 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -807,7 +807,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler) for (j = 0; j < MAX_MON_MOVES; j++) { aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); - if (MoveHasAdditionalEffectSelf(aiMove, MOVE_EFFECT_RAPID_SPIN) + if (gMovesInfo[aiMove].effect == EFFECT_RAPID_SPIN || (B_DEFOG_EFFECT_CLEARING >= GEN_6 && gMovesInfo[aiMove].effect == EFFECT_DEFOG) || gMovesInfo[aiMove].effect == EFFECT_TIDY_UP) { diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index b68112374d..ac6f214134 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -4013,7 +4013,7 @@ bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData { if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0 - || HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) + || HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) || HasMoveEffect(battlerDef, EFFECT_DEFOG)) return FALSE; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 554ec7b6c5..01b97938ef 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3578,10 +3578,6 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattlescriptCurrInstr = BattleScript_AllStatsUp; } break; - case MOVE_EFFECT_RAPID_SPIN: - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_RapidSpinAway; - break; case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower if (!NoAliveMonsForEitherParty()) { @@ -5910,6 +5906,17 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + case MOVEEND_RAPID_SPIN: + if (gMovesInfo[gCurrentMove].effect == EFFECT_RAPID_SPIN + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && TARGET_TURN_DAMAGED) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RapidSpinAway; + effect = TRUE; + } + gBattleScripting.moveendState++; + break; case MOVEEND_ITEM_EFFECTS_ATTACKER: if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker, FALSE)) effect = TRUE; diff --git a/src/battle_tv.c b/src/battle_tv.c index ccea3551cd..a269634cf7 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -933,7 +933,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) // Various cases to add/remove points if (gMovesInfo[arg2].recoil > 0) baseFromEffect++; // Recoil moves - if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_RAPID_SPIN)) + if (gMovesInfo[arg2].effect == EFFECT_RAPID_SPIN) baseFromEffect++; if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_SP_ATK_MINUS_2) || MoveHasAdditionalEffect(arg2, MOVE_EFFECT_ATK_DEF_DOWN)) baseFromEffect += 2; // Overheat, Superpower, etc. diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index ae9e831e4a..ee281d6fe2 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2219,4 +2219,10 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_RAPID_SPIN] = + { + .battleScript = BattleScript_EffectHit, + .battleTvScore = 0, // TODO: Assign points + }, }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 4ff3b71f4c..13544bdabc 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -5811,7 +5811,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Spins the body at high\n" "speed to strike the foe."), - .effect = EFFECT_HIT, + .effect = EFFECT_RAPID_SPIN, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 50 : 20, .type = TYPE_NORMAL, .accuracy = 100, @@ -5820,12 +5820,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .additionalEffects = ADDITIONAL_EFFECTS({ - .moveEffect = MOVE_EFFECT_RAPID_SPIN, - .self = TRUE, - } + .additionalEffects = ADDITIONAL_EFFECTS( #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 - ,{ + { .moveEffect = MOVE_EFFECT_SPD_PLUS_1, .self = TRUE, .chance = 100, @@ -19576,7 +19573,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Erases trap moves and Leech\n" "Seed. Poisons adjacent foes."), - .effect = EFFECT_HIT, + .effect = EFFECT_RAPID_SPIN, .power = 30, .type = TYPE_POISON, .accuracy = 100, @@ -19585,10 +19582,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .additionalEffects = ADDITIONAL_EFFECTS({ - .moveEffect = MOVE_EFFECT_RAPID_SPIN, - .self = TRUE, - }, + .additionalEffects = ADDITIONAL_EFFECTS( { .moveEffect = MOVE_EFFECT_POISON, .chance = 100, diff --git a/test/battle/ability/shield_dust.c b/test/battle/ability/shield_dust.c index 9374a5f018..9e3dc0bf19 100644 --- a/test/battle/ability/shield_dust.c +++ b/test/battle/ability/shield_dust.c @@ -93,8 +93,8 @@ SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary o PARAMETRIZE { move = MOVE_METEOR_ASSAULT; } GIVEN { + ASSUME(gMovesInfo[MOVE_RAPID_SPIN].effect == EFFECT_RAPID_SPIN); ASSUME(MoveHasAdditionalEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE); - ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_MINUS_2) == TRUE); ASSUME(MoveHasAdditionalEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/ai/ai_powerful_status.c b/test/battle/ai/ai_powerful_status.c index 4a14c0bf80..c58c4f3af9 100644 --- a/test/battle/ai/ai_powerful_status.c +++ b/test/battle/ai/ai_powerful_status.c @@ -22,7 +22,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers to set up a powerful Status over fainting a ta AI_SINGLE_BATTLE_TEST("AI will try to do damage on target instead of setting up hazards if target has a way to remove them") { GIVEN { - ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); + ASSUME(gMovesInfo[MOVE_RAPID_SPIN].effect == EFFECT_RAPID_SPIN); ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK); ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_POWERFUL_STATUS | AI_FLAG_OMNISCIENT); diff --git a/test/battle/hold_effect/covert_cloak.c b/test/battle/hold_effect/covert_cloak.c index b55b1492da..d2f371bbe5 100644 --- a/test/battle/hold_effect/covert_cloak.c +++ b/test/battle/hold_effect/covert_cloak.c @@ -97,8 +97,8 @@ SINGLE_BATTLE_TEST("Covert Cloak does not block self-targeting effects, primary PARAMETRIZE { move = MOVE_METEOR_ASSAULT; } GIVEN { + ASSUME(gMovesInfo[MOVE_RAPID_SPIN].effect == EFFECT_RAPID_SPIN); ASSUME(MoveHasAdditionalEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE); - ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_MINUS_2) == TRUE); ASSUME(MoveHasAdditionalEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect_secondary/rapid_spin.c b/test/battle/move_effect/rapid_spin.c similarity index 65% rename from test/battle/move_effect_secondary/rapid_spin.c rename to test/battle/move_effect/rapid_spin.c index 4e490164d7..e5457395b9 100644 --- a/test/battle/move_effect_secondary/rapid_spin.c +++ b/test/battle/move_effect/rapid_spin.c @@ -3,15 +3,30 @@ ASSUMPTIONS { - ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); + ASSUME(gMovesInfo[MOVE_RAPID_SPIN].effect == EFFECT_RAPID_SPIN); + ASSUME(gMovesInfo[MOVE_MORTAL_SPIN].effect == EFFECT_RAPID_SPIN); #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_SPD_PLUS_1) == TRUE); #endif - ASSUME(MoveHasAdditionalEffectSelf(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); ASSUME(MoveHasAdditionalEffect(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON) == TRUE); } -SINGLE_BATTLE_TEST("Rapin Spin blows away Wrap, hazards and raises Speed (Gen 8+)") +SINGLE_BATTLE_TEST("Rapid Spin activates after Toxic Debris") +{ + GIVEN { + PLAYER(SPECIES_GLIMMORA) { Ability(ABILITY_TOXIC_DEBRIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_RAPID_SPIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAPID_SPIN, opponent); + ABILITY_POPUP(player, ABILITY_TOXIC_DEBRIS); + MESSAGE("Poison spikes were scattered on the ground all around the opposing team!"); + MESSAGE("The opposing Wobbuffet blew away Toxic Spikes!"); + } +} + +SINGLE_BATTLE_TEST("Rapid Spin blows away Wrap, hazards and raises Speed (Gen 8+)") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -22,16 +37,16 @@ SINGLE_BATTLE_TEST("Rapin Spin blows away Wrap, hazards and raises Speed (Gen 8+ } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_RAPID_SPIN, player); - MESSAGE("Wobbuffet got free of the opposing 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 + MESSAGE("Wobbuffet got free of the opposing Wobbuffet's Wrap!"); + MESSAGE("Wobbuffet blew away Stealth Rock!"); } } -SINGLE_BATTLE_TEST("Mortal Spin blows away Wrap, hazards and poisons foe") +SINGLE_BATTLE_TEST("Rapid Spin: Mortal Spin blows away Wrap, hazards and poisons foe") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -42,10 +57,9 @@ SINGLE_BATTLE_TEST("Mortal Spin blows away Wrap, hazards and poisons foe") } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_MORTAL_SPIN, player); - MESSAGE("Wobbuffet got free of the opposing Wobbuffet's Wrap!"); - MESSAGE("Wobbuffet blew away Stealth Rock!"); MESSAGE("The opposing Wobbuffet was poisoned!"); STATUS_ICON(opponent, poison: TRUE); + MESSAGE("Wobbuffet got free of the opposing Wobbuffet's Wrap!"); + MESSAGE("Wobbuffet blew away Stealth Rock!"); } } -