Adds Commander and Order Up (#5246)

* Adds Commander

* review points

* new line

* correction

* regression / double targeting still broken

* fix wrong target order

* transform fixes

* haze test

* fixes, tests

* bring back wrongly removed else if case

* Eject Pack / Button test + fix

* red card fix

* test fixes

* Fixes Tatsu being hit by multi hit move

* change transform check

* fix test + revert change

* Fix Tatsugiri attacking after freed up from Dozo in the same turn

* Dragon Darts tests

* fix test

* review comments

* assumtion in wrong file

* Order Up test fixes

---------

Co-authored-by: hedara90 <90hedara@gmail.com>
This commit is contained in:
Alex 2024-09-29 22:45:50 +02:00 committed by GitHub
parent 8d33169100
commit 42c43a3f8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 872 additions and 44 deletions

View file

@ -1351,7 +1351,6 @@
.4byte \func .4byte \func
.endm .endm
@ callnative macros
.macro savetarget .macro savetarget
callnative BS_SaveTarget callnative BS_SaveTarget
.endm .endm
@ -1727,6 +1726,11 @@
.4byte \failInstr .4byte \failInstr
.endm .endm
.macro jumpifcommanderactive jumpInstr:req
callnative BS_JumpIfCommanderActive
.4byte \jumpInstr
.endm
@ various command changed to more readable macros @ various command changed to more readable macros
.macro cancelmultiturnmoves battler:req .macro cancelmultiturnmoves battler:req
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES

View file

@ -3265,6 +3265,7 @@ BattleScript_EffectRoar::
attackstring attackstring
ppreduce ppreduce
jumpifroarfails BattleScript_ButItFailed jumpifroarfails BattleScript_ButItFailed
jumpifcommanderactive BattleScript_ButItFailed
jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_ButItFailed jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_ButItFailed
jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut
jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted
@ -8008,11 +8009,52 @@ BattleScript_CostarActivates::
BattleScript_ZeroToHeroActivates:: BattleScript_ZeroToHeroActivates::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUpScripting
printstring STRINGID_ZEROTOHEROTRANSFORMATION printstring STRINGID_ZEROTOHEROTRANSFORMATION
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
end3 end3
BattleScript_CommanderActivates::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUpScripting
printstring STRINGID_COMMANDERACTIVATES
waitmessage B_WAIT_TIME_LONG
BattleScript_CommanderAtkIncrease:
setbyte sSTAT_ANIM_PLAYED, FALSE
playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_DEF | BIT_SPATK | BIT_SPDEF | BIT_SPEED, STAT_CHANGE_BY_TWO
setstatchanger STAT_ATK, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderDefIncrease
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderDefIncrease
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_CommanderDefIncrease:
setstatchanger STAT_DEF, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpAtkIncrease
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpAtkIncrease
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_CommanderSpAtkIncrease:
setstatchanger STAT_SPATK, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpDefIncrease
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpDefIncrease
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_CommanderSpDefIncrease:
setstatchanger STAT_SPDEF, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpeedIncrease
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpeedIncrease
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_CommanderSpeedIncrease:
setstatchanger STAT_SPEED, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderEnd
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderEnd
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_CommanderEnd:
restoreattacker
end3
BattleScript_HospitalityActivates:: BattleScript_HospitalityActivates::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
@ -9533,6 +9575,14 @@ BattleScript_StickyBarbTransfer::
removeitem BS_TARGET removeitem BS_TARGET
return return
BattleScript_RedCardActivationNoSwitch::
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT
printstring STRINGID_REDCARDACTIVATE
waitmessage B_WAIT_TIME_LONG
removeitem BS_SCRIPTING
restoretarget
return
BattleScript_RedCardActivates:: BattleScript_RedCardActivates::
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT
printstring STRINGID_REDCARDACTIVATE printstring STRINGID_REDCARDACTIVATE

View file

@ -201,10 +201,13 @@ struct ProtectStruct
u16 eatMirrorHerb:1; u16 eatMirrorHerb:1;
u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
u16 usedAllySwitch:1; u16 usedAllySwitch:1;
u16 padding:2;
// End of 16-bit bitfield
u32 physicalDmg; u32 physicalDmg;
u32 specialDmg; u32 specialDmg;
u8 physicalBattlerId; u8 physicalBattlerId;
u8 specialBattlerId; u8 specialBattlerId;
}; };
struct SpecialStatus struct SpecialStatus
@ -818,9 +821,13 @@ struct BattleStruct
u8 boosterEnergyActivates; u8 boosterEnergyActivates;
u8 distortedTypeMatchups; u8 distortedTypeMatchups;
u8 categoryOverride; // for Z-Moves and Max Moves u8 categoryOverride; // for Z-Moves and Max Moves
u8 commandingDondozo;
u16 commanderActive[NUM_BATTLE_SIDES];
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
u8 fickleBeamBoosted:1; u8 fickleBeamBoosted:1;
u8 obedienceResult:3; u8 obedienceResult:3;
u8 padding:4;
u8 usedEjectItem;
u8 usedMicleBerry; u8 usedMicleBerry;
}; };

View file

@ -57,6 +57,8 @@ bool32 IsMoveNotAllowedInSkyBattles(u32 move);
bool32 DoSwitchInAbilities(u32 battlerId); bool32 DoSwitchInAbilities(u32 battlerId);
u8 GetFirstFaintedPartyIndex(u8 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId);
bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler); bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler);
void SaveBattlerTarget(u32 battler);
void SaveBattlerAttacker(u32 battler);
extern void (* const gBattleScriptingCommandsTable[])(void); extern void (* const gBattleScriptingCommandsTable[])(void);
extern const struct StatFractions gAccuracyStageRatios[]; extern const struct StatFractions gAccuracyStageRatios[];

View file

@ -412,6 +412,7 @@ extern const u8 BattleScript_BattlerGotOverItsInfatuation[];
extern const u8 BattleScript_Pickpocket[]; extern const u8 BattleScript_Pickpocket[];
extern const u8 BattleScript_StickyBarbTransfer[]; extern const u8 BattleScript_StickyBarbTransfer[];
extern const u8 BattleScript_AttackerItemStatRaise[]; extern const u8 BattleScript_AttackerItemStatRaise[];
extern const u8 BattleScript_RedCardActivationNoSwitch[];
extern const u8 BattleScript_RedCardActivates[]; extern const u8 BattleScript_RedCardActivates[];
extern const u8 BattleScript_EjectButtonActivates[]; extern const u8 BattleScript_EjectButtonActivates[];
extern const u8 BattleScript_EjectPackActivate_Ret[]; extern const u8 BattleScript_EjectPackActivate_Ret[];
@ -477,6 +478,7 @@ extern const u8 BattleScript_CudChewActivates[];
extern const u8 BattleScript_SupremeOverlordActivates[]; extern const u8 BattleScript_SupremeOverlordActivates[];
extern const u8 BattleScript_CostarActivates[]; extern const u8 BattleScript_CostarActivates[];
extern const u8 BattleScript_ZeroToHeroActivates[]; extern const u8 BattleScript_ZeroToHeroActivates[];
extern const u8 BattleScript_CommanderActivates[];
extern const u8 BattleScript_HospitalityActivates[]; extern const u8 BattleScript_HospitalityActivates[];
extern const u8 BattleScript_ToxicDebrisActivates[]; extern const u8 BattleScript_ToxicDebrisActivates[];
extern const u8 BattleScript_EarthEaterActivates[]; extern const u8 BattleScript_EarthEaterActivates[];

