Fix White Herb Known Failing tests (#4258)

* Fix White Herb Known Failing tests

* get out agbcc

* remove unneeded white herb test
This commit is contained in:
DizzyEggg 2024-03-29 17:43:05 +01:00 committed by GitHub
parent 8c7ba8a849
commit 46e6324fe2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 229 additions and 200 deletions

View File

@ -1360,6 +1360,11 @@
.byte \battler .byte \battler
.4byte \jumpInstr .4byte \jumpInstr
.endm .endm
.macro itemstatchangeeffects battler:req
callnative BS_RunStatChangeItems
.byte \battler
.endm
.macro allyswitchswapbattlers .macro allyswitchswapbattlers
callnative BS_AllySwitchSwapBattler callnative BS_AllySwitchSwapBattler

View File

@ -7742,11 +7742,12 @@ BattleScript_ActivateWeatherAbilities_Increment:
restoretarget restoretarget
return return
BattleScript_TryAdrenalineOrb: BattleScript_TryIntimidateHoldEffects:
jumpifnoholdeffect BS_TARGET, HOLD_EFFECT_ADRENALINE_ORB, BattleScript_TryAdrenalineOrbRet itemstatchangeeffects BS_TARGET
jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPEED, 12, BattleScript_TryAdrenalineOrbRet jumpifnoholdeffect BS_TARGET, HOLD_EFFECT_ADRENALINE_ORB, BattleScript_TryIntimidateHoldEffectsRet
jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPEED, 12, BattleScript_TryIntimidateHoldEffectsRet
setstatchanger STAT_SPEED, 1, FALSE setstatchanger STAT_SPEED, 1, FALSE
statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | MOVE_EFFECT_CERTAIN | STAT_CHANGE_ALLOW_PTR, BattleScript_TryAdrenalineOrbRet statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | MOVE_EFFECT_CERTAIN | STAT_CHANGE_ALLOW_PTR, BattleScript_TryIntimidateHoldEffectsRet
playanimation BS_TARGET, B_ANIM_HELD_ITEM_EFFECT playanimation BS_TARGET, B_ANIM_HELD_ITEM_EFFECT
setgraphicalstatchangevalues setgraphicalstatchangevalues
playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
@ -7755,7 +7756,7 @@ BattleScript_TryAdrenalineOrb:
printstring STRINGID_USINGITEMSTATOFPKMNROSE printstring STRINGID_USINGITEMSTATOFPKMNROSE
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
removeitem BS_TARGET removeitem BS_TARGET
BattleScript_TryAdrenalineOrbRet: BattleScript_TryIntimidateHoldEffectsRet:
return return
BattleScript_IntimidateActivates:: BattleScript_IntimidateActivates::
@ -7781,7 +7782,7 @@ BattleScript_IntimidateEffect:
BattleScript_IntimidateEffect_WaitString: BattleScript_IntimidateEffect_WaitString:
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
copybyte sBATTLER, gBattlerTarget copybyte sBATTLER, gBattlerTarget
call BattleScript_TryAdrenalineOrb call BattleScript_TryIntimidateHoldEffects
BattleScript_IntimidateLoopIncrement: BattleScript_IntimidateLoopIncrement:
addbyte gBattlerTarget, 1 addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_IntimidateLoop jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_IntimidateLoop
@ -7807,7 +7808,7 @@ BattleScript_IntimidateInReverse:
call BattleScript_AbilityPopUpTarget call BattleScript_AbilityPopUpTarget
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
modifybattlerstatstage BS_TARGET, STAT_ATK, INCREASE, 1, BattleScript_IntimidateLoopIncrement, ANIM_ON modifybattlerstatstage BS_TARGET, STAT_ATK, INCREASE, 1, BattleScript_IntimidateLoopIncrement, ANIM_ON
call BattleScript_TryAdrenalineOrb call BattleScript_TryIntimidateHoldEffects
goto BattleScript_IntimidateLoopIncrement goto BattleScript_IntimidateLoopIncrement
BattleScript_SupersweetSyrupActivates:: BattleScript_SupersweetSyrupActivates::
@ -7834,7 +7835,7 @@ BattleScript_SupersweetSyrupEffect:
BattleScript_SupersweetSyrupEffect_WaitString: BattleScript_SupersweetSyrupEffect_WaitString:
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
copybyte sBATTLER, gBattlerTarget copybyte sBATTLER, gBattlerTarget
call BattleScript_TryAdrenalineOrb call BattleScript_TryIntimidateHoldEffects
BattleScript_SupersweetSyrupLoopIncrement: BattleScript_SupersweetSyrupLoopIncrement:
addbyte gBattlerTarget, 1 addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_SupersweetSyrupLoop jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_SupersweetSyrupLoop

View File

@ -54,6 +54,7 @@
#define ITEMEFFECT_ORBS 6 #define ITEMEFFECT_ORBS 6
#define ITEMEFFECT_LIFEORB_SHELLBELL 7 #define ITEMEFFECT_LIFEORB_SHELLBELL 7
#define ITEMEFFECT_USE_LAST_ITEM 8 // move end effects for just the battler, not whole field #define ITEMEFFECT_USE_LAST_ITEM 8 // move end effects for just the battler, not whole field
#define ITEMEFFECT_STATS_CHANGED 9 // For White Herb and Eject Pack
#define WEATHER_HAS_EFFECT ((!IsAbilityOnField(ABILITY_CLOUD_NINE) && !IsAbilityOnField(ABILITY_AIR_LOCK))) #define WEATHER_HAS_EFFECT ((!IsAbilityOnField(ABILITY_CLOUD_NINE) && !IsAbilityOnField(ABILITY_AIR_LOCK)))

View File

@ -304,9 +304,9 @@
#define MOVEEND_DEFROST 23 #define MOVEEND_DEFROST 23
#define MOVEEND_RECOIL 24 #define MOVEEND_RECOIL 24
#define MOVEEND_MAGICIAN 25 // Occurs after final multi-hit strike, and after other items/abilities would activate #define MOVEEND_MAGICIAN 25 // Occurs after final multi-hit strike, and after other items/abilities would activate
#define MOVEEND_EJECT_BUTTON 26 #define MOVEEND_EJECT_ITEMS 26
#define MOVEEND_RED_CARD 27 #define MOVEEND_WHITE_HERB 27
#define MOVEEND_EJECT_PACK 28 #define MOVEEND_RED_CARD 28
#define MOVEEND_LIFEORB_SHELLBELL 29 // Includes shell bell, throat spray, etc #define MOVEEND_LIFEORB_SHELLBELL 29 // Includes shell bell, throat spray, etc
#define MOVEEND_CHANGED_ITEMS 30 #define MOVEEND_CHANGED_ITEMS 30
#define MOVEEND_PICKPOCKET 31 #define MOVEEND_PICKPOCKET 31

View File

@ -5870,31 +5870,7 @@ static void Cmd_moveend(void)
} }
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_MAGICIAN: case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon.
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MAGICIAN
&& gCurrentMove != MOVE_FLING && gCurrentMove != MOVE_NATURAL_GIFT
&& gBattleMons[gBattlerAttacker].item == ITEM_NONE
&& gBattleMons[gBattlerTarget].item != ITEM_NONE
&& IsBattlerAlive(gBattlerAttacker)
&& TARGET_TURN_DAMAGED
&& CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item)
&& !gSpecialStatuses[gBattlerAttacker].gemBoost // In base game, gems are consumed after magician would activate.
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerTarget)] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])
&& !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& (GetBattlerAbility(gBattlerTarget) != ABILITY_STICKY_HOLD || !IsBattlerAlive(gBattlerTarget)))
{
StealTargetItem(gBattlerAttacker, gBattlerTarget);
gBattleScripting.battler = gBattlerAbility = gBattlerAttacker;
gEffectBattler = gBattlerTarget;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MagicianActivates;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
effect = TRUE;
}
gBattleScripting.moveendState++;
break;
case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokémon.
{ {
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
// Set a flag if move hits either target (for throat spray that can't check damage) // Set a flag if move hits either target (for throat spray that can't check damage)
@ -6014,98 +5990,165 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
} }
case MOVEEND_EJECT_BUTTON: // The order of abilities/items activating after moves hitting multiple targets is
if (gMovesInfo[gCurrentMove].effect != EFFECT_HIT_SWITCH_TARGET // 1. Magician
// 2. The fastest mon gets switched out using Eject Button / Eject Pack
// 3. White Herb activates
// 4. Red Card activates
// 5. Life Orb / Shell Bell
// 6. Pickpocket
case MOVEEND_MAGICIAN:
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MAGICIAN
&& gCurrentMove != MOVE_FLING && gCurrentMove != MOVE_NATURAL_GIFT
&& gBattleMons[gBattlerAttacker].item == ITEM_NONE
&& gBattleMons[gBattlerTarget].item != ITEM_NONE
&& IsBattlerAlive(gBattlerAttacker) && IsBattlerAlive(gBattlerAttacker)
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) && TARGET_TURN_DAMAGED
&& (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER || (gBattleTypeFlags & BATTLE_TYPE_TRAINER))) && CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item)
&& !gSpecialStatuses[gBattlerAttacker].gemBoost // In base game, gems are consumed after magician would activate.
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerTarget)] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])
&& !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& (GetBattlerAbility(gBattlerTarget) != ABILITY_STICKY_HOLD || !IsBattlerAlive(gBattlerTarget)))
{ {
// Since we check if battler was damaged, we don't need to check move result. StealTargetItem(gBattlerAttacker, gBattlerTarget);
// In fact, doing so actually prevents multi-target moves from activating eject button properly gBattleScripting.battler = gBattlerAbility = gBattlerAttacker;
u8 battlers[4] = {0, 1, 2, 3}; gEffectBattler = gBattlerTarget;
SortBattlersBySpeed(battlers, FALSE); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MagicianActivates;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
effect = TRUE;
}
gBattleScripting.moveendState++;
break;
case MOVEEND_EJECT_ITEMS:
{
// Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items.
u32 ejectPackBattlers = 0, ejectButtonBattlers = 0, i;
for (i = 0; i < gBattlersCount; i++) for (i = 0; i < gBattlersCount; i++)
{ {
u8 battler = battlers[i]; u32 holdEffect;
// Attacker is the damage-dealer, battler is mon to be switched out if (i == gBattlerAttacker)
if (IsBattlerAlive(battler) continue;
&& gBattlerAttacker != battler holdEffect = GetBattlerHoldEffect(i, TRUE);
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_BUTTON if (holdEffect == HOLD_EFFECT_EJECT_BUTTON)
&& BATTLER_TURN_DAMAGED(battler) ejectButtonBattlers |= gBitTable[i];
&& CountUsablePartyMons(battler) > 0) // Has mon to switch into else if (holdEffect == HOLD_EFFECT_EJECT_PACK)
ejectPackBattlers |= gBitTable[i];
}
if (ejectButtonBattlers || ejectPackBattlers)
{
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{ {
gBattleScripting.battler = battler; u32 battler = battlers[i];
gLastUsedItem = gBattleMons[battler].item;
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE) if (ejectButtonBattlers & gBitTable[battler])
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection {
BattleScriptPushCursor(); if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) // Apparently Sheer Force blocks Eject Button, but not Eject Pack
gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; continue;
effect = TRUE; // Since we check if battler was damaged, we don't need to check move result.
break; // Only the fastest Eject Button activates // In fact, doing so actually prevents multi-target moves from activating eject button properly
if (!BATTLER_TURN_DAMAGED(battler))
continue;
}
else if (ejectPackBattlers & gBitTable[battler])
{
if (!gProtectStructs[battler].statFell || gProtectStructs[battler].disableEjectPack)
continue;
}
else
{
continue;
}
if (IsBattlerAlive(battler)
&& CountUsablePartyMons(battler) > 0 // Has mon to switch into
// Does not activate if attacker used Parting Shot and can switch out
&& !(gMovesInfo[gCurrentMove].effect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(gBattlerAttacker))
)
{
gBattleScripting.battler = battler;
gLastUsedItem = gBattleMons[battler].item;
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
effect = TRUE;
BattleScriptPushCursor();
if (ejectButtonBattlers & gBitTable[battler])
{
gBattlescriptCurrInstr = BattleScript_EjectButtonActivates;
}
else // Eject Pack
{
gBattlescriptCurrInstr = BattleScript_EjectPackActivates;
// Are these 2 lines below needed?
gProtectStructs[battler].statFell = FALSE;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
}
break; // Only the fastest Eject item activates
}
} }
} }
} }
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_WHITE_HERB:
for (i = 0; i < gBattlersCount; i++)
{
if (IsBattlerAlive(i)
&& ItemBattleEffects(ITEMEFFECT_STATS_CHANGED, i, FALSE))
{
effect = TRUE;
break;
}
}
if (!effect)
gBattleScripting.moveendState++;
break;
case MOVEEND_RED_CARD: case MOVEEND_RED_CARD:
if ((gMovesInfo[gCurrentMove].effect != EFFECT_HIT_SWITCH_TARGET || gBattleStruct->hitSwitchTargetFailed)
&& IsBattlerAlive(gBattlerAttacker)
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_GUARD_DOG)
{ {
// Since we check if battler was damaged, we don't need to check move result. u32 redCardBattlers = 0, i;
// In fact, doing so actually prevents multi-target moves from activating red card properly
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++) for (i = 0; i < gBattlersCount; i++)
{ {
u8 battler = battlers[i]; if (i == gBattlerAttacker)
// Search for fastest hit pokemon with a red card continue;
// Attacker is the one to be switched out, battler is one with red card if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_RED_CARD)
if (battler != gBattlerAttacker redCardBattlers |= gBitTable[i];
&& IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RED_CARD
&& BATTLER_TURN_DAMAGED(battler)
&& CanBattlerSwitch(gBattlerAttacker))
{
gLastUsedItem = gBattleMons[battler].item;
gBattleStruct->savedBattlerTarget = gBattleScripting.battler = battler; // Battler with red card
gEffectBattler = gBattlerAttacker;
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
effect = TRUE;
break; // Only fastest red card activates
}
} }
} if (redCardBattlers
gBattleScripting.moveendState++; && (gMovesInfo[gCurrentMove].effect != EFFECT_HIT_SWITCH_TARGET || gBattleStruct->hitSwitchTargetFailed)
break; && IsBattlerAlive(gBattlerAttacker)
case MOVEEND_EJECT_PACK: && !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
{ && GetBattlerAbility(gBattlerAttacker) != ABILITY_GUARD_DOG)
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{ {
u8 battler = battlers[i]; // Since we check if battler was damaged, we don't need to check move result.
if (IsBattlerAlive(battler) // In fact, doing so actually prevents multi-target moves from activating red card properly
&& gProtectStructs[battler].statFell u8 battlers[4] = {0, 1, 2, 3};
&& gProtectStructs[battler].disableEjectPack == 0 SortBattlersBySpeed(battlers, FALSE);
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_PACK for (i = 0; i < gBattlersCount; i++)
&& !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker)) // Does not activate if attacker used Parting Shot and can switch out
&& CountUsablePartyMons(battler) > 0) // Has mon to switch into
{ {
gProtectStructs[battler].statFell = FALSE; u32 battler = battlers[i];
gBattleScripting.battler = battler; // Search for fastest hit pokemon with a red card
gLastUsedItem = gBattleMons[battler].item; // Attacker is the one to be switched out, battler is one with red card
BattleScriptPushCursor(); if (redCardBattlers & gBitTable[battler]
gBattlescriptCurrInstr = BattleScript_EjectPackActivates; && IsBattlerAlive(battler)
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
effect = TRUE; && BATTLER_TURN_DAMAGED(battler)
break; // Only fastest eject pack activates && CanBattlerSwitch(gBattlerAttacker))
{
gLastUsedItem = gBattleMons[battler].item;
gBattleStruct->savedBattlerTarget = gBattleScripting.battler = battler; // Battler with red card
gEffectBattler = gBattlerAttacker;
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
effect = TRUE;
break; // Only fastest red card activates
}
} }
} }
} }
@ -16708,6 +16751,15 @@ void BS_SetPhotonGeyserCategory(void)
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
} }
void BS_RunStatChangeItems(void)
{
NATIVE_ARGS(u8 battler);
// Change instruction before calling ItemBattleEffects.
gBattlescriptCurrInstr = cmd->nextInstr;
ItemBattleEffects(ITEMEFFECT_STATS_CHANGED, GetBattlerForBattleScript(cmd->battler), FALSE);
}
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount) static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount)
{ {
u32 i; u32 i;

View File

@ -6762,10 +6762,29 @@ static u8 TryConsumeMirrorHerb(u32 battler, bool32 execute)
return effect; return effect;
} }
static u32 RestoreWhiteHerbStats(u32 battler)
{
u32 i, effect = 0;
for (i = 0; i < NUM_BATTLE_STATS; i++)
{
if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE)
{
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
effect = ITEM_STATS_CHANGE;
}
}
if (effect != 0)
{
gBattleScripting.battler = battler;
gPotentialItemEffectBattler = battler;
}
return effect;
}
static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect) static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect)
{ {
u8 effect = 0; u8 effect = 0;
u32 i;
switch (holdEffect) switch (holdEffect)
{ {
@ -6945,24 +6964,6 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect)
effect = ITEM_STATUS_CHANGE; effect = ITEM_STATUS_CHANGE;
} }
break; break;
case HOLD_EFFECT_RESTORE_STATS:
for (i = 0; i < NUM_BATTLE_STATS; i++)
{
if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE)
{
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
effect = ITEM_STATS_CHANGE;
}
}
if (effect != 0)
{
gBattleScripting.battler = battler;
gPotentialItemEffectBattler = battler;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
return effect;
}
break;
case HOLD_EFFECT_CRITICAL_UP: // lansat berry case HOLD_EFFECT_CRITICAL_UP: // lansat berry
if (B_BERRIES_INSTANT >= GEN_4 if (B_BERRIES_INSTANT >= GEN_4
&& !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY)
@ -7032,18 +7033,9 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
} }
break; break;
case HOLD_EFFECT_RESTORE_STATS: case HOLD_EFFECT_RESTORE_STATS:
for (i = 0; i < NUM_BATTLE_STATS; i++) effect = RestoreWhiteHerbStats(battler);
{
if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE)
{
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
effect = ITEM_STATS_CHANGE;
}
}
if (effect != 0) if (effect != 0)
{ {
gBattleScripting.battler = battler;
gPotentialItemEffectBattler = battler;
gBattlerAttacker = battler; gBattlerAttacker = battler;
BattleScriptExecute(BattleScript_WhiteHerbEnd2); BattleScriptExecute(BattleScript_WhiteHerbEnd2);
} }
@ -7314,18 +7306,9 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
effect = ItemRestorePp(battler, gLastUsedItem, TRUE); effect = ItemRestorePp(battler, gLastUsedItem, TRUE);
break; break;
case HOLD_EFFECT_RESTORE_STATS: case HOLD_EFFECT_RESTORE_STATS:
for (i = 0; i < NUM_BATTLE_STATS; i++) effect = RestoreWhiteHerbStats(battler);
{
if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE)
{
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
effect = ITEM_STATS_CHANGE;
}
}
if (effect != 0) if (effect != 0)
{ {
gBattleScripting.battler = battler;
gPotentialItemEffectBattler = battler;
gBattlerAttacker = battler; gBattlerAttacker = battler;
BattleScriptExecute(BattleScript_WhiteHerbEnd2); BattleScriptExecute(BattleScript_WhiteHerbEnd2);
} }
@ -7885,6 +7868,19 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
} }
} }
break; break;
case ITEMEFFECT_STATS_CHANGED:
switch (battlerHoldEffect)
{
case HOLD_EFFECT_RESTORE_STATS:
effect = RestoreWhiteHerbStats(battler);
if (effect != 0)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
}
break;
}
break;
} }
// Berry was successfully used on a Pokemon. // Berry was successfully used on a Pokemon.

