Refactors Attackstring and PP deduction (#7402)
This commit is contained in:
parent
a8e60a8ba3
commit
0422340356
@ -9,11 +9,11 @@
|
||||
.2byte \move
|
||||
.endm
|
||||
|
||||
.macro attackstring
|
||||
.macro printattackstring
|
||||
.byte 0x2
|
||||
.endm
|
||||
|
||||
.macro ppreduce
|
||||
.macro unused0x3
|
||||
.byte 0x3
|
||||
.endm
|
||||
|
||||
@ -877,7 +877,7 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro metronome
|
||||
.macro setcalledmove
|
||||
.byte 0x9e
|
||||
.endm
|
||||
|
||||
@ -1453,11 +1453,6 @@
|
||||
.4byte \sidestatus
|
||||
.endm
|
||||
|
||||
.macro trycopycat failInstr:req
|
||||
callnative BS_TryCopycat
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro setzeffect
|
||||
callnative BS_SetZEffect
|
||||
.endm
|
||||
@ -2207,11 +2202,6 @@
|
||||
callnative BS_InvertStatStages
|
||||
.endm
|
||||
|
||||
.macro trymefirst failInstr:req
|
||||
callnative BS_TryMeFirst
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro tryelectrify failInstr:req
|
||||
callnative BS_TryElectrify
|
||||
.4byte \failInstr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -96,11 +96,11 @@ Each move's effect is governed by a script defined here. For a simple example, l
|
||||
```
|
||||
BattleScript_EffectFirstTurnOnly::
|
||||
attackcanceler
|
||||
jumpifnotfirstturn BattleScript_FailedFromAtkString
|
||||
jumpifnotfirstturn BattleScript_ButItFailed
|
||||
goto BattleScript_EffectHit
|
||||
```
|
||||
|
||||
`attackcanceler` is a command that covers all the cases that could cause a move to fail before it's even attempted (e.g. paralysis). And as we can tell from the commands, if it's not the first turn, we go to `BattleScript_FailedFromAtkString` which evidently causes us to print the `attackstring` ("POKEMON used MOVE") then fail ("But it failed!"). Otherwise, we go to the generic "hit" effect which is the same script for moves that just deal damage and nothing else.
|
||||
`attackcanceler` is a command that covers all the cases that could cause a move to fail before it's even attempted (e.g. paralysis). And as we can tell from the commands, if it's not the first turn, we go to `BattleScript_ButItFailed` which evidently causes us to print the `attackstring` ("POKEMON used MOVE") then fail ("But it failed!"). Otherwise, we go to the generic "hit" effect which is the same script for moves that just deal damage and nothing else.
|
||||
|
||||
This is the most advanced part of the ROM. There are dozens upon dozens of commands and hundreds of scripts so this guide would go on forever if I were to go into more detail. To learn how these scripts work, it's best to look at a few examples of moves you know.
|
||||
|
||||
|
||||
@ -151,11 +151,10 @@ struct ProtectStruct
|
||||
u32 unableToUseMove:1; // Not to be confused with HITMARKER_UNABLE_TO_USE_MOVE (It is questionable though if there is a difference. Needs further research)
|
||||
u32 notFirstStrike:1;
|
||||
u32 palaceUnableToUseMove:1;
|
||||
u32 powderSelfDmg:1;
|
||||
u32 statRaised:1;
|
||||
u32 usedCustapBerry:1; // also quick claw
|
||||
u32 touchedProtectLike:1;
|
||||
u32 unused:8;
|
||||
u32 unused:9;
|
||||
// End of 32-bit bitfield
|
||||
u16 disableEjectPack:1;
|
||||
u16 tryEjectPack:1;
|
||||
@ -666,7 +665,7 @@ struct BattleStruct
|
||||
u8 multipleSwitchInState:2;
|
||||
u8 multipleSwitchInCursor:3;
|
||||
u8 sleepClauseNotBlocked:1;
|
||||
u8 padding1:1;
|
||||
u8 isSkyBattle:1;
|
||||
u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT];
|
||||
void (*savedCallback)(void);
|
||||
u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle
|
||||
@ -745,7 +744,6 @@ struct BattleStruct
|
||||
u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies.
|
||||
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
|
||||
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
|
||||
u8 isSkyBattle:1;
|
||||
s32 aiDelayTimer; // Counts number of frames AI takes to choose an action.
|
||||
s32 aiDelayFrames; // Number of frames it took to choose an action.
|
||||
s32 aiDelayCycles; // Number of cycles it took to choose an action.
|
||||
@ -780,7 +778,8 @@ struct BattleStruct
|
||||
u8 hazardsQueue[NUM_BATTLE_SIDES][HAZARDS_MAX_COUNT];
|
||||
u8 numHazards[NUM_BATTLE_SIDES];
|
||||
u8 hazardsCounter:4; // Counter for applying hazard on switch in
|
||||
u8 padding2:4;
|
||||
enum SubmoveState submoveAnnouncement:2;
|
||||
u8 padding2:2;
|
||||
};
|
||||
|
||||
struct AiBattleData
|
||||
|
||||
@ -64,7 +64,6 @@ bool32 IsShieldsDownProtected(u32 battler, u32 ability);
|
||||
u32 IsAbilityStatusProtected(u32 battler, u32 ability);
|
||||
bool32 TryResetBattlerStatChanges(u8 battler);
|
||||
bool32 CanCamouflage(u8 battlerId);
|
||||
u32 GetNaturePowerMove(u32 battler);
|
||||
void StealTargetItem(u8 battlerStealer, u8 battlerItem);
|
||||
u8 GetCatchingBattler(void);
|
||||
u32 GetHighestStatId(u32 battlerId);
|
||||
|
||||
@ -9,11 +9,10 @@ extern const u8 BattleScript_NotAffected[];
|
||||
extern const u8 BattleScript_HitFromCritCalc[];
|
||||
extern const u8 BattleScript_MoveEnd[];
|
||||
extern const u8 BattleScript_MakeMoveMissed[];
|
||||
extern const u8 BattleScript_PrintMoveMissed[];
|
||||
extern const u8 BattleScript_MoveMissedPause[];
|
||||
extern const u8 BattleScript_MoveMissedPause[];
|
||||
extern const u8 BattleScript_MoveMissed[];
|
||||
extern const u8 BattleScript_FlingFailConsumeItem[];
|
||||
extern const u8 BattleScript_FailedFromAtkString[];
|
||||
extern const u8 BattleScript_FailedFromAtkCanceler[];
|
||||
extern const u8 BattleScript_ButItFailed[];
|
||||
extern const u8 BattleScript_StatUp[];
|
||||
@ -180,11 +179,8 @@ extern const u8 BattleScript_DroughtActivates[];
|
||||
extern const u8 BattleScript_TookAttack[];
|
||||
extern const u8 BattleScript_SturdyPreventsOHKO[];
|
||||
extern const u8 BattleScript_DampStopsExplosion[];
|
||||
extern const u8 BattleScript_MoveHPDrain_PPLoss[];
|
||||
extern const u8 BattleScript_MoveHPDrain[];
|
||||
extern const u8 BattleScript_MonMadeMoveUseless_PPLoss[];
|
||||
extern const u8 BattleScript_MonMadeMoveUseless[];
|
||||
extern const u8 BattleScript_FlashFireBoost_PPLoss[];
|
||||
extern const u8 BattleScript_FlashFireBoost[];
|
||||
extern const u8 BattleScript_AbilityNoStatLoss[];
|
||||
extern const u8 BattleScript_ItemNoStatLoss[];
|
||||
@ -279,7 +275,6 @@ extern const u8 BattleScript_WaterSportEnds[];
|
||||
extern const u8 BattleScript_SturdiedMsg[];
|
||||
extern const u8 BattleScript_GravityEnds[];
|
||||
extern const u8 BattleScript_MoveStatDrain[];
|
||||
extern const u8 BattleScript_MoveStatDrain_PPLoss[];
|
||||
extern const u8 BattleScript_TargetsStatWasMaxedOut[];
|
||||
extern const u8 BattleScript_AttackerAbilityStatRaise[];
|
||||
extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[];
|
||||
@ -328,7 +323,6 @@ extern const u8 BattleScript_ProteanActivates[];
|
||||
extern const u8 BattleScript_DazzlingProtected[];
|
||||
extern const u8 BattleScript_MoveUsedPsychicTerrainPrevents[];
|
||||
extern const u8 BattleScript_MoveUsedPowder[];
|
||||
extern const u8 BattleScript_ZMoveActivatePowder[];
|
||||
extern const u8 BattleScript_SelectingNotAllowedStuffCheeks[];
|
||||
extern const u8 BattleScript_SelectingNotAllowedStuffCheeksInPalace[];
|
||||
extern const u8 BattleScript_SelectingNotAllowedBelch[];
|
||||
@ -581,7 +575,6 @@ extern const u8 BattleScript_EffectAbsorb[];
|
||||
extern const u8 BattleScript_EffectAbsorbLiquidOoze[];
|
||||
extern const u8 BattleScript_EffectExplosion[];
|
||||
extern const u8 BattleScript_EffectDreamEater[];
|
||||
extern const u8 BattleScript_EffectMirrorMove[];
|
||||
extern const u8 BattleScript_EffectAttackUp[];
|
||||
extern const u8 BattleScript_EffectDefenseUp[];
|
||||
extern const u8 BattleScript_EffectSpeedUp[];
|
||||
@ -631,7 +624,6 @@ extern const u8 BattleScript_EffectTwoTurnsAttack[];
|
||||
extern const u8 BattleScript_EffectSubstitute[];
|
||||
extern const u8 BattleScript_EffectRage[];
|
||||
extern const u8 BattleScript_EffectMimic[];
|
||||
extern const u8 BattleScript_EffectMetronome[];
|
||||
extern const u8 BattleScript_EffectLeechSeed[];
|
||||
extern const u8 BattleScript_EffectDoNothing[];
|
||||
extern const u8 BattleScript_EffectHoldHands[];
|
||||
@ -645,7 +637,6 @@ extern const u8 BattleScript_EffectSnore[];
|
||||
extern const u8 BattleScript_EffectConversion2[];
|
||||
extern const u8 BattleScript_EffectLockOn[];
|
||||
extern const u8 BattleScript_EffectSketch[];
|
||||
extern const u8 BattleScript_EffectSleepTalk[];
|
||||
extern const u8 BattleScript_EffectDestinyBond[];
|
||||
extern const u8 BattleScript_EffectSpite[];
|
||||
extern const u8 BattleScript_EffectHealBell[];
|
||||
@ -700,14 +691,12 @@ extern const u8 BattleScript_EffectNonVolatileStatus[];
|
||||
extern const u8 BattleScript_EffectMemento[];
|
||||
extern const u8 BattleScript_EffectFocusPunch[];
|
||||
extern const u8 BattleScript_EffectFollowMe[];
|
||||
extern const u8 BattleScript_EffectNaturePower[];
|
||||
extern const u8 BattleScript_EffectCharge[];
|
||||
extern const u8 BattleScript_EffectTaunt[];
|
||||
extern const u8 BattleScript_EffectHelpingHand[];
|
||||
extern const u8 BattleScript_EffectTrick[];
|
||||
extern const u8 BattleScript_EffectRolePlay[];
|
||||
extern const u8 BattleScript_EffectWish[];
|
||||
extern const u8 BattleScript_EffectAssist[];
|
||||
extern const u8 BattleScript_EffectIngrain[];
|
||||
extern const u8 BattleScript_EffectMagicCoat[];
|
||||
extern const u8 BattleScript_EffectRecycle[];
|
||||
@ -768,7 +757,6 @@ extern const u8 BattleScript_EffectElectricTerrain[];
|
||||
extern const u8 BattleScript_EffectPsychicTerrain[];
|
||||
extern const u8 BattleScript_EffectAttackAccUp[];
|
||||
extern const u8 BattleScript_EffectAttackSpAttackUp[];
|
||||
extern const u8 BattleScript_EffectMeFirst[];
|
||||
extern const u8 BattleScript_EffectQuiverDance[];
|
||||
extern const u8 BattleScript_EffectCoil[];
|
||||
extern const u8 BattleScript_EffectElectrify[];
|
||||
@ -788,7 +776,6 @@ extern const u8 BattleScript_AbilityPreventsPhasingOutRet[];
|
||||
extern const u8 BattleScript_PrintMonIsRootedRet[];
|
||||
extern const u8 BattleScript_FinalGambit[];
|
||||
extern const u8 BattleScript_EffectAutotomize[];
|
||||
extern const u8 BattleScript_EffectCopycat[];
|
||||
extern const u8 BattleScript_EffectDefog[];
|
||||
extern const u8 BattleScript_EffectHitEnemyHealAlly[];
|
||||
extern const u8 BattleScript_EffectSynchronoise[];
|
||||
@ -865,5 +852,10 @@ extern const u8 BattleScript_FickleBeamDoubled[];
|
||||
extern const u8 BattleScript_QuestionForfeitBattle[];
|
||||
extern const u8 BattleScript_ForfeitBattleGaveMoney[];
|
||||
extern const u8 BattleScript_AbilityPopUp[];
|
||||
extern const u8 BattleScript_Attackstring[];
|
||||
extern const u8 BattleScript_SubmoveAttackstring[];
|
||||
extern const u8 BattleScript_MetronomeAttackstring[];
|
||||
extern const u8 BattleScript_SleepTalkAttackstring[];
|
||||
extern const u8 BattleScript_NaturePowerAttackstring[];
|
||||
|
||||
#endif // GUARD_BATTLE_SCRIPTS_H
|
||||
|
||||
@ -110,20 +110,25 @@ enum MoveSuccessOrder
|
||||
CANCELLER_SKY_DROP,
|
||||
CANCELLER_RECHARGE,
|
||||
CANCELLER_ASLEEP_OR_FROZEN,
|
||||
CANCELLER_POWER_POINTS,
|
||||
CANCELLER_OBEDIENCE,
|
||||
CANCELLER_TRUANT,
|
||||
CANCELLER_FLINCH,
|
||||
CANCELLER_DISABLED,
|
||||
CANCELLER_VOLATILE_BLOCKED,
|
||||
CANCELLER_VOLATILE_BLOCKED, // Gravity / Heal Block / Throat Chop
|
||||
CANCELLER_TAUNTED,
|
||||
CANCELLER_IMPRISONED,
|
||||
CANCELLER_CONFUSED,
|
||||
CANCELLER_PARALYSED,
|
||||
CANCELLER_INFATUATION,
|
||||
CANCELLER_BIDE,
|
||||
CANCELLER_Z_MOVES,
|
||||
CANCELLER_CHOICE_LOCK,
|
||||
CANCELLER_CALLSUBMOVE,
|
||||
CANCELLER_THAW,
|
||||
CANCELLER_STANCE_CHANGE_2,
|
||||
CANCELLER_CHOICE_LOCK,
|
||||
CANCELLER_ATTACKSTRING,
|
||||
CANCELLER_PPDEDUCTION,
|
||||
CANCELLER_WEATHER_PRIMAL,
|
||||
CANCELLER_DYNAMAX_BLOCKED,
|
||||
CANCELLER_POWDER_STATUS,
|
||||
@ -131,7 +136,6 @@ enum MoveSuccessOrder
|
||||
CANCELLER_PSYCHIC_TERRAIN,
|
||||
CANCELLER_EXPLODING_DAMP,
|
||||
CANCELLER_MULTIHIT_MOVES,
|
||||
CANCELLER_Z_MOVES,
|
||||
CANCELLER_MULTI_TARGET_MOVES,
|
||||
CANCELLER_END,
|
||||
};
|
||||
@ -149,7 +153,8 @@ enum Obedience
|
||||
enum MoveCanceller
|
||||
{
|
||||
MOVE_STEP_SUCCESS,
|
||||
MOVE_STEP_BREAK,
|
||||
MOVE_STEP_BREAK, // Breaks out of the function to run a script
|
||||
MOVE_STEP_FAILURE, // Same as break but breaks out of it due to move failure and jumps to script that handles the failure
|
||||
MOVE_STEP_REMOVES_STATUS,
|
||||
};
|
||||
|
||||
@ -238,7 +243,6 @@ u32 DoEndTurnEffects(void);
|
||||
bool32 HandleFaintedMonActions(void);
|
||||
void TryClearRageAndFuryCutter(void);
|
||||
enum MoveCanceller AtkCanceller_MoveSuccessOrder(void);
|
||||
void SetAtkCancellerForCalledMove(void);
|
||||
bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2);
|
||||
bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility);
|
||||
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option);
|
||||
@ -408,5 +412,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u
|
||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||
bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander);
|
||||
bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move);
|
||||
u32 GetNaturePowerMove(u32 battler);
|
||||
u32 GetNaturePowerMove(u32 battler);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
||||
@ -237,9 +237,9 @@ enum SemiInvulnerableExclusion
|
||||
#define HITMARKER_DESTINYBOND (1 << 6)
|
||||
#define HITMARKER_NO_ANIMATIONS (1 << 7) // set from battleSceneOff. Never changed during battle
|
||||
#define HITMARKER_IGNORE_SUBSTITUTE (1 << 8)
|
||||
#define HITMARKER_NO_ATTACKSTRING (1 << 9)
|
||||
#define HITMARKER_ATTACKSTRING_PRINTED (1 << 10)
|
||||
#define HITMARKER_NO_PPDEDUCT (1 << 11)
|
||||
#define HITMARKER_ATTACKSTRING_PRINTED (1 << 9)
|
||||
#define HITMARKER_UNUSED_10 (1 << 10)
|
||||
#define HITMARKER_UNUSED_11 (1 << 11)
|
||||
#define HITMARKER_UNUSED_12 (1 << 12)
|
||||
#define HITMARKER_STATUS_ABILITY_EFFECT (1 << 13)
|
||||
#define HITMARKER_UNUSED_14 (1 << 14)
|
||||
@ -251,7 +251,7 @@ enum SemiInvulnerableExclusion
|
||||
#define HITMARKER_PASSIVE_HP_UPDATE (1 << 20)
|
||||
#define HITMARKER_UNUSED_21 (1 << 21)
|
||||
#define HITMARKER_PLAYER_FAINTED (1 << 22)
|
||||
#define HITMARKER_ALLOW_NO_PP (1 << 23)
|
||||
#define HITMARKER_UNUSED_23 (1 << 23)
|
||||
#define HITMARKER_GRUDGE (1 << 24)
|
||||
#define HITMARKER_OBEYS (1 << 25)
|
||||
#define HITMARKER_UNUSED_26 (1 << 26)
|
||||
@ -679,4 +679,11 @@ enum __attribute__((packed)) CalcDamageState
|
||||
CHECK_ACCURACY,
|
||||
};
|
||||
|
||||
enum SubmoveState
|
||||
{
|
||||
SUBMOVE_NO_EFFECT,
|
||||
SUBMOVE_SUCCESS,
|
||||
SUBMOVE_FAILURE,
|
||||
};
|
||||
|
||||
#endif // GUARD_CONSTANTS_BATTLE_H
|
||||
|
||||
@ -226,7 +226,6 @@ enum StringID
|
||||
STRINGID_BUTNOTHINGHAPPENED,
|
||||
STRINGID_BUTITFAILED,
|
||||
STRINGID_ITHURTCONFUSION,
|
||||
STRINGID_MIRRORMOVEFAILED,
|
||||
STRINGID_STARTEDTORAIN,
|
||||
STRINGID_DOWNPOURSTARTED,
|
||||
STRINGID_RAINCONTINUES,
|
||||
|
||||
@ -870,10 +870,6 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
if (gBattleStruct->gimmick.usableGimmick[battlerAtk] && GetActiveGimmick(battlerAtk) == GIMMICK_NONE
|
||||
&& gBattleStruct->gimmick.usableGimmick[battlerAtk] != GIMMICK_NONE && considerGimmickAtk == USE_GIMMICK)
|
||||
{
|
||||
// Set Z-Move variables if needed
|
||||
if (gBattleStruct->gimmick.usableGimmick[battlerAtk] == GIMMICK_Z_MOVE && IsViableZMove(battlerAtk, move))
|
||||
gBattleStruct->zmove.baseMoves[battlerAtk] = move;
|
||||
|
||||
toggledGimmickAtk = TRUE;
|
||||
SetActiveGimmick(battlerAtk, gBattleStruct->gimmick.usableGimmick[battlerAtk]);
|
||||
}
|
||||
@ -973,7 +969,6 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
// Undo temporary settings
|
||||
gBattleStruct->dynamicMoveType = 0;
|
||||
gBattleStruct->swapDamageCategory = FALSE;
|
||||
gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE;
|
||||
if (toggledGimmickAtk)
|
||||
SetActiveGimmick(battlerAtk, GIMMICK_NONE);
|
||||
if (toggledGimmickDef)
|
||||
|
||||
@ -3982,8 +3982,8 @@ void BattleTurnPassed(void)
|
||||
gBattleStruct->faintedActionsState = 0;
|
||||
|
||||
TurnValuesCleanUp(FALSE);
|
||||
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
|
||||
gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gHitMarker &= ~HITMARKER_PLAYER_FAINTED;
|
||||
gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE;
|
||||
gBattleScripting.animTurn = 0;
|
||||
@ -5378,7 +5378,7 @@ static void RunTurnActionsFunctions(void)
|
||||
{
|
||||
if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battler
|
||||
{
|
||||
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,7 +385,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
|
||||
[STRINGID_BUTNOTHINGHAPPENED] = COMPOUND_STRING("But nothing happened!"),
|
||||
[STRINGID_BUTITFAILED] = COMPOUND_STRING("But it failed!"),
|
||||
[STRINGID_ITHURTCONFUSION] = COMPOUND_STRING("It hurt itself in its confusion!"),
|
||||
[STRINGID_MIRRORMOVEFAILED] = COMPOUND_STRING("The Mirror Move failed!"), //not in gen 5+, uses "but it failed"
|
||||
[STRINGID_STARTEDTORAIN] = COMPOUND_STRING("It started to rain!"),
|
||||
[STRINGID_DOWNPOURSTARTED] = COMPOUND_STRING("A downpour started!"), // corresponds to DownpourText in pokegold and pokecrystal and is used by Rain Dance in GSC
|
||||
[STRINGID_RAINCONTINUES] = COMPOUND_STRING("Rain continues to fall."), //not in gen 5+
|
||||
|
||||
@ -339,8 +339,8 @@ static bool32 CanAbilityShieldActivateForBattler(u32 battler);
|
||||
|
||||
static void Cmd_attackcanceler(void);
|
||||
static void Cmd_accuracycheck(void);
|
||||
static void Cmd_attackstring(void);
|
||||
static void Cmd_ppreduce(void);
|
||||
static void Cmd_printattackstring(void);
|
||||
static void Cmd_unused0x3(void);
|
||||
static void Cmd_critcalc(void);
|
||||
static void Cmd_damagecalc(void);
|
||||
static void Cmd_typecalc(void);
|
||||
@ -461,7 +461,7 @@ static void Cmd_tryexplosion(void);
|
||||
static void Cmd_setatkhptozero(void);
|
||||
static void Cmd_jumpifnexttargetvalid(void);
|
||||
static void Cmd_tryhealhalfhealth(void);
|
||||
static void Cmd_trymirrormove(void);
|
||||
static void Cmd_unused_0x7e(void);
|
||||
static void Cmd_setfieldweather(void);
|
||||
static void Cmd_setreflect(void);
|
||||
static void Cmd_setseeded(void);
|
||||
@ -495,7 +495,7 @@ static void Cmd_setfocusenergy(void);
|
||||
static void Cmd_transformdataexecution(void);
|
||||
static void Cmd_setsubstitute(void);
|
||||
static void Cmd_mimicattackcopy(void);
|
||||
static void Cmd_metronome(void);
|
||||
static void Cmd_setcalledmove(void);
|
||||
static void Cmd_unused_0x9f(void);
|
||||
static void Cmd_unused_0xA0(void);
|
||||
static void Cmd_counterdamagecalculator(void);
|
||||
@ -506,7 +506,7 @@ static void Cmd_painsplitdmgcalc(void);
|
||||
static void Cmd_settypetorandomresistance(void);
|
||||
static void Cmd_setalwayshitflag(void);
|
||||
static void Cmd_copymovepermanently(void);
|
||||
static void Cmd_trychoosesleeptalkmove(void);
|
||||
static void Cmd_unused_0xA9(void);
|
||||
static void Cmd_trysetdestinybond(void);
|
||||
static void Cmd_trysetdestinybondtohappen(void);
|
||||
static void Cmd_settailwind(void);
|
||||
@ -541,7 +541,7 @@ static void Cmd_unused_c8(void);
|
||||
static void Cmd_trymemento(void);
|
||||
static void Cmd_setforcedtarget(void);
|
||||
static void Cmd_setcharge(void);
|
||||
static void Cmd_callenvironmentattack(void);
|
||||
static void Cmd_unused_0xCC(void);
|
||||
static void Cmd_curestatuswithmove(void);
|
||||
static void Cmd_settorment(void);
|
||||
static void Cmd_jumpifnodamage(void);
|
||||
@ -559,7 +559,7 @@ static void Cmd_tryswapabilities(void);
|
||||
static void Cmd_tryimprison(void);
|
||||
static void Cmd_setstealthrock(void);
|
||||
static void Cmd_trysetvolatile(void);
|
||||
static void Cmd_assistattackselect(void);
|
||||
static void Cmd_unused_0xde(void);
|
||||
static void Cmd_trysetmagiccoat(void);
|
||||
static void Cmd_trysetsnatch(void);
|
||||
static void Cmd_unused2(void);
|
||||
@ -598,8 +598,8 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
{
|
||||
Cmd_attackcanceler, //0x0
|
||||
Cmd_accuracycheck, //0x1
|
||||
Cmd_attackstring, //0x2
|
||||
Cmd_ppreduce, //0x3
|
||||
Cmd_printattackstring, //0x2
|
||||
Cmd_unused0x3, //0x3
|
||||
Cmd_critcalc, //0x4
|
||||
Cmd_damagecalc, //0x5
|
||||
Cmd_typecalc, //0x6
|
||||
@ -720,7 +720,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_setatkhptozero, //0x79
|
||||
Cmd_jumpifnexttargetvalid, //0x7A
|
||||
Cmd_tryhealhalfhealth, //0x7B
|
||||
Cmd_trymirrormove, //0x7C
|
||||
Cmd_unused_0x7e, //0x7C
|
||||
Cmd_setfieldweather, //0x7D
|
||||
Cmd_setreflect, //0x7E
|
||||
Cmd_setseeded, //0x7F
|
||||
@ -754,7 +754,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_transformdataexecution, //0x9B
|
||||
Cmd_setsubstitute, //0x9C
|
||||
Cmd_mimicattackcopy, //0x9D
|
||||
Cmd_metronome, //0x9E
|
||||
Cmd_setcalledmove, //0x9E
|
||||
Cmd_unused_0x9f, //0x9F
|
||||
Cmd_unused_0xA0, //0xA0
|
||||
Cmd_counterdamagecalculator, //0xA1
|
||||
@ -765,7 +765,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_settypetorandomresistance, //0xA6
|
||||
Cmd_setalwayshitflag, //0xA7
|
||||
Cmd_copymovepermanently, //0xA8
|
||||
Cmd_trychoosesleeptalkmove, //0xA9
|
||||
Cmd_unused_0xA9, //0xA9
|
||||
Cmd_trysetdestinybond, //0xAA
|
||||
Cmd_trysetdestinybondtohappen, //0xAB
|
||||
Cmd_settailwind, //0xAC
|
||||
@ -800,7 +800,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_trymemento, //0xC9
|
||||
Cmd_setforcedtarget, //0xCA
|
||||
Cmd_setcharge, //0xCB
|
||||
Cmd_callenvironmentattack, //0xCC
|
||||
Cmd_unused_0xCC, //0xCC
|
||||
Cmd_curestatuswithmove, //0xCD
|
||||
Cmd_settorment, //0xCE
|
||||
Cmd_jumpifnodamage, //0xCF
|
||||
@ -818,7 +818,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_tryimprison, //0xDB
|
||||
Cmd_setstealthrock, //0xDC
|
||||
Cmd_trysetvolatile, //0xDD
|
||||
Cmd_assistattackselect, //0xDE
|
||||
Cmd_unused_0xde, //0xDE
|
||||
Cmd_trysetmagiccoat, //0xDF
|
||||
Cmd_trysetsnatch, //0xE0
|
||||
Cmd_unused2, //0xE1
|
||||
@ -1107,13 +1107,13 @@ static void Cmd_attackcanceler(void)
|
||||
|
||||
if (!IsBattlerAlive(gBattlerAttacker)
|
||||
&& effect != EFFECT_EXPLOSION
|
||||
&& effect != EFFECT_MISTY_EXPLOSION
|
||||
&& !(gHitMarker & HITMARKER_NO_ATTACKSTRING))
|
||||
&& effect != EFFECT_MISTY_EXPLOSION)
|
||||
{
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEnd;
|
||||
return;
|
||||
}
|
||||
|
||||
if (AtkCanceller_MoveSuccessOrder() != MOVE_STEP_SUCCESS)
|
||||
return;
|
||||
|
||||
@ -1129,7 +1129,6 @@ static void Cmd_attackcanceler(void)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
||||
if (CanAbilityBlockMove(
|
||||
gBattlerAttacker,
|
||||
@ -1155,17 +1154,6 @@ static void Cmd_attackcanceler(void)
|
||||
if (IsMovePowderBlocked(gBattlerAttacker, gBattlerTarget, gCurrentMove))
|
||||
return;
|
||||
|
||||
if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE
|
||||
&& !(gHitMarker & (HITMARKER_ALLOW_NO_PP | HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT))
|
||||
&& !(gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_NoPPForMove;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
}
|
||||
|
||||
gHitMarker &= ~HITMARKER_ALLOW_NO_PP;
|
||||
|
||||
// Check if no available target present on the field or if Sky Battles ban the move
|
||||
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
|
||||
&& (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)))
|
||||
@ -1176,7 +1164,7 @@ static void Cmd_attackcanceler(void)
|
||||
if (effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling.
|
||||
gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem;
|
||||
else
|
||||
gBattlescriptCurrInstr = BattleScript_FailedFromAtkString;
|
||||
gBattlescriptCurrInstr = BattleScript_ButItFailed;
|
||||
|
||||
if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
@ -1192,7 +1180,6 @@ static void Cmd_attackcanceler(void)
|
||||
// Edge case for bouncing a powder move against a grass type pokemon.
|
||||
|
||||
ClearDamageCalcResults();
|
||||
SetAtkCancellerForCalledMove();
|
||||
gEffectBattler = gBattlerTarget;
|
||||
if (BlocksPrankster(gCurrentMove, gBattlerTarget, gBattlerAttacker, TRUE))
|
||||
{
|
||||
@ -1226,7 +1213,6 @@ static void Cmd_attackcanceler(void)
|
||||
if (gBattleStruct->bouncedMoveIsUsed)
|
||||
{
|
||||
ClearDamageCalcResults();
|
||||
SetAtkCancellerForCalledMove(); // Edge case for bouncing a powder move against a grass type pokemon.
|
||||
BattleScriptCall(BattleScript_MagicBounce);
|
||||
gBattlerAbility = battler;
|
||||
return;
|
||||
@ -1489,76 +1475,20 @@ static void Cmd_accuracycheck(void)
|
||||
AccuracyCheck(FALSE, cmd->nextInstr, cmd->failInstr, cmd->move);
|
||||
}
|
||||
|
||||
static void Cmd_attackstring(void)
|
||||
static void Cmd_printattackstring(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
||||
if (gBattleControllerExecFlags)
|
||||
return;
|
||||
|
||||
if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED)))
|
||||
{
|
||||
PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker);
|
||||
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker);
|
||||
gBattleCommunication[MSG_DISPLAY] = 0;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_ppreduce(void)
|
||||
static void Cmd_unused0x3(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
||||
s32 i, ppToDeduct = 1;
|
||||
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
|
||||
if (gBattleControllerExecFlags)
|
||||
return;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
|
||||
if (moveTarget == MOVE_TARGET_BOTH
|
||||
|| moveTarget == MOVE_TARGET_FOES_AND_ALLY
|
||||
|| moveTarget == MOVE_TARGET_ALL_BATTLERS
|
||||
|| MoveForcesPressure(gCurrentMove))
|
||||
{
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (!IsBattlerAlly(i, gBattlerAttacker) && IsBattlerAlive(i))
|
||||
ppToDeduct += (GetBattlerAbility(i) == ABILITY_PRESSURE);
|
||||
}
|
||||
}
|
||||
else if (moveTarget != MOVE_TARGET_OPPONENTS_FIELD)
|
||||
{
|
||||
if (gBattlerAttacker != gBattlerTarget && GetBattlerAbility(gBattlerTarget) == ABILITY_PRESSURE)
|
||||
ppToDeduct++;
|
||||
}
|
||||
|
||||
if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBattlerAttacker].pp[gCurrMovePos])
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].notFirstStrike = TRUE;
|
||||
|
||||
// For item Metronome, echoed voice
|
||||
if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || WasUnableToUseMove(gBattlerAttacker))
|
||||
gBattleStruct->sameMoveTurns[gBattlerAttacker] = 0;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].pp[gCurrMovePos] > ppToDeduct)
|
||||
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] -= ppToDeduct;
|
||||
else
|
||||
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = 0;
|
||||
|
||||
if (MOVE_IS_PERMANENT(gBattlerAttacker, gCurrMovePos))
|
||||
{
|
||||
BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0,
|
||||
sizeof(gBattleMons[gBattlerAttacker].pp[gCurrMovePos]),
|
||||
&gBattleMons[gBattlerAttacker].pp[gCurrMovePos]);
|
||||
MarkBattlerForControllerExec(gBattlerAttacker);
|
||||
}
|
||||
}
|
||||
|
||||
gHitMarker &= ~HITMARKER_NO_PPDEDUCT;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// The chance is 1/N for each stage.
|
||||
@ -6354,11 +6284,9 @@ static void Cmd_moveend(void)
|
||||
&& IsDoubleBattle()
|
||||
&& !gProtectStructs[gBattlerAttacker].chargingTurn
|
||||
&& (moveTarget == MOVE_TARGET_BOTH
|
||||
|| moveTarget == MOVE_TARGET_FOES_AND_ALLY)
|
||||
&& !(gHitMarker & HITMARKER_NO_ATTACKSTRING))
|
||||
|| moveTarget == MOVE_TARGET_FOES_AND_ALLY))
|
||||
{
|
||||
u32 nextTarget = GetNextTarget(moveTarget, FALSE);
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
|
||||
if (nextTarget != MAX_BATTLERS_COUNT)
|
||||
{
|
||||
@ -6367,8 +6295,11 @@ static void Cmd_moveend(void)
|
||||
MoveValuesCleanUp();
|
||||
gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect;
|
||||
|
||||
if (moveEffect == EFFECT_EXPLOSION || moveEffect == EFFECT_MISTY_EXPLOSION // Edge case for Explosion not changing targets
|
||||
|| moveEffect == EFFECT_SYNCHRONOISE) // So we don't go back to the Synchronoise script
|
||||
// Edge cases for moves that shouldn't repeat their own script
|
||||
if (moveEffect == EFFECT_EXPLOSION
|
||||
|| moveEffect == EFFECT_MISTY_EXPLOSION
|
||||
|| moveEffect == EFFECT_MAGNITUDE
|
||||
|| moveEffect == EFFECT_SYNCHRONOISE)
|
||||
BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript);
|
||||
else
|
||||
BattleScriptPush(GetMoveBattleScript(gCurrentMove));
|
||||
@ -6398,9 +6329,6 @@ static void Cmd_moveend(void)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
|
||||
gHitMarker &= ~HITMARKER_NO_PPDEDUCT;
|
||||
}
|
||||
RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove);
|
||||
gBattleScripting.moveendState++;
|
||||
@ -6445,7 +6373,6 @@ static void Cmd_moveend(void)
|
||||
if (gSpecialStatuses[gBattlerAttacker].parentalBondState)
|
||||
gSpecialStatuses[gBattlerAttacker].parentalBondState--;
|
||||
|
||||
gHitMarker |= (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING);
|
||||
gBattleScripting.animTargetsHit = 0;
|
||||
gBattleScripting.moveendState = 0;
|
||||
gSpecialStatuses[gBattlerAttacker].multiHitOn = TRUE;
|
||||
@ -6879,7 +6806,6 @@ static void Cmd_moveend(void)
|
||||
gSpecialStatuses[gBattlerTarget].berryReduced = FALSE;
|
||||
gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_NONE;
|
||||
gBattleStruct->isAtkCancelerForCalledMove = FALSE;
|
||||
gBattleStruct->swapDamageCategory = FALSE;
|
||||
gBattleStruct->categoryOverride = FALSE;
|
||||
gBattleStruct->additionalEffectsCounter = 0;
|
||||
@ -8422,7 +8348,7 @@ static void ResetValuesForCalledMove(void)
|
||||
if (gBattlerByTurnOrder[gCurrentTurnActionNumber] != gBattlerAttacker)
|
||||
gBattleStruct->atkCancellerTracker = 0;
|
||||
else
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattleStruct->atkCancellerTracker = CANCELLER_VOLATILE_BLOCKED;
|
||||
gBattleScripting.animTurn = 0;
|
||||
gBattleScripting.animTargetsHit = 0;
|
||||
SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker);
|
||||
@ -9627,59 +9553,8 @@ static void Cmd_tryhealhalfhealth(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void SetMoveForMirrorMove(u32 move)
|
||||
static void Cmd_unused_0x7e(void)
|
||||
{
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
// Edge case, we used Z Mirror Move, got the stat boost and now need to use the Z-move
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move))
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move;
|
||||
gCurrentMove = GetTypeBasedZMove(move);
|
||||
}
|
||||
else
|
||||
{
|
||||
gCurrentMove = move;
|
||||
}
|
||||
|
||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
ResetValuesForCalledMove();
|
||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||
}
|
||||
|
||||
static void Cmd_trymirrormove(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
||||
s32 i, validMovesCount;
|
||||
u16 move;
|
||||
u16 validMoves[MAX_BATTLERS_COUNT] = {0};
|
||||
|
||||
for (validMovesCount = 0, i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (i != gBattlerAttacker)
|
||||
{
|
||||
move = gBattleStruct->lastTakenMoveFrom[gBattlerAttacker][i];
|
||||
if (move != MOVE_NONE && move != MOVE_UNAVAILABLE)
|
||||
{
|
||||
validMoves[validMovesCount] = move;
|
||||
validMovesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
move = gBattleStruct->lastTakenMove[gBattlerAttacker];
|
||||
if (move != MOVE_NONE && move != MOVE_UNAVAILABLE)
|
||||
{
|
||||
SetMoveForMirrorMove(move);
|
||||
}
|
||||
else if (validMovesCount != 0)
|
||||
{
|
||||
SetMoveForMirrorMove(validMoves[Random() % validMovesCount]);
|
||||
}
|
||||
else // no valid moves found
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
static void Cmd_setfieldweather(void)
|
||||
@ -11255,41 +11130,11 @@ static void Cmd_mimicattackcopy(void)
|
||||
}
|
||||
}
|
||||
|
||||
static bool32 InvalidMetronomeMove(u32 move)
|
||||
{
|
||||
return GetMoveEffect(move) == EFFECT_PLACEHOLDER
|
||||
|| IsMoveMetronomeBanned(move);
|
||||
}
|
||||
|
||||
static void Cmd_metronome(void)
|
||||
static void Cmd_setcalledmove(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
||||
#if B_METRONOME_MOVES >= GEN_9
|
||||
u32 moveCount = MOVES_COUNT_GEN9;
|
||||
#elif B_METRONOME_MOVES >= GEN_8
|
||||
u32 moveCount = MOVES_COUNT_GEN8;
|
||||
#elif B_METRONOME_MOVES >= GEN_7
|
||||
u32 moveCount = MOVES_COUNT_GEN7;
|
||||
#elif B_METRONOME_MOVES >= GEN_6
|
||||
u32 moveCount = MOVES_COUNT_GEN6;
|
||||
#elif B_METRONOME_MOVES >= GEN_5
|
||||
u32 moveCount = MOVES_COUNT_GEN5;
|
||||
#elif B_METRONOME_MOVES >= GEN_4
|
||||
u32 moveCount = MOVES_COUNT_GEN4;
|
||||
#elif B_METRONOME_MOVES >= GEN_3
|
||||
u32 moveCount = MOVES_COUNT_GEN3;
|
||||
#elif B_METRONOME_MOVES >= GEN_2
|
||||
u32 moveCount = MOVES_COUNT_GEN2;
|
||||
#else
|
||||
u32 moveCount = MOVES_COUNT_GEN1;
|
||||
#endif
|
||||
|
||||
gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove);
|
||||
PrepareStringBattle(STRINGID_WAGGLINGAFINGER, gBattlerAttacker);
|
||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
ResetValuesForCalledMove();
|
||||
gCurrentMove = gCalledMove;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_unused_0x9f(void)
|
||||
@ -11635,49 +11480,8 @@ static void Cmd_copymovepermanently(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void Cmd_trychoosesleeptalkmove(void)
|
||||
static void Cmd_unused_0xA9(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
|
||||
u32 i, unusableMovesBits = 0, movePosition;
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (IsMoveSleepTalkBanned(gBattleMons[gBattlerAttacker].moves[i])
|
||||
|| gBattleMoveEffects[GetMoveEffect(gBattleMons[gBattlerAttacker].moves[i])].twoTurnEffect)
|
||||
{
|
||||
unusableMovesBits |= (1 << (i));
|
||||
}
|
||||
}
|
||||
|
||||
unusableMovesBits = CheckMoveLimitations(gBattlerAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP | MOVE_LIMITATION_CHOICE_ITEM));
|
||||
if (unusableMovesBits == ALL_MOVES_MASK) // all 4 moves cannot be chosen
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else // at least one move can be chosen
|
||||
{
|
||||
// Set Sleep Talk as used move, so it works with Last Resort.
|
||||
gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos;
|
||||
do
|
||||
{
|
||||
movePosition = MOD(Random(), MAX_MON_MOVES);
|
||||
} while ((1u << movePosition) & unusableMovesBits);
|
||||
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gBattleMons[gBattlerAttacker].moves[movePosition]))
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[gBattlerAttacker] = gBattleMons[gBattlerAttacker].moves[movePosition];
|
||||
gCalledMove = GetTypeBasedZMove(gBattleMons[gBattlerAttacker].moves[movePosition]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gCalledMove = gBattleMons[gBattlerAttacker].moves[movePosition];
|
||||
}
|
||||
gCurrMovePos = movePosition;
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool32 IsDanamaxMonPresent(void)
|
||||
@ -12629,39 +12433,8 @@ static void Cmd_setcharge(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// Nature Power
|
||||
static void Cmd_callenvironmentattack(void)
|
||||
static void Cmd_unused_0xCC(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gCurrentMove = GetNaturePowerMove(gBattlerAttacker);
|
||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
BattleScriptPush(GetMoveBattleScript(gCurrentMove));
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
u32 GetNaturePowerMove(u32 battler)
|
||||
{
|
||||
u32 move = gBattleEnvironmentInfo[gBattleEnvironment].naturePower;
|
||||
if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)
|
||||
move = MOVE_MOONBLAST;
|
||||
else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
|
||||
move = MOVE_THUNDERBOLT;
|
||||
else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)
|
||||
move = MOVE_ENERGY_BALL;
|
||||
else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)
|
||||
move = MOVE_PSYCHIC;
|
||||
else if (gBattleEnvironmentInfo[gBattleEnvironment].naturePower == MOVE_NONE)
|
||||
move = MOVE_TRI_ATTACK;
|
||||
|
||||
if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE)
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move;
|
||||
move = GetTypeBasedZMove(move);
|
||||
}
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
static void Cmd_curestatuswithmove(void)
|
||||
@ -13192,53 +12965,8 @@ static void Cmd_trysetvolatile(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void Cmd_assistattackselect(void)
|
||||
static void Cmd_unused_0xde(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
|
||||
s32 chooseableMovesNo = 0;
|
||||
struct Pokemon *party;
|
||||
s32 monId, moveId;
|
||||
u16 *validMoves = Alloc(sizeof(u16) * PARTY_SIZE * MAX_MON_MOVES);
|
||||
|
||||
if (validMoves != NULL)
|
||||
{
|
||||
party = GetBattlerParty(gBattlerAttacker);
|
||||
|
||||
for (monId = 0; monId < PARTY_SIZE; monId++)
|
||||
{
|
||||
if (monId == gBattlerPartyIndexes[gBattlerAttacker])
|
||||
continue;
|
||||
if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE)
|
||||
continue;
|
||||
if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG)
|
||||
continue;
|
||||
|
||||
for (moveId = 0; moveId < MAX_MON_MOVES; moveId++)
|
||||
{
|
||||
u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
|
||||
|
||||
if (IsMoveAssistBanned(move))
|
||||
continue;
|
||||
|
||||
validMoves[chooseableMovesNo++] = move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chooseableMovesNo)
|
||||
{
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gCalledMove = validMoves[Random() % chooseableMovesNo];
|
||||
gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
|
||||
TRY_FREE_AND_SET_NULL(validMoves);
|
||||
}
|
||||
|
||||
static void Cmd_trysetmagiccoat(void)
|
||||
@ -15362,9 +15090,6 @@ void BS_SetPledge(void)
|
||||
|
||||
if (gBattleStruct->pledgeMove && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE))
|
||||
{
|
||||
PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker);
|
||||
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
|
||||
|
||||
if ((gCurrentMove == MOVE_GRASS_PLEDGE && partnerMove == MOVE_WATER_PLEDGE)
|
||||
|| (gCurrentMove == MOVE_WATER_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE))
|
||||
{
|
||||
@ -15531,36 +15256,6 @@ void BS_TryHealPulse(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BS_TryCopycat(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
|
||||
if (gLastUsedMove == MOVE_NONE || gLastUsedMove == MOVE_UNAVAILABLE || IsMoveCopycatBanned(gLastUsedMove) || IsZMove(gLastUsedMove))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gLastUsedMove))
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[gBattlerAttacker] = gLastUsedMove;
|
||||
gCalledMove = GetTypeBasedZMove(gLastUsedMove);
|
||||
}
|
||||
else if (IsMaxMove(gLastUsedMove))
|
||||
{
|
||||
gCalledMove = gBattleStruct->dynamax.lastUsedBaseMove;
|
||||
}
|
||||
else
|
||||
{
|
||||
gCalledMove = gLastUsedMove;
|
||||
}
|
||||
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
void BS_TryDefog(void)
|
||||
{
|
||||
NATIVE_ARGS(u8 clear, const u8 *failInstr);
|
||||
@ -17433,32 +17128,6 @@ void BS_InvertStatStages(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_TryMeFirst(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
u16 move = gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]];
|
||||
if (IsBattleMoveStatus(move) || IsMoveMeFirstBanned(move)
|
||||
|| GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move))
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move;
|
||||
gCalledMove = GetTypeBasedZMove(move);
|
||||
}
|
||||
else
|
||||
{
|
||||
gCalledMove = move;
|
||||
}
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
void BS_TryElectrify(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
@ -17571,7 +17240,6 @@ void BS_TryInstruct(void)
|
||||
else
|
||||
{
|
||||
gEffectBattler = gBattleStruct->lastMoveTarget[gBattlerTarget];
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget]);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "battle.h"
|
||||
#include "battle_anim.h"
|
||||
#include "battle_arena.h"
|
||||
#include "battle_environment.h"
|
||||
#include "battle_pyramid.h"
|
||||
#include "battle_util.h"
|
||||
#include "battle_controllers.h"
|
||||
@ -69,6 +70,14 @@ static bool32 IsAnyTargetAffected(u32 battlerAtk);
|
||||
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum FunctionCallOption option);
|
||||
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option);
|
||||
|
||||
// Submoves
|
||||
static u32 GetMirrorMoveMove(void);
|
||||
static u32 GetMetronomeMove(void);
|
||||
static u32 GetAssistMove(void);
|
||||
static u32 GetSleepTalkMove(void);
|
||||
static u32 GetCopyCatMove(void);
|
||||
static u32 GetMeFirstMove(void);
|
||||
|
||||
ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12(u32 percent);
|
||||
ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12_Floored(u32 percent);
|
||||
|
||||
@ -410,7 +419,6 @@ void HandleAction_UseMove(void)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].noValidMoves = FALSE;
|
||||
gCurrentMove = gChosenMove = MOVE_STRUGGLE;
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE);
|
||||
}
|
||||
else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gBattleMons[gBattlerAttacker].volatiles.recharge)
|
||||
@ -880,9 +888,8 @@ void HandleAction_NothingIsFainted(void)
|
||||
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
|
||||
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE;
|
||||
gHitMarker &= ~(HITMARKER_DESTINYBOND
|
||||
| HITMARKER_IGNORE_SUBSTITUTE
|
||||
| HITMARKER_ATTACKSTRING_PRINTED
|
||||
| HITMARKER_NO_PPDEDUCT
|
||||
| HITMARKER_IGNORE_SUBSTITUTE
|
||||
| HITMARKER_STATUS_ABILITY_EFFECT
|
||||
| HITMARKER_PASSIVE_HP_UPDATE
|
||||
| HITMARKER_OBEYS);
|
||||
@ -899,7 +906,6 @@ void HandleAction_ActionFinished(void)
|
||||
gHitMarker &= ~(HITMARKER_DESTINYBOND
|
||||
| HITMARKER_IGNORE_SUBSTITUTE
|
||||
| HITMARKER_ATTACKSTRING_PRINTED
|
||||
| HITMARKER_NO_PPDEDUCT
|
||||
| HITMARKER_STATUS_ABILITY_EFFECT
|
||||
| HITMARKER_PASSIVE_HP_UPDATE
|
||||
| HITMARKER_OBEYS
|
||||
@ -1152,7 +1158,6 @@ bool32 WasUnableToUseMove(u32 battler)
|
||||
{
|
||||
if (gProtectStructs[battler].nonVolatileStatusImmobility
|
||||
|| gProtectStructs[battler].unableToUseMove
|
||||
|| gProtectStructs[battler].powderSelfDmg
|
||||
|| gProtectStructs[battler].confusionSelfDmg)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
@ -1898,12 +1903,6 @@ static inline bool32 TryActivatePowderStatus(u32 move)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void SetAtkCancellerForCalledMove(void)
|
||||
{
|
||||
gBattleStruct->atkCancellerTracker = CANCELLER_VOLATILE_BLOCKED;
|
||||
gBattleStruct->isAtkCancelerForCalledMove = TRUE;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerFlags(void)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].volatiles.destinyBond = FALSE;
|
||||
@ -1914,7 +1913,7 @@ static enum MoveCanceller CancellerFlags(void)
|
||||
|
||||
static enum MoveCanceller CancellerStanceChangeOne(void)
|
||||
{
|
||||
if (B_STANCE_CHANGE_FAIL < GEN_7 && TryFormChangeBeforeMove())
|
||||
if (B_STANCE_CHANGE_FAIL < GEN_7 && gChosenMove == gCurrentMove && TryFormChangeBeforeMove())
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -1926,7 +1925,7 @@ static enum MoveCanceller CancellerSkyDrop(void)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEnd;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -1940,7 +1939,7 @@ static enum MoveCanceller CancellerRecharge(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -1996,7 +1995,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(void)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility = TRUE;
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsFrozen;
|
||||
gHitMarker |= (HITMARKER_NO_ATTACKSTRING | HITMARKER_UNABLE_TO_USE_MOVE);
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
}
|
||||
else // unfreeze
|
||||
{
|
||||
@ -2004,29 +2003,28 @@ static enum MoveCanceller CancellerAsleepOrFrozen(void)
|
||||
BattleScriptCall(BattleScript_MoveUsedUnfroze);
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED;
|
||||
}
|
||||
return MOVE_STEP_REMOVES_STATUS;
|
||||
return MOVE_STEP_REMOVES_STATUS; // Move failure but also removes status
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerObedience(void)
|
||||
{
|
||||
enum Obedience obedienceResult = GetAttackerObedienceForAction();
|
||||
if (!(gHitMarker & HITMARKER_NO_PPDEDUCT) // Don't check obedience after first hit of multi target move or multi hit moves
|
||||
&& !gBattleMons[gBattlerAttacker].volatiles.multipleTurns)
|
||||
if (!gBattleMons[gBattlerAttacker].volatiles.multipleTurns)
|
||||
{
|
||||
enum Obedience obedienceResult = GetAttackerObedienceForAction();
|
||||
switch (obedienceResult)
|
||||
{
|
||||
case OBEYS:
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
break;
|
||||
return MOVE_STEP_SUCCESS;
|
||||
case DISOBEYS_LOAFS:
|
||||
// Randomly select, then print a disobedient string
|
||||
// B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
break;
|
||||
return MOVE_STEP_FAILURE;
|
||||
case DISOBEYS_HITS_SELF:
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
struct DamageContext ctx;
|
||||
@ -2041,31 +2039,45 @@ static enum MoveCanceller CancellerObedience(void)
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
break;
|
||||
return MOVE_STEP_FAILURE; // Move doesn't fail but mon hits itself
|
||||
case DISOBEYS_FALL_ASLEEP:
|
||||
if (IsSleepClauseEnabled())
|
||||
gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE;
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
return MOVE_STEP_FAILURE;
|
||||
break;
|
||||
case DISOBEYS_WHILE_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
break;
|
||||
return MOVE_STEP_FAILURE;
|
||||
case DISOBEYS_RANDOM_MOVE:
|
||||
gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
|
||||
gCurrentMove = gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
||||
BattleScriptCall(BattleScript_IgnoresAndUsesRandomMove);
|
||||
gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
break;
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerPowerPoints(void)
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].pp[gCurrMovePos] == 0
|
||||
&& gCurrentMove != MOVE_STRUGGLE
|
||||
&& !gSpecialStatuses[gBattlerAttacker].dancerUsedMove
|
||||
&& !gBattleMons[gBattlerAttacker].volatiles.multipleTurns)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_NoPPForMove;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerTruant(void)
|
||||
{
|
||||
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
|
||||
@ -2076,7 +2088,7 @@ static enum MoveCanceller CancellerTruant(void)
|
||||
gBattlerAbility = gBattlerAttacker;
|
||||
gBattlescriptCurrInstr = BattleScript_TruantLoafingAround;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2089,7 +2101,7 @@ static enum MoveCanceller CancellerFlinch(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2103,7 +2115,7 @@ static enum MoveCanceller CancellerDisabled(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2117,7 +2129,7 @@ static enum MoveCanceller CancellerVolatileBlocked(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
else if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(gCurrentMove))
|
||||
{
|
||||
@ -2126,7 +2138,7 @@ static enum MoveCanceller CancellerVolatileBlocked(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer > gBattleTurnCounter && IsSoundMove(gCurrentMove))
|
||||
{
|
||||
@ -2134,7 +2146,7 @@ static enum MoveCanceller CancellerVolatileBlocked(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2160,16 +2172,13 @@ static enum MoveCanceller CancellerImprisoned(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerConfused(void)
|
||||
{
|
||||
if (gBattleStruct->isAtkCancelerForCalledMove)
|
||||
return MOVE_STEP_SUCCESS;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns)
|
||||
{
|
||||
if (!gBattleMons[gBattlerAttacker].volatiles.infiniteConfusion)
|
||||
@ -2211,8 +2220,7 @@ static enum MoveCanceller CancellerConfused(void)
|
||||
|
||||
static enum MoveCanceller CancellerParalysed(void)
|
||||
{
|
||||
if (!gBattleStruct->isAtkCancelerForCalledMove
|
||||
&& (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS)
|
||||
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS
|
||||
&& !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD))
|
||||
&& !RandomPercentage(RNG_PARALYSIS, 75))
|
||||
{
|
||||
@ -2221,19 +2229,20 @@ static enum MoveCanceller CancellerParalysed(void)
|
||||
//CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerInfatuation(void)
|
||||
{
|
||||
if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].volatiles.infatuation)
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.infatuation)
|
||||
{
|
||||
gBattleScripting.battler = gBattleMons[gBattlerAttacker].volatiles.infatuation - 1;
|
||||
if (!RandomPercentage(RNG_INFATUATION, 50))
|
||||
{
|
||||
BattleScriptCall(BattleScript_MoveUsedIsInLove);
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2242,8 +2251,8 @@ static enum MoveCanceller CancellerInfatuation(void)
|
||||
gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2267,17 +2276,122 @@ static enum MoveCanceller CancellerBide(void)
|
||||
if (gAbsentBattlerFlags & (1u << gBattlerTarget))
|
||||
gBattlerTarget = GetBattleMoveTarget(MOVE_BIDE, MOVE_TARGET_SELECTED + 1);
|
||||
gBattlescriptCurrInstr = BattleScript_BideAttack;
|
||||
return MOVE_STEP_BREAK; // Jumps to a different script but no failure
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerZMoves(void)
|
||||
{
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||
{
|
||||
// attacker has a queued z move
|
||||
RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_Z_CRYSTAL);
|
||||
SetGimmickAsActivated(gBattlerAttacker, GIMMICK_Z_MOVE);
|
||||
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
if (GetMoveCategory(gCurrentMove) == DAMAGE_CATEGORY_STATUS)
|
||||
BattleScriptCall(BattleScript_ZMoveActivateStatus);
|
||||
else
|
||||
BattleScriptCall(BattleScript_ZMoveActivateDamaging);
|
||||
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerChoiceLock(void)
|
||||
{
|
||||
u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker];
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
|
||||
|
||||
if (gChosenMove != MOVE_STRUGGLE
|
||||
&& (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE)
|
||||
&& (IsHoldEffectChoice(holdEffect) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS))
|
||||
*choicedMoveAtk = gChosenMove;
|
||||
|
||||
u32 moveIndex;
|
||||
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].moves[moveIndex] == *choicedMoveAtk)
|
||||
break;
|
||||
}
|
||||
|
||||
if (moveIndex == MAX_MON_MOVES)
|
||||
*choicedMoveAtk = MOVE_NONE;
|
||||
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerCallSubmove(void)
|
||||
{
|
||||
u32 noEffect = FALSE;
|
||||
u32 calledMove = MOVE_NONE;
|
||||
u32 effect = GetMoveEffect(gCurrentMove);
|
||||
const u8 *battleScript = NULL;
|
||||
battleScript = BattleScript_SubmoveAttackstring;
|
||||
|
||||
switch(effect)
|
||||
{
|
||||
case EFFECT_MIRROR_MOVE:
|
||||
calledMove = GetMirrorMoveMove();
|
||||
break;
|
||||
case EFFECT_METRONOME:
|
||||
calledMove = GetMetronomeMove();
|
||||
battleScript = BattleScript_MetronomeAttackstring;
|
||||
break;
|
||||
case EFFECT_ASSIST:
|
||||
calledMove = GetAssistMove();
|
||||
break;
|
||||
case EFFECT_NATURE_POWER:
|
||||
calledMove = GetNaturePowerMove(gBattlerAttacker);
|
||||
battleScript = BattleScript_NaturePowerAttackstring;
|
||||
break;
|
||||
case EFFECT_SLEEP_TALK:
|
||||
calledMove = GetSleepTalkMove();
|
||||
battleScript = BattleScript_SleepTalkAttackstring;
|
||||
break;
|
||||
case EFFECT_COPYCAT:
|
||||
calledMove = GetCopyCatMove();
|
||||
break;
|
||||
case EFFECT_ME_FIRST:
|
||||
calledMove = GetMeFirstMove();
|
||||
break;
|
||||
default:
|
||||
noEffect = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (noEffect)
|
||||
{
|
||||
gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT;
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
if (calledMove != MOVE_NONE)
|
||||
{
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(calledMove))
|
||||
calledMove = GetTypeBasedZMove(calledMove);
|
||||
if (effect == EFFECT_COPYCAT && IsMaxMove(calledMove))
|
||||
calledMove = gBattleStruct->dynamax.lastUsedBaseMove;
|
||||
|
||||
gBattleStruct->submoveAnnouncement = SUBMOVE_SUCCESS;
|
||||
gCalledMove = calledMove;
|
||||
BattleScriptCall(battleScript);
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
|
||||
gBattleStruct->submoveAnnouncement = SUBMOVE_FAILURE;
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerThaw(void)
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE)
|
||||
@ -2305,30 +2419,95 @@ static enum MoveCanceller CancellerThaw(void)
|
||||
|
||||
static enum MoveCanceller CancellerStanceChangeTwo(void)
|
||||
{
|
||||
if (B_STANCE_CHANGE_FAIL >= GEN_7 && !gBattleStruct->isAtkCancelerForCalledMove && TryFormChangeBeforeMove())
|
||||
if (B_STANCE_CHANGE_FAIL >= GEN_7 && gChosenMove == gCurrentMove && TryFormChangeBeforeMove())
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerChoiceLock(void)
|
||||
static enum MoveCanceller CancellerAttackstring(void)
|
||||
{
|
||||
u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker];
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
|
||||
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
|
||||
BattleScriptCall(BattleScript_Attackstring);
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
|
||||
if (gChosenMove != MOVE_STRUGGLE
|
||||
&& (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE)
|
||||
&& (IsHoldEffectChoice(holdEffect) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS))
|
||||
*choicedMoveAtk = gChosenMove;
|
||||
static enum MoveCanceller CancellerPPDeduction(void)
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns
|
||||
|| gSpecialStatuses[gBattlerAttacker].dancerUsedMove
|
||||
|| gCurrentMove == MOVE_STRUGGLE)
|
||||
return MOVE_STEP_SUCCESS;
|
||||
|
||||
u32 moveIndex;
|
||||
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
|
||||
s32 ppToDeduct = 1;
|
||||
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
u32 movePosition = gCurrMovePos;
|
||||
|
||||
if (gBattleStruct->submoveAnnouncement == SUBMOVE_SUCCESS)
|
||||
movePosition = gChosenMovePos;
|
||||
|
||||
if (moveTarget == MOVE_TARGET_BOTH
|
||||
|| moveTarget == MOVE_TARGET_FOES_AND_ALLY
|
||||
|| moveTarget == MOVE_TARGET_ALL_BATTLERS
|
||||
|| MoveForcesPressure(gCurrentMove))
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].moves[moveIndex] == *choicedMoveAtk)
|
||||
break;
|
||||
for (u32 i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (!IsBattlerAlly(i, gBattlerAttacker) && IsBattlerAlive(i))
|
||||
ppToDeduct += (GetBattlerAbility(i) == ABILITY_PRESSURE);
|
||||
}
|
||||
}
|
||||
else if (moveTarget != MOVE_TARGET_OPPONENTS_FIELD)
|
||||
{
|
||||
if (gBattlerAttacker != gBattlerTarget && GetBattlerAbility(gBattlerTarget) == ABILITY_PRESSURE)
|
||||
ppToDeduct++;
|
||||
}
|
||||
|
||||
if (moveIndex == MAX_MON_MOVES)
|
||||
*choicedMoveAtk = MOVE_NONE;
|
||||
gProtectStructs[gBattlerAttacker].notFirstStrike = TRUE;
|
||||
|
||||
// For item Metronome, echoed voice
|
||||
if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || WasUnableToUseMove(gBattlerAttacker))
|
||||
gBattleStruct->sameMoveTurns[gBattlerAttacker] = 0;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].pp[movePosition] > ppToDeduct)
|
||||
gBattleMons[gBattlerAttacker].pp[movePosition] -= ppToDeduct;
|
||||
else
|
||||
gBattleMons[gBattlerAttacker].pp[movePosition] = 0;
|
||||
|
||||
if (MOVE_IS_PERMANENT(gBattlerAttacker, movePosition))
|
||||
{
|
||||
BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_PPMOVE1_BATTLE + movePosition, 0,
|
||||
sizeof(gBattleMons[gBattlerAttacker].pp[movePosition]),
|
||||
&gBattleMons[gBattlerAttacker].pp[movePosition]);
|
||||
MarkBattlerForControllerExec(gBattlerAttacker);
|
||||
}
|
||||
|
||||
if (gBattleStruct->submoveAnnouncement != SUBMOVE_NO_EFFECT)
|
||||
{
|
||||
if (gBattleStruct->submoveAnnouncement == SUBMOVE_FAILURE)
|
||||
{
|
||||
gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT;
|
||||
gBattlescriptCurrInstr = BattleScript_ButItFailed;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
else if (CancellerVolatileBlocked() == MOVE_STEP_FAILURE) // Check Gravity/Heal Block/Throat Chop for Submove
|
||||
{
|
||||
gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT;
|
||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
gBattleScripting.animTurn = 0;
|
||||
gBattleScripting.animTargetsHit = 0;
|
||||
|
||||
// Possibly better to just move type setting and redirection to attackcanceller as a new case at this point
|
||||
SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker);
|
||||
HandleMoveTargetRedirection();
|
||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||
return MOVE_STEP_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2342,20 +2521,20 @@ static enum MoveCanceller CancellerWeatherPrimal(void)
|
||||
if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (B_POWDER_RAIN >= GEN_7 || !TryActivatePowderStatus(gCurrentMove)))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN;
|
||||
effect = MOVE_STEP_BREAK;
|
||||
effect = MOVE_STEP_FAILURE;
|
||||
}
|
||||
else if (moveType == TYPE_WATER && (gBattleWeather & B_WEATHER_SUN_PRIMAL))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_EVAPORATED_IN_SUN;
|
||||
effect = MOVE_STEP_BREAK;
|
||||
effect = MOVE_STEP_FAILURE;
|
||||
}
|
||||
if (effect == MOVE_STEP_BREAK)
|
||||
if (effect == MOVE_STEP_FAILURE)
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_NONE;
|
||||
gProtectStructs[gBattlerAttacker].chargingTurn = FALSE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
BattleScriptCall(BattleScript_PrimalWeatherBlocksMove);
|
||||
gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove;
|
||||
}
|
||||
}
|
||||
return effect;
|
||||
@ -2366,8 +2545,8 @@ static enum MoveCanceller CancellerDynamaxBlocked(void)
|
||||
if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove))
|
||||
{
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
BattleScriptCall(BattleScript_MoveBlockedByDynamax);
|
||||
return MOVE_STEP_BREAK;
|
||||
gBattlescriptCurrInstr = BattleScript_MoveBlockedByDynamax;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2376,10 +2555,10 @@ static enum MoveCanceller CancellerPowderStatus(void)
|
||||
{
|
||||
if (TryActivatePowderStatus(gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].powderSelfDmg = TRUE;
|
||||
if (!IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD))
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
||||
|
||||
// This might be incorrect
|
||||
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE
|
||||
|| HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE))
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedPowder;
|
||||
@ -2418,7 +2597,7 @@ static enum MoveCanceller CancellerPsychicTerrain(void)
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2431,7 +2610,7 @@ static enum MoveCanceller CancellerExplodingDamp(void)
|
||||
gBattleScripting.battler = dampBattler - 1;
|
||||
gBattlescriptCurrInstr = BattleScript_DampStopsExplosion;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return MOVE_STEP_BREAK;
|
||||
return MOVE_STEP_FAILURE;
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
@ -2503,38 +2682,6 @@ static enum MoveCanceller CancellerMultihitMoves(void)
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerZMoves(void)
|
||||
{
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||
{
|
||||
// For Z-Mirror Move, so it doesn't play the animation twice.
|
||||
bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE);
|
||||
|
||||
// attacker has a queued z move
|
||||
RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_Z_CRYSTAL);
|
||||
SetGimmickAsActivated(gBattlerAttacker, GIMMICK_Z_MOVE);
|
||||
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
if (gProtectStructs[gBattlerAttacker].powderSelfDmg)
|
||||
{
|
||||
if (!alreadyUsed)
|
||||
BattleScriptCall(BattleScript_ZMoveActivatePowder);
|
||||
}
|
||||
else if (GetMoveCategory(gCurrentMove) == DAMAGE_CATEGORY_STATUS)
|
||||
{
|
||||
if (!alreadyUsed)
|
||||
BattleScriptCall(BattleScript_ZMoveActivateStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!alreadyUsed)
|
||||
BattleScriptCall(BattleScript_ZMoveActivateDamaging);
|
||||
}
|
||||
return MOVE_STEP_BREAK; // The original move is cancelled, not the z move
|
||||
}
|
||||
return MOVE_STEP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum MoveCanceller CancellerMultiTargetMoves(void)
|
||||
{
|
||||
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
@ -2591,19 +2738,24 @@ static enum MoveCanceller (*const sMoveSuccessOrderCancellers[])(void) =
|
||||
[CANCELLER_RECHARGE] = CancellerRecharge,
|
||||
[CANCELLER_ASLEEP_OR_FROZEN] = CancellerAsleepOrFrozen,
|
||||
[CANCELLER_OBEDIENCE] = CancellerObedience,
|
||||
[CANCELLER_POWER_POINTS] = CancellerPowerPoints,
|
||||
[CANCELLER_TRUANT] = CancellerTruant,
|
||||
[CANCELLER_FLINCH] = CancellerFlinch,
|
||||
[CANCELLER_INFATUATION] = CancellerInfatuation,
|
||||
[CANCELLER_DISABLED] = CancellerDisabled,
|
||||
[CANCELLER_VOLATILE_BLOCKED] = CancellerVolatileBlocked,
|
||||
[CANCELLER_TAUNTED] = CancellerTaunted,
|
||||
[CANCELLER_IMPRISONED] = CancellerImprisoned,
|
||||
[CANCELLER_CONFUSED] = CancellerConfused,
|
||||
[CANCELLER_PARALYSED] = CancellerParalysed,
|
||||
[CANCELLER_INFATUATION] = CancellerInfatuation,
|
||||
[CANCELLER_BIDE] = CancellerBide,
|
||||
[CANCELLER_Z_MOVES] = CancellerZMoves,
|
||||
[CANCELLER_CHOICE_LOCK] = CancellerChoiceLock,
|
||||
[CANCELLER_CALLSUBMOVE] = CancellerCallSubmove,
|
||||
[CANCELLER_THAW] = CancellerThaw,
|
||||
[CANCELLER_STANCE_CHANGE_2] = CancellerStanceChangeTwo,
|
||||
[CANCELLER_CHOICE_LOCK] = CancellerChoiceLock,
|
||||
[CANCELLER_ATTACKSTRING] = CancellerAttackstring,
|
||||
[CANCELLER_PPDEDUCTION] = CancellerPPDeduction,
|
||||
[CANCELLER_WEATHER_PRIMAL] = CancellerWeatherPrimal,
|
||||
[CANCELLER_DYNAMAX_BLOCKED] = CancellerDynamaxBlocked,
|
||||
[CANCELLER_POWDER_STATUS] = CancellerPowderStatus,
|
||||
@ -2611,7 +2763,6 @@ static enum MoveCanceller (*const sMoveSuccessOrderCancellers[])(void) =
|
||||
[CANCELLER_PSYCHIC_TERRAIN] = CancellerPsychicTerrain,
|
||||
[CANCELLER_EXPLODING_DAMP] = CancellerExplodingDamp,
|
||||
[CANCELLER_MULTIHIT_MOVES] = CancellerMultihitMoves,
|
||||
[CANCELLER_Z_MOVES] = CancellerZMoves,
|
||||
[CANCELLER_MULTI_TARGET_MOVES] = CancellerMultiTargetMoves,
|
||||
};
|
||||
|
||||
@ -3017,29 +3168,17 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
{
|
||||
case ABILITY_SOUNDPROOF:
|
||||
if (IsSoundMove(move) && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER))
|
||||
{
|
||||
if (gBattleMons[battlerAtk].volatiles.multipleTurns)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_SoundproofProtected;
|
||||
}
|
||||
break;
|
||||
case ABILITY_BULLETPROOF:
|
||||
if (IsBallisticMove(move))
|
||||
{
|
||||
if (gBattleMons[battlerAtk].volatiles.multipleTurns)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_SoundproofProtected;
|
||||
}
|
||||
break;
|
||||
case ABILITY_DAZZLING:
|
||||
case ABILITY_QUEENLY_MAJESTY:
|
||||
case ABILITY_ARMOR_TAIL:
|
||||
if (atkPriority > 0 && !IsBattlerAlly(battlerAtk, battlerDef))
|
||||
{
|
||||
if (gBattleMons[battlerAtk].volatiles.multipleTurns)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_DazzlingProtected;
|
||||
}
|
||||
break;
|
||||
case ABILITY_GOOD_AS_GOLD:
|
||||
if (IsBattleMoveStatus(move))
|
||||
@ -3081,8 +3220,6 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
case ABILITY_DAZZLING:
|
||||
case ABILITY_QUEENLY_MAJESTY:
|
||||
case ABILITY_ARMOR_TAIL:
|
||||
if (gBattleMons[battlerAtk].volatiles.multipleTurns)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battlerAbility = partnerDef;
|
||||
battleScriptBlocksMove = BattleScript_DazzlingProtected;
|
||||
break;
|
||||
@ -3190,18 +3327,11 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32
|
||||
gBattleStruct->pledgeMove = FALSE;
|
||||
if (IsBattlerAtMaxHp(battlerDef) || (B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battlerDef].volatiles.healBlock))
|
||||
{
|
||||
if ((gProtectStructs[battlerAtk].notFirstStrike))
|
||||
battleScript = BattleScript_MonMadeMoveUseless;
|
||||
else
|
||||
battleScript = BattleScript_MonMadeMoveUseless_PPLoss;
|
||||
battleScript = BattleScript_MonMadeMoveUseless;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gProtectStructs[battlerAtk].notFirstStrike)
|
||||
battleScript = BattleScript_MoveHPDrain;
|
||||
else
|
||||
battleScript = BattleScript_MoveHPDrain_PPLoss;
|
||||
|
||||
battleScript = BattleScript_MoveHPDrain;
|
||||
gBattleStruct->moveDamage[battlerDef] = GetNonDynamaxMaxHP(battlerDef) / 4;
|
||||
if (gBattleStruct->moveDamage[battlerDef] == 0)
|
||||
gBattleStruct->moveDamage[battlerDef] = 1;
|
||||
@ -3212,18 +3342,11 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32
|
||||
gBattleStruct->pledgeMove = FALSE;
|
||||
if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
if ((gProtectStructs[battlerAtk].notFirstStrike))
|
||||
battleScript = BattleScript_MonMadeMoveUseless;
|
||||
else
|
||||
battleScript = BattleScript_MonMadeMoveUseless_PPLoss;
|
||||
battleScript = BattleScript_MonMadeMoveUseless;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gProtectStructs[battlerAtk].notFirstStrike)
|
||||
battleScript = BattleScript_MoveStatDrain;
|
||||
else
|
||||
battleScript = BattleScript_MoveStatDrain_PPLoss;
|
||||
|
||||
battleScript = BattleScript_MoveStatDrain;
|
||||
SET_STATCHANGER(statId, statAmount, FALSE);
|
||||
if (B_ABSORBING_ABILITY_STRING < GEN_5)
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
|
||||
@ -3234,19 +3357,13 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32
|
||||
if (!gDisableStructs[battlerDef].flashFireBoosted)
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_BOOST;
|
||||
if (gProtectStructs[battlerAtk].notFirstStrike)
|
||||
battleScript = BattleScript_FlashFireBoost;
|
||||
else
|
||||
battleScript = BattleScript_FlashFireBoost_PPLoss;
|
||||
battleScript = BattleScript_FlashFireBoost;
|
||||
gDisableStructs[battlerDef].flashFireBoosted = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_NO_BOOST;
|
||||
if (gProtectStructs[battlerAtk].notFirstStrike)
|
||||
battleScript = BattleScript_FlashFireBoost;
|
||||
else
|
||||
battleScript = BattleScript_FlashFireBoost_PPLoss;
|
||||
battleScript = BattleScript_FlashFireBoost;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5048,13 +5165,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
// Set the target to the original target of the mon that first used a Dance move
|
||||
gBattlerTarget = gBattleScripting.savedBattler & 0x3;
|
||||
|
||||
// Edge case for dance moves that hit multiply targets
|
||||
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
|
||||
|
||||
// Make sure that the target isn't an ally - if it is, target the original user
|
||||
if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker))
|
||||
gBattlerTarget = (gBattleScripting.savedBattler & 0xF0) >> 4;
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
BattleScriptExecute(BattleScript_DancerActivates);
|
||||
effect++;
|
||||
}
|
||||
@ -7998,7 +8111,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx)
|
||||
u32 weight, hpFraction, speed;
|
||||
|
||||
if (GetActiveGimmick(battlerAtk) == GIMMICK_Z_MOVE)
|
||||
return GetZMovePower(gBattleStruct->zmove.baseMoves[battlerAtk]);
|
||||
return GetZMovePower(gCurrentMove);
|
||||
|
||||
if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX)
|
||||
return GetMaxMovePower(move);
|
||||
@ -11862,3 +11975,180 @@ bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static u32 GetMirrorMoveMove(void)
|
||||
{
|
||||
s32 i, validMovesCount;
|
||||
u16 move = MOVE_NONE;
|
||||
u16 validMoves[MAX_BATTLERS_COUNT] = {0};
|
||||
|
||||
for (validMovesCount = 0, i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (i != gBattlerAttacker)
|
||||
{
|
||||
move = gBattleStruct->lastTakenMoveFrom[gBattlerAttacker][i];
|
||||
if (move != MOVE_NONE && move != MOVE_UNAVAILABLE)
|
||||
{
|
||||
validMoves[validMovesCount] = move;
|
||||
validMovesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
move = gBattleStruct->lastTakenMove[gBattlerAttacker];
|
||||
if ((move == MOVE_NONE || move == MOVE_UNAVAILABLE) && validMovesCount != 0)
|
||||
move = validMoves[Random() % validMovesCount];
|
||||
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move))
|
||||
move = GetTypeBasedZMove(move);
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
static bool32 InvalidMetronomeMove(u32 move)
|
||||
{
|
||||
return GetMoveEffect(move) == EFFECT_PLACEHOLDER
|
||||
|| IsMoveMetronomeBanned(move);
|
||||
}
|
||||
|
||||
static u32 GetMetronomeMove(void)
|
||||
{
|
||||
u32 move = MOVE_NONE;
|
||||
|
||||
#if B_METRONOME_MOVES >= GEN_9
|
||||
u32 moveCount = MOVES_COUNT_GEN9;
|
||||
#elif B_METRONOME_MOVES >= GEN_8
|
||||
u32 moveCount = MOVES_COUNT_GEN8;
|
||||
#elif B_METRONOME_MOVES >= GEN_7
|
||||
u32 moveCount = MOVES_COUNT_GEN7;
|
||||
#elif B_METRONOME_MOVES >= GEN_6
|
||||
u32 moveCount = MOVES_COUNT_GEN6;
|
||||
#elif B_METRONOME_MOVES >= GEN_5
|
||||
u32 moveCount = MOVES_COUNT_GEN5;
|
||||
#elif B_METRONOME_MOVES >= GEN_4
|
||||
u32 moveCount = MOVES_COUNT_GEN4;
|
||||
#elif B_METRONOME_MOVES >= GEN_3
|
||||
u32 moveCount = MOVES_COUNT_GEN3;
|
||||
#elif B_METRONOME_MOVES >= GEN_2
|
||||
u32 moveCount = MOVES_COUNT_GEN2;
|
||||
#else
|
||||
u32 moveCount = MOVES_COUNT_GEN1;
|
||||
#endif
|
||||
|
||||
move = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove);
|
||||
return move;
|
||||
}
|
||||
|
||||
static u32 GetAssistMove(void)
|
||||
{
|
||||
u32 move = MOVE_NONE;
|
||||
s32 chooseableMovesNo = 0;
|
||||
struct Pokemon *party;
|
||||
u16 *validMoves = Alloc(sizeof(u16) * PARTY_SIZE * MAX_MON_MOVES);
|
||||
|
||||
if (validMoves != NULL)
|
||||
{
|
||||
party = GetBattlerParty(gBattlerAttacker);
|
||||
|
||||
for (u32 monId = 0; monId < PARTY_SIZE; monId++)
|
||||
{
|
||||
if (monId == gBattlerPartyIndexes[gBattlerAttacker])
|
||||
continue;
|
||||
if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE)
|
||||
continue;
|
||||
if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG)
|
||||
continue;
|
||||
|
||||
for (u32 moveId = 0; moveId < MAX_MON_MOVES; moveId++)
|
||||
{
|
||||
u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
|
||||
|
||||
if (IsMoveAssistBanned(move))
|
||||
continue;
|
||||
|
||||
validMoves[chooseableMovesNo++] = move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chooseableMovesNo)
|
||||
move = validMoves[Random() % chooseableMovesNo];
|
||||
|
||||
TRY_FREE_AND_SET_NULL(validMoves);
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
u32 GetNaturePowerMove(u32 battler)
|
||||
{
|
||||
u32 move = gBattleEnvironmentInfo[gBattleEnvironment].naturePower;
|
||||
if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)
|
||||
move = MOVE_MOONBLAST;
|
||||
else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
|
||||
move = MOVE_THUNDERBOLT;
|
||||
else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)
|
||||
move = MOVE_ENERGY_BALL;
|
||||
else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)
|
||||
move = MOVE_PSYCHIC;
|
||||
else if (gBattleEnvironmentInfo[gBattleEnvironment].naturePower == MOVE_NONE)
|
||||
move = MOVE_TRI_ATTACK;
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
static u32 GetSleepTalkMove(void)
|
||||
{
|
||||
u32 move = MOVE_NONE;
|
||||
|
||||
u32 i, unusableMovesBits = 0, movePosition;
|
||||
|
||||
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_COMATOSE
|
||||
&& !(gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP))
|
||||
return move;
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (IsMoveSleepTalkBanned(gBattleMons[gBattlerAttacker].moves[i])
|
||||
|| gBattleMoveEffects[GetMoveEffect(gBattleMons[gBattlerAttacker].moves[i])].twoTurnEffect)
|
||||
unusableMovesBits |= (1 << (i));
|
||||
}
|
||||
|
||||
unusableMovesBits = CheckMoveLimitations(gBattlerAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP | MOVE_LIMITATION_CHOICE_ITEM));
|
||||
if (unusableMovesBits == ALL_MOVES_MASK) // all 4 moves cannot be chosen
|
||||
return move;
|
||||
|
||||
// Set Sleep Talk as used move, so it works with Last Resort.
|
||||
gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos;
|
||||
do
|
||||
{
|
||||
movePosition = MOD(Random(), MAX_MON_MOVES);
|
||||
} while ((1u << movePosition) & unusableMovesBits);
|
||||
|
||||
move = gBattleMons[gBattlerAttacker].moves[movePosition];
|
||||
gCurrMovePos = movePosition;
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
static u32 GetCopyCatMove(void)
|
||||
{
|
||||
if (gLastUsedMove == MOVE_NONE
|
||||
|| gLastUsedMove == MOVE_UNAVAILABLE
|
||||
|| IsMoveCopycatBanned(gLastUsedMove)
|
||||
|| IsZMove(gLastUsedMove))
|
||||
return MOVE_NONE;
|
||||
|
||||
return gLastUsedMove;
|
||||
}
|
||||
|
||||
static u32 GetMeFirstMove(void)
|
||||
{
|
||||
u32 move = gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]];
|
||||
|
||||
if (IsBattleMoveStatus(move)
|
||||
|| IsMoveMeFirstBanned(move)
|
||||
|| GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
return MOVE_NONE;
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
@ -161,7 +161,6 @@ u32 GetUsableZMove(u32 battler, u32 move)
|
||||
|
||||
void ActivateZMove(u32 battler)
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
|
||||
SetActiveGimmick(battler, GIMMICK_Z_MOVE);
|
||||
}
|
||||
|
||||
@ -438,7 +437,7 @@ static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler)
|
||||
void SetZEffect(void)
|
||||
{
|
||||
u32 i;
|
||||
u32 effect = GetMoveZEffect(gBattleStruct->zmove.baseMoves[gBattlerAttacker]);
|
||||
u32 effect = GetMoveZEffect(gChosenMove);
|
||||
|
||||
if (effect == Z_EFFECT_CURSE)
|
||||
{
|
||||
|
||||
@ -49,7 +49,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_MIRROR_MOVE] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectMirrorMove,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 1,
|
||||
},
|
||||
|
||||
@ -398,7 +398,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_METRONOME] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectMetronome,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 1,
|
||||
},
|
||||
|
||||
@ -502,7 +502,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_SLEEP_TALK] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectSleepTalk,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 3,
|
||||
.encourageEncore = TRUE,
|
||||
},
|
||||
@ -911,7 +911,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_NATURE_POWER] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectNaturePower,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
@ -956,7 +956,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_ASSIST] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectAssist,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 2,
|
||||
},
|
||||
|
||||
@ -1486,7 +1486,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_ME_FIRST] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectMeFirst,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
@ -1601,7 +1601,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_COPYCAT] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectCopycat,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
|
||||
@ -21,6 +21,27 @@ TO_DO_BATTLE_TEST("Copycat ignores the recharging turn of recharging moves (Gen
|
||||
TO_DO_BATTLE_TEST("Copycat can copy Bide on all turns");
|
||||
TO_DO_BATTLE_TEST("Copycat copies moves called by other calling moves instead of the calling move (Gen 5+)");
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_COPYCAT) == EFFECT_COPYCAT);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Copycat deducts power points from itself, not the copied move")
|
||||
{
|
||||
ASSUME(GetMovePP(MOVE_COPYCAT) == 20);
|
||||
ASSUME(GetMovePP(MOVE_POUND) == 35);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_COPYCAT); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_POUND); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_POUND); MOVE(player, MOVE_COPYCAT); }
|
||||
} SCENE {
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->pp[0], 34);
|
||||
EXPECT_EQ(player->pp[0], 19);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their base moves copied by Copycat")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_ME_FIRST) == EFFECT_ME_FIRST);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Me First copies the move from the target and increases it's power by 1.5", s16 damage)
|
||||
{
|
||||
u32 move;
|
||||
@ -77,4 +82,21 @@ SINGLE_BATTLE_TEST("Me First can be selected if users holds Assault Vest")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Me Frist deducts power points from itself, not the copied move")
|
||||
{
|
||||
ASSUME(GetMovePP(MOVE_ME_FIRST) == 20);
|
||||
ASSUME(GetMovePP(MOVE_POUND) == 35);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_ME_FIRST); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_POUND); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ME_FIRST); MOVE(opponent, MOVE_POUND); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ME_FIRST, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->pp[0], 34);
|
||||
EXPECT_EQ(player->pp[0], 19);
|
||||
}
|
||||
}
|
||||
|
||||
// TO_DO_BATTLE_TEST: Not everything has been tested
|
||||
|
||||
@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Mirror Move fails if no move was used before")
|
||||
TURN { MOVE(player, MOVE_MIRROR_MOVE); MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Mirror Move!");
|
||||
MESSAGE("The Mirror Move failed!");
|
||||
MESSAGE("But it failed!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player);
|
||||
}
|
||||
|
||||
@ -146,3 +146,21 @@ DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Sto
|
||||
ABILITY_POPUP(opponentRight, ABILITY_STORM_DRAIN);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sleep Talk deducts power points from itself, not the called move")
|
||||
{
|
||||
ASSUME(GetMovePP(MOVE_SLEEP_TALK) == 10);
|
||||
ASSUME(GetMovePP(MOVE_POUND) == 35);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_POUND); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SLEEP_TALK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLEEP_TALK, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->pp[0], 9);
|
||||
EXPECT_EQ(player->pp[1], 35);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user