View file

@ -166,7 +166,7 @@
#define STATUS3_YAWN_TURN(num) (((num) << 11) & STATUS3_YAWN) #define STATUS3_YAWN_TURN(num) (((num) << 11) & STATUS3_YAWN)
#define STATUS3_IMPRISONED_OTHERS (1 << 13) #define STATUS3_IMPRISONED_OTHERS (1 << 13)
#define STATUS3_GRUDGE (1 << 14) #define STATUS3_GRUDGE (1 << 14)
#define STATUS3___UNUSED (1 << 15) #define STATUS3_COMMANDER (1 << 15)
#define STATUS3_GASTRO_ACID (1 << 16) #define STATUS3_GASTRO_ACID (1 << 16)
#define STATUS3_EMBARGO (1 << 17) #define STATUS3_EMBARGO (1 << 17)
#define STATUS3_UNDERWATER (1 << 18) #define STATUS3_UNDERWATER (1 << 18)
@ -183,7 +183,8 @@
#define STATUS3_LASER_FOCUS (1 << 29) #define STATUS3_LASER_FOCUS (1 << 29)
#define STATUS3_POWER_TRICK (1 << 30) #define STATUS3_POWER_TRICK (1 << 30)
#define STATUS3_SKY_DROPPED (1 << 31) // Target of Sky Drop #define STATUS3_SKY_DROPPED (1 << 31) // Target of Sky Drop
#define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) #define STATUS3_SEMI_INVULNERABLE_NO_COMMANDER (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) // Exception for Transform / Imposter
#define STATUS3_SEMI_INVULNERABLE (STATUS3_SEMI_INVULNERABLE_NO_COMMANDER | STATUS3_COMMANDER)
#define STATUS4_ELECTRIFIED (1 << 0) #define STATUS4_ELECTRIFIED (1 << 0)
#define STATUS4_MUD_SPORT (1 << 1) // Only used if B_SPORT_TURNS < GEN_6 #define STATUS4_MUD_SPORT (1 << 1) // Only used if B_SPORT_TURNS < GEN_6
@ -401,8 +402,9 @@
#define MOVE_EFFECT_SECRET_POWER 77 #define MOVE_EFFECT_SECRET_POWER 77
#define MOVE_EFFECT_PSYCHIC_NOISE 78 #define MOVE_EFFECT_PSYCHIC_NOISE 78
#define MOVE_EFFECT_TERA_BLAST 79 #define MOVE_EFFECT_TERA_BLAST 79
#define MOVE_EFFECT_ORDER_UP 80
#define NUM_MOVE_EFFECTS 80 #define NUM_MOVE_EFFECTS 81
#define MOVE_EFFECT_AFFECTS_USER 0x2000 #define MOVE_EFFECT_AFFECTS_USER 0x2000
#define MOVE_EFFECT_CERTAIN 0x4000 #define MOVE_EFFECT_CERTAIN 0x4000

View file

@ -354,6 +354,7 @@ enum {
EFFECT_DRAGON_DARTS, EFFECT_DRAGON_DARTS,
EFFECT_GUARDIAN_OF_ALOLA, EFFECT_GUARDIAN_OF_ALOLA,
EFFECT_SHELL_SIDE_ARM, EFFECT_SHELL_SIDE_ARM,
EFFECT_ORDER_UP,
NUM_BATTLE_MOVE_EFFECTS, NUM_BATTLE_MOVE_EFFECTS,
}; };

View file

@ -712,8 +712,9 @@
#define STRINGID_FOGLIFTED 710 #define STRINGID_FOGLIFTED 710
#define STRINGID_PKMNMADESHELLGLEAM 711 #define STRINGID_PKMNMADESHELLGLEAM 711
#define STRINGID_FICKLEBEAMDOUBLED 712 #define STRINGID_FICKLEBEAMDOUBLED 712
#define STRINGID_COMMANDERACTIVATES 713
#define BATTLESTRINGS_COUNT 713 #define BATTLESTRINGS_COUNT 714
// This is the string id that gBattleStringsTable starts with. // This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table, // String ids before this (e.g. STRINGID_INTROMSG) are not in the table,

View file