View File

@ -55,10 +55,10 @@ DOUBLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimi
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft);
MESSAGE("Foe Wobbuffet's White Herb restored its status!"); MESSAGE("Foe Wobbuffet's White Herb restored its status!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
MESSAGE("Foe Wynaut's White Herb restored its status!"); MESSAGE("Foe Wynaut's White Herb restored its status!");
} THEN { } THEN {
@ -71,7 +71,6 @@ DOUBLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimi
SINGLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimidate while switching in") SINGLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimidate while switching in")
{ {
KNOWN_FAILING;
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); } PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
@ -95,7 +94,6 @@ SINGLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimi
} }
} }
SINGLE_BATTLE_TEST("White Herb restores stats after all hits of a multi hit move happened") SINGLE_BATTLE_TEST("White Herb restores stats after all hits of a multi hit move happened")
{ {
u16 species; u16 species;
@ -104,7 +102,6 @@ SINGLE_BATTLE_TEST("White Herb restores stats after all hits of a multi hit move
PARAMETRIZE { species = SPECIES_SLIGGOO_HISUIAN; ability = ABILITY_GOOEY; } PARAMETRIZE { species = SPECIES_SLIGGOO_HISUIAN; ability = ABILITY_GOOEY; }
PARAMETRIZE { species = SPECIES_DUGTRIO_ALOLAN; ability = ABILITY_TANGLING_HAIR; } PARAMETRIZE { species = SPECIES_DUGTRIO_ALOLAN; ability = ABILITY_TANGLING_HAIR; }
KNOWN_FAILING;
GIVEN { GIVEN {
ASSUME(gMovesInfo[MOVE_DUAL_WINGBEAT].strikeCount == 2); ASSUME(gMovesInfo[MOVE_DUAL_WINGBEAT].strikeCount == 2);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); } PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); }
@ -114,10 +111,11 @@ SINGLE_BATTLE_TEST("White Herb restores stats after all hits of a multi hit move
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DUAL_WINGBEAT, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_DUAL_WINGBEAT, player);
ABILITY_POPUP(opponent, ability); ABILITY_POPUP(opponent, ability);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Speed fell!"); MESSAGE("Wobbuffet's Speed fell!");
ABILITY_POPUP(opponent, ability); ABILITY_POPUP(opponent, ability);
MESSAGE("Wobbuffet's Speed fell!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Speed fell!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet's White Herb restored its status!"); MESSAGE("Wobbuffet's White Herb restored its status!");
} THEN { } THEN {
@ -133,7 +131,6 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if it is knocked off o
PARAMETRIZE { move = MOVE_THIEF; } PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_KNOCK_OFF; } PARAMETRIZE { move = MOVE_KNOCK_OFF; }
KNOWN_FAILING; // Knock off fails, Thief is fine
GIVEN { GIVEN {
ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE); ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE);
ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF); ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF);
@ -143,14 +140,16 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if it is knocked off o
TURN { MOVE(opponent, move); } TURN { MOVE(opponent, move); }
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, opponent); ANIMATION(ANIM_TYPE_MOVE, move, opponent);
if (move == MOVE_THIEF) if (move == MOVE_THIEF) {
MESSAGE("Foe Wobbuffet stole Slugma's White Herb!"); MESSAGE("Foe Wobbuffet stole Slugma's White Herb!");
else }
MESSAGE("Foe Wobbuffet knocked off Slugma's White Herb!");
ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); ABILITY_POPUP(player, ABILITY_WEAK_ARMOR);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Slugma's Weak Armor lowered its Defense!"); MESSAGE("Slugma's Weak Armor lowered its Defense!");
MESSAGE("Slugma's Weak Armor raised its Speed!"); MESSAGE("Slugma's Weak Armor raised its Speed!");
if (move == MOVE_KNOCK_OFF) {
MESSAGE("Foe Wobbuffet knocked off Slugma's White Herb!");
}
NONE_OF { NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet's White Herb restored its status!"); MESSAGE("Wobbuffet's White Herb restored its status!");
@ -163,7 +162,6 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if it is knocked off o
SINGLE_BATTLE_TEST("White Herb wont have time to activate if Magician steals it") SINGLE_BATTLE_TEST("White Herb wont have time to activate if Magician steals it")
{ {
KNOWN_FAILING; // White Herb is activated
GIVEN { GIVEN {
PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); Item(ITEM_WHITE_HERB); } PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_FENNEKIN) { Ability(ABILITY_MAGICIAN); } OPPONENT(SPECIES_FENNEKIN) { Ability(ABILITY_MAGICIAN); }
@ -171,11 +169,12 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if Magician steals it"
TURN { MOVE(opponent, MOVE_TACKLE); } TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
ABILITY_POPUP(player, ABILITY_WEAK_ARMOR);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Slugma's Weak Armor lowered its Defense!");
MESSAGE("Slugma's Weak Armor raised its Speed!");
ABILITY_POPUP(opponent, ABILITY_MAGICIAN); ABILITY_POPUP(opponent, ABILITY_MAGICIAN);
ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); MESSAGE("Foe Fennekin stole Slugma's White Herb!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Slugma's Weak Armor lowered its Defense!");
MESSAGE("Slugma's Weak Armor raised its Speed!");
NONE_OF { NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet's White Herb restored its status!"); MESSAGE("Wobbuffet's White Herb restored its status!");
@ -186,33 +185,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if Magician steals it"
} }
} }
SINGLE_BATTLE_TEST("White Herb wont have time to activate if Pickpocket steals it") SINGLE_BATTLE_TEST("White Herb has correct interactions with Intimidate triggered Defiant and Competitive")
{
KNOWN_FAILING; // White Herb is activated
GIVEN {
ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN));
PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_LEAF_STORM); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_LEAF_STORM, player);
ABILITY_POPUP(player, ABILITY_PICKPOCKET);
ABILITY_POPUP(player, ABILITY_WEAK_ARMOR);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Slugma's Weak Armor lowered its Defense!");
MESSAGE("Slugma's Weak Armor raised its Speed!");
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet's White Herb restored its status!");
}
} THEN {
EXPECT(player->statStages[STAT_DEF] = DEFAULT_STAT_STAGE - 1);
EXPECT(player->statStages[STAT_SPEED] = DEFAULT_STAT_STAGE + 1);
}
}
SINGLE_BATTLE_TEST("White Herb restores stats after Defiant or Competitive were triggered")
{ {
u16 species; u16 species;
u16 ability; u16 ability;
@ -220,7 +193,6 @@ SINGLE_BATTLE_TEST("White Herb restores stats after Defiant or Competitive were
PARAMETRIZE { species = SPECIES_IGGLYBUFF; ability = ABILITY_COMPETITIVE; } PARAMETRIZE { species = SPECIES_IGGLYBUFF; ability = ABILITY_COMPETITIVE; }
PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_DEFIANT; } PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_DEFIANT; }
KNOWN_FAILING;
GIVEN { GIVEN {
PLAYER(species) { Ability(ability); Item(ITEM_WHITE_HERB); } PLAYER(species) { Ability(ability); Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
@ -230,16 +202,18 @@ SINGLE_BATTLE_TEST("White Herb restores stats after Defiant or Competitive were
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
ABILITY_POPUP(player, ability); ABILITY_POPUP(player, ability);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); // Defiant activates first, so White Herb doesn't have a chance to trigger.
MESSAGE("Wobbuffet's White Herb restored its status!"); if (ability == ABILITY_COMPETITIVE) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Igglybuff's White Herb restored its status!");
}
} THEN { } THEN {
EXPECT(player->item == ITEM_NONE); if (ability == ABILITY_COMPETITIVE) {
if (species == SPECIES_IGGLYBUFF) EXPECT(player->item == ITEM_NONE);
{
EXPECT(player->statStages[STAT_ATK] = DEFAULT_STAT_STAGE); EXPECT(player->statStages[STAT_ATK] = DEFAULT_STAT_STAGE);
EXPECT(player->statStages[STAT_SPATK] = DEFAULT_STAT_STAGE + 2); EXPECT(player->statStages[STAT_SPATK] = DEFAULT_STAT_STAGE + 2);
} else {
EXPECT(player->statStages[STAT_ATK] = DEFAULT_STAT_STAGE + 1);
} }
else
EXPECT(player->statStages[STAT_ATK] = DEFAULT_STAT_STAGE + 3);
} }
} }