Merge branch 'RHH/master' into RHH/upcoming

This commit is contained in:
Eduardo Quezada 2023-06-30 16:14:57 -04:00
commit 2c4a9b754d
15 changed files with 591 additions and 82 deletions

View File

@ -4828,8 +4828,6 @@ BattleScript_PartyHealEnd::
BattleScript_EffectTripleKick:: BattleScript_EffectTripleKick::
attackcanceler attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
jumpifmove MOVE_TRIPLE_AXEL BS_TripleAxel jumpifmove MOVE_TRIPLE_AXEL BS_TripleAxel
addbyte sTRIPLE_KICK_POWER, 10 @ triple kick gets +10 power addbyte sTRIPLE_KICK_POWER, 10 @ triple kick gets +10 power
goto BattleScript_HitFromAtkString goto BattleScript_HitFromAtkString
@ -8751,10 +8749,7 @@ BattleScript_IntimidateLoop:
jumpiftargetally BattleScript_IntimidateLoopIncrement jumpiftargetally BattleScript_IntimidateLoopIncrement
jumpifabsent BS_TARGET, BattleScript_IntimidateLoopIncrement jumpifabsent BS_TARGET, BattleScript_IntimidateLoopIncrement
jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_IntimidateLoopIncrement jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_IntimidateLoopIncrement
jumpifholdeffect BS_TARGET, HOLD_EFFECT_CLEAR_AMULET, BattleScript_IntimidatePrevented_Item
jumpifability BS_TARGET, ABILITY_CLEAR_BODY, BattleScript_IntimidatePrevented
jumpifability BS_TARGET, ABILITY_HYPER_CUTTER, BattleScript_IntimidatePrevented jumpifability BS_TARGET, ABILITY_HYPER_CUTTER, BattleScript_IntimidatePrevented
jumpifability BS_TARGET, ABILITY_WHITE_SMOKE, BattleScript_IntimidatePrevented
.if B_UPDATED_INTIMIDATE >= GEN_8 .if B_UPDATED_INTIMIDATE >= GEN_8
jumpifability BS_TARGET, ABILITY_INNER_FOCUS, BattleScript_IntimidatePrevented jumpifability BS_TARGET, ABILITY_INNER_FOCUS, BattleScript_IntimidatePrevented
jumpifability BS_TARGET, ABILITY_SCRAPPY, BattleScript_IntimidatePrevented jumpifability BS_TARGET, ABILITY_SCRAPPY, BattleScript_IntimidatePrevented
@ -8795,7 +8790,6 @@ BattleScript_IntimidateContrary_WontIncrease:
BattleScript_IntimidatePrevented: BattleScript_IntimidatePrevented:
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
pause B_WAIT_TIME_LONG pause B_WAIT_TIME_LONG
BattleScript_IntimidatePrevented_Item:
setbyte gBattleCommunication STAT_ATK setbyte gBattleCommunication STAT_ATK
stattextbuffer BS_TARGET stattextbuffer BS_TARGET
printstring STRINGID_STATWASNOTLOWERED printstring STRINGID_STATWASNOTLOWERED
@ -9123,6 +9117,12 @@ BattleScript_AbilityNoStatLoss::
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
return return
BattleScript_ItemNoStatLoss::
pause B_WAIT_TIME_SHORT
printstring STRINGID_STATWASNOTLOWERED
waitmessage B_WAIT_TIME_LONG
return
BattleScript_BRNPrevention:: BattleScript_BRNPrevention::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
printfromtable gBRNPreventionStringIds printfromtable gBRNPreventionStringIds
@ -9569,6 +9569,7 @@ BattleScript_IgnoresWhileAsleep::
BattleScript_IgnoresAndUsesRandomMove:: BattleScript_IgnoresAndUsesRandomMove::
printstring STRINGID_PKMNIGNOREDORDERS printstring STRINGID_PKMNIGNOREDORDERS
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
setbyte sMOVE_EFFECT, 0
jumptocalledmove FALSE jumptocalledmove FALSE
BattleScript_MoveUsedLoafingAround:: BattleScript_MoveUsedLoafingAround::

View File