@ -835,6 +835,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk))
RETURN_SCORE_MINUS(10); RETURN_SCORE_MINUS(10);
if (gBattleStruct->commandingDondozo & (1u << battlerDef))
RETURN_SCORE_MINUS(20);
// check if negates type // check if negates type
switch (effectiveness) switch (effectiveness)
{ {

View file

@ -412,6 +412,9 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
if (battlerDef == BATTLE_PARTNER(battlerAtk)) if (battlerDef == BATTLE_PARTNER(battlerAtk))
battlerDefAbility = aiData->abilities[battlerDef]; battlerDefAbility = aiData->abilities[battlerDef];
if (gBattleStruct->commandingDondozo & (1u << battlerDef))
return TRUE;
switch (battlerDefAbility) switch (battlerDefAbility)
{ {
case ABILITY_LIGHTNING_ROD: case ABILITY_LIGHTNING_ROD:
@ -1508,6 +1511,8 @@ bool32 IsSemiInvulnerable(u32 battlerDef, u32 move)
{ {
if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE)
return TRUE; return TRUE;
else if (gBattleStruct->commandingDondozo & (1u << battlerDef))
return TRUE;
else if (!gMovesInfo[move].damagesAirborne && gStatuses3[battlerDef] & STATUS3_ON_AIR) else if (!gMovesInfo[move].damagesAirborne && gStatuses3[battlerDef] & STATUS3_ON_AIR)
return TRUE; return TRUE;
else if (!gMovesInfo[move].damagesUnderwater && gStatuses3[battlerDef] & STATUS3_UNDERWATER) else if (!gMovesInfo[move].damagesUnderwater && gStatuses3[battlerDef] & STATUS3_UNDERWATER)

View file

@ -3343,6 +3343,16 @@ const u8* FaintClearSetData(u32 battler)
gBattleStruct->palaceFlags &= ~(1u << battler); gBattleStruct->palaceFlags &= ~(1u << battler);
gBattleStruct->boosterEnergyActivates &= ~(1u << battler); gBattleStruct->boosterEnergyActivates &= ~(1u << battler);
if (gBattleStruct->commanderActive[battler] != SPECIES_NONE)
{
u32 partner = BATTLE_PARTNER(battler);
if (IsBattlerAlive(partner))
{
BtlController_EmitSpriteInvisibility(partner, BUFFER_A, FALSE);
MarkBattlerForControllerExec(partner);
}
}
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
{ {
// User of sticky web fainted, so reset the stored battler ID // User of sticky web fainted, so reset the stored battler ID
@ -4194,7 +4204,7 @@ static void HandleTurnActionSelectionState(void)
|| gBattleStruct->absentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(position))) || gBattleStruct->absentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(position)))
|| gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED) || gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED)
{ {
if (gBattleStruct->absentBattlerFlags & (1u << battler)) if ((gBattleStruct->absentBattlerFlags & (1u << battler)) || (gBattleStruct->commandingDondozo & (1u << battler)))
{ {
gChosenActionByBattler[battler] = B_ACTION_NOTHING_FAINTED; gChosenActionByBattler[battler] = B_ACTION_NOTHING_FAINTED;
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
@ -5116,6 +5126,9 @@ static void TurnValuesCleanUp(bool8 var0)
if (gDisableStructs[i].substituteHP == 0) if (gDisableStructs[i].substituteHP == 0)
gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE;
if (!(gStatuses3[i] & STATUS3_COMMANDER))
gBattleStruct->commandingDondozo &= ~(1u << i);
gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF;
} }
@ -5124,6 +5137,7 @@ static void TurnValuesCleanUp(bool8 var0)
gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; gSideTimers[B_SIDE_PLAYER].followmeTimer = 0;
gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0;
gBattleStruct->usedEjectItem = 0;
gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller
} }

View file

@ -830,7 +830,8 @@ static const u8 sText_TargetIsBeingSaltCured[] = _("{B_DEF_NAME_WITH_PREFIX} is
static const u8 sText_TargetIsHurtBySaltCure[] = _("{B_DEF_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"); static const u8 sText_TargetIsHurtBySaltCure[] = _("{B_DEF_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!");
static const u8 sText_TargetCoveredInStickyCandySyrup[] = _("{B_DEF_NAME_WITH_PREFIX} got covered\nin sticky syrup!"); static const u8 sText_TargetCoveredInStickyCandySyrup[] = _("{B_DEF_NAME_WITH_PREFIX} got covered\nin sticky syrup!");
static const u8 sText_PkmnTellChillingReceptionJoke[] = _("{B_ATK_NAME_WITH_PREFIX} is preparing to tell a\nchillingly bad joke!"); static const u8 sText_PkmnTellChillingReceptionJoke[] = _("{B_ATK_NAME_WITH_PREFIX} is preparing to tell a\nchillingly bad joke!");
static const u8 sText_ZeroToHeroTransformation[] = _("{B_ATK_NAME_WITH_PREFIX} underwent a heroic\ntransformation!"); static const u8 sText_ZeroToHeroTransformation[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} underwent a heroic\ntransformation!");
static const u8 sText_CommanderActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} was swallowed by Dondozo\nand became Dondozo's commander!");
static const u8 sText_TheTwoMovesBecomeOne[] = _("The two moves become one!\nIt's a combined move!{PAUSE 16}"); static const u8 sText_TheTwoMovesBecomeOne[] = _("The two moves become one!\nIt's a combined move!{PAUSE 16}");
static const u8 sText_ARainbowAppearedOnSide[] = _("A rainbow appeared in the sky\non {B_ATK_TEAM2} team's side!"); static const u8 sText_ARainbowAppearedOnSide[] = _("A rainbow appeared in the sky\non {B_ATK_TEAM2} team's side!");
static const u8 sText_TheRainbowDisappeared[] = _("The rainbow on {B_ATK_TEAM2}\nside disappeared!"); static const u8 sText_TheRainbowDisappeared[] = _("The rainbow on {B_ATK_TEAM2}\nside disappeared!");
@ -869,6 +870,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
[STRINGID_ARAINBOWAPPEAREDONSIDE - BATTLESTRINGS_TABLE_START] = sText_ARainbowAppearedOnSide, [STRINGID_ARAINBOWAPPEAREDONSIDE - BATTLESTRINGS_TABLE_START] = sText_ARainbowAppearedOnSide,
[STRINGID_THETWOMOVESBECOMEONE - BATTLESTRINGS_TABLE_START] = sText_TheTwoMovesBecomeOne, [STRINGID_THETWOMOVESBECOMEONE - BATTLESTRINGS_TABLE_START] = sText_TheTwoMovesBecomeOne,
[STRINGID_ZEROTOHEROTRANSFORMATION - BATTLESTRINGS_TABLE_START] = sText_ZeroToHeroTransformation, [STRINGID_ZEROTOHEROTRANSFORMATION - BATTLESTRINGS_TABLE_START] = sText_ZeroToHeroTransformation,
[STRINGID_COMMANDERACTIVATES - BATTLESTRINGS_TABLE_START] = sText_CommanderActivates,
[STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE - BATTLESTRINGS_TABLE_START] = sText_PkmnTellChillingReceptionJoke, [STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE - BATTLESTRINGS_TABLE_START] = sText_PkmnTellChillingReceptionJoke,
[STRINGID_MOVEBLOCKEDBYDYNAMAX - BATTLESTRINGS_TABLE_START] = sText_MoveBlockedByDynamax, [STRINGID_MOVEBLOCKEDBYDYNAMAX - BATTLESTRINGS_TABLE_START] = sText_MoveBlockedByDynamax,
[STRINGID_TARGETISHURTBYSALTCURE - BATTLESTRINGS_TABLE_START] = sText_TargetIsHurtBySaltCure, [STRINGID_TARGETISHURTBYSALTCURE - BATTLESTRINGS_TABLE_START] = sText_TargetIsHurtBySaltCure,

View file

@ -337,8 +337,6 @@ static bool8 CanBurnHitThaw(u16 move);
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove); static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move); static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move);
static void SaveBattlerAttacker(u32 battler);
static void SaveBattlerTarget(u32 battler);
static void Cmd_attackcanceler(void); static void Cmd_attackcanceler(void);
static void Cmd_accuracycheck(void); static void Cmd_accuracycheck(void);
@ -1197,6 +1195,13 @@ static void Cmd_attackcanceler(void)
u16 attackerAbility = GetBattlerAbility(gBattlerAttacker); u16 attackerAbility = GetBattlerAbility(gBattlerAttacker);
u32 moveType = GetMoveType(gCurrentMove); u32 moveType = GetMoveType(gCurrentMove);
if (gBattleStruct->usedEjectItem & (1u << gBattlerAttacker))
{
gBattleStruct->usedEjectItem = 0;
gCurrentActionFuncId = B_ACTION_TRY_FINISH;
return;
}
// Weight-based moves are blocked by Dynamax. // Weight-based moves are blocked by Dynamax.
if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove)) if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove))
{ {
@ -1516,14 +1521,17 @@ static bool32 AccuracyCalcHelper(u16 move)
return TRUE; return TRUE;
} }
// If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits. // If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits.
else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD && (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)) else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD
&& !(gStatuses3[gBattlerTarget] & STATUS3_COMMANDER)
&& (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF))
{ {
if (!JumpIfMoveFailed(7, move)) if (!JumpIfMoveFailed(7, move))
RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD); RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD);
return TRUE; return TRUE;
} }
// If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits. // If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits.
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_NO_GUARD && (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)) else if (GetBattlerAbility(gBattlerTarget) == ABILITY_NO_GUARD
&& (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF))
{ {
if (!JumpIfMoveFailed(7, move)) if (!JumpIfMoveFailed(7, move))
RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD); RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD);
@ -1531,8 +1539,8 @@ static bool32 AccuracyCalcHelper(u16 move)
} }
// If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits. // If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits.
else if (gStatuses3[gBattlerTarget] & STATUS3_TELEKINESIS else if (gStatuses3[gBattlerTarget] & STATUS3_TELEKINESIS
&& !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE) && !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE)
&& gMovesInfo[move].effect != EFFECT_OHKO) && gMovesInfo[move].effect != EFFECT_OHKO)
{ {
JumpIfMoveFailed(7, move); JumpIfMoveFailed(7, move);
return TRUE; return TRUE;
@ -1544,10 +1552,11 @@ static bool32 AccuracyCalcHelper(u16 move)
return TRUE; return TRUE;
} }
if ((gStatuses3[gBattlerTarget] & STATUS3_PHANTOM_FORCE) if ((gStatuses3[gBattlerTarget] & STATUS3_COMMANDER)
|| ((gStatuses3[gBattlerTarget] & STATUS3_ON_AIR) && !(gMovesInfo[move].damagesAirborne || gMovesInfo[move].damagesAirborneDoubleDamage)) || (gStatuses3[gBattlerTarget] & STATUS3_PHANTOM_FORCE)
|| ((gStatuses3[gBattlerTarget] & STATUS3_UNDERGROUND) && !gMovesInfo[move].damagesUnderground) || ((gStatuses3[gBattlerTarget] & STATUS3_ON_AIR) && !(gMovesInfo[move].damagesAirborne || gMovesInfo[move].damagesAirborneDoubleDamage))
|| ((gStatuses3[gBattlerTarget] & STATUS3_UNDERWATER) && !gMovesInfo[move].damagesUnderwater)) || ((gStatuses3[gBattlerTarget] & STATUS3_UNDERGROUND) && !gMovesInfo[move].damagesUnderground)
|| ((gStatuses3[gBattlerTarget] & STATUS3_UNDERWATER) && !gMovesInfo[move].damagesUnderwater))
{ {
gMoveResultFlags |= MOVE_RESULT_MISSED; gMoveResultFlags |= MOVE_RESULT_MISSED;
JumpIfMoveFailed(7, move); JumpIfMoveFailed(7, move);
@ -2943,9 +2952,10 @@ void SetMoveEffect(bool32 primary, bool32 certain)
INCREMENT_RESET_RETURN INCREMENT_RESET_RETURN
if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT)
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) && TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& !primary && !(gMovesInfo[gCurrentMove].effect == EFFECT_ORDER_UP && gBattleStruct->commanderActive[gBattlerAttacker])
&& gBattleScripting.moveEffect != MOVE_EFFECT_CHARGING) && !primary
&& gBattleScripting.moveEffect != MOVE_EFFECT_CHARGING)
INCREMENT_RESET_RETURN INCREMENT_RESET_RETURN
if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint) if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
@ -3919,6 +3929,43 @@ void SetMoveEffect(bool32 primary, bool32 certain)
gBattlescriptCurrInstr = BattleScript_LowerAtkSpAtk; gBattlescriptCurrInstr = BattleScript_LowerAtkSpAtk;
} }
break; break;
case MOVE_EFFECT_ORDER_UP:
{
u32 stat = 0;
bool32 commanderAffected = TRUE;
switch (gBattleStruct->commanderActive[gEffectBattler])
{
case SPECIES_TATSUGIRI_CURLY:
stat = STAT_ATK;
break;
case SPECIES_TATSUGIRI_DROOPY:
stat = STAT_DEF;
break;
case SPECIES_TATSUGIRI_STRETCHY:
stat = STAT_SPEED;
break;
default:
commanderAffected = FALSE;
break;
}
if (!commanderAffected
|| NoAliveMonsForEitherParty()
|| ChangeStatBuffs(SET_STAT_BUFF_VALUE(1),
stat,
affectsUser | STAT_CHANGE_UPDATE_MOVE_EFFECT,
0) == STAT_CHANGE_DIDNT_WORK)
{
gBattlescriptCurrInstr++;
}
else
{
gBattleScripting.animArg1 = gBattleScripting.moveEffect & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN);
gBattleScripting.animArg2 = 0;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_StatUp;
}
}
break;
} }
} }
} }
@ -5482,17 +5529,17 @@ static bool32 TryKnockOffBattleScript(u32 battlerDef)
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent) static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent)
{ {
u32 i; u32 battler;
for (i = 0; i < MAX_BATTLERS_COUNT; i++) for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++)
{ {
if (i != gBattlerAttacker if (battler != gBattlerAttacker
&& !(excludeCurrent && i == gBattlerTarget) && !(excludeCurrent && battler == gBattlerTarget)
&& IsBattlerAlive(i) && IsBattlerAlive(battler)
&& !(gBattleStruct->targetsDone[gBattlerAttacker] & (1u << i)) && !(gBattleStruct->targetsDone[gBattlerAttacker] & (1u << battler))
&& (GetBattlerSide(i) != GetBattlerSide(gBattlerAttacker) || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) && (GetBattlerSide(battler) != GetBattlerSide(gBattlerAttacker) || moveTarget == MOVE_TARGET_FOES_AND_ALLY))
break; break;
} }
return i; return battler;
} }
static void Cmd_moveend(void) static void Cmd_moveend(void)
@ -6245,6 +6292,7 @@ static void Cmd_moveend(void)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
effect = TRUE; effect = TRUE;
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattleStruct->usedEjectItem |= 1u << battler;
if (ejectButtonBattlers & (1u << battler)) if (ejectButtonBattlers & (1u << battler))
{ {
gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; gBattlescriptCurrInstr = BattleScript_EjectButtonActivates;
@ -6314,8 +6362,15 @@ static void Cmd_moveend(void)
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE) if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RedCardActivates; if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE)
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; {
gBattlescriptCurrInstr = BattleScript_RedCardActivationNoSwitch;
}
else
{
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
}
effect = TRUE; effect = TRUE;
break; // Only fastest red card activates break; // Only fastest red card activates
} }
@ -6478,8 +6533,6 @@ static void Cmd_moveend(void)
&& (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn && (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
if (gBattleStruct->savedAttackerCount > 0) if (gBattleStruct->savedAttackerCount > 0)
{ {
// #if TESTING // #if TESTING
@ -6525,6 +6578,18 @@ static void Cmd_moveend(void)
if (B_CHARGE <= GEN_8 || moveType == TYPE_ELECTRIC) if (B_CHARGE <= GEN_8 || moveType == TYPE_ELECTRIC)
gStatuses3[gBattlerAttacker] &= ~(STATUS3_CHARGED_UP); gStatuses3[gBattlerAttacker] &= ~(STATUS3_CHARGED_UP);
memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts));
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleStruct->commanderActive[i] != SPECIES_NONE && !IsBattlerAlive(i))
{
u32 partner = BATTLE_PARTNER(i);
gBattleStruct->commanderActive[i] = SPECIES_NONE;
if (IsBattlerAlive(partner))
gStatuses3[partner] &= ~STATUS3_COMMANDER;
}
}
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_COUNT: case MOVEEND_COUNT:
@ -7425,6 +7490,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
switch (GetBattlerAbility(i)) switch (GetBattlerAbility(i))
{ {
case ABILITY_TRACE: case ABILITY_TRACE:
case ABILITY_COMMANDER:
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0)) if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0))
return TRUE; return TRUE;
break; break;
@ -12567,7 +12633,7 @@ static void Cmd_transformdataexecution(void)
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
if (gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED if (gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED
|| gBattleStruct->illusion[gBattlerTarget].on || gBattleStruct->illusion[gBattlerTarget].on
|| gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE) || gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER)
{ {
gMoveResultFlags |= MOVE_RESULT_FAILED; gMoveResultFlags |= MOVE_RESULT_FAILED;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TRANSFORM_FAILED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TRANSFORM_FAILED;
@ -13357,7 +13423,8 @@ static void Cmd_trysetperishsong(void)
{ {
if (gStatuses3[i] & STATUS3_PERISH_SONG if (gStatuses3[i] & STATUS3_PERISH_SONG
|| GetBattlerAbility(i) == ABILITY_SOUNDPROOF || GetBattlerAbility(i) == ABILITY_SOUNDPROOF
|| BlocksPrankster(gCurrentMove, gBattlerAttacker, i, TRUE)) || BlocksPrankster(gCurrentMove, gBattlerAttacker, i, TRUE)
|| gStatuses3[i] & STATUS3_COMMANDER)
{ {
notAffectedCount++; notAffectedCount++;
} }
@ -15767,7 +15834,7 @@ static void Cmd_callnative(void)
// Callnative Funcs // Callnative Funcs
static void SaveBattlerTarget(u32 battler) void SaveBattlerTarget(u32 battler)
{ {
if (gBattleStruct->savedTargetCount < NELEMS(gBattleStruct->savedBattlerTarget)) if (gBattleStruct->savedTargetCount < NELEMS(gBattleStruct->savedBattlerTarget))
gBattleStruct->savedBattlerTarget[gBattleStruct->savedTargetCount++] = battler; gBattleStruct->savedBattlerTarget[gBattleStruct->savedTargetCount++] = battler;
@ -15775,7 +15842,7 @@ static void SaveBattlerTarget(u32 battler)
DebugPrintfLevel(MGBA_LOG_WARN, "Attempting to exceed savedBattlerTarget array size!"); DebugPrintfLevel(MGBA_LOG_WARN, "Attempting to exceed savedBattlerTarget array size!");
} }
static void SaveBattlerAttacker(u32 battler) void SaveBattlerAttacker(u32 battler)
{ {
if (gBattleStruct->savedAttackerCount < NELEMS(gBattleStruct->savedBattlerAttacker)) if (gBattleStruct->savedAttackerCount < NELEMS(gBattleStruct->savedBattlerAttacker))
gBattleStruct->savedBattlerAttacker[gBattleStruct->savedAttackerCount++] = battler; gBattleStruct->savedBattlerAttacker[gBattleStruct->savedAttackerCount++] = battler;
@ -17344,3 +17411,15 @@ void BS_TryRevivalBlessing(void)
MarkBattlerForControllerExec(gBattlerAttacker); MarkBattlerForControllerExec(gBattlerAttacker);
} }
} }
void BS_JumpIfCommanderActive(void)
{
NATIVE_ARGS(const u8 *jumpInstr);
if (gBattleStruct->commanderActive[gBattlerTarget] != SPECIES_NONE)
gBattlescriptCurrInstr = cmd->jumpInstr;
else if (gStatuses3[gBattlerTarget] & STATUS3_COMMANDER)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
}

View file

@ -130,7 +130,9 @@ void HandleAction_UseMove(void)
u16 moveTarget; u16 moveTarget;
gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
if (gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker) || !IsBattlerAlive(gBattlerAttacker)) if (gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker)
|| gBattleStruct->commandingDondozo & (1u << gBattlerAttacker)
|| !IsBattlerAlive(gBattlerAttacker))
{ {
gCurrentActionFuncId = B_ACTION_FINISHED; gCurrentActionFuncId = B_ACTION_FINISHED;
return; return;
@ -4113,7 +4115,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
u32 moveType, move; u32 moveType, move;
u32 side; u32 side;
u32 i, j; u32 i, j;
u32 partner; u32 partner = 0;
struct Pokemon *mon; struct Pokemon *mon;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
@ -4404,7 +4406,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& !(gBattleMons[BATTLE_OPPOSITE(battler)].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE)) && !(gBattleMons[BATTLE_OPPOSITE(battler)].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& !(gBattleStruct->illusion[BATTLE_OPPOSITE(battler)].on) && !(gBattleStruct->illusion[BATTLE_OPPOSITE(battler)].on)
&& !(gStatuses3[BATTLE_OPPOSITE(battler)] & STATUS3_SEMI_INVULNERABLE)) && !(gStatuses3[BATTLE_OPPOSITE(battler)] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER))
{ {
gBattlerAttacker = battler; gBattlerAttacker = battler;
gBattlerTarget = BATTLE_OPPOSITE(battler); gBattlerTarget = BATTLE_OPPOSITE(battler);
@ -4907,7 +4909,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& !(gBattleStruct->transformZeroToHero[side] & (1u << gBattlerPartyIndexes[battler]))) && !(gBattleStruct->transformZeroToHero[side] & (1u << gBattlerPartyIndexes[battler])))
{ {
gSpecialStatuses[battler].switchInAbilityDone = TRUE; gSpecialStatuses[battler].switchInAbilityDone = TRUE;
gBattlerAttacker = battler;
gBattleStruct->transformZeroToHero[side] |= 1u << gBattlerPartyIndexes[battler]; gBattleStruct->transformZeroToHero[side] |= 1u << gBattlerPartyIndexes[battler];
BattleScriptPushCursorAndCallback(BattleScript_ZeroToHeroActivates); BattleScriptPushCursorAndCallback(BattleScript_ZeroToHeroActivates);
effect++; effect++;
@ -4980,6 +4981,28 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
effect++; effect++;
} }
break; break;
case ABILITY_COMMANDER:
partner = BATTLE_PARTNER(battler);
if (!gSpecialStatuses[battler].switchInAbilityDone
&& gBattleStruct->commanderActive[partner] == SPECIES_NONE
&& gBattleMons[partner].species == SPECIES_DONDOZO
&& GET_BASE_SPECIES_ID(GetMonData(GetPartyBattlerData(battler), MON_DATA_SPECIES)) == SPECIES_TATSUGIRI)
{
SaveBattlerAttacker(gBattlerAttacker);
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
gBattlerAttacker = partner;
gBattleStruct->commandingDondozo |= 1u << battler;
gBattleStruct->commanderActive[partner] = gBattleMons[battler].species;
gStatuses3[battler] |= STATUS3_COMMANDER;
if (gBattleMons[battler].status2 & STATUS2_CONFUSION
&& !(gStatuses4[battler] & STATUS4_INFINITE_CONFUSION))
gBattleMons[battler].status2 -= STATUS2_CONFUSION_TURN(1);
BtlController_EmitSpriteInvisibility(battler, BUFFER_A, TRUE);
MarkBattlerForControllerExec(battler);
BattleScriptPushCursorAndCallback(BattleScript_CommanderActivates);
effect++;
}
break;
} }
break; break;
case ABILITYEFFECT_ENDTURN: case ABILITYEFFECT_ENDTURN:
@ -6519,7 +6542,9 @@ u32 IsAbilityPreventingEscape(u32 battler)
bool32 CanBattlerEscape(u32 battler) // no ability check bool32 CanBattlerEscape(u32 battler) // no ability check
{ {
if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SHED_SHELL) if (gBattleStruct->commanderActive[battler] != SPECIES_NONE)
return FALSE;
else if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SHED_SHELL)
return TRUE; return TRUE;
else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
return TRUE; return TRUE;

