Merge branch '_RHH/master' into _RHH/upcoming

This commit is contained in:
Eduardo Quezada 2024-12-28 15:28:07 -03:00
commit 3bc4126558
46 changed files with 1489 additions and 292 deletions

View File

@ -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

View File

@ -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

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 830 B

After

Width:  |  Height:  |  Size: 757 B

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 B

After

Width:  |  Height:  |  Size: 485 B

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 880 B

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 B

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -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[];

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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];

View File

@ -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,

View File

@ -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,
},

View File

@ -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
)

View File

@ -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[] =

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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")

View File

@ -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!");
}
}
}
}

View File

@ -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 {

View File

@ -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!");
}
}
}

View File

@ -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!");
}
}
}
}

View File

@ -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!");
}
}
}
}

View File

@ -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();