@ -168,6 +168,7 @@ extern const u8 BattleScript_MonMadeMoveUseless[];
extern const u8 BattleScript_FlashFireBoost_PPLoss[]; 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_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[];

View File

@ -525,12 +525,13 @@ static void Cmd_createsprite(void)
subpriority = GetSubpriorityForMoveAnim(argVar); subpriority = GetSubpriorityForMoveAnim(argVar);
CreateSpriteAndAnimate( if (CreateSpriteAndAnimate(template,
template,
GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2), GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2),
GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET), GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET),
subpriority); subpriority) != MAX_SPRITES) // Don't increment the task count if the sprite couldn't be created(i.e. there are too many created sprites atm).
gAnimVisualTaskCount++; {
gAnimVisualTaskCount++;
}
} }
static void CreateSpriteOnTargets(const struct SpriteTemplate *template, u8 argVar, u8 battlerArgIndex, u8 argsCount, bool32 overwriteAnimTgt) static void CreateSpriteOnTargets(const struct SpriteTemplate *template, u8 argVar, u8 battlerArgIndex, u8 argsCount, bool32 overwriteAnimTgt)
@ -555,12 +556,13 @@ static void CreateSpriteOnTargets(const struct SpriteTemplate *template, u8 argV
if (overwriteAnimTgt) if (overwriteAnimTgt)
gBattleAnimArgs[battlerArgIndex] = targets[i]; gBattleAnimArgs[battlerArgIndex] = targets[i];
CreateSpriteAndAnimate( if (CreateSpriteAndAnimate(template,
template,
GetBattlerSpriteCoord(targets[i], BATTLER_COORD_X_2), GetBattlerSpriteCoord(targets[i], BATTLER_COORD_X_2),
GetBattlerSpriteCoord(targets[i], BATTLER_COORD_Y_PIC_OFFSET), GetBattlerSpriteCoord(targets[i], BATTLER_COORD_Y_PIC_OFFSET),
subpriority); subpriority) != MAX_SPRITES) // Don't increment the task count if the sprite couldn't be created(i.e. there are too many created sprites atm).
gAnimVisualTaskCount++; {
gAnimVisualTaskCount++;
}
} }
} }

View File

