Master to upcoming merge
This commit is contained in:
commit
a4470cac2c
@ -381,7 +381,9 @@ BattleScript_MoveEffectSaltCure::
|
||||
BattleScript_SaltCureExtraDamage::
|
||||
playanimation BS_ATTACKER, B_ANIM_SALT_CURE_DAMAGE, NULL
|
||||
waitanimation
|
||||
call BattleScript_HurtTarget_NoString
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE
|
||||
healthbarupdate BS_ATTACKER
|
||||
datahpupdate BS_ATTACKER
|
||||
printstring STRINGID_TARGETISHURTBYSALTCURE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryfaintmon BS_ATTACKER
|
||||
@ -1371,14 +1373,17 @@ BattleScript_EffectFlowerShield::
|
||||
attackcanceler
|
||||
savetarget
|
||||
selectfirstvalidtarget
|
||||
BattleScript_FlowerShieldIsAnyGrass:
|
||||
BattleScript_FlowerShieldIsAnyValidTarget:
|
||||
jumpifvolatile BS_TARGET, VOLATILE_SEMI_INVULNERABLE, BattleScript_FlowerShieldCheckNextTarget
|
||||
jumpiftype BS_TARGET, TYPE_GRASS, BattleScript_FlowerShieldLoopStart
|
||||
jumpifnexttargetvalid BattleScript_FlowerShieldIsAnyGrass
|
||||
BattleScript_FlowerShieldCheckNextTarget:
|
||||
jumpifnexttargetvalid BattleScript_FlowerShieldIsAnyValidTarget
|
||||
goto BattleScript_RestoreTargetButItFailed
|
||||
BattleScript_FlowerShieldLoopStart:
|
||||
selectfirstvalidtarget
|
||||
BattleScript_FlowerShieldLoop:
|
||||
movevaluescleanup
|
||||
jumpifvolatile BS_TARGET, VOLATILE_SEMI_INVULNERABLE, BattleScript_FlowerShieldMoveTargetEnd
|
||||
jumpiftype BS_TARGET, TYPE_GRASS, BattleScript_FlowerShieldLoop2
|
||||
goto BattleScript_FlowerShieldMoveTargetEnd
|
||||
BattleScript_FlowerShieldLoop2:
|
||||
@ -1399,6 +1404,7 @@ BattleScript_FlowerShieldMoveTargetEnd:
|
||||
moveendto MOVEEND_NEXT_TARGET
|
||||
jumpifnexttargetvalid BattleScript_FlowerShieldLoop
|
||||
restoretarget
|
||||
moveendfrom MOVEEND_ITEM_EFFECTS_ATTACKER
|
||||
end
|
||||
|
||||
BattleScript_EffectRototiller::
|
||||
@ -1468,7 +1474,6 @@ BattleScript_EffectAfterYou::
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_MoveEffectFlameBurst::
|
||||
tryfaintmon BS_TARGET
|
||||
printstring STRINGID_BURSTINGFLAMESHIT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE
|
||||
@ -2897,7 +2902,6 @@ BattleScript_LeafGuardPreventsRest::
|
||||
|
||||
BattleScript_EffectOHKO::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
|
||||
typecalc
|
||||
jumpifmovehadnoeffect BattleScript_HitFromAtkAnimation
|
||||
tryKO BattleScript_KOFail
|
||||
@ -7854,15 +7858,15 @@ BattleScript_ItemHealHP_RemoveItemEnd2_Anim:
|
||||
end2
|
||||
|
||||
BattleScript_BerryPPHealRet::
|
||||
jumpifability BS_ATTACKER, ABILITY_RIPEN, BattleScript_BerryPPHeal_AbilityPopup
|
||||
jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_BerryPPHeal_AbilityPopup
|
||||
goto BattleScript_BerryPPHeal_Anim
|
||||
BattleScript_BerryPPHeal_AbilityPopup:
|
||||
call BattleScript_AbilityPopUp
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
BattleScript_BerryPPHeal_Anim:
|
||||
playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT
|
||||
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT
|
||||
printstring STRINGID_PKMNSITEMRESTOREDPP
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
removeitem BS_ATTACKER
|
||||
removeitem BS_SCRIPTING
|
||||
return
|
||||
|
||||
BattleScript_BerryPPHealEnd2::
|
||||
|
||||
@ -19,7 +19,7 @@ If you've done this before and just need a quick lookup, here's what files you n
|
||||
## The Graphics
|
||||
|
||||
### 1. Edit the sprites
|
||||
We will start with a graphic that we want to use for our new trainer pic. Unlike with adding Pokémon, the trainer sprites aren't sorted in individual folders, but rather in one folder: [`graphics/trainers/front_pics`](./graphics/trainers/front_pics). **Trainers sprites cannot be more than 16 - this includes the color that will be transparent, which is the first slot of the palette.**
|
||||
We will start with a graphic that we want to use for our new trainer pic. Unlike with adding Pokémon, the trainer sprites aren't sorted in individual folders, but rather in one folder: [`graphics/trainers/front_pics`](./graphics/trainers/front_pics). **Trainers sprites cannot have more than 16 colors - this includes the color that will be transparent, which is the first slot of the palette.**
|
||||
|
||||
### 2. Register the sprites
|
||||
Sadly, just putting the image files into the graphics folder is not enough. To use the sprites we have to register them by linking the graphic files in [`src/data/graphics/trainers`](./data/graphics/trainers.h):
|
||||
|
||||
@ -141,7 +141,6 @@ struct ProtectStruct
|
||||
{
|
||||
u32 protected:7; // 126 protect options
|
||||
u32 noValidMoves:1;
|
||||
u32 helpingHand:1;
|
||||
u32 bounceMove:1;
|
||||
u32 stealMove:1;
|
||||
u32 nonVolatileStatusImmobility:1;
|
||||
@ -162,13 +161,14 @@ struct ProtectStruct
|
||||
u32 shellTrap:1;
|
||||
u32 eatMirrorHerb:1;
|
||||
u32 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
|
||||
u32 usedAllySwitch:1;
|
||||
u16 usedAllySwitch:1;
|
||||
// End of 32-bit bitfield
|
||||
u16 helpingHand:3;
|
||||
u16 lashOutAffected:1;
|
||||
u16 assuranceDoubled:1;
|
||||
u16 myceliumMight:1;
|
||||
u16 laggingTail:1;
|
||||
u16 padding:12;
|
||||
u16 padding:9;
|
||||
// End of 16-bit bitfield
|
||||
u16 physicalDmg;
|
||||
u16 specialDmg;
|
||||
@ -1124,7 +1124,7 @@ extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
|
||||
extern u8 gMultiUsePlayerCursor;
|
||||
extern u8 gNumberOfMovesToChoose;
|
||||
extern bool8 gHasFetchedBall;
|
||||
extern u8 gLastUsedBall;
|
||||
extern u16 gLastUsedBall;
|
||||
extern u16 gLastThrownBall;
|
||||
extern u16 gBallToDisplay;
|
||||
extern bool8 gLastUsedBallMenuPresent;
|
||||
|
||||
@ -44,7 +44,8 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA
|
||||
s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk);
|
||||
s32 GetCritHitOdds(s32 critChanceIndex);
|
||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||
u8 GetBattlerTurnOrderNum(u8 battler);
|
||||
bool32 HasBattlerActedThisTurn(u32 battler);
|
||||
u32 GetBattlerTurnOrderNum(u32 battler);
|
||||
bool32 NoAliveMonsForBattlerSide(u32 battler);
|
||||
bool32 NoAliveMonsForPlayer(void);
|
||||
bool32 NoAliveMonsForEitherParty(void);
|
||||
|
||||
@ -156,14 +156,14 @@ enum MoveEndEffects
|
||||
MOVEEND_ABILITY_BLOCK,
|
||||
MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist
|
||||
MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell
|
||||
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
|
||||
MOVEEND_RED_CARD,
|
||||
MOVEEND_EJECT_BUTTON,
|
||||
MOVEEND_LIFEORB_SHELLBELL, // Shell Bell / Life Orb / Throat Spray
|
||||
MOVEEND_LIFEORB_SHELLBELL,
|
||||
MOVEEND_FORM_CHANGE,
|
||||
MOVEEND_EMERGENCY_EXIT,
|
||||
MOVEEND_EJECT_PACK,
|
||||
MOVEEND_HIT_ESCAPE,
|
||||
MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts
|
||||
MOVEEND_OPPORTUNIST,
|
||||
MOVEEND_MIRROR_HERB,
|
||||
MOVEEND_PICKPOCKET,
|
||||
MOVEEND_WHITE_HERB,
|
||||
|
||||
@ -215,6 +215,8 @@ enum RandomTag
|
||||
RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN,
|
||||
RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM,
|
||||
RNG_WRAP,
|
||||
RNG_BALLTHROW_CRITICAL,
|
||||
RNG_BALLTHROW_SHAKE,
|
||||
RNG_PRESENT,
|
||||
RNG_MAGNITUDE,
|
||||
};
|
||||
|
||||
@ -1009,6 +1009,8 @@ struct ItemContext
|
||||
u16 explicitPartyIndex:1;
|
||||
u16 move;
|
||||
u16 explicitMove:1;
|
||||
struct TurnRNG rng;
|
||||
u16 explicitRNG:1;
|
||||
};
|
||||
|
||||
void OpenTurn(u32 sourceLine);
|
||||
|
||||
@ -236,7 +236,7 @@ EWRAM_DATA u16 gBattleTurnCounter = 0;
|
||||
EWRAM_DATA u8 gBattlerAbility = 0;
|
||||
EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0};
|
||||
EWRAM_DATA bool8 gHasFetchedBall = FALSE;
|
||||
EWRAM_DATA u8 gLastUsedBall = 0;
|
||||
EWRAM_DATA u16 gLastUsedBall = 0;
|
||||
EWRAM_DATA u16 gLastThrownBall = 0;
|
||||
EWRAM_DATA u16 gBallToDisplay = 0;
|
||||
EWRAM_DATA bool8 gLastUsedBallMenuPresent = FALSE;
|
||||
@ -3325,7 +3325,7 @@ const u8* FaintClearSetData(u32 battler)
|
||||
|
||||
gProtectStructs[battler].quash = FALSE;
|
||||
gProtectStructs[battler].noValidMoves = FALSE;
|
||||
gProtectStructs[battler].helpingHand = FALSE;
|
||||
gProtectStructs[battler].helpingHand = 0;
|
||||
gProtectStructs[battler].bounceMove = FALSE;
|
||||
gProtectStructs[battler].stealMove = FALSE;
|
||||
gProtectStructs[battler].nonVolatileStatusImmobility = FALSE;
|
||||
|
||||
@ -803,7 +803,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
|
||||
[STRINGID_TEAMGAINEDEXP] = COMPOUND_STRING("The rest of your team gained Exp. Points thanks to the Exp. Share!\p"),
|
||||
[STRINGID_CURRENTMOVECANTSELECT] = COMPOUND_STRING("{B_BUFF1} cannot be used!\p"),
|
||||
[STRINGID_TARGETISBEINGSALTCURED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is being salt cured!"),
|
||||
[STRINGID_TARGETISHURTBYSALTCURE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"),
|
||||
[STRINGID_TARGETISHURTBYSALTCURE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"),
|
||||
[STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} got covered in sticky candy syrup!"),
|
||||
[STRINGID_SHARPSTEELFLOATS] = COMPOUND_STRING("Sharp-pointed pieces of steel started floating around {B_DEF_TEAM2} Pokémon!"),
|
||||
[STRINGID_SHARPSTEELDMG] = COMPOUND_STRING("The sharp steel bit into {B_DEF_NAME_WITH_PREFIX2}!"),
|
||||
|
||||
@ -2752,9 +2752,20 @@ static void Cmd_printselectionstringfromtable(void)
|
||||
}
|
||||
}
|
||||
|
||||
u8 GetBattlerTurnOrderNum(u8 battler)
|
||||
bool32 HasBattlerActedThisTurn(u32 battler)
|
||||
{
|
||||
s32 i;
|
||||
u32 i;
|
||||
for (i = 0; i < gCurrentTurnActionNumber; i++)
|
||||
{
|
||||
if (gBattlerByTurnOrder[i] == battler)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
u32 GetBattlerTurnOrderNum(u32 battler)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattlerByTurnOrder[i] == battler)
|
||||
@ -3039,8 +3050,8 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
||||
{
|
||||
gBattlescriptCurrInstr++;
|
||||
}
|
||||
else if (GetBattlerTurnOrderNum(gEffectBattler) > gCurrentTurnActionNumber
|
||||
&& !(GetActiveGimmick(gEffectBattler) == GIMMICK_DYNAMAX))
|
||||
else if (!HasBattlerActedThisTurn(gEffectBattler)
|
||||
&& GetActiveGimmick(gEffectBattler) != GIMMICK_DYNAMAX)
|
||||
{
|
||||
gBattleMons[gEffectBattler].volatiles.flinched = TRUE;
|
||||
gBattlescriptCurrInstr++;
|
||||
@ -3373,7 +3384,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
||||
}
|
||||
break;
|
||||
case MOVE_EFFECT_CORE_ENFORCER:
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)
|
||||
if (HasBattlerActedThisTurn(gBattlerTarget)
|
||||
&& !NoAliveMonsForEitherParty())
|
||||
{
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
@ -5651,6 +5662,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
|
||||
case EFFECT_KNOCK_OFF:
|
||||
if (gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff
|
||||
&& gBattleMons[gBattlerTarget].item != ITEM_NONE
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerAttacker))
|
||||
{
|
||||
u32 side = GetBattlerSide(gBattlerTarget);
|
||||
@ -5826,7 +5838,9 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
|
||||
}
|
||||
break;
|
||||
case EFFECT_STONE_AXE:
|
||||
if (!IsHazardOnSide(GetBattlerSide(gBattlerTarget), HAZARDS_STEALTH_ROCK) && IsBattlerAlive(gBattlerAttacker))
|
||||
if (!IsHazardOnSide(GetBattlerSide(gBattlerTarget), HAZARDS_STEALTH_ROCK)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerAttacker))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_POINTEDSTONESFLOAT;
|
||||
BattleScriptPushCursor();
|
||||
@ -5835,7 +5849,9 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
|
||||
}
|
||||
break;
|
||||
case EFFECT_CEASELESS_EDGE:
|
||||
if (gSideTimers[GetBattlerSide(gBattlerTarget)].spikesAmount < 3 && IsBattlerAlive(gBattlerAttacker))
|
||||
if (gSideTimers[GetBattlerSide(gBattlerTarget)].spikesAmount < 3
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerAttacker))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SPIKESSCATTERED;
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
@ -9434,10 +9450,12 @@ static bool32 ChangeOrderTargetAfterAttacker(void)
|
||||
u32 i;
|
||||
u8 data[MAX_BATTLERS_COUNT];
|
||||
u8 actionsData[MAX_BATTLERS_COUNT];
|
||||
u32 attackerTurnOrderNum = GetBattlerTurnOrderNum(gBattlerAttacker);
|
||||
u32 targetTurnOrderNum = GetBattlerTurnOrderNum(gBattlerTarget);
|
||||
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
if (attackerTurnOrderNum > targetTurnOrderNum)
|
||||
return FALSE;
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) + 1 == GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
if (attackerTurnOrderNum + 1 == targetTurnOrderNum)
|
||||
return GetGenConfig(GEN_CONFIG_AFTER_YOU_TURN_ORDER) >= GEN_8;
|
||||
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
@ -9445,14 +9463,14 @@ static bool32 ChangeOrderTargetAfterAttacker(void)
|
||||
data[i] = gBattlerByTurnOrder[i];
|
||||
actionsData[i] = gActionsByTurnOrder[i];
|
||||
}
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) == 0 && GetBattlerTurnOrderNum(gBattlerTarget) == 2)
|
||||
if (attackerTurnOrderNum == 0 && targetTurnOrderNum == 2)
|
||||
{
|
||||
gBattlerByTurnOrder[1] = gBattlerTarget;
|
||||
gActionsByTurnOrder[1] = actionsData[2];
|
||||
gBattlerByTurnOrder[2] = data[1];
|
||||
gActionsByTurnOrder[2] = actionsData[1];
|
||||
}
|
||||
else if (GetBattlerTurnOrderNum(gBattlerAttacker) == 0 && GetBattlerTurnOrderNum(gBattlerTarget) == 3)
|
||||
else if (attackerTurnOrderNum == 0 && targetTurnOrderNum == 3)
|
||||
{
|
||||
gBattlerByTurnOrder[1] = gBattlerTarget;
|
||||
gActionsByTurnOrder[1] = actionsData[3];
|
||||
@ -9461,7 +9479,7 @@ static bool32 ChangeOrderTargetAfterAttacker(void)
|
||||
gBattlerByTurnOrder[3] = data[2];
|
||||
gActionsByTurnOrder[3] = actionsData[2];
|
||||
}
|
||||
else // Attacker == 1, Target == 3
|
||||
else // attackerTurnOrderNum == 1, targetTurnOrderNum == 3
|
||||
{
|
||||
gBattlerByTurnOrder[2] = gBattlerTarget;
|
||||
gActionsByTurnOrder[2] = actionsData[3];
|
||||
@ -10738,6 +10756,11 @@ static void Cmd_setlightscreen(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// for var lands
|
||||
#define NO_HIT 0
|
||||
#define CALC_ACC 1
|
||||
#define SURE_HIT 2
|
||||
// for var endured
|
||||
#define NOT_ENDURED 0
|
||||
#define FOCUS_SASHED 1
|
||||
#define FOCUS_BANDED 2
|
||||
@ -10746,7 +10769,6 @@ static void Cmd_tryKO(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
|
||||
bool32 lands = FALSE;
|
||||
enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove);
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget, TRUE);
|
||||
u16 targetAbility = GetBattlerAbility(gBattlerTarget);
|
||||
@ -10792,24 +10814,28 @@ static void Cmd_tryKO(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level
|
||||
&& ((gBattleMons[gBattlerTarget].volatiles.lockOn
|
||||
&& gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
||||
|| IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_NO_GUARD)
|
||||
|| IsAbilityAndRecord(gBattlerTarget, targetAbility, ABILITY_NO_GUARD)))
|
||||
{
|
||||
lands = TRUE;
|
||||
}
|
||||
else
|
||||
u32 lands = NO_HIT;
|
||||
if (gBattleMons[gBattlerTarget].level > gBattleMons[gBattlerAttacker].level)
|
||||
lands = NO_HIT;
|
||||
else if ((gBattleMons[gBattlerTarget].volatiles.lockOn && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
||||
|| IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_NO_GUARD)
|
||||
|| IsAbilityAndRecord(gBattlerTarget, targetAbility, ABILITY_NO_GUARD))
|
||||
lands = SURE_HIT;
|
||||
else if (IsSemiInvulnerable(gBattlerTarget, CHECK_ALL))
|
||||
lands = NO_HIT;
|
||||
else if (!JumpIfMoveAffectedByProtect(gCurrentMove, gBattlerTarget, TRUE, cmd->failInstr))
|
||||
lands = CALC_ACC;
|
||||
|
||||
if (lands == CALC_ACC)
|
||||
{
|
||||
u16 odds = GetMoveAccuracy(gCurrentMove) + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level);
|
||||
if (B_SHEER_COLD_ACC >= GEN_7 && effect == EFFECT_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE))
|
||||
odds -= 10;
|
||||
if (RandomPercentage(RNG_ACCURACY, odds) && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
|
||||
lands = TRUE;
|
||||
lands = SURE_HIT;
|
||||
}
|
||||
|
||||
if (lands)
|
||||
if (lands == SURE_HIT)
|
||||
{
|
||||
if (gDisableStructs[gBattlerTarget].endured)
|
||||
{
|
||||
@ -10845,6 +10871,9 @@ static void Cmd_tryKO(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef NO_HIT
|
||||
#undef CALC_ACC
|
||||
#undef SURE_HIT
|
||||
#undef NOT_ENDURED
|
||||
#undef FOCUS_SASHED
|
||||
#undef FOCUS_BANDED
|
||||
@ -11276,7 +11305,7 @@ static void Cmd_trysetencore(void)
|
||||
gDisableStructs[gBattlerTarget].encoredMove = gBattleMons[gBattlerTarget].moves[i];
|
||||
gDisableStructs[gBattlerTarget].encoredMovePos = i;
|
||||
// Encore always lasts 3 turns, but we need to account for a scenario where Encore changes the move during the same turn.
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
if (HasBattlerActedThisTurn(gBattlerTarget))
|
||||
gDisableStructs[gBattlerTarget].encoreTimer = 4;
|
||||
else
|
||||
gDisableStructs[gBattlerTarget].encoreTimer = 3;
|
||||
@ -12489,7 +12518,7 @@ static void Cmd_settaunt(void)
|
||||
if (B_TAUNT_TURNS >= GEN_5)
|
||||
{
|
||||
turns = 4;
|
||||
if (GetBattlerTurnOrderNum(gBattlerTarget) > GetBattlerTurnOrderNum(gBattlerAttacker))
|
||||
if (!HasBattlerActedThisTurn(gBattlerTarget))
|
||||
turns--; // If the target hasn't yet moved this turn, Taunt lasts for only three turns (source: Bulbapedia)
|
||||
}
|
||||
else if (B_TAUNT_TURNS >= GEN_4)
|
||||
@ -12518,10 +12547,9 @@ static void Cmd_trysethelpinghand(void)
|
||||
|
||||
if (IsDoubleBattle()
|
||||
&& !(gAbsentBattlerFlags & (1u << gBattlerTarget))
|
||||
&& !gProtectStructs[gBattlerAttacker].helpingHand
|
||||
&& !gProtectStructs[gBattlerTarget].helpingHand)
|
||||
&& !HasBattlerActedThisTurn(gBattlerTarget))
|
||||
{
|
||||
gProtectStructs[gBattlerTarget].helpingHand = TRUE;
|
||||
gProtectStructs[gBattlerTarget].helpingHand++;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
@ -13652,7 +13680,11 @@ static void Cmd_handleballthrow(void)
|
||||
{
|
||||
odds = Sqrt(Sqrt(16711680 / odds));
|
||||
odds = 1048560 / odds;
|
||||
for (shakes = 0; shakes < maxShakes && Random() < odds; shakes++);
|
||||
for (shakes = 0; shakes < maxShakes; shakes++)
|
||||
{
|
||||
if (RandomUniform(RNG_BALLTHROW_SHAKE, 0, MAX_u16) >= odds)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BtlController_EmitBallThrowAnim(gBattlerAttacker, B_COMM_TO_CONTROLLER, shakes);
|
||||
@ -14451,7 +14483,7 @@ static bool32 CriticalCapture(u32 odds)
|
||||
odds = 255;
|
||||
|
||||
odds /= 6;
|
||||
if ((Random() % 256) < odds)
|
||||
if (RandomUniform(RNG_BALLTHROW_CRITICAL, 0, MAX_u8) < odds)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
@ -14872,7 +14904,7 @@ void BS_ItemRestorePP(void)
|
||||
void BS_TryRevertWeatherForm(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
if (TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_WEATHER))
|
||||
if (IsBattlerAlive(gBattlerTarget) && TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_WEATHER))
|
||||
{
|
||||
gBattleScripting.battler = gBattlerTarget;
|
||||
BattleScriptPush(cmd->nextInstr);
|
||||
@ -15082,7 +15114,7 @@ void BS_SetPledge(void)
|
||||
else if ((gChosenActionByBattler[partner] == B_ACTION_USE_MOVE)
|
||||
&& IsDoubleBattle()
|
||||
&& IsBattlerAlive(partner)
|
||||
&& GetBattlerTurnOrderNum(gBattlerAttacker) < GetBattlerTurnOrderNum(partner)
|
||||
&& !HasBattlerActedThisTurn(partner)
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& gCurrentMove != partnerMove
|
||||
&& GetMoveEffect(partnerMove) == EFFECT_PLEDGE)
|
||||
@ -15251,7 +15283,7 @@ void BS_TryUpperHand(void)
|
||||
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
||||
u32 prio = GetChosenMovePriority(gBattlerTarget, abilityDef);
|
||||
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)
|
||||
if (HasBattlerActedThisTurn(gBattlerTarget)
|
||||
|| gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE
|
||||
|| IsBattleMoveStatus(gChosenMoveByBattler[gBattlerTarget])
|
||||
|| prio < 1
|
||||
@ -15468,7 +15500,7 @@ void BS_TryQuash(void)
|
||||
u32 i, j;
|
||||
|
||||
// It's true if foe is faster, has a bigger priority, or switches
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
if (HasBattlerActedThisTurn(gBattlerTarget))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
return;
|
||||
@ -17071,7 +17103,7 @@ void BS_InvertStatStages(void)
|
||||
void BS_TryElectrify(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
if (HasBattlerActedThisTurn(gBattlerTarget))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
|
||||
@ -1005,7 +1005,7 @@ void TrainerBattleLoadArgsSecondTrainer(const u8 *data)
|
||||
|
||||
void SetMapVarsToTrainerA(void)
|
||||
{
|
||||
if (TRAINER_BATTLE_PARAM.objEventLocalIdA != 0)
|
||||
if (TRAINER_BATTLE_PARAM.objEventLocalIdA != LOCALID_NONE)
|
||||
{
|
||||
gSpecialVar_LastTalked = TRAINER_BATTLE_PARAM.objEventLocalIdA;
|
||||
gSelectedObjectEvent = GetObjectEventIdByLocalIdAndMap(TRAINER_BATTLE_PARAM.objEventLocalIdA, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
|
||||
|
||||
@ -2640,8 +2640,8 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx)
|
||||
battleScript = BattleScript_InsomniaProtects;
|
||||
break;
|
||||
case EFFECT_SUCKER_PUNCH:
|
||||
if ((GetBattlerTurnOrderNum(ctx->battlerAtk) > GetBattlerTurnOrderNum(ctx->battlerDef))
|
||||
|| (IsBattleMoveStatus(gBattleMons[ctx->battlerDef].moves[gBattleStruct->chosenMovePositions[ctx->battlerDef]]) && !gProtectStructs[ctx->battlerDef].noValidMoves))
|
||||
if (HasBattlerActedThisTurn(ctx->battlerDef)
|
||||
|| (IsBattleMoveStatus(gBattleMons[ctx->battlerDef].moves[gBattleStruct->chosenMovePositions[ctx->battlerDef]]) && !gProtectStructs[ctx->battlerDef].noValidMoves))
|
||||
battleScript = BattleScript_ButItFailed;
|
||||
break;
|
||||
case EFFECT_SNORE:
|
||||
@ -4686,14 +4686,15 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
break;
|
||||
case ABILITY_BALL_FETCH:
|
||||
if (gBattleMons[battler].item == ITEM_NONE
|
||||
&& gBattleResults.catchAttempts[gLastUsedBall - ITEM_ULTRA_BALL] >= 1
|
||||
&& gBattleResults.catchAttempts[ItemIdToBallId(gLastUsedBall)] >= 1
|
||||
&& !gHasFetchedBall)
|
||||
{
|
||||
gLastUsedItem = gLastUsedBall;
|
||||
gBattleScripting.battler = battler;
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedBall);
|
||||
gBattleMons[battler].item = gLastUsedItem;
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
gHasFetchedBall = TRUE;
|
||||
gLastUsedItem = gLastUsedBall;
|
||||
BattleScriptExecute(BattleScript_BallFetch);
|
||||
effect++;
|
||||
}
|
||||
@ -6408,6 +6409,7 @@ static u32 ItemRestorePp(u32 battler, u32 itemId, enum ItemCaseId caseID)
|
||||
else
|
||||
BattleScriptCall(BattleScript_BerryPPHealRet);
|
||||
|
||||
gBattleScripting.battler = battler;
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
if (MOVE_IS_PERMANENT(battler, i))
|
||||
@ -6760,6 +6762,21 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect)
|
||||
case HOLD_EFFECT_BERSERK_GENE:
|
||||
effect = ConsumeBerserkGene(battler, ITEMEFFECT_NONE);
|
||||
break;
|
||||
case HOLD_EFFECT_THROAT_SPRAY:
|
||||
if (IsSoundMove(gCurrentMove)
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsAnyTargetAffected(gBattlerAttacker)
|
||||
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end
|
||||
{
|
||||
gLastUsedItem = gBattleMons[gBattlerAttacker].item;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
effect = ITEM_STATS_CHANGE;
|
||||
BattleScriptCall(BattleScript_AttackerItemStatRaise);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -7031,6 +7048,9 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
if (B_BERRIES_INSTANT >= GEN_4)
|
||||
effect = ItemHealHp(battler, gLastUsedItem, caseID, TRUE);
|
||||
break;
|
||||
case HOLD_EFFECT_RESTORE_PP:
|
||||
effect = ItemRestorePp(battler, gLastUsedItem, caseID);
|
||||
break;
|
||||
case HOLD_EFFECT_AIR_BALLOON:
|
||||
effect = ITEM_EFFECT_OTHER;
|
||||
gBattleScripting.battler = battler;
|
||||
@ -7388,20 +7408,6 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
gLastUsedItem = atkItem;
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_THROAT_SPRAY: // Does NOT need to be a damaging move
|
||||
if (IsSoundMove(gCurrentMove)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsAnyTargetAffected(gBattlerAttacker)
|
||||
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end
|
||||
{
|
||||
gLastUsedItem = atkItem;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
effect = ITEM_STATS_CHANGE;
|
||||
BattleScriptCall(BattleScript_AttackerItemStatRaise);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -8487,12 +8493,12 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx)
|
||||
}
|
||||
break;
|
||||
case EFFECT_PAYBACK:
|
||||
if (GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef)
|
||||
if (HasBattlerActedThisTurn(battlerDef)
|
||||
&& (B_PAYBACK_SWITCH_BOOST < GEN_5 || gDisableStructs[battlerDef].isFirstTurn != 2))
|
||||
basePower *= 2;
|
||||
break;
|
||||
case EFFECT_BOLT_BEAK:
|
||||
if (GetBattlerTurnOrderNum(battlerAtk) < GetBattlerTurnOrderNum(battlerDef)
|
||||
if (!HasBattlerActedThisTurn(battlerDef)
|
||||
|| gDisableStructs[battlerDef].isFirstTurn == 2)
|
||||
basePower *= 2;
|
||||
break;
|
||||
@ -8647,8 +8653,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
|
||||
}
|
||||
|
||||
// various effects
|
||||
if (gProtectStructs[battlerAtk].helpingHand)
|
||||
for (u32 i = 0; i < gProtectStructs[battlerAtk].helpingHand; i++)
|
||||
modifier = uq4_12_multiply(modifier, UQ_4_12(1.5));
|
||||
|
||||
if (gSpecialStatuses[battlerAtk].gemBoost)
|
||||
modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(gSpecialStatuses[battlerAtk].gemParam)));
|
||||
if (gBattleMons[battlerAtk].volatiles.charge && moveType == TYPE_ELECTRIC)
|
||||
@ -12119,7 +12126,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
|
||||
calc = (calc * (100 + atkParam)) / 100;
|
||||
break;
|
||||
case HOLD_EFFECT_ZOOM_LENS:
|
||||
if (GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef))
|
||||
if (HasBattlerActedThisTurn(battlerDef))
|
||||
calc = (calc * (100 + atkParam)) / 100;
|
||||
break;
|
||||
}
|
||||
@ -12352,7 +12359,7 @@ static u32 GetMeFirstMove(void)
|
||||
|
||||
if (IsBattleMoveStatus(move)
|
||||
|| IsMoveMeFirstBanned(move)
|
||||
|| GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
|| HasBattlerActedThisTurn(gBattlerTarget))
|
||||
return MOVE_NONE;
|
||||
|
||||
return move;
|
||||
|
||||
@ -36,10 +36,10 @@ void BreakStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enu
|
||||
{
|
||||
if (src[currIndex] == CHAR_PROMPT_CLEAR)
|
||||
{
|
||||
u8 replacedChar = src[currIndex + 1];
|
||||
src[currIndex + 1] = EOS;
|
||||
u8 replacedChar = src[currIndex];
|
||||
src[currIndex] = EOS;
|
||||
BreakSubStringAutomatic(currSrc, maxWidth, screenLines, fontId, toggleScrollPrompt);
|
||||
src[currIndex + 1] = replacedChar;
|
||||
src[currIndex] = replacedChar;
|
||||
currSrc = &src[currIndex + 1];
|
||||
}
|
||||
currIndex++;
|
||||
|
||||
@ -4478,7 +4478,7 @@ bool32 DoesMonMeetAdditionalConditions(struct Pokemon *mon, const struct Evoluti
|
||||
{
|
||||
// Gen 2
|
||||
case IF_GENDER:
|
||||
if (gender == GetMonGender(mon))
|
||||
if (gender == params[i].arg1)
|
||||
currentCondition = TRUE;
|
||||
break;
|
||||
case IF_MIN_FRIENDSHIP:
|
||||
|
||||
@ -10081,7 +10081,7 @@ void UpdateSpeciesSpritePSS(struct BoxPokemon *boxMon)
|
||||
DestroyBoxMonIconAtPosition(sCursorPosition);
|
||||
CreateBoxMonIconAtPos(sCursorPosition);
|
||||
if (sStorage->boxOption == OPTION_MOVE_ITEMS)
|
||||
SetBoxMonIconObjMode(sCursorPosition, (GetBoxMonData(boxMon, MON_DATA_HELD_ITEM) == ITEM_NONE ? ST_OAM_OBJ_NORMAL : ST_OAM_OBJ_BLEND));
|
||||
SetBoxMonIconObjMode(sCursorPosition, (GetBoxMonData(boxMon, MON_DATA_HELD_ITEM) == ITEM_NONE ? ST_OAM_OBJ_BLEND : ST_OAM_OBJ_NORMAL));
|
||||
}
|
||||
}
|
||||
sJustOpenedBag = FALSE;
|
||||
|
||||
@ -374,7 +374,7 @@ bool8 CheckForTrainersWantingBattle(void)
|
||||
{
|
||||
if (!gObjectEvents[i].active)
|
||||
continue;
|
||||
if (gObjectEvents[i].trainerType != TRAINER_TYPE_NORMAL && gObjectEvents[i].trainerType != TRAINER_TYPE_BURIED)
|
||||
if (gObjectEvents[i].trainerType != TRAINER_TYPE_NORMAL && gObjectEvents[i].trainerType != TRAINER_TYPE_SEE_ALL_DIRECTIONS && gObjectEvents[i].trainerType != TRAINER_TYPE_BURIED)
|
||||
continue;
|
||||
trainerObjects[trainerObjectsCount++] = i;
|
||||
}
|
||||
|
||||
@ -1,7 +1,121 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Ball Fetch causes the Pokémon to pick up the last failed Ball at the end of the turn");
|
||||
TO_DO_BATTLE_TEST("Ball Fetch doesn't trigger if the Pokémon is already holding an item");
|
||||
TO_DO_BATTLE_TEST("Ball Fetch only picks up the first failed ball, once per battle"); // Bestow can help test this
|
||||
WILD_BATTLE_TEST("Ball Fetch causes the Pokémon to pick up the last failed Ball at the end of the turn")
|
||||
{
|
||||
u32 item = 0;
|
||||
|
||||
PARAMETRIZE { item = ITEM_POKE_BALL; }
|
||||
PARAMETRIZE { item = ITEM_GREAT_BALL; }
|
||||
PARAMETRIZE { item = ITEM_ULTRA_BALL; }
|
||||
PARAMETRIZE { item = ITEM_STRANGE_BALL; }
|
||||
PARAMETRIZE { item = ITEM_X_ACCURACY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); }
|
||||
OPPONENT(SPECIES_METAGROSS);
|
||||
} WHEN {
|
||||
TURN { USE_ITEM(player, item, WITH_RNG(RNG_BALLTHROW_SHAKE, MAX_u16) );}
|
||||
TURN {}
|
||||
} SCENE {
|
||||
if (item != ITEM_X_ACCURACY)
|
||||
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
else
|
||||
NOT ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
} THEN {
|
||||
if (item != ITEM_X_ACCURACY)
|
||||
EXPECT_EQ(player->item, item);
|
||||
else
|
||||
EXPECT_EQ(player->item, ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
WILD_BATTLE_TEST("Ball Fetch doesn't trigger if the Pokémon is already holding an item")
|
||||
{
|
||||
u32 item = 0;
|
||||
|
||||
PARAMETRIZE { item = ITEM_NONE; }
|
||||
PARAMETRIZE { item = ITEM_NUGGET; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); Item(item); }
|
||||
OPPONENT(SPECIES_METAGROSS);
|
||||
} WHEN {
|
||||
TURN { USE_ITEM(player, ITEM_GREAT_BALL, WITH_RNG(RNG_BALLTHROW_SHAKE, MAX_u16)); }
|
||||
} SCENE {
|
||||
if (item == ITEM_NONE)
|
||||
{
|
||||
MESSAGE("You used Great Ball!");
|
||||
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
MESSAGE("Yamper found a Great Ball!");
|
||||
}
|
||||
else
|
||||
{
|
||||
NONE_OF
|
||||
{
|
||||
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
MESSAGE("Yamper found a Great Ball!");
|
||||
}
|
||||
}
|
||||
} THEN {
|
||||
if (item == ITEM_NONE)
|
||||
EXPECT_EQ(player->item, ITEM_GREAT_BALL);
|
||||
else
|
||||
EXPECT_EQ(player->item, item);
|
||||
}
|
||||
}
|
||||
|
||||
WILD_BATTLE_TEST("Ball Fetch only picks up the first failed ball, once per battle")
|
||||
{
|
||||
u32 item = 0;
|
||||
u32 item2 = 0;
|
||||
|
||||
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_X_ACCURACY; }
|
||||
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_ULTRA_BALL; }
|
||||
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_FAST_BALL; }
|
||||
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_STRANGE_BALL; }
|
||||
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); }
|
||||
OPPONENT(SPECIES_METAGROSS);
|
||||
} WHEN {
|
||||
TURN { USE_ITEM(player, item, WITH_RNG(RNG_BALLTHROW_SHAKE, MAX_u16)); }
|
||||
TURN { MOVE(player, MOVE_BESTOW); }
|
||||
TURN { USE_ITEM(player, item2, WITH_RNG(RNG_BALLTHROW_SHAKE, MAX_u16)); }
|
||||
} SCENE {
|
||||
MESSAGE("You used Great Ball!");
|
||||
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
MESSAGE("Yamper found a Great Ball!");
|
||||
MESSAGE("Yamper used Bestow!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BESTOW, player);
|
||||
MESSAGE("The wild Metagross received Great Ball from Yamper!");
|
||||
NOT ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->item, ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ball Fetch doesn't trigger in Trainer Battles")
|
||||
{
|
||||
u32 item = 0;
|
||||
|
||||
PARAMETRIZE { item = ITEM_POKE_BALL; }
|
||||
PARAMETRIZE { item = ITEM_GREAT_BALL; }
|
||||
PARAMETRIZE { item = ITEM_ULTRA_BALL; }
|
||||
PARAMETRIZE { item = ITEM_STRANGE_BALL; }
|
||||
PARAMETRIZE { item = ITEM_X_ACCURACY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); }
|
||||
OPPONENT(SPECIES_METAGROSS);
|
||||
} WHEN {
|
||||
TURN { USE_ITEM(player, item, WITH_RNG(RNG_BALLTHROW_SHAKE, 0)); }
|
||||
} SCENE {
|
||||
NOT ABILITY_POPUP(player, ABILITY_BALL_FETCH);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->item, ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Ball Fetch doesn't trigger in Max Raid Battles");
|
||||
|
||||
@ -40,6 +40,7 @@ DOUBLE_BATTLE_TEST("Overcoat blocks damage from sandstorm")
|
||||
DOUBLE_BATTLE_TEST("Overcoat blocks damage from hail")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL);
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); Ability(ABILITY_SNOW_CLOAK); }
|
||||
PLAYER(SPECIES_SOLOSIS) { Speed(40); Ability(ABILITY_RUN_AWAY); }
|
||||
OPPONENT(SPECIES_PINECO) { Speed(30); Ability(ABILITY_OVERCOAT); }
|
||||
|
||||
@ -54,6 +54,7 @@ SINGLE_BATTLE_TEST("Slush Rush doesn't prevent non-Ice types from taking damage
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_WOBBUFFET, 0) != TYPE_ICE);
|
||||
ASSUME(GetSpeciesType(SPECIES_WOBBUFFET, 1) != TYPE_ICE);
|
||||
ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CETITAN) { Ability(ABILITY_SLUSH_RUSH); }
|
||||
} WHEN {
|
||||
|
||||
@ -249,7 +249,11 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 201-300")
|
||||
case EFFECT_HEAL_BELL:
|
||||
case EFFECT_SUNNY_DAY:
|
||||
case EFFECT_RAIN_DANCE:
|
||||
#if B_PREFERRED_ICE_WEATHER == B_ICE_WEATHER_SNOW
|
||||
case EFFECT_SNOWSCAPE:
|
||||
#else
|
||||
case EFFECT_HAIL:
|
||||
#endif
|
||||
case EFFECT_ROLE_PLAY:
|
||||
case EFFECT_REFRESH:
|
||||
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
|
||||
SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_AEGISLASH_SHIELD) { HP(1); }
|
||||
PLAYER(SPECIES_AEGISLASH_BLADE) { HP(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
@ -16,3 +17,26 @@ SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting")
|
||||
EXPECT_EQ(GetMonData(&PLAYER_PARTY[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Causing a Forecast or Flower Gift Pokémon to faint should not cause a message") // issue 7795
|
||||
{
|
||||
u32 species;
|
||||
PARAMETRIZE { species = SPECIES_CASTFORM; }
|
||||
PARAMETRIZE { species = SPECIES_CHERRIM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_VULPIX) { Ability(ABILITY_DROUGHT); }
|
||||
OPPONENT(species) { HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_GYRO_BALL, target: opponentRight); }
|
||||
} SCENE {
|
||||
if (species == SPECIES_CASTFORM) {
|
||||
MESSAGE("The opposing Castform fainted!");
|
||||
NOT MESSAGE("The opposing Castform transformed!");
|
||||
} else {
|
||||
MESSAGE("The opposing Cherrim fainted!");
|
||||
NOT MESSAGE("The opposing Cherrim transformed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -838,7 +838,11 @@ SINGLE_BATTLE_TEST("Dynamax: Max Geyser sets up heavy rain")
|
||||
}
|
||||
}
|
||||
|
||||
#if B_PREFERRED_ICE_WEATHER == B_ICE_WEATHER_SNOW
|
||||
SINGLE_BATTLE_TEST("Dynamax: Max Hailstorm sets up snow")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Dynamax: Max Hailstorm sets up hail")
|
||||
#endif
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_MAX_HAILSTORM, MOVE_EFFECT_HAIL));
|
||||
@ -848,9 +852,15 @@ SINGLE_BATTLE_TEST("Dynamax: Max Hailstorm sets up hail")
|
||||
TURN { MOVE(player, MOVE_POWDER_SNOW, gimmick: GIMMICK_DYNAMAX); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Max Hailstorm!");
|
||||
#if B_PREFERRED_ICE_WEATHER == B_ICE_WEATHER_SNOW
|
||||
MESSAGE("It started to snow!");
|
||||
MESSAGE("The opposing Wobbuffet used Celebrate!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SNOW_CONTINUES);
|
||||
#else
|
||||
MESSAGE("It started to hail!");
|
||||
MESSAGE("The opposing Wobbuffet used Celebrate!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HAIL_CONTINUES);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
23
test/battle/hold_effect/restore_pp.c
Normal file
23
test/battle/hold_effect/restore_pp.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gItemsInfo[ITEM_LEPPA_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PP);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Restore PP berry activates immediately on switch in")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LEPPA_BERRY); MovesWithPP({MOVE_SCRATCH, 0}, {MOVE_CELEBRATE, 20}); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_POUND); MOVE(player, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player);
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
@ -88,3 +88,32 @@ SINGLE_BATTLE_TEST("Throat Spray does not activate if move fails")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Throat Spray does not activate if user flinches")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_THROAT_SPRAY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FAKE_OUT); MOVE(player, MOVE_HYPER_VOICE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Throat Spray is not blocked by Sheer Force")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_THROAT_SPRAY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BUG_BUZZ); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BUG_BUZZ, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,3 +78,19 @@ SINGLE_BATTLE_TEST("Ceaseless Edge fails to set up hazards if user faints")
|
||||
NOT MESSAGE("Spikes were scattered on the ground all around the opposing team!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ceaseless Edge does not set up hazards if target was not hit")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_CEASELESS_EDGE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player);
|
||||
MESSAGE("Spikes were scattered on the ground all around the opposing team!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,41 @@ DOUBLE_BATTLE_TEST("Flower Shield raises the defense of all Grass-type Pokémon"
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Flower Shield fails if there's no Grass-type Pokémon on the field")
|
||||
SINGLE_BATTLE_TEST("Flower Shield fails if there's no Grass-type Pokémon on the field")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FLOWER_SHIELD); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, player);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Flower Shield doesn't affect Grass-type Pokémon that are in a semi-invulnerable position")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_BULBASAUR);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_BULBASAUR);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentLeft, MOVE_FLY, target: playerLeft);
|
||||
MOVE(playerLeft, MOVE_FLOWER_SHIELD);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLY, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Flower Shield")
|
||||
{
|
||||
|
||||
@ -1,4 +1,125 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_HELPING_HAND) == EFFECT_HELPING_HAND);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Helping Hand fails in a Single Battle")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_HELPING_HAND); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Helping Hand fails if ally already acted")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_HELPING_HAND, target: playerRight); MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, playerLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Helping Hand boosts the power of attacking moves by 50%", s16 damage)
|
||||
{
|
||||
bool32 useHelpingHand;
|
||||
|
||||
PARAMETRIZE { useHelpingHand = FALSE; }
|
||||
PARAMETRIZE { useHelpingHand = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (useHelpingHand)
|
||||
TURN { MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft); MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
|
||||
else
|
||||
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
|
||||
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Helping Hand still boosts moves used due to Instruct", s16 damage)
|
||||
{
|
||||
bool32 useHelpingHand;
|
||||
|
||||
PARAMETRIZE { useHelpingHand = FALSE; }
|
||||
PARAMETRIZE { useHelpingHand = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (useHelpingHand)
|
||||
{
|
||||
TURN { MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft);
|
||||
MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft);
|
||||
MOVE(opponentLeft, MOVE_INSTRUCT, target: playerLeft); }
|
||||
}
|
||||
else
|
||||
{
|
||||
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft);
|
||||
MOVE(opponentLeft, MOVE_INSTRUCT, target: playerLeft); }
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
|
||||
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Helping Hand boosts the power of attacking moves by 125% if Instructed into using it again", s16 damage)
|
||||
{
|
||||
bool32 useHelpingHandTwice;
|
||||
|
||||
PARAMETRIZE { useHelpingHandTwice = FALSE; }
|
||||
PARAMETRIZE { useHelpingHandTwice = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (useHelpingHandTwice)
|
||||
TURN { MOVE(playerRight, MOVE_HELPING_HAND, target: playerLeft);
|
||||
MOVE(opponentLeft, MOVE_INSTRUCT, target: playerRight);
|
||||
MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
|
||||
else
|
||||
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
|
||||
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.25), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Helping Hand (Move Effect) test titles")
|
||||
|
||||
@ -1,4 +1,188 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Lash Out (Move Effect) test titles")
|
||||
SINGLE_BATTLE_TEST("Lash Out damage is boosted if the user's stats are dropped the turn it is used")
|
||||
{
|
||||
s16 damage[2];
|
||||
u32 move = MOVE_NONE;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move = MOVE_GROWL; }
|
||||
PARAMETRIZE { move = MOVE_LEER; }
|
||||
PARAMETRIZE { move = MOVE_STRING_SHOT; }
|
||||
PARAMETRIZE { move = MOVE_CONFIDE; }
|
||||
PARAMETRIZE { move = MOVE_SAND_ATTACK; }
|
||||
PARAMETRIZE { move = MOVE_SWEET_SCENT; }
|
||||
PARAMETRIZE { move = MOVE_CHARM; }
|
||||
PARAMETRIZE { move = MOVE_SCREECH; }
|
||||
PARAMETRIZE { move = MOVE_SCARY_FACE; }
|
||||
PARAMETRIZE { move = MOVE_CAPTIVATE; }
|
||||
PARAMETRIZE { move = MOVE_EERIE_IMPULSE; }
|
||||
PARAMETRIZE { move = MOVE_FAKE_TEARS; }
|
||||
PARAMETRIZE { move = MOVE_NOBLE_ROAR; }
|
||||
PARAMETRIZE { move = MOVE_LUNGE; }
|
||||
PARAMETRIZE { move = MOVE_FIRE_LASH; }
|
||||
PARAMETRIZE { move = MOVE_BULLDOZE; }
|
||||
PARAMETRIZE { move = MOVE_MYSTICAL_FIRE; }
|
||||
PARAMETRIZE { move = MOVE_BUG_BUZZ; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GRIMMSNARL) { Gender(MON_MALE); Speed(1); Moves(MOVE_LASH_OUT); }
|
||||
OPPONENT(SPECIES_GOLEM) { Gender(MON_FEMALE); Speed(2); Moves(move, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LASH_OUT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_LASH_OUT); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[0]);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
} THEN {
|
||||
if (move == MOVE_TACKLE || move == MOVE_CHARM)
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
else if (move == MOVE_GROWL || move == MOVE_LUNGE || move == MOVE_NOBLE_ROAR)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]);
|
||||
else
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(2.00), damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Lash Out damage is only boosted on the turn that Intimidate switches in")
|
||||
{
|
||||
s16 damage[3] = {0};
|
||||
u32 move = MOVE_NONE;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LASH_OUT; }
|
||||
PARAMETRIZE { move = MOVE_SPLASH; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GRIMMSNARL) { Moves(move, MOVE_CELEBRATE, MOVE_LASH_OUT); }
|
||||
OPPONENT(SPECIES_INCINEROAR) { Ability(ABILITY_BLAZE); Moves(MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_INCINEROAR) { Ability(ABILITY_INTIMIDATE); Moves(MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LASH_OUT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, move); SWITCH(opponent, 1); }
|
||||
TURN { MOVE(player, MOVE_LASH_OUT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[0]);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
if (move == MOVE_LASH_OUT)
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[2]);
|
||||
} THEN {
|
||||
EXPECT_EQ(damage[0], damage[2]);
|
||||
EXPECT_MUL_EQ(damage[0], (move == MOVE_LASH_OUT ? UQ_4_12(1.33) : UQ_4_12(0.00)), damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Lash Out damage is boosted on turn 1 by switch in abilities")
|
||||
{
|
||||
s16 damage[2] = {0};
|
||||
u32 species = SPECIES_NONE, ability = ABILITY_NONE;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_INCINEROAR, ability = ABILITY_BLAZE; }
|
||||
PARAMETRIZE { species = SPECIES_INCINEROAR, ability = ABILITY_INTIMIDATE; }
|
||||
PARAMETRIZE { species = SPECIES_HYDRAPPLE, ability = ABILITY_REGENERATOR; }
|
||||
PARAMETRIZE { species = SPECIES_HYDRAPPLE, ability = ABILITY_SUPERSWEET_SYRUP; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GRIMMSNARL) { Moves(MOVE_LASH_OUT); }
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LASH_OUT); }
|
||||
TURN { MOVE(player, MOVE_LASH_OUT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[0]);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
|
||||
} THEN {
|
||||
if (ability == ABILITY_INTIMIDATE)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33) , damage[1]);
|
||||
else if (ability == ABILITY_SUPERSWEET_SYRUP)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(2.00) , damage[1]);
|
||||
else
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Lash Out damage is boosted by Cotton Down activation in doubles")
|
||||
{
|
||||
s16 damage[2] = {0};
|
||||
u32 ability = ABILITY_NONE;
|
||||
|
||||
PARAMETRIZE { ability = ABILITY_REGENERATOR; }
|
||||
PARAMETRIZE { ability = ABILITY_COTTON_DOWN; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GRIMMSNARL) { Speed(1); Moves(MOVE_LASH_OUT); }
|
||||
PLAYER(SPECIES_RATTATA) { Speed(2); Moves(MOVE_TACKLE, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_ELDEGOSS) { Speed(3); Ability(ability); }
|
||||
OPPONENT(SPECIES_GOLEM) { Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_LASH_OUT, target:opponentRight); MOVE(playerRight, MOVE_TACKLE, target:opponentLeft); }
|
||||
TURN { MOVE(playerLeft, MOVE_LASH_OUT, target:opponentRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, playerLeft);
|
||||
HP_BAR(opponentRight, captureDamage: &damage[0]);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, playerLeft);
|
||||
HP_BAR(opponentRight, captureDamage: &damage[1]);
|
||||
|
||||
} THEN {
|
||||
if (ability == ABILITY_COTTON_DOWN)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(2.00) , damage[1]);
|
||||
else
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Lash Out damage is not boosted by Treasure of Ruin ability activation in doubles")
|
||||
{
|
||||
s16 damage[2] = {0};
|
||||
u32 species = SPECIES_NONE, ability = ABILITY_NONE;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_KANGASKHAN, ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { species = SPECIES_HYDRAPPLE, ability = ABILITY_SUPERSWEET_SYRUP; }
|
||||
PARAMETRIZE { species = SPECIES_WO_CHIEN, ability = ABILITY_TABLETS_OF_RUIN; }
|
||||
PARAMETRIZE { species = SPECIES_CHIEN_PAO, ability = ABILITY_SWORD_OF_RUIN; }
|
||||
PARAMETRIZE { species = SPECIES_TING_LU, ability = ABILITY_VESSEL_OF_RUIN; }
|
||||
PARAMETRIZE { species = SPECIES_CHI_YU, ability = ABILITY_BEADS_OF_RUIN; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GRIMMSNARL) { Moves(MOVE_LASH_OUT); }
|
||||
PLAYER(SPECIES_RATTATA);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GOLEM);
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_LASH_OUT, target:opponentRight); }
|
||||
TURN { MOVE(playerLeft, MOVE_LASH_OUT, target:opponentRight); SWITCH(opponentLeft, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, playerLeft);
|
||||
HP_BAR(opponentRight, captureDamage: &damage[0]);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASH_OUT, playerLeft);
|
||||
HP_BAR(opponentRight, captureDamage: &damage[1]);
|
||||
|
||||
} THEN {
|
||||
if (ability == ABILITY_SUPERSWEET_SYRUP)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(2.00) , damage[1]);
|
||||
else if (ability == ABILITY_TABLETS_OF_RUIN)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75) , damage[1]);
|
||||
else if (ability == ABILITY_SWORD_OF_RUIN)
|
||||
EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33) , damage[1]);
|
||||
else
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,18 @@ SINGLE_BATTLE_TEST("OHKO moves can hit semi-invulnerable mons when the user has
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("OHKO moves can not hit semi-invulnerable")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FLY); MOVE(player, MOVE_FISSURE); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FISSURE, player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("OHKO moves can can be endured by Focus Sash")
|
||||
{
|
||||
GIVEN {
|
||||
@ -48,7 +60,29 @@ SINGLE_BATTLE_TEST("OHKO moves can can be endured by Sturdy")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("OHKO moves always fails if the target has a higher level than the user")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Level(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Level(2); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FISSURE); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FISSURE, player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("OHKO moves fail if target protects")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_FISSURE); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FISSURE, player);
|
||||
}
|
||||
}
|
||||
TO_DO_BATTLE_TEST("OHKO moves faints the target, skipping regular damage calculations")
|
||||
TO_DO_BATTLE_TEST("OHKO moves always fails if the target has a higher level than the user")
|
||||
TO_DO_BATTLE_TEST("OHKO moves's accuracy increases by 1% for every level the user has over the target")
|
||||
TO_DO_BATTLE_TEST("OHKO moves's ignores non-stage accuracy modifiers") // Gravity, Wide Lens, Compound Eyes
|
||||
|
||||
@ -51,3 +51,22 @@ SINGLE_BATTLE_TEST("Sucker Punch doesn't hit targets that has already moved")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sucker Punch fails if the target has attempted to act even if previously successful")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); MOVE(playerLeft, MOVE_SUCKER_PUNCH, target: opponentLeft); MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUCKER_PUNCH, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerRight);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SUCKER_PUNCH, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,3 +132,25 @@ AI_SINGLE_BATTLE_TEST("AI won't use Upper Hand unless it has seen a priority mov
|
||||
TURN { MOVE(player, move); EXPECT_MOVE(opponent, move == MOVE_QUICK_ATTACK ? MOVE_UPPER_HAND : MOVE_KARATE_CHOP); }
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Upper Hand fails if the target has attempted to act even if previously successful")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_EXTREME_SPEED) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(GetMovePriority(MOVE_EXTREME_SPEED) == 2);
|
||||
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
|
||||
PLAYER(SPECIES_MIENSHAO);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_EXTREME_SPEED, target: playerLeft); MOVE(playerLeft, MOVE_UPPER_HAND, target: opponentLeft); MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_UPPER_HAND, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
MESSAGE("The opposing Wobbuffet flinched and couldn't move!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EXTREME_SPEED, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerRight);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_UPPER_HAND, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,3 +22,35 @@ DOUBLE_BATTLE_TEST("Flame Burst Substitute")
|
||||
NOT MESSAGE("The substitute took damage for the opposing Wynaut!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Flame Burst doesn't crash, opponent to player")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_FLAME_BURST, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAME_BURST, opponentRight);
|
||||
HP_BAR(playerRight);
|
||||
MESSAGE("Wobbuffet fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Flame Burst doesn't crash, player to opponent")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET)
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_FLAME_BURST, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAME_BURST, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
MESSAGE("The opposing Wynaut fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,3 +132,19 @@ SINGLE_BATTLE_TEST("If Salt Cure faints the target, messages will be applied in
|
||||
MESSAGE("The opposing Wobbuffet fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Salt Cure works in double battles")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SALT_CURE, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SALT_CURE, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2560,6 +2560,9 @@ void UseItem(u32 sourceLine, struct BattlePokemon *battler, struct ItemContext c
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (ctx.explicitRNG)
|
||||
DATA.battleRecordTurns[DATA.turns][battlerId].rng = ctx.rng;
|
||||
PushBattlerAction(sourceLine, battlerId, RECORDED_ACTION_TYPE, B_ACTION_USE_ITEM);
|
||||
PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, (ctx.itemId >> 8) & 0xFF);
|
||||
PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, ctx.itemId & 0xFF);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user