diff --git a/INSTALL.md b/INSTALL.md index 25e6adb428..6e52559f67 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -110,9 +110,9 @@ To compile the `modern` target with this toolchain, the subdirectories `lib`, `i ### Building with debug info -To build **pokeemerald.elf** with debug symbols under a modern toolchain: +To build **pokeemerald.elf** with debug symbols and debug-compatible optimization under a modern toolchain: ```bash -make DINFO=1 +make debug ``` # Useful additional tools diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 118aebab8f..48920a04a2 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1426,11 +1426,6 @@ callnative BS_TryRevertWeatherForm .endm - .macro applysaltcure battler:req - callnative BS_ApplySaltCure - .byte \battler - .endm - .macro trysetoctolock battler:req, failInstr:req callnative BS_TrySetOctolock .byte \battler @@ -2242,11 +2237,6 @@ .4byte \jumpInstr .endm - .macro eeriespellppreduce failInstr:req - various BS_TARGET, VARIOUS_EERIE_SPELL_PP_REDUCE - .4byte \failInstr - .endm - .macro jumpifteamhealthy battler:req, jumpInstr:req various \battler, VARIOUS_JUMP_IF_TEAM_HEALTHY .4byte \jumpInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index f8a8747752..0b30087472 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -404,16 +404,10 @@ BattleScript_EffectHit_Pledge:: tryfaintmon BS_TARGET return -BattleScript_EffectSaltCure:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - jumpiffainted BS_TARGET, TRUE, BattleScript_EffectSaltCure_End - jumpifsubstituteblocks BattleScript_EffectSaltCure_End - applysaltcure BS_TARGET +BattleScript_MoveEffectSaltCure:: printstring STRINGID_TARGETISBEINGSALTCURED waitmessage B_WAIT_TIME_LONG -BattleScript_EffectSaltCure_End: - goto BattleScript_MoveEnd + return BattleScript_SaltCureExtraDamage:: playanimation BS_TARGET, B_ANIM_SALT_CURE_DAMAGE, NULL @@ -957,13 +951,10 @@ BattleScript_HyperspaceFuryRemoveProtect:: waitmessage B_WAIT_TIME_LONG return -BattleScript_EffectPlasmaFists:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - orword gFieldStatuses, STATUS_FIELD_ION_DELUGE +BattleScript_MoveEffectIonDeluge:: printstring STRINGID_IONDELUGEON waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_EffectSparklySwirl:: call BattleScript_EffectHit_Ret @@ -974,41 +965,25 @@ BattleScript_EffectSparklySwirl:: waitstate goto BattleScript_MoveEnd -BattleScript_EffectFreezyFrost:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - normalisebuffs +BattleScript_MoveEffectHaze:: printstring STRINGID_STATCHANGESGONE waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return -BattleScript_EffectSappySeed:: - jumpifstatus3 BS_TARGET, STATUS3_LEECHSEED, BattleScript_EffectHit - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - jumpifhasnohp BS_TARGET, BattleScript_MoveEnd - setseeded - printfromtable gLeechSeedStringIds +BattleScript_MoveEffectLeechSeed:: + printstring STRINGID_PKMNSEEDED waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectBaddyBad:: - jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_REFLECT, BattleScript_EffectHit - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - setreflect +BattleScript_MoveEffectReflect:: printfromtable gReflectLightScreenSafeguardStringIds waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return -BattleScript_EffectGlitzyGlow:: - jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_LIGHTSCREEN, BattleScript_EffectHit - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - setlightscreen +BattleScript_MoveEffectLightScreen:: printfromtable gReflectLightScreenSafeguardStringIds waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_EffectStuffCheeks:: attackcanceler @@ -4087,13 +4062,10 @@ BattleScript_EffectDestinyBond:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectEerieSpell:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - eeriespellppreduce BattleScript_MoveEnd +BattleScript_MoveEffectEerieSpell:: printstring STRINGID_PKMNREDUCEDPP waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_EffectSpite:: attackcanceler @@ -6747,7 +6719,7 @@ BattleScript_WishComesTrue:: playanimation BS_TARGET, B_ANIM_WISH_HEAL printstring STRINGID_PKMNWISHCAMETRUE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE healthbarupdate BS_TARGET datahpupdate BS_TARGET printstring STRINGID_PKMNREGAINEDHEALTH diff --git a/graphics/pokemon/ariados/anim_front.png b/graphics/pokemon/ariados/anim_front.png index 945c4d188f..82d947054b 100644 Binary files a/graphics/pokemon/ariados/anim_front.png and b/graphics/pokemon/ariados/anim_front.png differ diff --git a/graphics/pokemon/diggersby/anim_front.png b/graphics/pokemon/diggersby/anim_front.png index f2a0998e88..69c49c5276 100644 Binary files a/graphics/pokemon/diggersby/anim_front.png and b/graphics/pokemon/diggersby/anim_front.png differ diff --git a/graphics/pokemon/diggersby/back.png b/graphics/pokemon/diggersby/back.png index 36a4373816..a1cc29260d 100644 Binary files a/graphics/pokemon/diggersby/back.png and b/graphics/pokemon/diggersby/back.png differ diff --git a/graphics/pokemon/diggersby/shiny.pal b/graphics/pokemon/diggersby/shiny.pal index 5fd7727a42..f5f12f2cf0 100644 --- a/graphics/pokemon/diggersby/shiny.pal +++ b/graphics/pokemon/diggersby/shiny.pal @@ -6,7 +6,7 @@ JASC-PAL 120 120 112 160 160 144 8 8 8 -120 120 112 +84 84 78 48 48 56 232 232 232 240 152 168 diff --git a/graphics/pokemon/duraludon/overworld.png b/graphics/pokemon/duraludon/overworld.png index 0c8228abcb..a7488c4960 100644 Binary files a/graphics/pokemon/duraludon/overworld.png and b/graphics/pokemon/duraludon/overworld.png differ diff --git a/graphics/pokemon/honedge/anim_front.png b/graphics/pokemon/honedge/anim_front.png index 9a5dc75078..6376e2d1e2 100644 Binary files a/graphics/pokemon/honedge/anim_front.png and b/graphics/pokemon/honedge/anim_front.png differ diff --git a/graphics/pokemon/honedge/back.png b/graphics/pokemon/honedge/back.png index d9092fa13a..b1bc8634b0 100644 Binary files a/graphics/pokemon/honedge/back.png and b/graphics/pokemon/honedge/back.png differ diff --git a/graphics/pokemon/honedge/normal.pal b/graphics/pokemon/honedge/normal.pal index 51f60119df..d6a8a50995 100644 --- a/graphics/pokemon/honedge/normal.pal +++ b/graphics/pokemon/honedge/normal.pal @@ -3,17 +3,17 @@ JASC-PAL 16 152 208 160 8 48 56 -0 128 160 +36 103 149 16 16 16 80 64 40 -248 208 128 -176 152 88 +255 215 132 +181 158 90 136 104 56 -152 232 248 +102 225 253 96 192 216 80 88 88 168 168 168 216 216 216 -48 56 40 -152 128 80 -136 88 56 +99 84 80 +201 185 131 +167 139 110 diff --git a/graphics/pokemon/maractus/back.png b/graphics/pokemon/maractus/back.png index bc83adca5c..66a6520840 100644 Binary files a/graphics/pokemon/maractus/back.png and b/graphics/pokemon/maractus/back.png differ diff --git a/graphics/pokemon/pichu/spiky_eared/front.png b/graphics/pokemon/pichu/spiky_eared/front.png deleted file mode 100644 index 15b9201a27..0000000000 Binary files a/graphics/pokemon/pichu/spiky_eared/front.png and /dev/null differ diff --git a/graphics/pokemon/pichu/spiky_eared/overworld.png b/graphics/pokemon/pichu/spiky_eared/overworld.png index 7208db5108..36c1040003 100644 Binary files a/graphics/pokemon/pichu/spiky_eared/overworld.png and b/graphics/pokemon/pichu/spiky_eared/overworld.png differ diff --git a/graphics/pokemon/pincurchin/anim_front.png b/graphics/pokemon/pincurchin/anim_front.png index b8ed4964e4..ffc6bb6008 100644 Binary files a/graphics/pokemon/pincurchin/anim_front.png and b/graphics/pokemon/pincurchin/anim_front.png differ diff --git a/include/battle_scripts.h b/include/battle_scripts.h index cac3ce990f..82c396996c 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -809,18 +809,18 @@ extern const u8 BattleScript_EffectGeomancy[]; extern const u8 BattleScript_EffectFairyLock[]; extern const u8 BattleScript_EffectAllySwitch[]; extern const u8 BattleScript_EffectRelicSong[]; -extern const u8 BattleScript_EffectEerieSpell[]; +extern const u8 BattleScript_MoveEffectEerieSpell[]; extern const u8 BattleScript_EffectJungleHealing[]; extern const u8 BattleScript_EffectCoaching[]; extern const u8 BattleScript_EffectDecorate[]; extern const u8 BattleScript_EffectRecoilHP25[]; extern const u8 BattleScript_EffectStuffCheeks[]; -extern const u8 BattleScript_EffectGlitzyGlow[]; -extern const u8 BattleScript_EffectBaddyBad[]; -extern const u8 BattleScript_EffectSappySeed[]; -extern const u8 BattleScript_EffectFreezyFrost[]; +extern const u8 BattleScript_MoveEffectLightScreen[]; +extern const u8 BattleScript_MoveEffectReflect[]; +extern const u8 BattleScript_MoveEffectLeechSeed[]; +extern const u8 BattleScript_MoveEffectHaze[]; extern const u8 BattleScript_EffectSparklySwirl[]; -extern const u8 BattleScript_EffectPlasmaFists[]; +extern const u8 BattleScript_MoveEffectIonDeluge[]; extern const u8 BattleScript_EffectHyperspaceFury[]; extern const u8 BattleScript_EffectAuraWheel[]; extern const u8 BattleScript_EffectPhotonGeyser[]; @@ -843,7 +843,7 @@ extern const u8 BattleScript_EffectRevivalBlessing[]; extern const u8 BattleScript_EffectSnow[]; extern const u8 BattleScript_EffectTakeHeart[]; extern const u8 BattleScript_EffectCorrosiveGas[]; -extern const u8 BattleScript_EffectSaltCure[]; +extern const u8 BattleScript_MoveEffectSaltCure[]; extern const u8 BattleScript_EffectChillyReception[]; extern const u8 BattleScript_EffectMaxMove[]; extern const u8 BattleScript_EffectGlaiveRush[]; diff --git a/include/constants/battle.h b/include/constants/battle.h index ed19a72d9c..a7300e6517 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -331,7 +331,11 @@ #define MOVE_EFFECT_TOXIC 6 #define MOVE_EFFECT_FROSTBITE 7 #define PRIMARY_STATUS_MOVE_EFFECT MOVE_EFFECT_FROSTBITE // All above move effects apply primary status -#define MOVE_EFFECT_FREEZE_OR_FROSTBITE (B_USE_FROSTBITE == TRUE ? MOVE_EFFECT_FROSTBITE : MOVE_EFFECT_FREEZE) +#if B_USE_FROSTBITE == TRUE +#define MOVE_EFFECT_FREEZE_OR_FROSTBITE MOVE_EFFECT_FROSTBITE +#else +#define MOVE_EFFECT_FREEZE_OR_FROSTBITE MOVE_EFFECT_FREEZE +#endif #define MOVE_EFFECT_CONFUSION 8 #define MOVE_EFFECT_FLINCH 9 #define MOVE_EFFECT_TRI_ATTACK 10 @@ -405,8 +409,16 @@ #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 NUM_MOVE_EFFECTS 81 +#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 15edbd28ef..df752bf496 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -285,7 +285,6 @@ enum { EFFECT_ALLY_SWITCH, EFFECT_RELIC_SONG, EFFECT_BODY_PRESS, - EFFECT_EERIE_SPELL, EFFECT_JUNGLE_HEALING, EFFECT_COACHING, EFFECT_LASH_OUT, @@ -296,12 +295,7 @@ enum { EFFECT_RECOIL_HP_25, EFFECT_STUFF_CHEEKS, EFFECT_GRAV_APPLE, - EFFECT_GLITZY_GLOW, - EFFECT_BADDY_BAD, - EFFECT_SAPPY_SEED, - EFFECT_FREEZY_FROST, EFFECT_SPARKLY_SWIRL, - EFFECT_PLASMA_FISTS, EFFECT_HYPERSPACE_FURY, EFFECT_AURA_WHEEL, EFFECT_PHOTON_GEYSER, @@ -334,7 +328,6 @@ enum { EFFECT_COLLISION_COURSE, EFFECT_CORROSIVE_GAS, EFFECT_POPULATION_BOMB, - EFFECT_SALT_CURE, EFFECT_CHILLY_RECEPTION, EFFECT_MAX_MOVE, EFFECT_GLAIVE_RUSH, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 50e39b767e..bd1c61ec09 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -187,7 +187,6 @@ enum CmdVarious VARIOUS_TERRAIN_SEED, VARIOUS_MAKE_INVISIBLE, VARIOUS_ROOM_SERVICE, - VARIOUS_EERIE_SPELL_PP_REDUCE, VARIOUS_JUMP_IF_TEAM_HEALTHY, VARIOUS_TRY_HEAL_QUARTER_HP, VARIOUS_JUMP_IF_PRANKSTER_BLOCKED, diff --git a/include/pokemon.h b/include/pokemon.h index f05332163e..0618c6c785 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -580,8 +580,12 @@ struct MoveInfo #define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__} #define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ )) -// Just a hack to make a move boosted by Sheer Force despite having no secondary effects affected -#define SHEER_FORCE_HACK { .moveEffect = 0, .chance = 100, } +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 { @@ -589,6 +593,8 @@ struct AdditionalEffect u8 self:1; u8 onlyIfTargetRaisedStats:1; u8 onChargeTurnOnly:1; + u8 sheerForceBoost:2; // Handles edge cases for Sheer Force + u8 padding:3; u8 chance; // 0% = effect certain, primary effect }; @@ -901,6 +907,7 @@ u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg); u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg); bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method); u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); +void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); bool32 SpeciesHasGenderDifferences(u16 species); bool32 TryFormChange(u32 monId, u32 side, u16 method); void TryToSetBattleFormChangeMoves(struct Pokemon *mon, u16 method); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index ce3d71ca95..83182fe07c 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -2523,8 +2523,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-4); break; //TODO - //case EFFECT_PLASMA_FISTS: - //break; //case EFFECT_SHELL_TRAP: //break; //case EFFECT_BEAK_BLAST: @@ -4437,10 +4435,6 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) || gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & STATUS1_ANY) ADJUST_SCORE(GOOD_EFFECT); break; - case EFFECT_SALT_CURE: - if (IS_BATTLER_ANY_TYPE(battlerDef, TYPE_WATER, TYPE_STEEL)) - ADJUST_SCORE(DECENT_EFFECT); - break; } // move effect checks // check move additional effects that are likely to happen @@ -4685,6 +4679,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (!HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) ADJUST_SCORE(BEST_EFFECT); break; + case MOVE_EFFECT_SALT_CURE: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_WATER) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + } } } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dc51b5ae15..dd1cd296da 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2434,7 +2434,7 @@ bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE - && !IS_MOVE_STATUS(moves[i]].type == type && gMovesInfo[moves[i])) + && gMovesInfo[moves[i]].type == type && !IS_MOVE_STATUS(moves[i])) return TRUE; } diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 826586cf9b..a3104122d1 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6736,6 +6736,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) SwapStructData(&gSpecialStatuses[battlerAtk], &gSpecialStatuses[battlerPartner], data, sizeof(struct SpecialStatus)); SwapStructData(&gProtectStructs[battlerAtk], &gProtectStructs[battlerPartner], data, sizeof(struct ProtectStruct)); SwapStructData(&gBattleSpritesDataPtr->battlerData[battlerAtk], &gBattleSpritesDataPtr->battlerData[battlerPartner], data, sizeof(struct BattleSpriteInfo)); + SwapStructData(&gBattleStruct->illusion[battlerAtk], &gBattleStruct->illusion[battlerPartner], data, sizeof(struct Illusion)); SWAP(gBattleSpritesDataPtr->battlerData[battlerAtk].invisible, gBattleSpritesDataPtr->battlerData[battlerPartner].invisible, temp); SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0c9a7dd811..13c24466f5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3124,7 +3124,8 @@ void SetMoveEffect(bool32 primary, bool32 certain) bool32 statusChanged = FALSE; bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); u32 flags = 0; - u16 battlerAbility; + u32 battlerAbility; + u32 side; bool8 activateAfterFaint = FALSE; // NULL move effect @@ -4214,6 +4215,117 @@ void SetMoveEffect(bool32 primary, bool32 certain) } } break; + case MOVE_EFFECT_ION_DELUGE: + if (!(gFieldStatuses & STATUS_FIELD_ION_DELUGE)) + { + gFieldStatuses |= STATUS_FIELD_ION_DELUGE; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectIonDeluge; + } + break; + // TODO: The moves aromatherapy and heal bell need a refactor first + // case MOVE_EFFECT_AROMATHERAPY: + // break; + case MOVE_EFFECT_HAZE: + for (i = 0; i < gBattlersCount; i++) + TryResetBattlerStatChanges(i); + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectHaze; + break; + case MOVE_EFFECT_LEECH_SEED: + if (!IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) && !(gStatuses3[gBattlerTarget] & STATUS3_LEECHSEED)) + { + gStatuses3[gBattlerTarget] |= gBattlerAttacker; + gStatuses3[gBattlerTarget] |= STATUS3_LEECHSEED; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectLeechSeed; + } + break; + case MOVE_EFFECT_REFLECT: + side = GetBattlerSide(gBattlerAttacker); + if (!(gSideStatuses[side] & SIDE_STATUS_REFLECT)) + { + gSideStatuses[side] |= SIDE_STATUS_REFLECT; + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[side].reflectTimer = 8; + else + gSideTimers[side].reflectTimer = 5; + gSideTimers[side].reflectBattlerId = gBattlerAttacker; + + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_DOUBLE; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_SINGLE; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectReflect; + } + break; + case MOVE_EFFECT_LIGHT_SCREEN: + side = GetBattlerSide(gBattlerAttacker); + if (!(gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN)) + { + gSideStatuses[side] |= SIDE_STATUS_LIGHTSCREEN; + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[side].lightscreenTimer = 8; + else + gSideTimers[side].lightscreenTimer = 5; + gSideTimers[side].lightscreenBattlerId = gBattlerAttacker; + + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_DOUBLE; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_SINGLE; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectLightScreen; + } + break; + case MOVE_EFFECT_SALT_CURE: + if (!(gStatuses4[gBattlerTarget] & STATUS4_SALT_CURE)) + { + gStatuses4[gBattlerTarget] |= STATUS4_SALT_CURE; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectSaltCure; + } + break; + case MOVE_EFFECT_EERIE_SPELL: + if (gLastMoves[gBattlerTarget] != MOVE_NONE && gLastMoves[gBattlerTarget] != 0xFFFF) + { + u32 i; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gLastMoves[gBattlerTarget] == gBattleMons[gBattlerTarget].moves[i]) + break; + } + + if (i != MAX_MON_MOVES && gBattleMons[gBattlerTarget].pp[i] != 0) + { + u32 ppToDeduct = 3; + + if (gBattleMons[gBattlerTarget].pp[i] < ppToDeduct) + ppToDeduct = gBattleMons[gBattlerTarget].pp[i]; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[gBattlerTarget]) + ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, STR_CONV_MODE_LEFT_ALIGN, 1); + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) + gBattleMons[gBattlerTarget].pp[i] -= ppToDeduct; + if (!(gDisableStructs[gBattlerTarget].mimickedMoves & (1u << i)) + && !(gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED)) + { + BtlController_EmitSetMonData(gBattlerTarget, BUFFER_A, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[gBattlerTarget].pp[i]), &gBattleMons[gBattlerTarget].pp[i]); + MarkBattlerForControllerExec(gBattlerTarget); + } + + if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF) + CancelMultiTurnMoves(gBattlerTarget); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectEerieSpell; + } + } + break; } } } @@ -10746,53 +10858,6 @@ static void Cmd_various(void) MarkBattlerForControllerExec(battler); break; } - case VARIOUS_EERIE_SPELL_PP_REDUCE: - { - VARIOUS_ARGS(const u8 *failInstr); - if (gLastMoves[battler] != 0 && gLastMoves[battler] != 0xFFFF) - { - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gLastMoves[battler] == gBattleMons[battler].moves[i]) - break; - } - - if (i != MAX_MON_MOVES && gBattleMons[battler].pp[i] != 0) - { - s32 ppToDeduct = 3; - - if (gBattleMons[battler].pp[i] < ppToDeduct) - ppToDeduct = gBattleMons[battler].pp[i]; - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[battler]) - ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, STR_CONV_MODE_LEFT_ALIGN, 1); - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) - gBattleMons[battler].pp[i] -= ppToDeduct; - if (!(gDisableStructs[battler].mimickedMoves & (1u << i)) - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) - { - BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[battler].pp[i]), &gBattleMons[battler].pp[i]); - MarkBattlerForControllerExec(battler); - } - - if (gBattleMons[battler].pp[i] == 0 && gBattleStruct->skyDropTargets[battler] == 0xFF) - CancelMultiTurnMoves(battler); - - gBattlescriptCurrInstr = cmd->nextInstr; // continue - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; // cant reduce pp - } - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; // cant reduce pp - } - return; - } case VARIOUS_JUMP_IF_TEAM_HEALTHY: { VARIOUS_ARGS(const u8 *jumpInstr); @@ -16855,15 +16920,6 @@ void BS_JumpIfElectricAbilityAffected(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_ApplySaltCure(void) -{ - NATIVE_ARGS(u8 battler); - - u8 battler = GetBattlerForBattleScript(cmd->battler); - gStatuses4[battler] |= STATUS4_SALT_CURE; - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_JumpIfArgument(void) { NATIVE_ARGS(u8 argument, const u8 *jumpInstr); diff --git a/src/battle_util.c b/src/battle_util.c index b09f3622f6..c0038fd42a 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -11879,8 +11879,13 @@ bool32 MoveIsAffectedBySheerForce(u32 move) u32 i; for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) { + if (gMovesInfo[move].additionalEffects[i].sheerForceBoost == SHEER_FORCE_NO_BOOST) + continue; + if (gMovesInfo[move].additionalEffects[i].chance > 0) return TRUE; + if (gMovesInfo[move].additionalEffects[i].sheerForceBoost == SHEER_FORCE_BOOST) + return TRUE; } return FALSE; } diff --git a/src/caps.c b/src/caps.c index 9c30e55527..941509c2a4 100644 --- a/src/caps.c +++ b/src/caps.c @@ -54,7 +54,7 @@ u32 GetSoftLevelCapExpValue(u32 level, u32 expValue) if (B_LEVEL_CAP_EXP_UP) { levelDifference = currentLevelCap - level; - if (levelDifference > ARRAY_COUNT(sExpScalingUp)) + if (levelDifference > ARRAY_COUNT(sExpScalingUp) - 1) return expValue + (expValue / sExpScalingUp[ARRAY_COUNT(sExpScalingUp) - 1]); else return expValue + (expValue / sExpScalingUp[levelDifference]); @@ -71,7 +71,7 @@ u32 GetSoftLevelCapExpValue(u32 level, u32 expValue) else if (B_EXP_CAP_TYPE == EXP_CAP_SOFT) { levelDifference = level - currentLevelCap; - if (levelDifference > ARRAY_COUNT(sExpScalingDown)) + if (levelDifference > ARRAY_COUNT(sExpScalingDown) - 1) return expValue / sExpScalingDown[ARRAY_COUNT(sExpScalingDown) - 1]; else return expValue / sExpScalingDown[levelDifference]; diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index ab70de3681..b9fcdd59f6 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1832,12 +1832,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_EERIE_SPELL] = - { - .battleScript = BattleScript_EffectEerieSpell, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_JUNGLE_HEALING] = { .battleScript = BattleScript_EffectJungleHealing, @@ -1901,42 +1895,12 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_GLITZY_GLOW] = - { - .battleScript = BattleScript_EffectGlitzyGlow, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_BADDY_BAD] = - { - .battleScript = BattleScript_EffectBaddyBad, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_SAPPY_SEED] = - { - .battleScript = BattleScript_EffectSappySeed, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_FREEZY_FROST] = - { - .battleScript = BattleScript_EffectFreezyFrost, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_SPARKLY_SWIRL] = { .battleScript = BattleScript_EffectSparklySwirl, .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_PLASMA_FISTS] = - { - .battleScript = BattleScript_EffectPlasmaFists, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_HYPERSPACE_FURY] = { .battleScript = BattleScript_EffectHyperspaceFury, @@ -2134,12 +2098,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_SALT_CURE] = - { - .battleScript = BattleScript_EffectSaltCure, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_CHILLY_RECEPTION] = { .battleScript = BattleScript_EffectChillyReception, diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 1b845368ab..2c28621286 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -16752,7 +16752,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Hits with electrical fists.\n" "Normal moves turn Electric."), - .effect = EFFECT_PLASMA_FISTS, + .effect = EFFECT_HIT, .power = 100, .type = TYPE_ELECTRIC, .accuracy = 100, @@ -16767,6 +16767,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_ION_DELUGE, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_PlasmaFists, }, @@ -16815,6 +16820,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_EVS_PLUS_1, .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), #endif .battleAnimScript = gBattleAnimMove_ZippyZap, @@ -16864,6 +16870,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), .battleAnimScript = gBattleAnimMove_FloatyFall, }, @@ -16931,6 +16938,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), .battleAnimScript = gBattleAnimMove_BuzzyBuzz, }, @@ -16956,6 +16964,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BURN, .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), .battleAnimScript = gBattleAnimMove_SizzlySlide, }, @@ -16966,7 +16975,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Telekinetic force that sets\n" "wall, lowering Sp. Atk damage."), - .effect = EFFECT_GLITZY_GLOW, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 80 : 90, .type = TYPE_PSYCHIC, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 95 : 100, @@ -16976,6 +16985,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_LIGHT_SCREEN, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_GlitzyGlow, }, @@ -16985,7 +16999,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Acting badly, attacks. Sets\n" "wall, lowering Attack damage."), - .effect = EFFECT_BADDY_BAD, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 80 : 90, .type = TYPE_DARK, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 95 : 100, @@ -16995,6 +17009,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_REFLECT, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_BaddyBad, }, @@ -17004,7 +17023,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Giant stalk scatters seeds\n" "that drain HP every turn."), - .effect = EFFECT_SAPPY_SEED, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 100 : 90, .type = TYPE_GRASS, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 90 : 100, @@ -17015,6 +17034,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .magicCoatAffected = TRUE, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_LEECH_SEED, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_SappySeed, }, @@ -17024,7 +17048,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Crystal from cold haze hits.\n" "Eliminates all stat changes."), - .effect = EFFECT_FREEZY_FROST, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 100 : 90, .type = TYPE_ICE, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 90 : 100, @@ -17034,6 +17058,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_HAZE, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_FreezyFrost, }, @@ -17043,7 +17072,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Wrap foe with whirlwind of\n" "scent. Heals party's status."), - .effect = EFFECT_SPARKLY_SWIRL, + .effect = EFFECT_SPARKLY_SWIRL, // Temprorary .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 120 : 90, .type = TYPE_FAIRY, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 85 : 100, @@ -17053,6 +17082,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + // .additionalEffects = ADDITIONAL_EFFECTS({ + // .moveEffect = 0, // MOVE_EFFECT_AROMATHERAPY, Added 0 for Sheer Force boost + // .chance = 100, + // .sheerForceBoost = SHEER_FORCE_NO_BOOST, + // }), .battleAnimScript = gBattleAnimMove_SparklySwirl, }, @@ -18677,7 +18711,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Attacks with psychic power.\n" "Foe's last move has 3 PP cut."), - .effect = EFFECT_EERIE_SPELL, + .effect = EFFECT_HIT, .power = 80, .type = TYPE_PSYCHIC, .accuracy = 100, @@ -18691,6 +18725,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_EERIE_SPELL, + .chance = 100, + }), .battleAnimScript = gBattleAnimMove_EerieSpell, }, @@ -19492,7 +19530,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Hurts foe every turn. Double\n" "damage to Steel and Water."), - .effect = EFFECT_SALT_CURE, + .effect = EFFECT_HIT, .power = 40, .type = TYPE_ROCK, .accuracy = 100, @@ -19501,6 +19539,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_SALT_CURE, + .chance = 100, + }), .battleAnimScript = gBattleAnimMove_SaltCure, }, @@ -20397,7 +20439,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .moveEffect = MOVE_EFFECT_SP_ATK_PLUS_1, .self = TRUE, .onChargeTurnOnly = TRUE, - }, SHEER_FORCE_HACK), + .sheerForceBoost = SHEER_FORCE_BOOST, + }), .battleAnimScript = gBattleAnimMove_ElectroShot, }, @@ -20671,6 +20714,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_TOXIC, .chance = 50, + .sheerForceBoost = SHEER_FORCE_BOOST, }), .battleAnimScript = gBattleAnimMove_MalignantChain, }, diff --git a/src/data/pokemon/species_info/gen_1_families.h b/src/data/pokemon/species_info/gen_1_families.h index ba9f845395..314b5bd73f 100644 --- a/src/data/pokemon/species_info/gen_1_families.h +++ b/src/data/pokemon/species_info/gen_1_families.h @@ -2533,7 +2533,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .frontPicSize = MON_COORDS_SIZE(32, 40), .frontPicYOffset = 13, .frontAnimFrames = sAnims_PichuSpikyEared, - //.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .frontAnimId = ANIM_V_JUMPS_H_JUMPS, .backPic = gMonBackPic_PichuSpikyEared, .backPicSize = MON_COORDS_SIZE(48, 56), .backPicYOffset = 8, @@ -2544,11 +2544,12 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .iconPalIndex = 1, SHADOW(2, 0, SHADOW_SIZE_S) FOOTPRINT(Pichu) - OVERWORLD( + OVERWORLD_SET_ANIM( sPicTable_PichuSpikyEared, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, + sAnimTable_Following_Asym, gOverworldPalette_PichuSpikyEared, gShinyOverworldPalette_PichuSpikyEared ) diff --git a/src/data/pokemon_graphics/front_pic_anims.h b/src/data/pokemon_graphics/front_pic_anims.h index 56ec319a57..adf64468aa 100644 --- a/src/data/pokemon_graphics/front_pic_anims.h +++ b/src/data/pokemon_graphics/front_pic_anims.h @@ -340,7 +340,17 @@ static const union AnimCmd sAnim_Pichu_1[] = ANIMCMD_END, }; -PLACEHOLDER_ANIM_SINGLE_FRAME(PichuSpikyEared); +static const union AnimCmd sAnim_PichuSpikyEared_1[] = +{ + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 1), + ANIMCMD_END, +}; #endif //P_GEN_2_CROSS_EVOS static const union AnimCmd sAnim_Pikachu_1[] = diff --git a/src/daycare.c b/src/daycare.c index 912537af56..4997f4efe9 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -590,27 +590,6 @@ static void UNUSED TriggerPendingDaycareMaleEgg(void) _TriggerPendingDaycareMaleEgg(&gSaveBlock1Ptr->daycare); } -// Removes the selected index from the given IV list and shifts the remaining -// elements to the left. -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) -{ - s32 i, j; - u8 temp[NUM_STATS]; - - ivs[selectedIv] = 0xFF; - for (i = 0; i < NUM_STATS; i++) - { - temp[i] = ivs[i]; - } - - j = 0; - for (i = 0; i < NUM_STATS; i++) - { - if (temp[i] != 0xFF) - ivs[j++] = temp[i]; - } -} - static void InheritIVs(struct Pokemon *egg, struct DayCare *daycare) { u16 motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM); diff --git a/src/field_screen_effect.c b/src/field_screen_effect.c index 073c92f3e0..e07d067afc 100644 --- a/src/field_screen_effect.c +++ b/src/field_screen_effect.c @@ -1374,7 +1374,6 @@ static void Task_RushInjuredPokemonToCenter(u8 taskId) ClearWindowTilemap(windowId); CopyWindowToVram(windowId, COPYWIN_MAP); RemoveWindow(windowId); - FillPalBufferBlack(); FadeInFromBlack(); gTasks[taskId].tState = FRLG_WHITEOUT_HEAL_SCRIPT; break; diff --git a/src/field_specials.c b/src/field_specials.c index 680b527dc7..e04a8011fe 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -2775,10 +2775,12 @@ static void ScrollableMultichoice_UpdateScrollArrows(u8 taskId) struct ScrollArrowsTemplate template = sScrollableMultichoice_ScrollArrowsTemplate; if (task->tMaxItemsOnScreen != task->tNumItems) { + u32 y0 = (8 * (task->tTop - 1)); + template.firstX = (task->tWidth / 2) * 8 + 12 + (task->tLeft - 1) * 8; - template.firstY = 8; + template.firstY = 8 + y0; template.secondX = (task->tWidth / 2) * 8 + 12 + (task->tLeft - 1) * 8; - template.secondY = task->tHeight * 8 + 10; + template.secondY = task->tHeight * 8 + 10 + y0; template.fullyUpThreshold = 0; template.fullyDownThreshold = task->tNumItems - task->tMaxItemsOnScreen; task->tScrollArrowId = AddScrollIndicatorArrowPair(&template, &gScrollableMultichoice_ScrollOffset); diff --git a/src/pokemon.c b/src/pokemon.c index 835c635f96..0771076b2a 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -75,7 +75,6 @@ static void EncryptBoxMon(struct BoxPokemon *boxMon); static void DecryptBoxMon(struct BoxPokemon *boxMon); static void Task_PlayMapChosenOrBattleBGM(u8 taskId); static bool8 ShouldSkipFriendshipChange(void); -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); void TrySpecialOverworldEvo(); EWRAM_DATA static u8 sLearningMoveTableID = 0; @@ -6684,7 +6683,9 @@ u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove) return 0; } -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) +// Removes the selected index from the given IV list and shifts the remaining +// elements to the left. +void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) { s32 i, j; u8 temp[NUM_STATS]; diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index 020094389a..fc248435a9 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -487,12 +487,49 @@ void ScrCmd_createmon(struct ScriptContext *ctx) u8 speedEv = PARSE_FLAG(8, 0); u8 spAtkEv = PARSE_FLAG(9, 0); u8 spDefEv = PARSE_FLAG(10, 0); - u8 hpIv = PARSE_FLAG(11, Random() % (MAX_PER_STAT_IVS + 1)); - u8 atkIv = PARSE_FLAG(12, Random() % (MAX_PER_STAT_IVS + 1)); - u8 defIv = PARSE_FLAG(13, Random() % (MAX_PER_STAT_IVS + 1)); - u8 speedIv = PARSE_FLAG(14, Random() % (MAX_PER_STAT_IVS + 1)); - u8 spAtkIv = PARSE_FLAG(15, Random() % (MAX_PER_STAT_IVS + 1)); - u8 spDefIv = PARSE_FLAG(16, Random() % (MAX_PER_STAT_IVS + 1)); + u8 hpIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 atkIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 defIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 speedIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 spAtkIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 spDefIv = Random() % (MAX_PER_STAT_IVS + 1); + + // Perfect IV calculation + u32 i; + u8 availableIVs[NUM_STATS]; + u8 selectedIvs[NUM_STATS]; + if (gSpeciesInfo[species].perfectIVCount != 0) + { + // Initialize a list of IV indices. + for (i = 0; i < NUM_STATS; i++) + availableIVs[i] = i; + + // Select the IVs that will be perfected. + for (i = 0; i < NUM_STATS && i < gSpeciesInfo[species].perfectIVCount; i++) + { + u8 index = Random() % (NUM_STATS - i); + selectedIvs[i] = availableIVs[index]; + RemoveIVIndexFromList(availableIVs, index); + } + for (i = 0; i < NUM_STATS && i < gSpeciesInfo[species].perfectIVCount; i++) + { + switch (selectedIvs[i]) + { + case STAT_HP: hpIv = MAX_PER_STAT_IVS; break; + case STAT_ATK: atkIv = MAX_PER_STAT_IVS; break; + case STAT_DEF: defIv = MAX_PER_STAT_IVS; break; + case STAT_SPEED: speedIv = MAX_PER_STAT_IVS; break; + case STAT_SPATK: spAtkIv = MAX_PER_STAT_IVS; break; + case STAT_SPDEF: spDefIv = MAX_PER_STAT_IVS; break; + } + } + } + hpIv = PARSE_FLAG(11, hpIv); + atkIv = PARSE_FLAG(12, atkIv); + defIv = PARSE_FLAG(13, defIv); + speedIv = PARSE_FLAG(14, speedIv); + spAtkIv = PARSE_FLAG(15, spAtkIv); + spDefIv = PARSE_FLAG(16, spDefIv); u16 move1 = PARSE_FLAG(17, MOVE_NONE); u16 move2 = PARSE_FLAG(18, MOVE_NONE); u16 move3 = PARSE_FLAG(19, MOVE_NONE); diff --git a/test/battle/ability/disguise.c b/test/battle/ability/disguise.c index 3a8df70be5..9c5f917e9d 100644 --- a/test/battle/ability/disguise.c +++ b/test/battle/ability/disguise.c @@ -173,3 +173,19 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu blocks a move after getting Gastro Acid Ba ABILITY_POPUP(player, ABILITY_DISGUISE); } } + +SINGLE_BATTLE_TEST("Disguise does not break from a teammate's Wish") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_WISH].effect == EFFECT_WISH); + PLAYER(SPECIES_JIRACHI); + PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); HP(219); MaxHP(220); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_WISH); } + TURN { SWITCH(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WISH, player); + NOT ABILITY_POPUP(player, ABILITY_DISGUISE); + } +} diff --git a/test/battle/ability/sheer_force.c b/test/battle/ability/sheer_force.c index 97dee48a31..e06e56c2c5 100644 --- a/test/battle/ability/sheer_force.c +++ b/test/battle/ability/sheer_force.c @@ -7,64 +7,909 @@ ASSUMPTIONS ASSUME(MoveIsAffectedBySheerForce(MOVE_ELECTRO_SHOT) == TRUE); } -SINGLE_BATTLE_TEST("Sheer Force boosts power, but removes secondary effects of moves", s16 damage) +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Magnitude", s16 damage) { - s32 j; - u32 ability = 0, move = 0; - - for (j = 1; j < MOVES_COUNT; j++) - { - if (MoveIsAffectedBySheerForce(j) - //&& gMovesInfo[j].effect != EFFECT_ORDER_UP - && gMovesInfo[j].effect != EFFECT_AURA_WHEEL - && gMovesInfo[j].effect != EFFECT_PLACEHOLDER) - { - PARAMETRIZE { ability = ABILITY_ANGER_POINT; move = j; } - PARAMETRIZE { ability = ABILITY_SHEER_FORCE; move = j; } - } - } - + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { - PLAYER(SPECIES_TAUROS) { Ability(ability); Status1(move == MOVE_SNORE ? STATUS1_SLEEP : STATUS1_NONE); } + PLAYER(SPECIES_TAUROS) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect - TURN { MOVE(opponent, MOVE_AGILITY); MOVE(player, move); } - else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move - TURN { MOVE(opponent, MOVE_QUICK_ATTACK); MOVE(player, move); } - else - TURN { MOVE(player, move); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE) { - TURN { SKIP_TURN(player); } - TURN { ; } - } + TURN { MOVE(player, MOVE_MAGNITUDE); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, move, player); HP_BAR(opponent, captureDamage: &results[i].damage); - if (ability == ABILITY_SHEER_FORCE) { - NONE_OF { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - STATUS_ICON(opponent, STATUS1_FREEZE); - STATUS_ICON(opponent, STATUS1_POISON); - STATUS_ICON(opponent, STATUS1_BURN); - STATUS_ICON(opponent, STATUS1_TOXIC_POISON); - STATUS_ICON(opponent, STATUS1_PARALYSIS); - MESSAGE("Wobbuffet is confused!"); - MESSAGE("Wobbuffet flinched and couldn't move!"); - } - // Volt Tackle/Flare Blitz edge case: recoil happens, but target isn't statused - if (gMovesInfo[move].recoil > 0) - { - HP_BAR(player); - MESSAGE("Tauros was damaged by the recoil!"); - } - } } FINALLY { - s32 j; - for (j = 0; j < gBattleTestRunnerState->parametersCount; j+=2) - { - EXPECT_GT(results[j+1].damage, results[j].damage); - } + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Eruption", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PRESENT); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Water Spout", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PRESENT); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Present", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PRESENT); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Psywave", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PSYWAVE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Round", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ROUND); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Gyro Ball", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GYRO_BALL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Electro Ball", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRO_BALL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Dragon Energy", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DRAGON_ENERGY); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Belch", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); HP(1); Item(ITEM_SITRUS_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Shell Trap", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SHELL_TRAP); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Burn Up", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ZEN_MODE; } + GIVEN { + PLAYER(SPECIES_DARMANITAN) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BURN_UP); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Double Shock", s16 damage) +{ + u16 move = 0; + PARAMETRIZE { move = MOVE_SKILL_SWAP; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_PIKACHU); + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_DOUBLE_SHOCK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Steel Roller", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_GRASSY_TERRAIN); MOVE(player, MOVE_STEEL_ROLLER); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Synchronoise", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); HP(1); Item(ITEM_SITRUS_BERRY); } + OPPONENT(SPECIES_CHANSEY); + } WHEN { + TURN { MOVE(player, MOVE_SYNCHRONOISE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Aura Wheel", s16 damage) +{ + u16 move = 0; + PARAMETRIZE { move = MOVE_SKILL_SWAP; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_MORPEKO); + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_AURA_WHEEL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Hyperspace Fury", s16 damage) +{ + u16 move = 0; + PARAMETRIZE { move = MOVE_SKILL_SWAP; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_HOOPA_UNBOUND); + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_HYPERSPACE_FURY); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Bolt Beak", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BOLT_BEAK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Fishious Rend", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FISHIOUS_REND); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_COMEUPPANCE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PAYBACK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} + +static inline bool32 IgnoreMoveForSheerForceBoost(u32 move) +{ + switch (move) { + case MOVE_PSYWAVE: // Just skip Psywve + case MOVE_PRESENT: // And Present... + case MOVE_MAGNITUDE: // And Magnitude... + case MOVE_ERUPTION: // And Eruption... + case MOVE_WATER_SPOUT: + case MOVE_GYRO_BALL: + case MOVE_SYNCHRONOISE: + case MOVE_ELECTRO_BALL: + case MOVE_ROUND: + case MOVE_BELCH: + case MOVE_HYPERSPACE_FURY: + case MOVE_BURN_UP: + case MOVE_SHELL_TRAP: + case MOVE_BOLT_BEAK: + case MOVE_FISHIOUS_REND: + case MOVE_AURA_WHEEL: + case MOVE_STEEL_ROLLER: + case MOVE_DRAGON_ENERGY: + case MOVE_DOUBLE_SHOCK: + case MOVE_COMEUPPANCE: + case MOVE_UPPER_HAND: // Bugged? + case MOVE_GLITZY_GLOW: // Light Screen Move Effect seems to be bugged + case MOVE_PAYBACK: + return TRUE; + } + return FALSE; +} + +static inline bool32 IsMoveSheerForceBoosted(u32 move) +{ + switch (move) { + case MOVE_AIR_SLASH: + case MOVE_ANCIENT_POWER: + case MOVE_ASTONISH: + case MOVE_BITE: + case MOVE_BLIZZARD: + case MOVE_BODY_SLAM: + case MOVE_BOUNCE: + case MOVE_BREAKING_SWIPE: + case MOVE_BUBBLE: + case MOVE_BUBBLE_BEAM: + case MOVE_BUG_BUZZ: + case MOVE_BULLDOZE: + case MOVE_BURNING_JEALOUSY: + case MOVE_CHARGE_BEAM: + case MOVE_CHILLING_WATER: + case MOVE_CONFUSION: + case MOVE_CRUNCH: + case MOVE_CRUSH_CLAW: + case MOVE_DARK_PULSE: + case MOVE_DRAGON_RUSH: + case MOVE_DRAGON_BREATH: + case MOVE_DYNAMIC_PUNCH: + case MOVE_EARTH_POWER: + case MOVE_EMBER: + case MOVE_ESPER_WING: + case MOVE_EXTRASENSORY: + case MOVE_FAKE_OUT: + case MOVE_FIRE_BLAST: + case MOVE_FIRE_FANG: + case MOVE_FIRE_PUNCH: + case MOVE_FLAME_CHARGE: + case MOVE_FLAME_WHEEL: + case MOVE_FLAMETHROWER: + case MOVE_FLARE_BLITZ: + case MOVE_FLASH_CANNON: + case MOVE_FOCUS_BLAST: + case MOVE_FORCE_PALM: + case MOVE_GUNK_SHOT: + case MOVE_HEADBUTT: + case MOVE_HEAT_WAVE: + case MOVE_HURRICANE: + case MOVE_ICE_BEAM: + case MOVE_ICE_FANG: + case MOVE_ICE_PUNCH: + case MOVE_ICICLE_CRASH: + case MOVE_ICY_WIND: + case MOVE_IRON_HEAD: + case MOVE_IRON_TAIL: + case MOVE_LAVA_PLUME: + case MOVE_LIQUIDATION: + case MOVE_LOW_SWEEP: + case MOVE_METAL_CLAW: + case MOVE_MUD_BOMB: + case MOVE_MUDDY_WATER: + case MOVE_MUD_SHOT: + case MOVE_MUD_SLAP: + case MOVE_MYSTICAL_FIRE: + case MOVE_PLAY_ROUGH: + case MOVE_POISON_FANG: + case MOVE_POISON_JAB: + case MOVE_POISON_STING: + case MOVE_POISON_TAIL: + case MOVE_POUNCE: + case MOVE_POWER_UP_PUNCH: + case MOVE_PSYBEAM: + case MOVE_PSYCHIC: + case MOVE_RAZOR_SHELL: + case MOVE_ROCK_CLIMB: + case MOVE_ROCK_SLIDE: + case MOVE_ROCK_SMASH: + case MOVE_ROCK_TOMB: + case MOVE_SANDSEAR_STORM: + case MOVE_SCALD: + case MOVE_SCORCHING_SANDS: + case MOVE_SECRET_POWER: + case MOVE_SHADOW_BALL: + case MOVE_SIGNAL_BEAM: + case MOVE_SKY_ATTACK: + case MOVE_SLUDGE_BOMB: + case MOVE_SLUDGE_WAVE: + case MOVE_SNARL: + case MOVE_SNORE: + case MOVE_STEEL_WING: + case MOVE_STOMP: + case MOVE_STONE_AXE: + case MOVE_STRUGGLE_BUG: + case MOVE_THROAT_CHOP: + case MOVE_THUNDER: + case MOVE_THUNDER_FANG: + case MOVE_THUNDERBOLT: + case MOVE_THUNDER_PUNCH: + case MOVE_TRAILBLAZE: + case MOVE_TWISTER: + case MOVE_UPPER_HAND: + case MOVE_WATER_PULSE: + case MOVE_WATERFALL: + case MOVE_ZAP_CANNON: + case MOVE_ZEN_HEADBUTT: + case MOVE_ACID: + case MOVE_ACID_SPRAY: + case MOVE_ALLURING_VOICE: + case MOVE_ANCHOR_SHOT: + case MOVE_APPLE_ACID: + case MOVE_AQUA_STEP: + case MOVE_AURA_WHEEL: + case MOVE_AURORA_BEAM: + case MOVE_AXE_KICK: + case MOVE_BARB_BARRAGE: + case MOVE_BITTER_MALICE: + case MOVE_BLAZE_KICK: + case MOVE_BLAZING_TORQUE: + case MOVE_BLEAKWIND_STORM: + case MOVE_BLUE_FLARE: + case MOVE_BOLT_STRIKE: + case MOVE_BONE_CLUB: + case MOVE_CEASELESS_EDGE: + case MOVE_CHATTER: + case MOVE_CLANGOROUS_SOULBLAZE: + case MOVE_COMBAT_TORQUE: + case MOVE_CONSTRICT: + case MOVE_CROSS_POISON: + case MOVE_DIAMOND_STORM: + case MOVE_DIRE_CLAW: + case MOVE_DISCHARGE: + case MOVE_DIZZY_PUNCH: + case MOVE_DOUBLE_IRON_BASH: + case MOVE_DRUM_BEATING: + case MOVE_EERIE_SPELL: + case MOVE_ELECTROWEB: + case MOVE_ENERGY_BALL: + case MOVE_FIERY_DANCE: + case MOVE_FIERY_WRATH: + case MOVE_FREEZING_GLARE: + case MOVE_FIRE_LASH: + case MOVE_FREEZE_DRY: + case MOVE_FREEZE_SHOCK: + case MOVE_GENESIS_SUPERNOVA: + case MOVE_GLACIATE: + case MOVE_GRAV_APPLE: + case MOVE_HEART_STAMP: + case MOVE_HYPER_FANG: + case MOVE_ICE_BURN: + case MOVE_INFERNAL_PARADE: + case MOVE_INFERNO: + case MOVE_LEAF_TORNADO: + case MOVE_LICK: + case MOVE_LUMINA_CRASH: + case MOVE_LUNGE: + case MOVE_LUSTER_PURGE: + case MOVE_MAGICAL_TORQUE: + case MOVE_MALIGNANT_CHAIN: + case MOVE_MATCHA_GOTCHA: + case MOVE_METEOR_MASH: + case MOVE_MIRROR_SHOT: + case MOVE_MIST_BALL: + case MOVE_MOONBLAST: + case MOVE_MORTAL_SPIN: + case MOVE_MOUNTAIN_GALE: + case MOVE_MYSTICAL_POWER: + case MOVE_NEEDLE_ARM: + case MOVE_NIGHT_DAZE: + case MOVE_NOXIOUS_TORQUE: + case MOVE_NUZZLE: + case MOVE_OCTAZOOKA: + case MOVE_OMINOUS_WIND: + case MOVE_ORDER_UP: + case MOVE_POWDER_SNOW: + case MOVE_PSYSHIELD_BASH: + case MOVE_PYRO_BALL: + case MOVE_RAPID_SPIN: + case MOVE_RELIC_SONG: + case MOVE_ROLLING_KICK: + case MOVE_SACRED_FIRE: + case MOVE_SALT_CURE: + case MOVE_SEARING_SHOT: + case MOVE_SEED_FLARE: + case MOVE_SHADOW_BONE: + case MOVE_SHELL_SIDE_ARM: + case MOVE_SILVER_WIND: + case MOVE_SKITTER_SMACK: + case MOVE_SLUDGE: + case MOVE_SMOG: + case MOVE_SPARK: + case MOVE_SPARKLING_ARIA: + case MOVE_SPIRIT_BREAK: + case MOVE_SPIRIT_SHACKLE: + case MOVE_SPLISHY_SPLASH: + case MOVE_SPRINGTIDE_STORM: + case MOVE_STEAM_ERUPTION: + case MOVE_STEAMROLLER: + case MOVE_STOKED_SPARKSURFER: + case MOVE_STRANGE_STEAM: + case MOVE_SYRUP_BOMB: + case MOVE_THUNDER_SHOCK: + case MOVE_THUNDEROUS_KICK: + case MOVE_TORCH_SONG: + case MOVE_TRI_ATTACK: + case MOVE_TRIPLE_ARROWS: + case MOVE_TROP_KICK: + case MOVE_TWINEEDLE: + case MOVE_VOLT_TACKLE: + case MOVE_WICKED_TORQUE: + case MOVE_WILDBOLT_STORM: + case MOVE_ZING_ZAP: + case MOVE_ELECTRO_SHOT: + case MOVE_PSYCHIC_NOISE: + return TRUE; + } + return FALSE; +} + +// Test split into four parts that handles ~1/4 of all moves each +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 1") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 1; j < MOVES_COUNT; j += 4) + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); + } +} +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 2") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 2; j < MOVES_COUNT; j += 4) + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); + } +} +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 3") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 3; j < MOVES_COUNT; j += 4) + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); + } +} +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 4") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 4; j < MOVES_COUNT; j += 4) + { + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); } } diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index 974730f120..dee29a58e0 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -277,5 +277,21 @@ DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is be } } +DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_ALLY_SWITCH].effect == EFFECT_ALLY_SWITCH); + PLAYER(SPECIES_HOOPA); + PLAYER(SPECIES_ZOROARK); + PLAYER(SPECIES_MAMOSWINE); // the third member here is required for zoroark + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); } + } THEN { + EXPECT(&gPlayerParty[2] == gBattleStruct->illusion[0].mon); + } +} + // Triple Battles required to test //TO_DO_BATTLE_TEST("Ally Switch fails if the user is in the middle of the field in a Triple Battle"); diff --git a/test/battle/move_effect/belch.c b/test/battle/move_effect/belch.c index 2a732e0e45..f8e28929f9 100644 --- a/test/battle/move_effect/belch.c +++ b/test/battle/move_effect/belch.c @@ -21,7 +21,7 @@ AI_SINGLE_BATTLE_TEST("AI: Belch has nonzero score after eating a berry") TURN { MOVE(player, MOVE_MUD_SHOT); EXPECT_MOVE(opponent, MOVE_TACKLE); } TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_BELCH);} } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, opponent); } } @@ -53,6 +53,64 @@ SINGLE_BATTLE_TEST("Belch cannot be used if the user has not eaten a berry") } } -TO_DO_BATTLE_TEST("Belch can still be used after switching out"); -TO_DO_BATTLE_TEST("Belch can still be used after fainting"); -TO_DO_BATTLE_TEST("Belch can still be used after restoring the consumed berry"); +SINGLE_BATTLE_TEST("Belch can still be used after switching out") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } + PLAYER(SPECIES_SKWOVET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + TURN { SWITCH(player, 1); } + TURN { SWITCH(player, 0); } + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + SWITCH_OUT_MESSAGE("Greedent"); + SWITCH_OUT_MESSAGE("Skwovet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player); + } +} + +SINGLE_BATTLE_TEST("Belch can still be used after fainting") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(gMovesInfo[MOVE_FISSURE].effect == EFFECT_OHKO); + ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING); + PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } + PLAYER(SPECIES_SKWOVET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); MOVE(opponent, MOVE_FISSURE); SEND_OUT(player, 1); } + TURN { MOVE(player, MOVE_REVIVAL_BLESSING, partyIndex: 0); } + TURN { SWITCH(player, 0); } + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FISSURE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVIVAL_BLESSING, player); + SWITCH_OUT_MESSAGE("Skwovet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player); + } +} + +SINGLE_BATTLE_TEST("Belch can still be used after restoring the consumed berry") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } + PLAYER(SPECIES_SKWOVET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + TURN { MOVE(player, MOVE_RECYCLE); } + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RECYCLE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player); + } +} diff --git a/test/battle/move_effect/salt_cure.c b/test/battle/move_effect/salt_cure.c index 495a7e8c80..afe811da50 100644 --- a/test/battle/move_effect/salt_cure.c +++ b/test/battle/move_effect/salt_cure.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SALT_CURE].effect == EFFECT_SALT_CURE); + ASSUME(MoveHasAdditionalEffect(MOVE_SALT_CURE, MOVE_EFFECT_SALT_CURE) == TRUE); } SINGLE_BATTLE_TEST("Salt Cure inflicts 1/8 of the target's maximum HP as damage per turn") diff --git a/test/battle/move_effect_secondary/haze.c b/test/battle/move_effect_secondary/haze.c new file mode 100644 index 0000000000..c3831f0768 --- /dev/null +++ b/test/battle/move_effect_secondary/haze.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_FREEZY_FROST, MOVE_EFFECT_HAZE) == TRUE); +} + +SINGLE_BATTLE_TEST("Freeze Frost restores stat changes when it was succesful") +{ + bool32 moveSuccess; + PARAMETRIZE { moveSuccess = FALSE; } + PARAMETRIZE { moveSuccess = TRUE; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FREEZY_FROST, hit: moveSuccess); } + } SCENE { + if (moveSuccess == TRUE) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FREEZY_FROST, player); + MESSAGE("All stat changes were eliminated!"); + } else { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FREEZY_FROST, player); + MESSAGE("All stat changes were eliminated!"); + } + } + } +} diff --git a/test/battle/move_effect/plasma_fists.c b/test/battle/move_effect_secondary/ion_deluge.c similarity index 80% rename from test/battle/move_effect/plasma_fists.c rename to test/battle/move_effect_secondary/ion_deluge.c index 93c8869026..efc66903bc 100644 --- a/test/battle/move_effect/plasma_fists.c +++ b/test/battle/move_effect_secondary/ion_deluge.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_PLASMA_FISTS].effect == EFFECT_PLASMA_FISTS); + ASSUME(MoveHasAdditionalEffect(MOVE_PLASMA_FISTS, MOVE_EFFECT_ION_DELUGE) == TRUE); } SINGLE_BATTLE_TEST("Ion Duldge turns normal moves into electric for the remainder of the current turn") @@ -47,6 +47,26 @@ SINGLE_BATTLE_TEST("Plasma Fists turns normal moves into electric for the remain } } +SINGLE_BATTLE_TEST("Plasma Fists does not set up Ion Deluge if it does not connect") +{ + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_PHANPY].types[0] == TYPE_GROUND || gSpeciesInfo[SPECIES_PHANPY].types[1] == TYPE_GROUND); + PLAYER(SPECIES_KRABBY); + OPPONENT(SPECIES_PHANPY); + } WHEN { + TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Krabby used Plasma Fists!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player); + MESSAGE("A deluge of ions showers the battlefield!"); + } + MESSAGE("The opposing Phanpy used Tackle!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + NOT MESSAGE("It's super effective!"); + } +} + SINGLE_BATTLE_TEST("Plasma Fists type-changing effect does not override Pixilate") { GIVEN { diff --git a/test/battle/move_effect_secondary/leech_seed.c b/test/battle/move_effect_secondary/leech_seed.c new file mode 100644 index 0000000000..c5a8db57cc --- /dev/null +++ b/test/battle/move_effect_secondary/leech_seed.c @@ -0,0 +1,37 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_SAPPY_SEED, MOVE_EFFECT_LEECH_SEED) == TRUE); +} + +SINGLE_BATTLE_TEST("Sappy Seed can seed the target") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SAPPY_SEED); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SAPPY_SEED, player); + MESSAGE("The opposing Wobbuffet was seeded!"); + MESSAGE("The opposing Wobbuffet's health is sapped by Leech Seed!"); + } +} + +SINGLE_BATTLE_TEST("Sappy Seed is not going to seed the target if it fails") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SAPPY_SEED, hit: FALSE); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SAPPY_SEED, player); + MESSAGE("The opposing Wobbuffet was seeded!"); + MESSAGE("The opposing Wobbuffet's health is sapped by Leech Seed!"); + } + } +} diff --git a/test/battle/move_effect_secondary/light_screen.c b/test/battle/move_effect_secondary/light_screen.c new file mode 100644 index 0000000000..244e469893 --- /dev/null +++ b/test/battle/move_effect_secondary/light_screen.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_GLITZY_GLOW, MOVE_EFFECT_LIGHT_SCREEN) == TRUE); +} + +SINGLE_BATTLE_TEST("Glitzy Glow sets up Light Screen when it was succesful") +{ + bool32 moveSuccess; + PARAMETRIZE { moveSuccess = FALSE; } + PARAMETRIZE { moveSuccess = TRUE; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GLITZY_GLOW, hit: moveSuccess); } + } SCENE { + if (moveSuccess == TRUE) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLITZY_GLOW, player); + MESSAGE("Light Screen made your team stronger against special moves!"); + } else { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLITZY_GLOW, player); + MESSAGE("Light Screen made your team stronger against special moves!"); + } + } + } +} diff --git a/test/battle/move_effect_secondary/reflect.c b/test/battle/move_effect_secondary/reflect.c new file mode 100644 index 0000000000..6a0dda06d8 --- /dev/null +++ b/test/battle/move_effect_secondary/reflect.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_BADDY_BAD, MOVE_EFFECT_REFLECT) == TRUE); +} + +SINGLE_BATTLE_TEST("Baddy Bad sets up Reflect when it was succesful") +{ + bool32 moveSuccess; + PARAMETRIZE { moveSuccess = FALSE; } + PARAMETRIZE { moveSuccess = TRUE; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BADDY_BAD, hit: moveSuccess); } + } SCENE { + if (moveSuccess == TRUE) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BADDY_BAD, player); + MESSAGE("Reflect made your team stronger against physical moves!"); + } else { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BADDY_BAD, player); + MESSAGE("Reflect made your team stronger against physical moves!"); + } + } + } +} diff --git a/test/pokemon.c b/test/pokemon.c index f5431559ee..00b08ebb79 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -210,6 +210,50 @@ TEST("givemon [simple]") EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); } +TEST("givemon respects perfectIVCount") +{ + ZeroPlayerPartyMons(); + u32 perfectIVs[6] = {0}; + + ASSUME(gSpeciesInfo[SPECIES_MEW].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_CELEBI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_JIRACHI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_MANAPHY].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_VICTINI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_DIANCIE].perfectIVCount == 3); + + RUN_OVERWORLD_SCRIPT( + givemon SPECIES_MEW, 100; + givemon SPECIES_CELEBI, 100; + givemon SPECIES_JIRACHI, 100; + givemon SPECIES_MANAPHY, 100; + givemon SPECIES_VICTINI, 100; + givemon SPECIES_DIANCIE, 100; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_MEW); + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_SPECIES), SPECIES_CELEBI); + EXPECT_EQ(GetMonData(&gPlayerParty[2], MON_DATA_SPECIES), SPECIES_JIRACHI); + EXPECT_EQ(GetMonData(&gPlayerParty[3], MON_DATA_SPECIES), SPECIES_MANAPHY); + EXPECT_EQ(GetMonData(&gPlayerParty[4], MON_DATA_SPECIES), SPECIES_VICTINI); + EXPECT_EQ(GetMonData(&gPlayerParty[5], MON_DATA_SPECIES), SPECIES_DIANCIE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[2], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[3], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[4], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[5], MON_DATA_LEVEL), 100); + for (u32 j = 0; j < 6; j++) + { + for (u32 k = 0; k < NUM_STATS; k++) + { + if (GetMonData(&gPlayerParty[j], MON_DATA_HP_IV + k) == MAX_PER_STAT_IVS) + perfectIVs[j]++; + } + EXPECT_GE(perfectIVs[j], 3); + } +} + TEST("givemon [moves]") { ZeroPlayerPartyMons();