@ -196,8 +196,8 @@ static void SpriteCB_StatusSummaryBalls_OnSwitchout(struct Sprite *);
static void SpriteCb_MegaTrigger(struct Sprite *); static void SpriteCb_MegaTrigger(struct Sprite *);
static void MegaIndicator_SetVisibilities(u32 healthboxId, bool32 invisible); static void MegaIndicator_SetVisibilities(u32 healthboxId, bool32 invisible);
static void MegaIndicator_UpdateLevel(u32 healthboxId, u32 level); static void MegaIndicator_UpdateLevel(u32 healthboxId, u32 level);
static void MegaIndicator_CreateSprites(u32 battlerId, u32 healthboxSpriteId); static void MegaIndicator_CreateSprite(u32 battlerId, u32 healthboxSpriteId);
static void MegaIndicator_UpdateOamPriorities(u32 healthboxId, u32 oamPriority); static void MegaIndicator_UpdateOamPriority(u32 healthboxId, u32 oamPriority);
static void SpriteCb_MegaIndicator(struct Sprite *); static void SpriteCb_MegaIndicator(struct Sprite *);
static u8 GetStatusIconForBattlerId(u8, u8); static u8 GetStatusIconForBattlerId(u8, u8);
@ -683,7 +683,7 @@ static const struct SpriteTemplate sSpriteTemplate_MegaTrigger =
// data fields for healthboxMain // data fields for healthboxMain
// oam.affineParam holds healthboxRight spriteId // oam.affineParam holds healthboxRight spriteId
#define hMain_MegaIndicatorIds data[3] // Mega, Alpha, Omega as u8 in data[3], data[3] + 1, data[4] #define hMain_MegaIndicatorId data[3]
#define hMain_HealthBarSpriteId data[5] #define hMain_HealthBarSpriteId data[5]
#define hMain_Battler data[6] #define hMain_Battler data[6]
#define hMain_Data7 data[7] #define hMain_Data7 data[7]
@ -798,8 +798,8 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId)
healthBarSpritePtr->hBar_Data6 = data6; healthBarSpritePtr->hBar_Data6 = data6;
healthBarSpritePtr->invisible = TRUE; healthBarSpritePtr->invisible = TRUE;
// Create mega indicator sprites. // Create mega indicator sprite.
MegaIndicator_CreateSprites(battlerId, healthboxLeftSpriteId); MegaIndicator_CreateSprite(battlerId, healthboxLeftSpriteId);
gBattleStruct->ballSpriteIds[0] = MAX_SPRITES; gBattleStruct->ballSpriteIds[0] = MAX_SPRITES;
gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; gBattleStruct->ballSpriteIds[1] = MAX_SPRITES;
@ -934,7 +934,7 @@ void UpdateOamPriorityInAllHealthboxes(u8 priority, bool32 hideHPBoxes)
gSprites[healthboxRightSpriteId].oam.priority = priority; gSprites[healthboxRightSpriteId].oam.priority = priority;
gSprites[healthbarSpriteId].oam.priority = priority; gSprites[healthbarSpriteId].oam.priority = priority;
MegaIndicator_UpdateOamPriorities(healthboxLeftSpriteId, priority); MegaIndicator_UpdateOamPriority(healthboxLeftSpriteId, priority);
#if B_HIDE_HEALTHBOX_IN_ANIMS #if B_HIDE_HEALTHBOX_IN_ANIMS
if (hideHPBoxes && IsBattlerAlive(i)) if (hideHPBoxes && IsBattlerAlive(i))
@ -1509,77 +1509,72 @@ void MegaIndicator_LoadSpritesGfx(void)
LoadSpritePalettes(sMegaIndicator_SpritePalettes); LoadSpritePalettes(sMegaIndicator_SpritePalettes);
} }
static bool32 MegaIndicator_ShouldBeInvisible(u32 battlerId, u32 indicatorType) static bool32 MegaIndicator_ShouldBeInvisible(u32 battlerId, struct Sprite *sprite)
{ {
u32 side = GetBattlerSide(battlerId); u32 side = GetBattlerSide(battlerId);
if (indicatorType == INDICATOR_MEGA) bool32 megaEvolved = IsBattlerMegaEvolved(battlerId);
{ bool32 primalReverted = IsBattlerPrimalReverted(battlerId);
if (IsBattlerMegaEvolved(battlerId))
return FALSE; if (!megaEvolved && !primalReverted)
} return TRUE;
else
{ if (megaEvolved)
if (indicatorType == INDICATOR_ALPHA && gBattleMons[battlerId].species != SPECIES_KYOGRE_PRIMAL) sprite->tType = INDICATOR_MEGA;
return TRUE; else if (primalReverted && gBattleMons[battlerId].species == SPECIES_KYOGRE_PRIMAL)
else if (indicatorType == INDICATOR_OMEGA && gBattleMons[battlerId].species != SPECIES_GROUDON_PRIMAL) sprite->tType = INDICATOR_ALPHA;
return TRUE; else if (primalReverted && gBattleMons[battlerId].species == SPECIES_GROUDON_PRIMAL)
if (IsBattlerPrimalReverted(battlerId)) sprite->tType = INDICATOR_OMEGA;
return FALSE;
} sprite->oam.tileNum = GetSpriteTileStartByTag(sMegaIndicatorTags[sprite->tType][0]);
return TRUE; sprite->oam.paletteNum = IndexOfSpritePaletteTag(sMegaIndicatorTags[sprite->tType][1]);
return FALSE;
} }
static u8 *MegaIndicator_GetSpriteIds(u32 healthboxSpriteId) static u8 *MegaIndicator_GetSpriteId(u32 healthboxSpriteId)
{ {
u8 *spriteIds = (u8 *)(&gSprites[healthboxSpriteId].hMain_MegaIndicatorIds); u8 *spriteId = (u8 *)(&gSprites[healthboxSpriteId].hMain_MegaIndicatorId);
return spriteIds; return spriteId;
} }
void MegaIndicator_SetVisibilities(u32 healthboxId, bool32 invisible) void MegaIndicator_SetVisibilities(u32 healthboxId, bool32 invisible)
{ {
u32 i; u8 *spriteId = MegaIndicator_GetSpriteId(healthboxId);
u8 *spriteIds = MegaIndicator_GetSpriteIds(healthboxId);
u32 battlerId = gSprites[healthboxId].hMain_Battler; u32 battlerId = gSprites[healthboxId].hMain_Battler;
if (GetSafariZoneFlag()) if (GetSafariZoneFlag())
return; return;
for (i = 0; i < INDICATOR_COUNT; i++) if (invisible == TRUE)
{ gSprites[*spriteId].invisible = TRUE;
if (invisible == TRUE) else // Try visible.
gSprites[spriteIds[i]].invisible = TRUE; gSprites[*spriteId].invisible = MegaIndicator_ShouldBeInvisible(battlerId, &gSprites[*spriteId]);
else // Try visible.
gSprites[spriteIds[i]].invisible = MegaIndicator_ShouldBeInvisible(battlerId, i);
}
} }
static void MegaIndicator_UpdateOamPriorities(u32 healthboxId, u32 oamPriority) static void MegaIndicator_UpdateOamPriority(u32 healthboxId, u32 oamPriority)
{ {
u32 i; u8 *spriteId = MegaIndicator_GetSpriteId(healthboxId);
u8 *spriteIds = MegaIndicator_GetSpriteIds(healthboxId); gSprites[*spriteId].oam.priority = oamPriority;
for (i = 0; i < INDICATOR_COUNT; i++)
gSprites[spriteIds[i]].oam.priority = oamPriority;
} }
static void MegaIndicator_UpdateLevel(u32 healthboxId, u32 level) static void MegaIndicator_UpdateLevel(u32 healthboxId, u32 level)
{ {
u32 i; u32 i;
s16 xDelta = 0; s16 xDelta = 0;
u8 *spriteIds = MegaIndicator_GetSpriteIds(healthboxId); u8 *spriteId = MegaIndicator_GetSpriteId(healthboxId);
if (level >= 100) if (level >= 100)
xDelta -= 4; xDelta -= 4;
else if (level < 10) else if (level < 10)
xDelta += 5; xDelta += 5;
for (i = 0; i < INDICATOR_COUNT; i++) gSprites[*spriteId].tLevelXDelta = xDelta;
gSprites[spriteIds[i]].tLevelXDelta = xDelta;
} }
static void MegaIndicator_CreateSprites(u32 battlerId, u32 healthboxSpriteId) static void MegaIndicator_CreateSprite(u32 battlerId, u32 healthboxSpriteId)
{ {
u32 position, i, level; struct SpriteTemplate sprTemplate;
u8 *spriteIds; u32 position, level;
u8 *spriteId;
s16 xHealthbox = 0, y = 0; s16 xHealthbox = 0, y = 0;
s32 x = 0; s32 x = 0;
@ -1589,18 +1584,15 @@ static void MegaIndicator_CreateSprites(u32 battlerId, u32 healthboxSpriteId)
x = sIndicatorPositions[position][0]; x = sIndicatorPositions[position][0];
y += sIndicatorPositions[position][1]; y += sIndicatorPositions[position][1];
spriteIds = MegaIndicator_GetSpriteIds(healthboxSpriteId); spriteId = MegaIndicator_GetSpriteId(healthboxSpriteId);
for (i = 0; i < INDICATOR_COUNT; i++) sprTemplate = sSpriteTemplate_MegaIndicator;
{ sprTemplate.tileTag = sMegaIndicatorTags[INDICATOR_MEGA][0];
struct SpriteTemplate sprTemplate = sSpriteTemplate_MegaIndicator; sprTemplate.paletteTag = sMegaIndicatorTags[INDICATOR_MEGA][1];
sprTemplate.tileTag = sMegaIndicatorTags[i][0]; *spriteId = CreateSpriteAtEnd(&sprTemplate, 0, y, 0);
sprTemplate.paletteTag = sMegaIndicatorTags[i][1]; gSprites[*spriteId].tType = INDICATOR_MEGA;
spriteIds[i] = CreateSpriteAtEnd(&sprTemplate, 0, y, 0); gSprites[*spriteId].tBattler = battlerId;
gSprites[spriteIds[i]].tType = i; gSprites[*spriteId].tPosX = x;
gSprites[spriteIds[i]].tBattler = battlerId; gSprites[*spriteId].invisible = TRUE;
gSprites[spriteIds[i]].tPosX = x;
gSprites[spriteIds[i]].invisible = TRUE;
}
} }
static void SpriteCb_MegaIndicator(struct Sprite *sprite) static void SpriteCb_MegaIndicator(struct Sprite *sprite)