View file

@ -2141,6 +2141,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.cantBeSwapped = TRUE, .cantBeSwapped = TRUE,
.cantBeTraced = TRUE, .cantBeTraced = TRUE,
.cantBeSuppressed = TRUE, .cantBeSuppressed = TRUE,
.cantBeOverwritten = TRUE,
}, },
[ABILITY_ELECTROMORPHOSIS] = [ABILITY_ELECTROMORPHOSIS] =

View file

@ -2255,4 +2255,10 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleScript = BattleScript_EffectHit, .battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
}, },
[EFFECT_ORDER_UP] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
}; };

View file

@ -19325,7 +19325,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.description = COMPOUND_STRING( .description = COMPOUND_STRING(
"Boosts a user's stats\n" "Boosts a user's stats\n"
"depending on Tatsugiri."), "depending on Tatsugiri."),
.effect = EFFECT_PLACEHOLDER, // EFFECT_ORDER_UP .effect = EFFECT_ORDER_UP,
.power = 80, .power = 80,
.type = TYPE_DRAGON, .type = TYPE_DRAGON,
.accuracy = 100, .accuracy = 100,
@ -19335,6 +19335,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.category = DAMAGE_CATEGORY_PHYSICAL, .category = DAMAGE_CATEGORY_PHYSICAL,
.mirrorMoveBanned = TRUE, .mirrorMoveBanned = TRUE,
.metronomeBanned = TRUE, .metronomeBanned = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_ORDER_UP,
.self = TRUE,
.chance = 100,
}),
.battleAnimScript = gBattleAnimMove_OrderUp, .battleAnimScript = gBattleAnimMove_OrderUp,
}, },

