Adds move Spicy Extract (#4211)
* Adds move Spicy Extract * remove uneeded line * anim, new tests, acc change * Clear Amulet, Contrary interaction * ai * correction * simplify script a bit * clean up * Spicy Extract script overhaul * merge rhh/upcoming * alignment * AI changes/additions * add Foul Play check * Remove useless ai checks * remove wrong test * review issues
This commit is contained in:
parent
7d84cd62ef
commit
faf61e62fb
@ -17848,10 +17848,54 @@ ElectroShotUnleash:
|
|||||||
blendoff
|
blendoff
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Move_SPICY_EXTRACT::
|
||||||
|
loadspritegfx ANIM_TAG_SMALL_EMBER
|
||||||
|
loadspritegfx ANIM_TAG_POISON_BUBBLE
|
||||||
|
loadspritegfx ANIM_TAG_SMALL_BUBBLES
|
||||||
|
createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_POISON_BUBBLE, 0, 12, 12, 0x061D @Orange
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
call SludgeBombProjectile
|
||||||
|
createvisualtask AnimTask_ShakeMon2, 5, ANIM_TARGET, 3, 0, 15, 1
|
||||||
|
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 3, 0, 9, RGB_RED
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, 42, 27, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, -27, 44, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, 39, -28, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, -42, -42, 20
|
||||||
|
playsewithpan SE_M_FLAME_WHEEL, SOUND_PAN_TARGET
|
||||||
|
delay 5
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, 0, 40, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, -8, -44, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, -46, -28, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, 46, 9, 20
|
||||||
|
playsewithpan SE_M_FLAME_WHEEL, SOUND_PAN_TARGET
|
||||||
|
delay 5
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, 42, 0, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, -43, -12, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, 16, -46, 20
|
||||||
|
createsprite gSludgeBombHitParticleSpriteTemplate, ANIM_TARGET, 2, -16, 44, 20
|
||||||
|
playsewithpan SE_M_FLAME_WHEEL, SOUND_PAN_TARGET
|
||||||
|
call LetsSnuggleForeverTears
|
||||||
|
delay 0x8
|
||||||
|
call LetsSnuggleForeverTears
|
||||||
|
delay 0x8
|
||||||
|
call LetsSnuggleForeverTears
|
||||||
|
waitsound
|
||||||
|
waitforvisualfinish
|
||||||
|
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 3, 9, 0, RGB_RED
|
||||||
|
waitforvisualfinish
|
||||||
|
end
|
||||||
|
|
||||||
Move_TERA_BLAST::
|
Move_TERA_BLAST::
|
||||||
Move_AXE_KICK::
|
Move_AXE_KICK::
|
||||||
Move_ORDER_UP::
|
Move_ORDER_UP::
|
||||||
Move_SPICY_EXTRACT::
|
|
||||||
Move_SPIN_OUT::
|
Move_SPIN_OUT::
|
||||||
Move_POPULATION_BOMB::
|
Move_POPULATION_BOMB::
|
||||||
Move_GLAIVE_RUSH::
|
Move_GLAIVE_RUSH::
|
||||||
|
|||||||
@ -52,6 +52,43 @@ BattleScript_LowerAtkSpAtkTrySpAtk::
|
|||||||
BattleScript_LowerAtkSpAtkEnd:
|
BattleScript_LowerAtkSpAtkEnd:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
BattleScript_EffectSpicyExtract::
|
||||||
|
attackcanceler
|
||||||
|
jumpifsubstituteblocks BattleScript_ButItFailed
|
||||||
|
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||||
|
jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE BattleScript_SpicyExtract_CheckShouldSkipAttackAnim
|
||||||
|
jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_SpicyExtract_CheckShouldSkipAttackAnim
|
||||||
|
goto BattleScript_ButItFailed
|
||||||
|
BattleScript_SpicyExtract_CheckShouldSkipAttackAnim:
|
||||||
|
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0, BattleScript_SpicyExtract_RaiseAtk
|
||||||
|
attackstring
|
||||||
|
ppreduce
|
||||||
|
bicword gHitMarker, HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT
|
||||||
|
goto BattleScript_SpicyExtract_SkipAttackAnim
|
||||||
|
BattleScript_SpicyExtract_RaiseAtk:
|
||||||
|
attackstring
|
||||||
|
ppreduce
|
||||||
|
attackanimation
|
||||||
|
waitanimation
|
||||||
|
BattleScript_SpicyExtract_SkipAttackAnim:
|
||||||
|
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||||
|
playstatchangeanimation BS_TARGET, BIT_ATK, STAT_CHANGE_BY_TWO
|
||||||
|
setstatchanger STAT_ATK, 2, FALSE
|
||||||
|
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_EffectSpicyExtractDefenseDown
|
||||||
|
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectSpicyExtractDefenseDown
|
||||||
|
printfromtable gStatUpStringIds
|
||||||
|
waitmessage B_WAIT_TIME_LONG
|
||||||
|
BattleScript_EffectSpicyExtractDefenseDown:
|
||||||
|
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||||
|
playstatchangeanimation BS_TARGET, BIT_DEF, STAT_CHANGE_NEGATIVE | STAT_CHANGE_BY_TWO
|
||||||
|
setstatchanger STAT_DEF, 2, TRUE
|
||||||
|
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_EffectSpicyExtract_End
|
||||||
|
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_EffectSpicyExtract_End
|
||||||
|
printfromtable gStatDownStringIds
|
||||||
|
waitmessage B_WAIT_TIME_LONG
|
||||||
|
BattleScript_EffectSpicyExtract_End:
|
||||||
|
goto BattleScript_MoveEnd
|
||||||
|
|
||||||
BattleScript_EffectTidyUp::
|
BattleScript_EffectTidyUp::
|
||||||
attackcanceler
|
attackcanceler
|
||||||
attackstring
|
attackstring
|
||||||
@ -3132,6 +3169,7 @@ BattleScript_EffectStatDown:
|
|||||||
BattleScript_StatDownFromAttackString:
|
BattleScript_StatDownFromAttackString:
|
||||||
attackstring
|
attackstring
|
||||||
ppreduce
|
ppreduce
|
||||||
|
BattleScript_EffectStatDownFromStatBuffChange:
|
||||||
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_StatDownEnd
|
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_StatDownEnd
|
||||||
jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_StatDownDoAnim
|
jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_StatDownDoAnim
|
||||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_StatDownEnd
|
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_StatDownEnd
|
||||||
@ -3142,6 +3180,7 @@ BattleScript_StatDownDoAnim::
|
|||||||
waitanimation
|
waitanimation
|
||||||
setgraphicalstatchangevalues
|
setgraphicalstatchangevalues
|
||||||
playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
|
playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
|
||||||
|
bicword gHitMarker, HITMARKER_DISABLE_ANIMATION
|
||||||
BattleScript_StatDownPrintString::
|
BattleScript_StatDownPrintString::
|
||||||
printfromtable gStatDownStringIds
|
printfromtable gStatDownStringIds
|
||||||
waitmessage B_WAIT_TIME_LONG
|
waitmessage B_WAIT_TIME_LONG
|
||||||
|
|||||||
@ -193,5 +193,6 @@ s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle);
|
|||||||
bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef);
|
bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef);
|
||||||
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
|
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
|
||||||
void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||||
|
bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData);
|
||||||
|
|
||||||
#endif //GUARD_BATTLE_AI_UTIL_H
|
#endif //GUARD_BATTLE_AI_UTIL_H
|
||||||
|
|||||||
@ -179,6 +179,7 @@ extern const u8 BattleScript_FlashFireBoost_PPLoss[];
|
|||||||
extern const u8 BattleScript_FlashFireBoost[];
|
extern const u8 BattleScript_FlashFireBoost[];
|
||||||
extern const u8 BattleScript_AbilityNoStatLoss[];
|
extern const u8 BattleScript_AbilityNoStatLoss[];
|
||||||
extern const u8 BattleScript_ItemNoStatLoss[];
|
extern const u8 BattleScript_ItemNoStatLoss[];
|
||||||
|
extern const u8 BattleScript_ItemNoStatLossSpicyExtract[];
|
||||||
extern const u8 BattleScript_BRNPrevention[];
|
extern const u8 BattleScript_BRNPrevention[];
|
||||||
extern const u8 BattleScript_PRLZPrevention[];
|
extern const u8 BattleScript_PRLZPrevention[];
|
||||||
extern const u8 BattleScript_PSNPrevention[];
|
extern const u8 BattleScript_PSNPrevention[];
|
||||||
@ -836,5 +837,6 @@ extern const u8 BattleScript_EffectFilletAway[];
|
|||||||
extern const u8 BattleScript_EffectShedTail[];
|
extern const u8 BattleScript_EffectShedTail[];
|
||||||
extern const u8 BattleScript_EffectUpperHand[];
|
extern const u8 BattleScript_EffectUpperHand[];
|
||||||
extern const u8 BattleScript_EffectTidyUp[];
|
extern const u8 BattleScript_EffectTidyUp[];
|
||||||
|
extern const u8 BattleScript_EffectSpicyExtract[];
|
||||||
|
|
||||||
#endif // GUARD_BATTLE_SCRIPTS_H
|
#endif // GUARD_BATTLE_SCRIPTS_H
|
||||||
|
|||||||
@ -350,6 +350,7 @@ enum {
|
|||||||
EFFECT_DRAGON_CHEER,
|
EFFECT_DRAGON_CHEER,
|
||||||
EFFECT_LAST_RESPECTS,
|
EFFECT_LAST_RESPECTS,
|
||||||
EFFECT_TIDY_UP,
|
EFFECT_TIDY_UP,
|
||||||
|
EFFECT_SPICY_EXTRACT,
|
||||||
EFFECT_TERA_BLAST,
|
EFFECT_TERA_BLAST,
|
||||||
EFFECT_TERA_STARSTORM,
|
EFFECT_TERA_STARSTORM,
|
||||||
NUM_BATTLE_MOVE_EFFECTS,
|
NUM_BATTLE_MOVE_EFFECTS,
|
||||||
|
|||||||
@ -439,7 +439,7 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3
|
|||||||
weather = AI_GetWeather(aiData);
|
weather = AI_GetWeather(aiData);
|
||||||
|
|
||||||
SetBattlerData(battlerAtk);
|
SetBattlerData(battlerAtk);
|
||||||
|
|
||||||
// Simulate dmg for both ai controlled mons and for player controlled mons.
|
// Simulate dmg for both ai controlled mons and for player controlled mons.
|
||||||
for (battlerDef = 0; battlerDef < battlersCount; battlerDef++)
|
for (battlerDef = 0; battlerDef < battlersCount; battlerDef++)
|
||||||
{
|
{
|
||||||
@ -1367,9 +1367,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||||||
break;
|
break;
|
||||||
case EFFECT_EVASION_DOWN:
|
case EFFECT_EVASION_DOWN:
|
||||||
case EFFECT_EVASION_DOWN_2:
|
case EFFECT_EVASION_DOWN_2:
|
||||||
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_EVASION))
|
|
||||||
ADJUST_SCORE(-10);
|
|
||||||
break;
|
|
||||||
case EFFECT_TICKLE:
|
case EFFECT_TICKLE:
|
||||||
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK))
|
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK))
|
||||||
ADJUST_SCORE(-10);
|
ADJUST_SCORE(-10);
|
||||||
@ -2639,6 +2636,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||||||
&& !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF))
|
&& !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF))
|
||||||
ADJUST_SCORE(-10);
|
ADJUST_SCORE(-10);
|
||||||
break;
|
break;
|
||||||
|
case EFFECT_SPICY_EXTRACT:
|
||||||
|
if (battlerAtk != BATTLE_PARTNER(battlerDef)
|
||||||
|
&& (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)
|
||||||
|
|| aiData->abilities[battlerDef] == ABILITY_CLEAR_BODY
|
||||||
|
|| aiData->abilities[battlerDef] == ABILITY_GOOD_AS_GOLD
|
||||||
|
|| aiData->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET))
|
||||||
|
ADJUST_SCORE(-10);
|
||||||
|
break;
|
||||||
case EFFECT_UPPER_HAND:
|
case EFFECT_UPPER_HAND:
|
||||||
if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move
|
if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move
|
||||||
ADJUST_SCORE(-10);
|
ADJUST_SCORE(-10);
|
||||||
@ -2769,6 +2774,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||||||
|| gMovesInfo[aiData->partnerMove].criticalHitStage > 0
|
|| gMovesInfo[aiData->partnerMove].criticalHitStage > 0
|
||||||
|| HasMoveWithCriticalHitChance(battlerAtkPartner))
|
|| HasMoveWithCriticalHitChance(battlerAtkPartner))
|
||||||
ADJUST_SCORE(GOOD_EFFECT);
|
ADJUST_SCORE(GOOD_EFFECT);
|
||||||
|
break;
|
||||||
} // our effect relative to partner
|
} // our effect relative to partner
|
||||||
|
|
||||||
// consider global move effects
|
// consider global move effects
|
||||||
@ -2922,6 +2928,12 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||||||
{
|
{
|
||||||
switch (effect)
|
switch (effect)
|
||||||
{
|
{
|
||||||
|
case EFFECT_SPICY_EXTRACT:
|
||||||
|
if (AI_ShouldSpicyExtract(battlerAtk, battlerAtkPartner, move, aiData))
|
||||||
|
{
|
||||||
|
RETURN_SCORE_PLUS(GOOD_EFFECT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case EFFECT_PURIFY:
|
case EFFECT_PURIFY:
|
||||||
if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY)
|
if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY)
|
||||||
{
|
{
|
||||||
@ -3383,6 +3395,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || aiData->abilities[battlerAtk] == ABILITY_NO_GUARD)
|
if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || aiData->abilities[battlerAtk] == ABILITY_NO_GUARD)
|
||||||
ADJUST_SCORE(-2);
|
ADJUST_SCORE(-2);
|
||||||
break;
|
break;
|
||||||
|
case EFFECT_SPICY_EXTRACT:
|
||||||
|
// TODO: Make IncreaseStatDownScore function, just like IncreaseStatUpScore
|
||||||
|
break;
|
||||||
case EFFECT_BIDE:
|
case EFFECT_BIDE:
|
||||||
if (aiData->hpPercents[battlerAtk] < 90)
|
if (aiData->hpPercents[battlerAtk] < 90)
|
||||||
ADJUST_SCORE(-2); // Should be either removed or turned into increasing score
|
ADJUST_SCORE(-2); // Should be either removed or turned into increasing score
|
||||||
@ -3404,7 +3419,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||||||
score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle);
|
score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle);
|
||||||
break;
|
break;
|
||||||
case EFFECT_ROAR:
|
case EFFECT_ROAR:
|
||||||
if ((gMovesInfo[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF)
|
if ((gMovesInfo[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF)
|
||||||
|| aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS)
|
|| aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS)
|
||||||
break;
|
break;
|
||||||
else if (IsDynamaxed(battlerDef))
|
else if (IsDynamaxed(battlerDef))
|
||||||
|
|||||||
@ -3819,3 +3819,42 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
|||||||
if (gStatuses3[battlerDef] & STATUS3_LEECHSEED)
|
if (gStatuses3[battlerDef] & STATUS3_LEECHSEED)
|
||||||
ADJUST_SCORE_PTR(-2);
|
ADJUST_SCORE_PTR(-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData)
|
||||||
|
{
|
||||||
|
u32 preventsStatLoss;
|
||||||
|
u32 partnerAbility;
|
||||||
|
u32 partnerHoldEffect = aiData->holdEffects[battlerAtkPartner];
|
||||||
|
|
||||||
|
if (DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
|
||||||
|
partnerAbility = ABILITY_NONE;
|
||||||
|
else
|
||||||
|
partnerAbility = aiData->abilities[battlerAtkPartner];
|
||||||
|
|
||||||
|
if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] == MAX_STAT_STAGE
|
||||||
|
|| partnerAbility == ABILITY_CONTRARY
|
||||||
|
|| partnerAbility == ABILITY_GOOD_AS_GOLD
|
||||||
|
|| HasMoveEffect(BATTLE_OPPOSITE(battlerAtk), EFFECT_FOUL_PLAY)
|
||||||
|
|| HasMoveEffect(BATTLE_OPPOSITE(battlerAtkPartner), EFFECT_FOUL_PLAY))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
preventsStatLoss = (partnerAbility == ABILITY_CLEAR_BODY
|
||||||
|
|| partnerAbility == ABILITY_FULL_METAL_BODY
|
||||||
|
|| partnerAbility == ABILITY_WHITE_SMOKE
|
||||||
|
|| partnerHoldEffect == HOLD_EFFECT_CLEAR_AMULET);
|
||||||
|
|
||||||
|
switch (gMovesInfo[aiData->partnerMove].effect)
|
||||||
|
{
|
||||||
|
case EFFECT_DEFENSE_UP:
|
||||||
|
case EFFECT_DEFENSE_UP_2:
|
||||||
|
case EFFECT_DEFENSE_UP_3:
|
||||||
|
case EFFECT_BULK_UP:
|
||||||
|
case EFFECT_STOCKPILE:
|
||||||
|
if (!preventsStatLoss)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (preventsStatLoss
|
||||||
|
&& AI_STRIKES_FIRST(battlerAtk, battlerAtkPartner, TRUE)
|
||||||
|
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL));
|
||||||
|
}
|
||||||
|
|||||||
@ -11647,17 +11647,18 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BattleScriptPush(BS_ptr);
|
|
||||||
gBattleScripting.battler = battler;
|
gBattleScripting.battler = battler;
|
||||||
if (battlerHoldEffect == HOLD_EFFECT_CLEAR_AMULET)
|
if (battlerHoldEffect == HOLD_EFFECT_CLEAR_AMULET)
|
||||||
{
|
{
|
||||||
gLastUsedItem = gBattleMons[battler].item;
|
gLastUsedItem = gBattleMons[battler].item;
|
||||||
|
BattleScriptPush(BS_ptr);
|
||||||
gBattlescriptCurrInstr = BattleScript_ItemNoStatLoss;
|
gBattlescriptCurrInstr = BattleScript_ItemNoStatLoss;
|
||||||
RecordItemEffectBattle(battler, HOLD_EFFECT_CLEAR_AMULET);
|
RecordItemEffectBattle(battler, HOLD_EFFECT_CLEAR_AMULET);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gBattlerAbility = battler;
|
gBattlerAbility = battler;
|
||||||
|
BattleScriptPush(BS_ptr);
|
||||||
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss;
|
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss;
|
||||||
gLastUsedAbility = battlerAbility;
|
gLastUsedAbility = battlerAbility;
|
||||||
RecordAbilityBattle(battler, gLastUsedAbility);
|
RecordAbilityBattle(battler, gLastUsedAbility);
|
||||||
|
|||||||
@ -2231,6 +2231,13 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
|||||||
.encourageEncore = TRUE,
|
.encourageEncore = TRUE,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[EFFECT_SPICY_EXTRACT] =
|
||||||
|
{
|
||||||
|
.battleScript = BattleScript_EffectSpicyExtract,
|
||||||
|
.battleTvScore = 0, // TODO: Assign points
|
||||||
|
.encourageEncore = TRUE,
|
||||||
|
},
|
||||||
|
|
||||||
[EFFECT_TERA_BLAST] =
|
[EFFECT_TERA_BLAST] =
|
||||||
{
|
{
|
||||||
.battleScript = BattleScript_EffectPhotonGeyser,
|
.battleScript = BattleScript_EffectPhotonGeyser,
|
||||||
|
|||||||
@ -18577,7 +18577,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
|||||||
.description = COMPOUND_STRING(
|
.description = COMPOUND_STRING(
|
||||||
"Sharply ups target's Attack,\n"
|
"Sharply ups target's Attack,\n"
|
||||||
"harshly lowers its Defense."),
|
"harshly lowers its Defense."),
|
||||||
.effect = EFFECT_PLACEHOLDER, // EFFECT_SPICY_EXTRACT
|
.effect = EFFECT_SPICY_EXTRACT,
|
||||||
.power = 0,
|
.power = 0,
|
||||||
.type = TYPE_GRASS,
|
.type = TYPE_GRASS,
|
||||||
.accuracy = 0,
|
.accuracy = 0,
|
||||||
|
|||||||
@ -5689,4 +5689,4 @@ const struct SpeciesInfo gSpeciesInfoGen4[] =
|
|||||||
|
|
||||||
#ifdef __INTELLISENSE__
|
#ifdef __INTELLISENSE__
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
209
test/battle/move_effect/spicy_extract.c
Normal file
209
test/battle/move_effect/spicy_extract.c
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test/battle.h"
|
||||||
|
|
||||||
|
ASSUMPTIONS
|
||||||
|
{
|
||||||
|
ASSUME(gMovesInfo[MOVE_SPICY_EXTRACT].effect == EFFECT_SPICY_EXTRACT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract raises target's Attack by 2 stages and lowers target's Defense by 2 stages")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wobbuffet's Attack sharply rose!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wobbuffet's Defense harshly fell!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract is prevented by target's ability if it's Attack stat is maxed out")
|
||||||
|
{
|
||||||
|
u16 ability;
|
||||||
|
|
||||||
|
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; }
|
||||||
|
PARAMETRIZE { ability = ABILITY_LIGHT_METAL; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_BELDUM) { Ability(ability); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_SWORDS_DANCE); }
|
||||||
|
TURN { MOVE(opponent, MOVE_SWORDS_DANCE); }
|
||||||
|
TURN { MOVE(opponent, MOVE_SWORDS_DANCE); MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Wobbuffet used Spicy Extract!");
|
||||||
|
if (ability == ABILITY_CLEAR_BODY) {
|
||||||
|
ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY);
|
||||||
|
MESSAGE("Foe Beldum's Clear Body prevents stat loss!");
|
||||||
|
NONE_OF {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract Defense loss is prevented by Big Pecks")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Spicy Extract!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Pidgey's Attack sharply rose!");
|
||||||
|
NONE_OF {
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wobbuffet's Defense harshly fell!");
|
||||||
|
}
|
||||||
|
ABILITY_POPUP(opponent, ABILITY_BIG_PECKS);
|
||||||
|
MESSAGE("Foe Pidgey's Big Pecks prevents Defense loss!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract bypasses accuracy checks")
|
||||||
|
{
|
||||||
|
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHTPOWDER); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Spicy Extract!");
|
||||||
|
NOT MESSAGE("Wobbuffet's attack missed!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wobbuffet's Attack sharply rose!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wobbuffet's Defense harshly fell!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract will fail if target is in a semi-invulnerability state")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHTPOWDER); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_DIVE); MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Wobbuffet used Dive!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, opponent);
|
||||||
|
MESSAGE("Wobbuffet used Spicy Extract!");
|
||||||
|
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
MESSAGE("Wobbuffet's attack missed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract stat changes will be inverted by Contrary")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_SNIVY) { Ability(ABILITY_CONTRARY); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Spicy Extract!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Snivy's Attack harshly fell!");
|
||||||
|
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Snivy's Defense sharply rose!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Spicy Extract against Clear Amulet and Contrary raises Defense only")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_SNIVY) { Ability(ABILITY_CONTRARY); Item(ITEM_CLEAR_AMULET); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SPICY_EXTRACT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Spicy Extract!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPICY_EXTRACT, player);
|
||||||
|
NONE_OF {
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Snivy's Attack harshly fell!");
|
||||||
|
}
|
||||||
|
MESSAGE("Foe Snivy's Clear Amulet prevents its stats from being lowered!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Snivy's Defense sharply rose!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AI_DOUBLE_BATTLE_TEST("Spicy Extract user will use it if partner holds Clear Amulet and a physical move")
|
||||||
|
{
|
||||||
|
u32 move;
|
||||||
|
|
||||||
|
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||||
|
PARAMETRIZE { move = MOVE_SWIFT;}
|
||||||
|
|
||||||
|
AI_LOG;
|
||||||
|
GIVEN {
|
||||||
|
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_CLEAR_AMULET); Moves(move); }
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) { Speed(40); Moves(MOVE_TACKLE, MOVE_SPICY_EXTRACT); }
|
||||||
|
} WHEN {
|
||||||
|
TURN {
|
||||||
|
if (move == MOVE_TACKLE)
|
||||||
|
EXPECT_MOVE(opponentRight, MOVE_SPICY_EXTRACT);
|
||||||
|
else
|
||||||
|
EXPECT_MOVE(opponentRight, MOVE_TACKLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AI_DOUBLE_BATTLE_TEST("Spicy Extract user will not choose the move if it does not benefit partner")
|
||||||
|
{
|
||||||
|
u32 species;
|
||||||
|
u32 ability;
|
||||||
|
|
||||||
|
PARAMETRIZE { species = SPECIES_GHOLDENGO; ability = ABILITY_GOOD_AS_GOLD; }
|
||||||
|
PARAMETRIZE { species = SPECIES_SNIVY; ability = ABILITY_CONTRARY; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
|
||||||
|
OPPONENT(species) { Speed(20); Ability(ability); Moves(MOVE_TACKLE); }
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) { Speed(40); Moves(MOVE_TACKLE, MOVE_SPICY_EXTRACT); }
|
||||||
|
} WHEN {
|
||||||
|
TURN {
|
||||||
|
EXPECT_MOVE(opponentRight, MOVE_TACKLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user