View File

@ -11955,10 +11955,17 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
{ {
BattleScriptPush(BS_ptr); BattleScriptPush(BS_ptr);
gBattleScripting.battler = gActiveBattler; gBattleScripting.battler = gActiveBattler;
gBattlerAbility = gActiveBattler; if (GetBattlerHoldEffect(gActiveBattler, TRUE) == HOLD_EFFECT_CLEAR_AMULET)
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss; {
gLastUsedAbility = activeBattlerAbility; gBattlescriptCurrInstr = BattleScript_ItemNoStatLoss;
RecordAbilityBattle(gActiveBattler, gLastUsedAbility); }
else
{
gBattlerAbility = gActiveBattler;
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss;
gLastUsedAbility = activeBattlerAbility;
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
}
gSpecialStatuses[gActiveBattler].statLowered = TRUE; gSpecialStatuses[gActiveBattler].statLowered = TRUE;
} }
} }

View File

@ -750,6 +750,7 @@ static void DebugAction_DestroyExtraWindow(u8 taskId)
ClearStdWindowAndFrame(gTasks[taskId].data[2], TRUE); ClearStdWindowAndFrame(gTasks[taskId].data[2], TRUE);
RemoveWindow(gTasks[taskId].data[2]); RemoveWindow(gTasks[taskId].data[2]);
DestroyListMenuTask(gTasks[taskId].data[0], NULL, NULL);
DestroyTask(taskId); DestroyTask(taskId);
ScriptContext_Enable(); ScriptContext_Enable();
UnfreezeObjectEvents(); UnfreezeObjectEvents();