View file

@ -0,0 +1,423 @@
#include "global.h"
#include "test/battle.h"
DOUBLE_BATTLE_TEST("Commander will activate once Dondozo switches in")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { SWITCH(playerLeft, 2); }
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
}
}
DOUBLE_BATTLE_TEST("Commander increases all stats by 2 stages once it is triggered")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
MESSAGE("Dondozo's Attack sharply rose!");
MESSAGE("Dondozo's Defense sharply rose!");
MESSAGE("Dondozo's Sp. Atk sharply rose!");
MESSAGE("Dondozo's Sp. Def sharply rose!");
MESSAGE("Dondozo's Speed sharply rose!");
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri avoids moves targetted towards it")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft); MOVE(opponentRight, MOVE_POUND, target: playerRight); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft);
MESSAGE("Foe Wobbuffet's attack missed!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponentRight);
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri will still take residual damage from a field effect while inside Dondozo")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_TYRANITAR) { Ability(ABILITY_SAND_STREAM); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ABILITY_POPUP(opponentLeft, ABILITY_SAND_STREAM);
MESSAGE("Dondozo is buffeted by the sandstorm!");
MESSAGE("Tatsugiri is buffeted by the sandstorm!");
MESSAGE("Foe Wobbuffet is buffeted by the sandstorm!");
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri will still take poison damage if while inside Dondozo")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); Status1(STATUS1_POISON); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
MESSAGE("Tatsugiri is hurt by poison!");
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri still avoids moves even when the attacker has No Guard")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_MACHAMP) { Ability(ABILITY_NO_GUARD); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft);
MESSAGE("Foe Machamp's attack missed!");
}
}
DOUBLE_BATTLE_TEST("Commander cannot affect a Dondozo that was previously affected by Commander until it faints and revived")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_TATSUGIRI) { HP(1); Ability(ABILITY_COMMANDER); Status1(STATUS1_POISON); }
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerRight, MOVE_CELEBRATE); SWITCH(playerLeft, 2); SEND_OUT(playerLeft, 3); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
MESSAGE("Tatsugiri is hurt by poison!");
NONE_OF {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
}
}
}
DOUBLE_BATTLE_TEST("Commander prevents Whirlwind from working against Dondozo or Tatsugiri while it's active")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_WHIRLWIND, target: playerLeft); }
TURN { MOVE(opponentRight, MOVE_WHIRLWIND, target: playerRight); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
MESSAGE("Foe Wobbuffet used Whirlwind!");
MESSAGE("But it failed!");
MESSAGE("Foe Wobbuffet used Whirlwind!");
MESSAGE("But it failed!");
}
}
DOUBLE_BATTLE_TEST("Commander prevents Red Card from working while Commander is active")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft);
} THEN {
EXPECT(opponentLeft->item == ITEM_NONE);
EXPECT(playerRight->species == SPECIES_DONDOZO);
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri is not damaged by a double target move if Dondozo faints")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY);
PLAYER(SPECIES_DONDOZO) { HP(1); };
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SURF); SEND_OUT(playerLeft, 2); }
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
HP_BAR(playerLeft);
MESSAGE("Dondozo fainted!");
NOT HP_BAR(playerRight);
HP_BAR(opponentRight);
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri takes no damage from multi-target damaging moves")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SURF); MOVE(opponentRight, MOVE_SURF); SWITCH(playerLeft, 2); }
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, opponentLeft);
HP_BAR(playerLeft);
NOT HP_BAR(playerRight);
HP_BAR(opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, opponentRight);
HP_BAR(playerLeft);
HP_BAR(opponentLeft);
NOT HP_BAR(playerRight);
}
}
DOUBLE_BATTLE_TEST("Commander doesn't prevent Transform from working on a Commander Tatsugiri")
{
GIVEN {
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentRight, MOVE_TRANSFORM, target: playerRight); }
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponentRight);
}
}
DOUBLE_BATTLE_TEST("Commander doesn't prevent Imposter from working on a Commander Tatsugiri")
{
GIVEN {
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_DITTO) { Ability(ABILITY_IMPOSTER); }
} WHEN {
TURN { }
TURN { SWITCH(opponentRight, 2); }
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ABILITY_POPUP(opponentRight, ABILITY_IMPOSTER);
MESSAGE("Foe Ditto transformed into Tatsugiri using Imposter!");
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri is still affected by Haze while controlling Dondozo")
{
GIVEN {
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_PERISH_SONG); }
TURN {}
TURN {}
TURN {}
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_PERISH_SONG, opponentLeft);
MESSAGE("All affected POKéMON will faint in three turns!");
MESSAGE("Dondozo's PERISH count fell to 0!");
MESSAGE("Dondozo fainted!");
MESSAGE("Foe Wobbuffet's PERISH count fell to 0!");
MESSAGE("Foe Wobbuffet fainted!");
NONE_OF {
MESSAGE("Tatsugiri's PERISH count fell to 0!");
MESSAGE("Tatsugiri fainted!");
}
MESSAGE("Foe Wynaut's PERISH count fell to 0!");
MESSAGE("Foe Wynaut fainted!");
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri is still affected by Haze while controlling Dondozo")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerRight, MOVE_SWORDS_DANCE); }
TURN { SWITCH(playerLeft, 2); MOVE(opponentRight, MOVE_HAZE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, playerRight);
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_HAZE, opponentRight);
} THEN {
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
}
}
DOUBLE_BATTLE_TEST("Commander Attacker is kept (Dondozo Left Slot)")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentRight, MOVE_TACKLE, target: opponentLeft); }
TURN { SWITCH(playerLeft, 2); MOVE(opponentLeft, MOVE_SURF); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight);
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, opponentLeft);
HP_BAR(playerLeft);
MESSAGE("Foe Wobbuffet's attack missed!");
HP_BAR(opponentRight);
}
}
DOUBLE_BATTLE_TEST("Commander Attacker is kept (Dondozo Right Slot)")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentRight, MOVE_TACKLE, target: opponentLeft); }
TURN { SWITCH(playerRight, 2); MOVE(opponentLeft, MOVE_SURF); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight);
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
MESSAGE("Foe Wobbuffet's attack missed!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, opponentLeft);
HP_BAR(playerRight);
HP_BAR(opponentRight);
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri does not attack if Dondozo faints the same turn it's switched in")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
SWITCH(playerLeft, 2);
MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft);
MOVE(opponentRight, MOVE_TACKLE, target: playerRight);
MOVE(playerRight, MOVE_CELEBRATE);
SEND_OUT(playerLeft, 0);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft);
HP_BAR(playerLeft);
MESSAGE("Dondozo fainted!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight);
HP_BAR(playerRight);
NOT MESSAGE("Tatsugiri used Celebrate!");
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri does not get hit by Dragon Darts when a commanded Dondozo faints")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_DRAGON_DARTS].effect == EFFECT_DRAGON_DARTS);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DONDOZO) { HP(1); }
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { SWITCH(playerLeft, 2); MOVE(opponentRight, MOVE_DRAGON_DARTS, target: playerRight); SEND_OUT(playerRight, 0); }
} SCENE {
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, opponentRight);
MESSAGE("Dondozo fainted!");
NOT HP_BAR(playerLeft);
}
}
DOUBLE_BATTLE_TEST("Commander Tatsugiri does not get hit by Dragon Darts when commanding Dondozo")
{
bool32 targetPlayerRight;
PARAMETRIZE { targetPlayerRight = TRUE; }
PARAMETRIZE { targetPlayerRight = FALSE; }
GIVEN {
ASSUME(gMovesInfo[MOVE_DRAGON_DARTS].effect == EFFECT_DRAGON_DARTS);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
if (targetPlayerRight == TRUE)
TURN { MOVE(opponentRight, MOVE_DRAGON_DARTS, target: playerRight); }
else
TURN { MOVE(opponentRight, MOVE_DRAGON_DARTS, target: playerLeft); }
} SCENE {
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, opponentRight);
HP_BAR(playerRight);
NOT HP_BAR(playerLeft);
HP_BAR(playerRight);
NOT HP_BAR(playerLeft);
}
}