38
test/ability_clear_body.c Normal file
View File

@ -0,0 +1,38 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Clear Body prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY);
MESSAGE("Foe Beldum's Clear Body prevents stat loss!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
TO_DO_BATTLE_TEST("Clear Body prevents stat stage reduction from moves"); // Growl, Leer, Confide, Fake Tears, Scary Face, Sweet Scent, Sand Attack (Attack, Defense, Sp. Attack, Sp. Defense, Speed, Evasion, Accuracy
TO_DO_BATTLE_TEST("Clear Body prevents Sticky Web");
TO_DO_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves used by the user"); // e.g. Superpower
TO_DO_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball");
TO_DO_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis");
TO_DO_BATTLE_TEST("Clear Body doesn't prevent Attack reduction from burn");
TO_DO_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes from Baton Pass");
TO_DO_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy");
TO_DO_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting positive stat changes");
TO_DO_BATTLE_TEST("Clear Body is ignored by Mold Breaker");

View File

@ -0,0 +1,38 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Full Metal Body prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_SOLGALEO) { Ability(ABILITY_FULL_METAL_BODY); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_FULL_METAL_BODY);
MESSAGE("Foe Solgaleo's Full Metal Body prevents stat loss!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
TO_DO_BATTLE_TEST("Full Metal Body prevents stat stage reduction from moves"); // Growl, Leer, Confide, Fake Tears, Scary Face, Sweet Scent, Sand Attack (Attack, Defense, Sp. Attack, Sp. Defense, Speed, Evasion, Accuracy
TO_DO_BATTLE_TEST("Full Metal Body prevents Sticky Web");
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent stat stage reduction from moves used by the user"); // e.g. Superpower
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent Speed reduction from Iron Ball");
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent Speed reduction from paralysis");
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent Attack reduction from burn");
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent receiving negative stat changes from Baton Pass");
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent Topsy-Turvy");
TO_DO_BATTLE_TEST("Full Metal Body doesn't prevent Spectral Thief from resetting positive stat changes");
TO_DO_BATTLE_TEST("Full Metal Body is ignored by Mold Breaker");

View File

@ -0,0 +1,35 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Hyper Cutter prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_HYPER_CUTTER);
MESSAGE("Foe Krabby's Attack was not lowered!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
TO_DO_BATTLE_TEST("Hyper Cutter prevents Attack stage reduction from moves"); // Growl
TO_DO_BATTLE_TEST("Hyper Cutter doesn't prevent Attack stage reduction from moves used by the user"); // e.g. Superpower
TO_DO_BATTLE_TEST("Hyper Cutter doesn't prevent Attack reduction from burn");
TO_DO_BATTLE_TEST("Hyper Cutter doesn't prevent receiving negative Attack stage changes from Baton Pass");
TO_DO_BATTLE_TEST("Hyper Cutter doesn't prevent Topsy-Turvy");
TO_DO_BATTLE_TEST("Hyper Cutter doesn't prevent Spectral Thief from resetting positive Attack stage changes");
TO_DO_BATTLE_TEST("Hyper Cutter is ignored by Mold Breaker");

View File

@ -0,0 +1,57 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Inner Focus prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
ASSUME(B_UPDATED_INTIMIDATE >= GEN_8);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_ZUBAT) { Ability(ABILITY_INNER_FOCUS); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_INNER_FOCUS);
MESSAGE("Foe Zubat's Attack was not lowered!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
SINGLE_BATTLE_TEST("Inner Focus prevents flinching")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ZUBAT) { Ability(ABILITY_INNER_FOCUS); };
} WHEN {
TURN { MOVE(player, MOVE_FAKE_OUT);
MOVE(opponent, MOVE_TACKLE);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, player);
NONE_OF { MESSAGE("Foe Zubat flinched!"); }
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
}
}
SINGLE_BATTLE_TEST("Inner Focus is ignored by Mold Breaker")
{
GIVEN {
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); };
OPPONENT(SPECIES_ZUBAT) { Ability(ABILITY_INNER_FOCUS); };
} WHEN {
TURN { MOVE(player, MOVE_FAKE_OUT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, player);
MESSAGE("Foe Zubat flinched!");
}
}

119
test/ability_own_tempo.c Normal file
View File

@ -0,0 +1,119 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Own Tempo prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
ASSUME(B_UPDATED_INTIMIDATE >= GEN_8);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
MESSAGE("Foe Slowpoke's Attack was not lowered!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the opponent")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
} WHEN {
TURN { MOVE(player, MOVE_CONFUSE_RAY); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
MESSAGE("Foe Slowpoke's Own Tempo prevents confusion!");
}
}
SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_PETAL_DANCE].effect == EFFECT_RAMPAGE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
} WHEN {
TURN { MOVE(opponent, MOVE_PETAL_DANCE); }
TURN { MOVE(opponent, MOVE_PETAL_DANCE); }
TURN { MOVE(opponent, MOVE_PETAL_DANCE); }
TURN { MOVE(opponent, MOVE_PETAL_DANCE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, opponent);
NONE_OF { MESSAGE("Foe Slowpoke became confused due to fatigue!"); }
}
}
SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mold Breaker")
{
KNOWN_FAILING;
GIVEN {
ASSUME(gBattleMoves[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE);
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); };
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
} WHEN {
TURN { MOVE(player, MOVE_CONFUSE_RAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player);
MESSAGE("Foe Slowpoke became confused!");
NONE_OF {
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, opponent);
}
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
MESSAGE("Foe Slowpoke's Own Tempo cured its confusion problem!");
}
}
SINGLE_BATTLE_TEST("Own Tempo cures confusion if it's obtained via Skill Swap")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE);
ASSUME(gBattleMoves[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP);
PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CONFUSE_RAY); }
TURN { MOVE(player, MOVE_SKILL_SWAP);
MOVE(opponent, MOVE_TACKLE);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player);
MESSAGE("Foe Wobbuffet became confused!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, player);
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
MESSAGE("Foe Wobbuffet's Own Tempo cured its confusion problem!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
}
}
SINGLE_BATTLE_TEST("Own Tempo prevents confusion from items")
{
GIVEN {
ASSUME(gItems[ITEM_BERSERK_GENE].holdEffect == HOLD_EFFECT_BERSERK_GENE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); Item(ITEM_BERSERK_GENE); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
}
}