View file

@ -208,3 +208,27 @@ SINGLE_BATTLE_TEST("Eject Button is not triggered after High Jump Kick crash dam
} }
} }
} }
DOUBLE_BATTLE_TEST("Eject Button activation will not trigger an attack from the incoming mon")
{
GIVEN {
PLAYER(SPECIES_TATSUGIRI) { Speed(10); Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Item(ITEM_EJECT_BUTTON); }
PLAYER(SPECIES_DONDOZO) { Speed(20); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Item(ITEM_EJECT_PACK); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(10); }
OPPONENT(SPECIES_WYNAUT) { Speed(1); }
} WHEN {
TURN { MOVE(opponentRight, MOVE_MAKE_IT_RAIN); SEND_OUT(playerRight, 2); SEND_OUT(opponentRight, 2); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAKE_IT_RAIN, opponentRight);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight);
MESSAGE("Wobbuffet is switched out with the Eject Button!");
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft);
MESSAGE("Wobbuffet is switched out with the Eject Pack!");
}
}
}

View file

@ -0,0 +1,172 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_ORDER_UP].additionalEffects[0].moveEffect == MOVE_EFFECT_ORDER_UP);
}
DOUBLE_BATTLE_TEST("Order Up increases a stat based on Tatsugiri's form")
{
u32 species = 0;
PARAMETRIZE { species = SPECIES_TATSUGIRI_CURLY; }
PARAMETRIZE { species = SPECIES_TATSUGIRI_DROOPY; }
PARAMETRIZE { species = SPECIES_TATSUGIRI_STRETCHY; }
GIVEN {
PLAYER(species) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); };
} WHEN {
TURN { MOVE(opponentRight, MOVE_HAZE); MOVE(playerRight, MOVE_ORDER_UP, target: opponentLeft); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HAZE, opponentRight); // Remove previous stat boosts
ANIMATION(ANIM_TYPE_MOVE, MOVE_ORDER_UP, playerRight);
switch (species)
{
case SPECIES_TATSUGIRI_CURLY:
MESSAGE("Dondozo's Attack rose!");
break;
case SPECIES_TATSUGIRI_DROOPY:
MESSAGE("Dondozo's Defense rose!");
break;
case SPECIES_TATSUGIRI_STRETCHY:
MESSAGE("Dondozo's Speed rose!");
break;
}
} THEN {
switch (species)
{
case SPECIES_TATSUGIRI_CURLY:
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
break;
case SPECIES_TATSUGIRI_DROOPY:
EXPECT_EQ(playerRight->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
break;
case SPECIES_TATSUGIRI_STRETCHY:
EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
break;
}
}
}
DOUBLE_BATTLE_TEST("Order Up increases a stat based on Tatsugiri's form even if Tatsugiri fainted inside Dondozo")
{
u32 species = 0;
PARAMETRIZE { species = SPECIES_TATSUGIRI_CURLY; }
PARAMETRIZE { species = SPECIES_TATSUGIRI_DROOPY; }
PARAMETRIZE { species = SPECIES_TATSUGIRI_STRETCHY; }
GIVEN {
PLAYER(species) { HP(1); Status1(STATUS1_POISON); Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); };
} WHEN {
TURN { }
TURN { MOVE(opponentRight, MOVE_HAZE); MOVE(playerRight, MOVE_ORDER_UP, target: opponentLeft); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_COMMANDER);
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
MESSAGE("Tatsugiri is hurt by poison!");
MESSAGE("Tatsugiri fainted!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_HAZE, opponentRight); // Remove previous stat boosts
ANIMATION(ANIM_TYPE_MOVE, MOVE_ORDER_UP, playerRight);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
switch (species)
{
case SPECIES_TATSUGIRI_CURLY:
MESSAGE("Dondozo's Attack rose!");
break;
case SPECIES_TATSUGIRI_DROOPY:
MESSAGE("Dondozo's Defense rose!");
break;
case SPECIES_TATSUGIRI_STRETCHY:
MESSAGE("Dondozo's Speed rose!");
break;
}
} THEN {
switch (species)
{
case SPECIES_TATSUGIRI_CURLY:
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
break;
case SPECIES_TATSUGIRI_DROOPY:
EXPECT_EQ(playerRight->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
break;
case SPECIES_TATSUGIRI_STRETCHY:
EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
break;
}
}
}
DOUBLE_BATTLE_TEST("Order up does not boosts any stats if Dondozo is not affected by Commander")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DONDOZO);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerRight, MOVE_ORDER_UP, target: opponentLeft); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
}
}
DOUBLE_BATTLE_TEST("Order Up is boosted by Sheer Force without removing the stat boosting effect")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_ENTRAINMENT].effect == EFFECT_ENTRAINMENT);
PLAYER(SPECIES_DONDOZO) { Speed(10); }
PLAYER(SPECIES_TATSUGIRI_CURLY) { Speed(9); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(8); }
OPPONENT(SPECIES_TAUROS) { Speed(21); Ability(ABILITY_SHEER_FORCE); }
} WHEN {
TURN { MOVE(opponentRight, MOVE_ENTRAINMENT, target: playerLeft); MOVE(playerLeft, MOVE_ORDER_UP, target: opponentLeft); }
} SCENE {
MESSAGE("Foe Tauros used Entrainment!");
MESSAGE("Dondozo acquired Sheer Force!");
MESSAGE("Dondozo used Order Up!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
}
}
DOUBLE_BATTLE_TEST("Order Up is always boosted by Sheer Force", s16 damage)
{
u32 move;
u32 ability;
PARAMETRIZE(move = MOVE_CELEBRATE, ability = ABILITY_STORM_DRAIN);
PARAMETRIZE(move = MOVE_ENTRAINMENT, ability = ABILITY_STORM_DRAIN);
PARAMETRIZE(move = MOVE_ENTRAINMENT, ability = ABILITY_COMMANDER);
GIVEN {
ASSUME(gMovesInfo[MOVE_HAZE].effect == EFFECT_HAZE);
ASSUME(gMovesInfo[MOVE_ENTRAINMENT].effect == EFFECT_ENTRAINMENT);
PLAYER(SPECIES_DONDOZO) { Speed(10); }
PLAYER(SPECIES_TATSUGIRI_CURLY) { Speed(9); Ability(ability); }
OPPONENT(SPECIES_TAUROS) { Speed(21); Ability(ABILITY_SHEER_FORCE); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(22); }
} WHEN {
TURN { MOVE(opponentRight, MOVE_HAZE);
MOVE(opponentLeft, move, target: playerLeft);
MOVE(playerLeft, MOVE_ORDER_UP, target: opponentRight); }
} SCENE {
MESSAGE("Foe Wobbuffet used Haze!");
if (move == MOVE_ENTRAINMENT)
{
MESSAGE("Foe Tauros used Entrainment!");
MESSAGE("Dondozo acquired Sheer Force!");
}
MESSAGE("Dondozo used Order Up!");
HP_BAR(opponentRight, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(1.3), results[1].damage);
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(1.3), results[2].damage);
}
}