View File

@ -33,18 +33,20 @@ DOUBLE_BATTLE_TEST("Pastel Veil prevents Poison Sting poison on partner")
SINGLE_BATTLE_TEST("Pastel Veil immediately cures Mold Breaker poison") SINGLE_BATTLE_TEST("Pastel Veil immediately cures Mold Breaker poison")
{ {
KNOWN_FAILING;
GIVEN { GIVEN {
ASSUME(gBattleMoves[MOVE_TOXIC].effect == EFFECT_TOXIC); ASSUME(gBattleMoves[MOVE_TOXIC].effect == EFFECT_TOXIC);
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }
OPPONENT(SPECIES_PONYTA_GALARIAN) { Ability(ABILITY_PASTEL_VEIL); } OPPONENT(SPECIES_PONYTA_GALARIAN) { Ability(ABILITY_PASTEL_VEIL); }
} WHEN { } WHEN {
TURN { MOVE(player, MOVE_TOXIC); } TURN { MOVE(player, MOVE_TOXIC); MOVE(opponent, MOVE_TACKLE); }
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
STATUS_ICON(opponent, badPoison: TRUE); STATUS_ICON(opponent, badPoison: TRUE);
ABILITY_POPUP(opponent, ABILITY_PASTEL_VEIL); ABILITY_POPUP(opponent, ABILITY_PASTEL_VEIL);
MESSAGE("Foe Ponyta's Pastel Veil cured its poison problem!"); MESSAGE("Foe Ponyta's Pastel Veil cured its poison problem!");
STATUS_ICON(opponent, none: TRUE); STATUS_ICON(opponent, none: TRUE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
} }
} }

66
test/ability_scrappy.c Normal file
View File

@ -0,0 +1,66 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Scrappy prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
ASSUME(B_UPDATED_INTIMIDATE >= GEN_8);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_SCRAPPY);
MESSAGE("Foe Kangaskhan's Attack was not lowered!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
SINGLE_BATTLE_TEST("Scrappy allows to hit Ghost-type Pokémon with Normal- and Fighting-type moves")
{
u32 move;
PARAMETRIZE { move = MOVE_TACKLE; }
PARAMETRIZE { move = MOVE_KARATE_CHOP; }
GIVEN {
PLAYER(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); };
OPPONENT(SPECIES_GASTLY);
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
}
}
SINGLE_BATTLE_TEST("Scrappy doesn't bypass a Ghost-type's Wonder Guard")
{
u32 move;
PARAMETRIZE { move = MOVE_TACKLE; }
PARAMETRIZE { move = MOVE_KARATE_CHOP; }
GIVEN {
PLAYER(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); };
OPPONENT(SPECIES_SHEDINJA) { Ability(ABILITY_WONDER_GUARD); };
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
}
ABILITY_POPUP(opponent, ABILITY_WONDER_GUARD);
MESSAGE("Foe Shedinja avoided damage with Wonder Guard!");
}
}

View File

@ -0,0 +1,39 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("White Smoke prevents intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_TORKOAL) { Ability(ABILITY_WHITE_SMOKE); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
ABILITY_POPUP(opponent, ABILITY_WHITE_SMOKE);
MESSAGE("Foe Torkoal's White Smoke prevents stat loss!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
TO_DO_BATTLE_TEST("White Smoke prevents stat stage reduction from moves"); // Growl, Leer, Confide, Fake Tears, Scary Face, Sweet Scent, Sand Attack (Attack, Defense, Sp. Attack, Sp. Defense, Speed, Evasion, Accuracy
TO_DO_BATTLE_TEST("White Smoke prevents Sticky Web");
TO_DO_BATTLE_TEST("White Smoke doesn't prevent stat stage reduction from moves used by the user"); // e.g. Superpower
TO_DO_BATTLE_TEST("White Smoke doesn't prevent Speed reduction from Iron Ball");
TO_DO_BATTLE_TEST("White Smoke doesn't prevent Speed reduction from paralysis");
TO_DO_BATTLE_TEST("White Smoke doesn't prevent Attack reduction from burn");
TO_DO_BATTLE_TEST("White Smoke doesn't prevent receiving negative stat changes from Baton Pass");
TO_DO_BATTLE_TEST("White Smoke doesn't prevent Topsy-Turvy");
TO_DO_BATTLE_TEST("White Smoke doesn't prevent Spectral Thief from resetting positive stat changes");
TO_DO_BATTLE_TEST("White Smoke is ignored by Mold Breaker");

View File

@ -0,0 +1,111 @@
#include "global.h"
#include "test_battle.h"
ASSUMPTIONS
{
ASSUME(gItems[ITEM_CLEAR_AMULET].holdEffect == HOLD_EFFECT_CLEAR_AMULET);
}
SINGLE_BATTLE_TEST("Clear Amulet prevents Intimidate")
{
s16 turnOneHit;
s16 turnTwoHit;
GIVEN {
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); };
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); };
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); };
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
HP_BAR(player, captureDamage: &turnOneHit);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); }
MESSAGE("Foe Wobbuffet's Attack was not lowered!");
HP_BAR(player, captureDamage: &turnTwoHit);
} THEN {
EXPECT_EQ(turnOneHit, turnTwoHit);
}
}
SINGLE_BATTLE_TEST("Clear Amulet prevents stat reducing effects")
{
u32 move;
PARAMETRIZE { move = MOVE_GROWL; }
PARAMETRIZE { move = MOVE_LEER; }
PARAMETRIZE { move = MOVE_CONFIDE; }
PARAMETRIZE { move = MOVE_FAKE_TEARS; }
PARAMETRIZE { move = MOVE_SCARY_FACE; }
PARAMETRIZE { move = MOVE_SWEET_SCENT; }
PARAMETRIZE { move = MOVE_SAND_ATTACK; }
GIVEN {
ASSUME(gBattleMoves[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN);
ASSUME(gBattleMoves[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN);
ASSUME(gBattleMoves[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN);
ASSUME(gBattleMoves[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2);
ASSUME(gBattleMoves[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2);
ASSUME(B_UPDATED_MOVE_DATA >= GEN_6);
ASSUME(gBattleMoves[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2);
ASSUME(gBattleMoves[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); };
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); }
switch (move)
{
case MOVE_GROWL:
MESSAGE("Foe Wobbuffet's Attack was not lowered!");
break;
case MOVE_LEER:
MESSAGE("Foe Wobbuffet's Defense was not lowered!");
break;
case MOVE_CONFIDE:
MESSAGE("Foe Wobbuffet's Sp. Atk was not lowered!");
break;
case MOVE_FAKE_TEARS:
MESSAGE("Foe Wobbuffet's Sp. Def was not lowered!");
break;
case MOVE_SCARY_FACE:
MESSAGE("Foe Wobbuffet's Speed was not lowered!");
break;
case MOVE_SWEET_SCENT:
MESSAGE("Foe Wobbuffet's evasiveness was not lowered!");
break;
case MOVE_SAND_ATTACK:
MESSAGE("Foe Wobbuffet's accuracy was not lowered!");
break;
}
}
}
SINGLE_BATTLE_TEST("Clear Amulet prevents secondary effects that reduce stats")
{
u32 move;
PARAMETRIZE { move = MOVE_AURORA_BEAM; }
PARAMETRIZE { move = MOVE_ROCK_SMASH; }
PARAMETRIZE { move = MOVE_SNARL; }
PARAMETRIZE { move = MOVE_PSYCHIC; }
PARAMETRIZE { move = MOVE_BUBBLE_BEAM; }
PARAMETRIZE { move = MOVE_MUD_SLAP; }
GIVEN {
ASSUME(gBattleMoves[MOVE_AURORA_BEAM].effect == EFFECT_ATTACK_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_ROCK_SMASH].effect == EFFECT_DEFENSE_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_SNARL].effect == EFFECT_SPECIAL_ATTACK_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_PSYCHIC].effect == EFFECT_SPECIAL_DEFENSE_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_BUBBLE_BEAM].effect == EFFECT_SPEED_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_MUD_SLAP].effect == EFFECT_ACCURACY_DOWN_HIT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); };
} WHEN {
TURN { MOVE(player, MOVE_ROCK_SMASH); }
} SCENE {
NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); }
}
}