Attackcanceller fixes and improvements (#7698)
This commit is contained in:
parent
4822d94667
commit
32f8464fec
@ -724,14 +724,12 @@
|
||||
.byte \mode
|
||||
.endm
|
||||
|
||||
.macro trysetrest failInstr:req
|
||||
.macro trysetrest
|
||||
.byte 0x81
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifnotfirstturn jumpInstr:req
|
||||
.macro unused_0x82
|
||||
.byte 0x82
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro unused_0x83
|
||||
@ -748,9 +746,8 @@
|
||||
.byte \id
|
||||
.endm
|
||||
|
||||
.macro stockpiletobasedamage failInstr:req
|
||||
.macro stockpiletobasedamage
|
||||
.byte 0x86
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro stockpiletohpheal failInstr:req
|
||||
@ -1045,9 +1042,8 @@
|
||||
.byte 0xc2
|
||||
.endm
|
||||
|
||||
.macro trysetfutureattack failInstr:req
|
||||
.macro setfutureattack
|
||||
.byte 0xc3
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro trydobeatup endInstr, failInstr
|
||||
@ -1224,10 +1220,8 @@
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifnotcurrentmoveargtype battler:req, failInstr:req
|
||||
.macro unused_0xE4
|
||||
.byte 0xe4
|
||||
.byte \battler
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro pickup
|
||||
@ -1378,12 +1372,6 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifcantfling battler:req, jumpInstr:req
|
||||
callnative BS_JumpIfCantFling
|
||||
.byte \battler
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro itemstatchangeeffects battler:req
|
||||
callnative BS_RunStatChangeItems
|
||||
.byte \battler
|
||||
@ -1438,10 +1426,6 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro setglaiverush
|
||||
callnative BS_SetGlaiveRush
|
||||
.endm
|
||||
|
||||
.macro setpledge jumpInstr:req
|
||||
callnative BS_SetPledge
|
||||
.4byte \jumpInstr
|
||||
@ -2179,11 +2163,6 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro suckerpunchcheck failInstr:req
|
||||
callnative BS_SuckerPunchCheck
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro setsimplebeam failInstr:req
|
||||
callnative BS_SetSimpleBeam
|
||||
.4byte \failInstr
|
||||
@ -2218,11 +2197,6 @@
|
||||
.byte \case_
|
||||
.endm
|
||||
|
||||
.macro trylastresort failInstr:req
|
||||
callnative BS_TryLastResort
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro tryautotomize failInstr:req
|
||||
callnative BS_TryAutotomize
|
||||
.4byte \failInstr
|
||||
@ -2411,13 +2385,8 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro checkpoltergeist failInstr:req
|
||||
callnative BS_CheckPoltergeist
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro trynoretreat failInstr:req
|
||||
callnative BS_TryNoRetreat
|
||||
.macro setpoltergeistmessage failInstr:req
|
||||
callnative BS_SetPoltergeistMessage
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
|
||||
@ -210,7 +210,7 @@ BattleScript_EffectDoodleMoveEnd:
|
||||
BattleScript_EffectGlaiveRush::
|
||||
call BattleScript_EffectHit_Ret
|
||||
jumpifmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_TryFaintMon
|
||||
setglaiverush
|
||||
setvolatile BS_ATTACKER, VOLATILE_GLAIVE_RUSH, 2
|
||||
goto BattleScript_TryFaintMon
|
||||
|
||||
BattleScript_SyrupBombActivates::
|
||||
@ -685,7 +685,6 @@ BattleScript_SkyDropFlyingAlreadyConfused:
|
||||
|
||||
BattleScript_EffectFling::
|
||||
attackcanceler
|
||||
jumpifcantfling BS_ATTACKER, BattleScript_ButItFailed
|
||||
setlastuseditem BS_ATTACKER
|
||||
accuracycheck BattleScript_FlingMissed, ACC_CURR_MOVE
|
||||
pause B_WAIT_TIME_SHORT
|
||||
@ -776,11 +775,6 @@ BattleScript_FlingMissed:
|
||||
removeitem BS_ATTACKER
|
||||
goto BattleScript_MoveMissedPause
|
||||
|
||||
BattleScript_EffectAuraWheel:: @ Aura Wheel can only be used by Morpeko
|
||||
jumpifspecies SPECIES_MORPEKO_FULL_BELLY, BattleScript_EffectHit
|
||||
jumpifspecies SPECIES_MORPEKO_HANGRY, BattleScript_EffectHit
|
||||
goto BattleScript_PokemonCantUseTheMove
|
||||
|
||||
BattleScript_EffectClangorousSoul::
|
||||
attackcanceler
|
||||
cutonethirdhpandraisestats BattleScript_ButItFailed
|
||||
@ -819,7 +813,7 @@ BattleScript_OctlockTurnDmgEnd:
|
||||
BattleScript_EffectPoltergeist::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
checkpoltergeist BattleScript_ButItFailed
|
||||
setpoltergeistmessage BattleScript_ButItFailed
|
||||
printstring STRINGID_ABOUTTOUSEPOLTERGEIST
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_HitFromCritCalc
|
||||
@ -844,7 +838,8 @@ BattleScript_TryTarShot:
|
||||
BattleScript_EffectNoRetreat::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
trynoretreat BattleScript_ButItFailed
|
||||
jumpifvolatile BS_TARGET, VOLATILE_NO_RETREAT, BattleScript_ButItFailed
|
||||
setvolatile BS_TARGET, VOLATILE_NO_RETREAT
|
||||
attackanimation
|
||||
waitanimation
|
||||
call BattleScript_AllStatsUp
|
||||
@ -901,7 +896,6 @@ BattleScript_MoveEffectLightScreen::
|
||||
|
||||
BattleScript_EffectStuffCheeks::
|
||||
attackcanceler
|
||||
jumpifnotberry BS_ATTACKER, BattleScript_ButItFailed
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sBERRY_OVERRIDE, 1
|
||||
@ -1049,12 +1043,6 @@ BattleScript_EffectFairyLock::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_FailIfNotArgType::
|
||||
attackcanceler
|
||||
jumpifnotcurrentmoveargtype BS_ATTACKER, BattleScript_ButItFailed
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
goto BattleScript_HitFromCritCalc
|
||||
|
||||
BattleScript_RemoveFireType::
|
||||
printstring STRINGID_ATTACKERLOSTFIRETYPE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
@ -1747,12 +1735,6 @@ BattleScript_ShellSmashTrySpeed:
|
||||
BattleScript_ShellSmashEnd:
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectLastResort::
|
||||
attackcanceler
|
||||
trylastresort BattleScript_ButItFailed
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
goto BattleScript_HitFromCritCalc
|
||||
|
||||
BattleScript_EffectGrowth::
|
||||
attackcanceler
|
||||
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_GrowthDoMoveAnim
|
||||
@ -2064,12 +2046,6 @@ BattleScript_EffectSimpleBeam::
|
||||
tryendneutralizinggas
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectSuckerPunch::
|
||||
attackcanceler
|
||||
suckerpunchcheck BattleScript_ButItFailed
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
goto BattleScript_HitFromAtkString
|
||||
|
||||
BattleScript_EffectLuckyChant::
|
||||
attackcanceler
|
||||
setluckychant BattleScript_ButItFailed
|
||||
@ -2577,7 +2553,7 @@ BattleScript_AbilityProtectsDoesntAffect::
|
||||
setmoveresultflags MOVE_RESULT_FAILED
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_InsomniaProtects:
|
||||
BattleScript_InsomniaProtects::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_PKMNSTAYEDAWAKEUSING
|
||||
@ -2866,16 +2842,10 @@ BattleScript_EffectLightScreen::
|
||||
|
||||
BattleScript_EffectRest::
|
||||
attackcanceler
|
||||
jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_RestIsAlreadyAsleep
|
||||
jumpifability BS_ATTACKER, ABILITY_COMATOSE, BattleScript_RestIsAlreadyAsleep
|
||||
jumpifuproarwakes BattleScript_RestCantSleep
|
||||
jumpifability BS_TARGET, ABILITY_INSOMNIA, BattleScript_InsomniaProtects
|
||||
jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_InsomniaProtects
|
||||
jumpifability BS_ATTACKER, ABILITY_PURIFYING_SALT, BattleScript_InsomniaProtects
|
||||
.if B_LEAF_GUARD_PREVENTS_REST >= GEN_5
|
||||
jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest
|
||||
.endif
|
||||
trysetrest BattleScript_AlreadyAtFullHp
|
||||
trysetrest
|
||||
pause B_WAIT_TIME_SHORT
|
||||
printfromtable gRestUsedStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
@ -3288,10 +3258,6 @@ BattleScript_EffectPainSplit::
|
||||
|
||||
BattleScript_EffectSnore::
|
||||
attackcanceler
|
||||
jumpifability BS_ATTACKER, ABILITY_COMATOSE, BattleScript_SnoreIsAsleep
|
||||
jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_SnoreIsAsleep
|
||||
goto BattleScript_ButItFailed
|
||||
BattleScript_SnoreIsAsleep::
|
||||
jumpifhalfword CMP_EQUAL, gChosenMove, MOVE_SLEEP_TALK, BattleScript_DoSnore
|
||||
printstring STRINGID_PKMNFASTASLEEP
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
@ -3331,7 +3297,7 @@ BattleScript_EffectSketch::
|
||||
|
||||
BattleScript_EffectDestinyBond::
|
||||
attackcanceler
|
||||
trysetdestinybond BattleScript_ButItFailed
|
||||
setvolatile BS_ATTACKER, VOLATILE_DESTINY_BOND, 2
|
||||
attackanimation
|
||||
waitanimation
|
||||
printstring STRINGID_PKMNTRYINGTOTAKEFOE
|
||||
@ -3463,15 +3429,9 @@ BattleScript_DoGhostCurse::
|
||||
tryfaintmon BS_ATTACKER
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectMatBlock::
|
||||
attackcanceler
|
||||
jumpifnotfirstturn BattleScript_ButItFailed
|
||||
goto BattleScript_ProtectLikeAttack
|
||||
|
||||
BattleScript_EffectProtect::
|
||||
BattleScript_EffectEndure::
|
||||
attackcanceler
|
||||
BattleScript_ProtectLikeAttack:
|
||||
setprotectlike
|
||||
attackanimation
|
||||
waitanimation
|
||||
@ -3785,7 +3745,7 @@ BattleScript_EffectMirrorCoat::
|
||||
|
||||
BattleScript_EffectFutureSight::
|
||||
attackcanceler
|
||||
trysetfutureattack BattleScript_ButItFailed
|
||||
setfutureattack
|
||||
attackanimation
|
||||
waitanimation
|
||||
printfromtable gFutureMoveUsedStringIds
|
||||
@ -3880,11 +3840,6 @@ BattleScript_AlreadyAtFullHp::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectFirstTurnOnly::
|
||||
attackcanceler
|
||||
jumpifnotfirstturn BattleScript_ButItFailed
|
||||
goto BattleScript_EffectHit
|
||||
|
||||
BattleScript_FailedFromAtkCanceler::
|
||||
attackcanceler
|
||||
BattleScript_ButItFailed::
|
||||
@ -3920,7 +3875,7 @@ BattleScript_EffectStockpile::
|
||||
stockpile 0
|
||||
attackanimation
|
||||
waitanimation
|
||||
printfromtable gStockpileUsedStringIds
|
||||
printstring STRINGID_PKMNSTOCKPILED
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
.if B_STOCKPILE_RAISES_DEFS < GEN_4
|
||||
goto BattleScript_EffectStockpileEnd
|
||||
@ -3965,29 +3920,22 @@ BattleScript_EffectSpitUp::
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
damagecalc
|
||||
adjustdamage
|
||||
stockpiletobasedamage BattleScript_SpitUpFail
|
||||
stockpiletobasedamage
|
||||
call BattleScript_Hit_RetFromAtkAnimation
|
||||
tryfaintmon BS_TARGET
|
||||
removestockpilecounters
|
||||
goto BattleScript_SpitUpEnd
|
||||
BattleScript_SpitUpFail::
|
||||
checkparentalbondcounter 2, BattleScript_SpitUpEnd
|
||||
pause B_WAIT_TIME_SHORT
|
||||
printstring STRINGID_FAILEDTOSPITUP
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_SpitUpEnd:
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_SpitUpFailProtect::
|
||||
pause B_WAIT_TIME_LONG
|
||||
stockpiletobasedamage BattleScript_SpitUpFail
|
||||
stockpiletobasedamage
|
||||
resultmessage
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectSwallow::
|
||||
attackcanceler
|
||||
stockpiletohpheal BattleScript_SwallowFail
|
||||
stockpiletohpheal BattleScript_ButItFailed
|
||||
attackanimation
|
||||
waitanimation
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
|
||||
@ -3998,13 +3946,6 @@ BattleScript_EffectSwallow::
|
||||
removestockpilecounters
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
|
||||
BattleScript_SwallowFail::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
printfromtable gSwallowFailStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectHail::
|
||||
attackcanceler
|
||||
call BattleScript_CheckPrimalWeather
|
||||
@ -4112,9 +4053,6 @@ BattleScript_EffectFocusPunch::
|
||||
|
||||
BattleScript_EffectFollowMe::
|
||||
attackcanceler
|
||||
.if B_UPDATED_MOVE_DATA >= GEN_8
|
||||
jumpifnotbattletype BATTLE_TYPE_DOUBLE, BattleScript_ButItFailed
|
||||
.endif
|
||||
setforcedtarget
|
||||
attackanimation
|
||||
waitanimation
|
||||
@ -4324,7 +4262,8 @@ BattleScript_EffectRefresh::
|
||||
|
||||
BattleScript_EffectGrudge::
|
||||
attackcanceler
|
||||
trysetvolatile BS_ATTACKER, VOLATILE_GRUDGE, BattleScript_ButItFailed
|
||||
jumpifvolatile BS_ATTACKER, VOLATILE_GRUDGE, BattleScript_ButItFailed
|
||||
setvolatile BS_ATTACKER, VOLATILE_GRUDGE, 2
|
||||
attackanimation
|
||||
waitanimation
|
||||
printstring STRINGID_PKMNWANTSGRUDGE
|
||||
@ -7246,8 +7185,10 @@ BattleScript_DazzlingProtected::
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_MoveUsedPsychicTerrainPrevents::
|
||||
printstring STRINGID_POKEMONCANNOTUSEMOVE
|
||||
pause B_WAIT_TIME_SHORT
|
||||
printstring STRINGID_PSYCHICTERRAINPREVENTS
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
setmoveresultflags MOVE_RESULT_NO_EFFECT
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_GrassyTerrainHeals::
|
||||
@ -8396,11 +8337,6 @@ BattleScript_TryFaint:
|
||||
tryfaintmon BS_TARGET
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectSteelRoller::
|
||||
attackcanceler
|
||||
jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ButItFailed
|
||||
goto BattleScript_HitFromAccCheck
|
||||
|
||||
BattleScript_RemoveTerrain::
|
||||
removeterrain
|
||||
playanimation BS_ATTACKER, B_ANIM_RESTORE_BG
|
||||
|
||||
@ -93,14 +93,21 @@ Contains more fundamental functions that control the flow of the battle. Functio
|
||||
### data/battle_scripts_1.s
|
||||
Each move's effect is governed by a script defined here. For a simple example, let's look at the script for Fake Out/First Impression:
|
||||
|
||||
TODO: New Script
|
||||
```
|
||||
BattleScript_EffectFirstTurnOnly::
|
||||
BattleScript_EffectTaunt::
|
||||
attackcanceler
|
||||
jumpifnotfirstturn BattleScript_ButItFailed
|
||||
goto BattleScript_EffectHit
|
||||
jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects
|
||||
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
|
||||
settaunt BattleScript_ButItFailed
|
||||
attackanimation
|
||||
waitanimation
|
||||
printstring STRINGID_PKMNFELLFORTAUNT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
```
|
||||
|
||||
`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.
|
||||
`attackcanceler` is a command that covers all cases that could cause a move to fail before it's even attempted (e.g. paralysis). The next command is a jump command. A jump command can check anything and usually comes with a jump instruction. Usually it jumps to a place from where the move should pick up because of certain conditions. The next one is an accuracy check. Accuracy checks happen after all prior move failure checks happened. The next set of commands are unique to a certain move, they are mostly the same for damaging moves but can widely differ for status moves. Lastly there is `BattleScript_MoveEnd` which the move after a succesful hit. An ability activation or specific move effect like Burn, Freeze, Absorb etc.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@ -113,7 +113,6 @@ struct DisableStruct
|
||||
u8 usedMoves:4;
|
||||
u8 truantCounter:1;
|
||||
u8 truantSwitchInHack:1;
|
||||
u8 noRetreat:1;
|
||||
u8 tarShot:1;
|
||||
u8 octolock:1;
|
||||
u8 cudChew:1;
|
||||
@ -123,6 +122,7 @@ struct DisableStruct
|
||||
u8 usedProteanLibero:1;
|
||||
u8 flashFireBoosted:1;
|
||||
u8 boosterEnergyActivated:1;
|
||||
u8 padding1:1;
|
||||
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
|
||||
u8 roostActive:1;
|
||||
u8 unburdenActive:1;
|
||||
@ -130,9 +130,9 @@ struct DisableStruct
|
||||
u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case
|
||||
u8 unnerveActivated:1; // Unnerve and As One (Unnerve part) activate only once per switch in
|
||||
u8 hazardsDone:1;
|
||||
u8 padding1:1;
|
||||
u8 padding2:1;
|
||||
u8 octolockedBy:3;
|
||||
u8 padding2:5;
|
||||
u8 padding3:5;
|
||||
};
|
||||
|
||||
// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects
|
||||
|
||||
@ -155,6 +155,7 @@ u32 CountPositiveStatStages(u32 battlerId);
|
||||
u32 CountNegativeStatStages(u32 battlerId);
|
||||
|
||||
// move checks
|
||||
bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData);
|
||||
bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
|
||||
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category);
|
||||
enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);
|
||||
@ -312,7 +313,7 @@ bool32 IsNaturalEnemy(u32 speciesAttacker, u32 speciesTarget);
|
||||
#define AI_EFFECT_TERRAIN (1 << 1)
|
||||
#define AI_EFFECT_CLEAR_HAZARDS (1 << 2)
|
||||
#define AI_EFFECT_BREAK_SCREENS (1 << 3)
|
||||
#define AI_EFFECT_RESET_STATS (1 << 4)
|
||||
#define AI_EFFECT_RESET_STATS (1 << 4)
|
||||
#define AI_EFFECT_FORCE_SWITCH (1 << 5)
|
||||
#define AI_EFFECT_TORMENT (1 << 6)
|
||||
#define AI_EFFECT_LIGHT_SCREEN (1 << 7)
|
||||
|
||||
@ -11,7 +11,6 @@ u16 GetNonDynamaxHP(u32 battler);
|
||||
u16 GetNonDynamaxMaxHP(u32 battler);
|
||||
void UndoDynamax(u32 battler);
|
||||
bool32 IsMoveBlockedByMaxGuard(u32 move);
|
||||
bool32 IsMoveBlockedByDynamax(u32 move);
|
||||
|
||||
u16 GetMaxMove(u32 battler, u32 baseMove);
|
||||
u32 GetMaxMovePower(u32 move);
|
||||
|
||||
@ -332,7 +332,6 @@ extern const u8 BattleScript_MistySurgeActivates[];
|
||||
extern const u8 BattleScript_ElectricSurgeActivates[];
|
||||
extern const u8 BattleScript_EffectSpectralThief[];
|
||||
extern const u8 BattleScript_EffectLifeDew[];
|
||||
extern const u8 BattleScript_EffectSteelRoller[];
|
||||
extern const u8 BattleScript_AbilityRaisesDefenderStat[];
|
||||
extern const u8 BattleScript_PowderMoveNoEffect[];
|
||||
extern const u8 BattleScript_GrassyTerrainHeals[];
|
||||
@ -597,6 +596,8 @@ extern const u8 BattleScript_EffectConversion[];
|
||||
extern const u8 BattleScript_EffectRestoreHp[];
|
||||
extern const u8 BattleScript_EffectLightScreen[];
|
||||
extern const u8 BattleScript_EffectRest[];
|
||||
extern const u8 BattleScript_RestIsAlreadyAsleep[];
|
||||
extern const u8 BattleScript_InsomniaProtects[];
|
||||
extern const u8 BattleScript_EffectOHKO[];
|
||||
extern const u8 BattleScript_EffectHealBlock[];
|
||||
extern const u8 BattleScript_RecoilIfMiss[];
|
||||
@ -677,7 +678,6 @@ extern const u8 BattleScript_EffectBeatUp[];
|
||||
extern const u8 BattleScript_EffectSemiInvulnerable[];
|
||||
extern const u8 BattleScript_EffectDefenseCurl[];
|
||||
extern const u8 BattleScript_EffectSoftboiled[];
|
||||
extern const u8 BattleScript_EffectFirstTurnOnly[];
|
||||
extern const u8 BattleScript_EffectStockpile[];
|
||||
extern const u8 BattleScript_EffectSpitUp[];
|
||||
extern const u8 BattleScript_EffectSwallow[];
|
||||
@ -742,7 +742,6 @@ extern const u8 BattleScript_EffectGuardSplit[];
|
||||
extern const u8 BattleScript_EffectStickyWeb[];
|
||||
extern const u8 BattleScript_EffectMetalBurst[];
|
||||
extern const u8 BattleScript_EffectLuckyChant[];
|
||||
extern const u8 BattleScript_EffectSuckerPunch[];
|
||||
extern const u8 BattleScript_EffectSimpleBeam[];
|
||||
extern const u8 BattleScript_EffectEntrainment[];
|
||||
extern const u8 BattleScript_EffectHealPulse[];
|
||||
@ -761,7 +760,6 @@ extern const u8 BattleScript_EffectElectrify[];
|
||||
extern const u8 BattleScript_EffectReflectType[];
|
||||
extern const u8 BattleScript_EffectSoak[];
|
||||
extern const u8 BattleScript_EffectGrowth[];
|
||||
extern const u8 BattleScript_EffectLastResort[];
|
||||
extern const u8 BattleScript_EffectShellSmash[];
|
||||
extern const u8 BattleScript_EffectShiftGear[];
|
||||
extern const u8 BattleScript_EffectDefenseUp3[];
|
||||
@ -790,14 +788,12 @@ extern const u8 BattleScript_EffectAcupressure[];
|
||||
extern const u8 BattleScript_EffectAromaticMist[];
|
||||
extern const u8 BattleScript_EffectPowder[];
|
||||
extern const u8 BattleScript_EffectPartingShot[];
|
||||
extern const u8 BattleScript_EffectMatBlock[];
|
||||
extern const u8 BattleScript_EffectInstruct[];
|
||||
extern const u8 BattleScript_EffectLaserFocus[];
|
||||
extern const u8 BattleScript_EffectMagneticFlux[];
|
||||
extern const u8 BattleScript_EffectGearUp[];
|
||||
extern const u8 BattleScript_EffectStrengthSap[];
|
||||
extern const u8 BattleScript_EffectPurify[];
|
||||
extern const u8 BattleScript_FailIfNotArgType[];
|
||||
extern const u8 BattleScript_EffectShoreUp[];
|
||||
extern const u8 BattleScript_EffectGeomancy[];
|
||||
extern const u8 BattleScript_EffectFairyLock[];
|
||||
@ -814,7 +810,6 @@ extern const u8 BattleScript_MoveEffectLeechSeed[];
|
||||
extern const u8 BattleScript_MoveEffectHaze[];
|
||||
extern const u8 BattleScript_MoveEffectIonDeluge[];
|
||||
extern const u8 BattleScript_EffectHyperspaceFury[];
|
||||
extern const u8 BattleScript_EffectAuraWheel[];
|
||||
extern const u8 BattleScript_EffectNoRetreat[];
|
||||
extern const u8 BattleScript_EffectTarShot[];
|
||||
extern const u8 BattleScript_EffectPoltergeist[];
|
||||
@ -855,5 +850,6 @@ extern const u8 BattleScript_SubmoveAttackstring[];
|
||||
extern const u8 BattleScript_MetronomeAttackstring[];
|
||||
extern const u8 BattleScript_SleepTalkAttackstring[];
|
||||
extern const u8 BattleScript_NaturePowerAttackstring[];
|
||||
extern const u8 BattleScript_PokemonCantUseTheMove[];
|
||||
|
||||
#endif // GUARD_BATTLE_SCRIPTS_H
|
||||
|
||||
@ -7,7 +7,7 @@ bool32 CanTerastallize(u32 battler);
|
||||
u32 GetBattlerTeraType(u32 battler);
|
||||
void ExpendTypeStellarBoost(u32 battler, u32 type);
|
||||
bool32 IsTypeStellarBoosted(u32 battler, u32 type);
|
||||
uq4_12_t GetTeraMultiplier(u32 battler, u32 type);
|
||||
uq4_12_t GetTeraMultiplier(struct DamageContext *ctx);
|
||||
|
||||
u16 GetTeraTypeRGB(u32 type);
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ struct TypePower
|
||||
|
||||
enum MoveSuccessOrder
|
||||
{
|
||||
CANCELLER_FLAGS,
|
||||
CANCELLER_CLEAR_FLAGS,
|
||||
CANCELLER_STANCE_CHANGE_1,
|
||||
CANCELLER_SKY_DROP,
|
||||
CANCELLER_RECHARGE,
|
||||
@ -130,10 +130,10 @@ enum MoveSuccessOrder
|
||||
CANCELLER_ATTACKSTRING,
|
||||
CANCELLER_PPDEDUCTION,
|
||||
CANCELLER_WEATHER_PRIMAL,
|
||||
CANCELLER_DYNAMAX_BLOCKED,
|
||||
CANCELLER_MOVE_FAILURE,
|
||||
CANCELLER_POWDER_STATUS,
|
||||
CANCELLER_PRIORITY_BLOCK,
|
||||
CANCELLER_PROTEAN,
|
||||
CANCELLER_PSYCHIC_TERRAIN,
|
||||
CANCELLER_EXPLODING_DAMP,
|
||||
CANCELLER_MULTIHIT_MOVES,
|
||||
CANCELLER_MULTI_TARGET_MOVES,
|
||||
@ -180,6 +180,15 @@ struct DamageContext
|
||||
enum ItemHoldEffect holdEffectDef:16;
|
||||
};
|
||||
|
||||
struct BattleContext
|
||||
{
|
||||
u32 battlerAtk:3;
|
||||
u32 battlerDef:3;
|
||||
u32 currentMove:16;
|
||||
enum BattleMoveEffects moveEffect:10;
|
||||
u16 ability[MAX_BATTLERS_COUNT];
|
||||
};
|
||||
|
||||
enum SleepClauseBlock
|
||||
{
|
||||
NOT_BLOCKED_BY_SLEEP_CLAUSE,
|
||||
@ -242,7 +251,7 @@ bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck);
|
||||
u32 DoEndTurnEffects(void);
|
||||
bool32 HandleFaintedMonActions(void);
|
||||
void TryClearRageAndFuryCutter(void);
|
||||
enum MoveCanceller AtkCanceller_MoveSuccessOrder(void);
|
||||
enum MoveCanceller AtkCanceller_MoveSuccessOrder(struct BattleContext *ctx);
|
||||
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);
|
||||
@ -414,5 +423,6 @@ bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move);
|
||||
u32 GetNaturePowerMove(u32 battler);
|
||||
u32 GetNaturePowerMove(u32 battler);
|
||||
void RemoveAbilityFlags(u32 battler);
|
||||
bool32 IsDazzlingAbility(u32 ability);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
||||
@ -162,7 +162,7 @@ enum VolatileFlags
|
||||
F(VOLATILE_RECHARGE, recharge, (u32, 1)) \
|
||||
F(VOLATILE_RAGE, rage, (u32, 1)) \
|
||||
F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \
|
||||
F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 1)) \
|
||||
F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 2)) \
|
||||
F(VOLATILE_ESCAPE_PREVENTION, escapePrevention, (u32, 1), V_BATON_PASSABLE) \
|
||||
F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \
|
||||
F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \
|
||||
@ -196,6 +196,7 @@ enum VolatileFlags
|
||||
F(VOLATILE_AQUA_RING, aquaRing, (u32, 1), V_BATON_PASSABLE) \
|
||||
F(VOLATILE_LASER_FOCUS, laserFocus, (u32, 1)) \
|
||||
F(VOLATILE_POWER_TRICK, powerTrick, (u32, 1), V_BATON_PASSABLE) \
|
||||
F(VOLATILE_NO_RETREAT, noRetreat, (u32, 1), V_BATON_PASSABLE) \
|
||||
F(VOLATILE_VESSEL_OF_RUIN, vesselOfRuin, (u32, 1)) \
|
||||
F(VOLATILE_SWORD_OF_RUIN, swordOfRuin, (u32, 1)) \
|
||||
F(VOLATILE_TABLETS_OF_RUIN, tabletsOfRuin, (u32, 1)) \
|
||||
|
||||
@ -113,7 +113,6 @@ enum StringID
|
||||
STRINGID_PKMNCALMEDDOWN,
|
||||
STRINGID_PKMNCANTSLEEPINUPROAR,
|
||||
STRINGID_PKMNSTOCKPILED,
|
||||
STRINGID_PKMNCANTSTOCKPILE,
|
||||
STRINGID_PKMNCANTSLEEPINUPROAR2,
|
||||
STRINGID_UPROARKEPTPKMNAWAKE,
|
||||
STRINGID_PKMNSTAYEDAWAKEUSING,
|
||||
@ -239,8 +238,6 @@ enum StringID
|
||||
STRINGID_STARTEDHAIL,
|
||||
STRINGID_HAILCONTINUES,
|
||||
STRINGID_HAILSTOPPED,
|
||||
STRINGID_FAILEDTOSPITUP,
|
||||
STRINGID_FAILEDTOSWALLOW,
|
||||
STRINGID_STATCHANGESGONE,
|
||||
STRINGID_COINSSCATTERED,
|
||||
STRINGID_TOOWEAKFORSUBSTITUTE,
|
||||
@ -858,20 +855,6 @@ enum UproarOverTurnStringID
|
||||
B_MSG_UPROAR_ENDS,
|
||||
};
|
||||
|
||||
// gStockpileUsedStringIds
|
||||
enum StockpileUsedStringID
|
||||
{
|
||||
B_MSG_STOCKPILED,
|
||||
B_MSG_CANT_STOCKPILE,
|
||||
};
|
||||
|
||||
// gSwallowFailStringIds
|
||||
enum SwallowFailStringID
|
||||
{
|
||||
B_MSG_SWALLOW_FAILED,
|
||||
B_MSG_SWALLOW_FULL_HP,
|
||||
};
|
||||
|
||||
// gKOFailedStringIds
|
||||
enum KOFailedStringID
|
||||
{
|
||||
|
||||
@ -1141,6 +1141,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// check non-user target
|
||||
if (!(moveTarget & MOVE_TARGET_USER))
|
||||
{
|
||||
if (Ai_IsPriorityBlocked(battlerAtk, battlerDef, move, aiData))
|
||||
return TRUE;
|
||||
|
||||
if (CanAbilityBlockMove(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK))
|
||||
RETURN_SCORE_MINUS(20);
|
||||
|
||||
@ -2871,7 +2874,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_NO_RETREAT:
|
||||
if (gDisableStructs[battlerAtk].noRetreat)
|
||||
if (gBattleMons[battlerAtk].volatiles.noRetreat)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_EXTREME_EVOBOOST:
|
||||
@ -3106,7 +3109,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
switch (effect)
|
||||
{
|
||||
case EFFECT_HELPING_HAND:
|
||||
if (!hasPartner
|
||||
if (!hasPartner
|
||||
|| !HasDamagingMove(battlerAtkPartner)
|
||||
|| (aiData->partnerMove != MOVE_NONE && IsBattleMoveStatus(aiData->partnerMove)))
|
||||
{
|
||||
@ -3122,7 +3125,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (hasTwoOpponents)
|
||||
{
|
||||
// Might be about to die
|
||||
if (CanTargetFaintAi(LEFT_FOE(battlerAtk), battlerAtk) && CanTargetFaintAi(RIGHT_FOE(battlerAtk), battlerAtk)
|
||||
if (CanTargetFaintAi(LEFT_FOE(battlerAtk), battlerAtk) && CanTargetFaintAi(RIGHT_FOE(battlerAtk), battlerAtk)
|
||||
&& AI_IsSlower(battlerAtk, LEFT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)
|
||||
&& AI_IsSlower(battlerAtk, RIGHT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
@ -3144,14 +3147,14 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
else if (IsBattlerAlive(RIGHT_FOE(battlerAtk)))
|
||||
{
|
||||
// Might be about to die
|
||||
if (CanTargetFaintAi(RIGHT_FOE(battlerAtk), battlerAtk)
|
||||
if (CanTargetFaintAi(RIGHT_FOE(battlerAtk), battlerAtk)
|
||||
&& AI_IsSlower(battlerAtk, RIGHT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
|
||||
if (ownHitsToKOFoe2 > partnerHitsToKOFoe2 && partnerHitsToKOFoe2 > 1)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EFFECT_PERISH_SONG:
|
||||
@ -3178,7 +3181,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_COACHING:
|
||||
if (!hasPartner
|
||||
if (!hasPartner
|
||||
|| !HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL))
|
||||
{
|
||||
ADJUST_SCORE(WORST_EFFECT);
|
||||
@ -5271,7 +5274,7 @@ case EFFECT_GUARD_SPLIT:
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
// Set it for next pokemon in singles.
|
||||
else if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !hasPartner && (CountUsablePartyMons(battlerAtk) != 0))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
// Don't unset it on last turn.
|
||||
else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != gBattleTurnCounter && ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
@ -5406,7 +5409,7 @@ case EFFECT_GUARD_SPLIT:
|
||||
u32 partnerSpeed = aiData->speedStats[BATTLE_PARTNER(battlerAtk)];
|
||||
u32 foe1Speed = aiData->speedStats[LEFT_FOE(battlerAtk)];
|
||||
u32 foe2Speed = aiData->speedStats[RIGHT_FOE(battlerAtk)];
|
||||
|
||||
|
||||
if (speed <= foe1Speed && (speed * 2) > foe1Speed)
|
||||
tailwindScore += 1;
|
||||
if (speed <= foe2Speed && (speed * 2) > foe2Speed)
|
||||
|
||||
@ -501,11 +501,11 @@ bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef)
|
||||
u32 GetTotalBaseStat(u32 species)
|
||||
{
|
||||
return GetSpeciesBaseHP(species)
|
||||
+ GetSpeciesBaseAttack(species)
|
||||
+ GetSpeciesBaseDefense(species)
|
||||
+ GetSpeciesBaseSpeed(species)
|
||||
+ GetSpeciesBaseSpAttack(species)
|
||||
+ GetSpeciesBaseSpDefense(species);
|
||||
+ GetSpeciesBaseAttack(species)
|
||||
+ GetSpeciesBaseDefense(species)
|
||||
+ GetSpeciesBaseSpeed(species)
|
||||
+ GetSpeciesBaseSpAttack(species)
|
||||
+ GetSpeciesBaseSpDefense(species);
|
||||
}
|
||||
|
||||
bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler)
|
||||
@ -535,6 +535,24 @@ bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffe
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData)
|
||||
{
|
||||
s32 atkPriority = GetBattleMovePriority(battlerAtk, aiData->abilities[battlerAtk], move);
|
||||
|
||||
if (atkPriority <= 0 || IsBattlerAlly(battlerAtk, battlerDef))
|
||||
return FALSE;
|
||||
|
||||
if (IsMoldBreakerTypeAbility(battlerAtk, aiData->abilities[battlerAtk]) || MoveIgnoresTargetAbility(move))
|
||||
return FALSE;
|
||||
|
||||
if (IsDazzlingAbility(aiData->abilities[battlerDef]))
|
||||
return TRUE;
|
||||
|
||||
if (IsDoubleBattle() && IsDazzlingAbility(aiData->abilities[BATTLE_PARTNER(battlerDef)]))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
// This function checks if all physical/special moves are either unusable or unreasonable to use.
|
||||
// Consider a pokemon boosting their attack against a ghost pokemon having only normal-type physical attacks.
|
||||
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category)
|
||||
@ -630,6 +648,9 @@ bool32 IsDamageMoveUnusable(struct DamageContext *ctx)
|
||||
partnerDefAbility = aiData->abilities[BATTLE_PARTNER(ctx->battlerDef)];
|
||||
}
|
||||
|
||||
if (Ai_IsPriorityBlocked(ctx->battlerAtk, ctx->battlerDef, ctx->move, aiData))
|
||||
return TRUE;
|
||||
|
||||
if (CanAbilityBlockMove(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, battlerDefAbility, ctx->move, AI_CHECK))
|
||||
return TRUE;
|
||||
|
||||
|
||||
@ -234,21 +234,6 @@ bool32 IsMoveBlockedByMaxGuard(u32 move)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Weight-based moves (and some other moves in Raids) are blocked by Dynamax.
|
||||
bool32 IsMoveBlockedByDynamax(u32 move)
|
||||
{
|
||||
// TODO: Certain moves are banned in raids.
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_HEAT_CRASH:
|
||||
case EFFECT_LOW_KICK:
|
||||
return TRUE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static u16 GetTypeBasedMaxMove(u32 battler, u32 type)
|
||||
{
|
||||
// Gigantamax check
|
||||
|
||||
@ -4840,7 +4840,9 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move)
|
||||
priority++;
|
||||
}
|
||||
else if (ability == ABILITY_TRIAGE && IsHealingMove(move))
|
||||
{
|
||||
priority += 3;
|
||||
}
|
||||
|
||||
if (gProtectStructs[battler].quash)
|
||||
priority = -8;
|
||||
|
||||
@ -272,7 +272,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
|
||||
[STRINGID_PKMNCALMEDDOWN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} calmed down."),
|
||||
[STRINGID_PKMNCANTSLEEPINUPROAR] = COMPOUND_STRING("But {B_DEF_NAME_WITH_PREFIX2} can't sleep in an uproar!"),
|
||||
[STRINGID_PKMNSTOCKPILED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stockpiled {B_BUFF1}!"),
|
||||
[STRINGID_PKMNCANTSTOCKPILE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can't stockpile any more!"), //I think this was replaced with just "But it failed!"
|
||||
[STRINGID_PKMNCANTSLEEPINUPROAR2] = COMPOUND_STRING("But {B_DEF_NAME_WITH_PREFIX2} can't sleep in an uproar!"),
|
||||
[STRINGID_UPROARKEPTPKMNAWAKE] = COMPOUND_STRING("But the uproar kept {B_DEF_NAME_WITH_PREFIX2} awake!"),
|
||||
[STRINGID_PKMNSTAYEDAWAKEUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} stayed awake using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
|
||||
@ -398,8 +397,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
|
||||
[STRINGID_STARTEDHAIL] = COMPOUND_STRING("It started to hail!"),
|
||||
[STRINGID_HAILCONTINUES] = COMPOUND_STRING("The hail is crashing down."),
|
||||
[STRINGID_HAILSTOPPED] = COMPOUND_STRING("The hail stopped."),
|
||||
[STRINGID_FAILEDTOSPITUP] = COMPOUND_STRING("But it failed to spit up a thing!"), //not in gen 5+, uses "but it failed"
|
||||
[STRINGID_FAILEDTOSWALLOW] = COMPOUND_STRING("But it failed to swallow a thing!"), //not in gen 5+, uses "but it failed"
|
||||
[STRINGID_STATCHANGESGONE] = COMPOUND_STRING("All stat changes were eliminated!"),
|
||||
[STRINGID_COINSSCATTERED] = COMPOUND_STRING("Coins were scattered everywhere!"),
|
||||
[STRINGID_TOOWEAKFORSUBSTITUTE] = COMPOUND_STRING("But it does not have enough HP left to make a substitute!"),
|
||||
@ -663,7 +660,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
|
||||
[STRINGID_MISTYTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with a protective mist!"),
|
||||
[STRINGID_GRASSYTERRAINHEALS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is healed by the grassy terrain!"),
|
||||
[STRINGID_ELECTRICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with electrified terrain!"),
|
||||
[STRINGID_PSYCHICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with psychic terrain!"),
|
||||
[STRINGID_PSYCHICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is protected by the Psychic Terrain!"),
|
||||
[STRINGID_SAFETYGOGGLESPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is not affected thanks to its {B_LAST_ITEM}!"),
|
||||
[STRINGID_FLOWERVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounded itself with a veil of petals!"),
|
||||
[STRINGID_SWEETVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} can't fall asleep due to a veil of sweetness!"),
|
||||
@ -1073,24 +1070,12 @@ const u16 gUproarOverTurnStringIds[] =
|
||||
[B_MSG_UPROAR_ENDS] = STRINGID_PKMNCALMEDDOWN
|
||||
};
|
||||
|
||||
const u16 gStockpileUsedStringIds[] =
|
||||
{
|
||||
[B_MSG_STOCKPILED] = STRINGID_PKMNSTOCKPILED,
|
||||
[B_MSG_CANT_STOCKPILE] = STRINGID_PKMNCANTSTOCKPILE,
|
||||
};
|
||||
|
||||
const u16 gWokeUpStringIds[] =
|
||||
{
|
||||
[B_MSG_WOKE_UP] = STRINGID_PKMNWOKEUP,
|
||||
[B_MSG_WOKE_UP_UPROAR] = STRINGID_PKMNWOKEUPINUPROAR
|
||||
};
|
||||
|
||||
const u16 gSwallowFailStringIds[] =
|
||||
{
|
||||
[B_MSG_SWALLOW_FAILED] = STRINGID_FAILEDTOSWALLOW,
|
||||
[B_MSG_SWALLOW_FULL_HP] = STRINGID_PKMNHPFULL
|
||||
};
|
||||
|
||||
const u16 gUproarAwakeStringIds[] =
|
||||
{
|
||||
[B_MSG_CANT_SLEEP_UPROAR] = STRINGID_PKMNCANTSLEEPINUPROAR2,
|
||||
|
||||
@ -467,7 +467,7 @@ static void Cmd_setreflect(void);
|
||||
static void Cmd_setseeded(void);
|
||||
static void Cmd_manipulatedamage(void);
|
||||
static void Cmd_trysetrest(void);
|
||||
static void Cmd_jumpifnotfirstturn(void);
|
||||
static void Cmd_unused_0x82(void);
|
||||
static void Cmd_unused_0x83(void);
|
||||
static void Cmd_jumpifuproarwakes(void);
|
||||
static void Cmd_stockpile(void);
|
||||
@ -507,7 +507,7 @@ static void Cmd_settypetorandomresistance(void);
|
||||
static void Cmd_setalwayshitflag(void);
|
||||
static void Cmd_copymovepermanently(void);
|
||||
static void Cmd_unused_0xA9(void);
|
||||
static void Cmd_trysetdestinybond(void);
|
||||
static void Cmd_unused_AA(void);
|
||||
static void Cmd_trysetdestinybondtohappen(void);
|
||||
static void Cmd_settailwind(void);
|
||||
static void Cmd_tryspiteppreduce(void);
|
||||
@ -532,7 +532,7 @@ static void Cmd_unused_0xBF(void);
|
||||
static void Cmd_recoverbasedonsunlight(void);
|
||||
static void Cmd_setstickyweb(void);
|
||||
static void Cmd_selectfirstvalidtarget(void);
|
||||
static void Cmd_trysetfutureattack(void);
|
||||
static void Cmd_setfutureattack(void);
|
||||
static void Cmd_trydobeatup(void);
|
||||
static void Cmd_setsemiinvulnerablebit(void);
|
||||
static void Cmd_tryfiretwoturnmovenowbyeffect(void);
|
||||
@ -565,7 +565,7 @@ static void Cmd_trysetsnatch(void);
|
||||
static void Cmd_unused2(void);
|
||||
static void Cmd_switchoutabilities(void);
|
||||
static void Cmd_jumpifhasnohp(void);
|
||||
static void Cmd_jumpifnotcurrentmoveargtype(void);
|
||||
static void Cmd_unused_0xE4(void);
|
||||
static void Cmd_pickup(void);
|
||||
static void Cmd_unused_0xE6(void);
|
||||
static void Cmd_unused_0xE7(void);
|
||||
@ -726,7 +726,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_setseeded, //0x7F
|
||||
Cmd_manipulatedamage, //0x80
|
||||
Cmd_trysetrest, //0x81
|
||||
Cmd_jumpifnotfirstturn, //0x82
|
||||
Cmd_unused_0x82, //0x82
|
||||
Cmd_unused_0x83, //0x83
|
||||
Cmd_jumpifuproarwakes, //0x84
|
||||
Cmd_stockpile, //0x85
|
||||
@ -766,7 +766,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_setalwayshitflag, //0xA7
|
||||
Cmd_copymovepermanently, //0xA8
|
||||
Cmd_unused_0xA9, //0xA9
|
||||
Cmd_trysetdestinybond, //0xAA
|
||||
Cmd_unused_AA, //0xAA
|
||||
Cmd_trysetdestinybondtohappen, //0xAB
|
||||
Cmd_settailwind, //0xAC
|
||||
Cmd_tryspiteppreduce, //0xAD
|
||||
@ -791,7 +791,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_recoverbasedonsunlight, //0xC0
|
||||
Cmd_setstickyweb, //0xC1
|
||||
Cmd_selectfirstvalidtarget, //0xC2
|
||||
Cmd_trysetfutureattack, //0xC3
|
||||
Cmd_setfutureattack, //0xC3
|
||||
Cmd_trydobeatup, //0xC4
|
||||
Cmd_setsemiinvulnerablebit, //0xC5
|
||||
Cmd_tryfiretwoturnmovenowbyeffect, //0xC6
|
||||
@ -824,7 +824,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
||||
Cmd_unused2, //0xE1
|
||||
Cmd_switchoutabilities, //0xE2
|
||||
Cmd_jumpifhasnohp, //0xE3
|
||||
Cmd_jumpifnotcurrentmoveargtype, //0xE4
|
||||
Cmd_unused_0xE4, //0xE4
|
||||
Cmd_pickup, //0xE5
|
||||
Cmd_unused_0xE6, //0xE6
|
||||
Cmd_unused_0xE7, //0xE7
|
||||
@ -1040,23 +1040,23 @@ u32 NumFaintedBattlersByAttacker(u32 battlerAtk)
|
||||
return numMonsFainted;
|
||||
}
|
||||
|
||||
bool32 IsMovePowderBlocked(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
bool32 IsMovePowderBlocked(struct BattleContext *ctx)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
|
||||
if (IsPowderMove(move) && (battlerAtk != battlerDef))
|
||||
if (IsPowderMove(ctx->currentMove) && (ctx->battlerAtk != ctx->battlerDef))
|
||||
{
|
||||
if (B_POWDER_GRASS >= GEN_6
|
||||
&& (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || GetBattlerAbility(battlerDef) == ABILITY_OVERCOAT))
|
||||
&& (IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GRASS) || ctx->ability[ctx->battlerDef] == ABILITY_OVERCOAT))
|
||||
{
|
||||
gBattlerAbility = battlerDef;
|
||||
RecordAbilityBattle(gBattlerTarget, ABILITY_OVERCOAT);
|
||||
gBattlerAbility = ctx->battlerDef;
|
||||
RecordAbilityBattle(ctx->battlerDef, ABILITY_OVERCOAT);
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_SAFETY_GOGGLES)
|
||||
else if (GetBattlerHoldEffect(ctx->battlerDef, TRUE) == HOLD_EFFECT_SAFETY_GOGGLES)
|
||||
{
|
||||
RecordItemEffectBattle(battlerDef, HOLD_EFFECT_SAFETY_GOGGLES);
|
||||
gLastUsedItem = gBattleMons[battlerDef].item;
|
||||
RecordItemEffectBattle(ctx->battlerDef, HOLD_EFFECT_SAFETY_GOGGLES);
|
||||
gLastUsedItem = gBattleMons[ctx->battlerDef].item;
|
||||
effect = TRUE;
|
||||
}
|
||||
|
||||
@ -1103,22 +1103,30 @@ static void Cmd_attackcanceler(void)
|
||||
return;
|
||||
}
|
||||
|
||||
enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove);
|
||||
struct BattleContext ctx = {0};
|
||||
ctx.battlerAtk = gBattlerAttacker;
|
||||
ctx.battlerDef = gBattlerTarget;
|
||||
ctx.currentMove = gCurrentMove;
|
||||
ctx.moveEffect = GetMoveEffect(ctx.currentMove);
|
||||
|
||||
if (!IsBattlerAlive(gBattlerAttacker)
|
||||
&& effect != EFFECT_EXPLOSION
|
||||
&& effect != EFFECT_MISTY_EXPLOSION)
|
||||
&& ctx.moveEffect != EFFECT_EXPLOSION
|
||||
&& ctx.moveEffect != EFFECT_MISTY_EXPLOSION)
|
||||
{
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEnd;
|
||||
return;
|
||||
}
|
||||
|
||||
if (AtkCanceller_MoveSuccessOrder() != MOVE_STEP_SUCCESS)
|
||||
// With how attackcanceller works right now we only need attacker and target abilities. Might change in the future
|
||||
ctx.ability[ctx.battlerAtk] = GetBattlerAbility(ctx.battlerAtk);
|
||||
ctx.ability[ctx.battlerDef] = GetBattlerAbility(ctx.battlerDef);
|
||||
|
||||
if (AtkCanceller_MoveSuccessOrder(&ctx) != MOVE_STEP_SUCCESS)
|
||||
return;
|
||||
|
||||
if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF
|
||||
&& GetBattlerAbility(gBattlerAttacker) == ABILITY_PARENTAL_BOND
|
||||
&& ctx.ability[ctx.battlerAtk] == ABILITY_PARENTAL_BOND
|
||||
&& IsMoveAffectedByParentalBond(gCurrentMove, gBattlerAttacker)
|
||||
&& !(gAbsentBattlerFlags & (1u << gBattlerTarget))
|
||||
&& GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE)
|
||||
@ -1129,44 +1137,43 @@ static void Cmd_attackcanceler(void)
|
||||
return;
|
||||
}
|
||||
|
||||
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
||||
if (CanAbilityBlockMove(
|
||||
gBattlerAttacker,
|
||||
gBattlerTarget,
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
abilityDef,
|
||||
gCurrentMove,
|
||||
ctx.battlerAtk,
|
||||
ctx.battlerDef,
|
||||
ctx.ability[ctx.battlerAtk],
|
||||
ctx.ability[ctx.battlerDef],
|
||||
ctx.currentMove,
|
||||
RUN_SCRIPT))
|
||||
return;
|
||||
|
||||
if (GetMoveNonVolatileStatus(gCurrentMove) == MOVE_EFFECT_PARALYSIS)
|
||||
if (GetMoveNonVolatileStatus(ctx.currentMove) == MOVE_EFFECT_PARALYSIS)
|
||||
{
|
||||
if (CanAbilityAbsorbMove(
|
||||
gBattlerAttacker,
|
||||
gBattlerTarget,
|
||||
abilityDef,
|
||||
gCurrentMove,
|
||||
GetBattleMoveType(gCurrentMove),
|
||||
ctx.battlerAtk,
|
||||
ctx.battlerDef,
|
||||
ctx.ability[ctx.battlerDef],
|
||||
ctx.currentMove,
|
||||
GetBattleMoveType(ctx.currentMove),
|
||||
RUN_SCRIPT))
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsMovePowderBlocked(gBattlerAttacker, gBattlerTarget, gCurrentMove))
|
||||
if (IsMovePowderBlocked(&ctx))
|
||||
return;
|
||||
|
||||
// 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)))
|
||||
&& (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)))
|
||||
|| (IsMoveNotAllowedInSkyBattles(gCurrentMove)))
|
||||
{
|
||||
gBattleStruct->noTargetPresent = TRUE;
|
||||
|
||||
if (effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling.
|
||||
if (ctx.moveEffect == 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_ButItFailed;
|
||||
|
||||
if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
|
||||
if (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
return;
|
||||
}
|
||||
@ -1197,7 +1204,7 @@ static void Cmd_attackcanceler(void)
|
||||
{
|
||||
u32 battler = gBattlerTarget;
|
||||
|
||||
if (abilityDef == ABILITY_MAGIC_BOUNCE)
|
||||
if (ctx.ability[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE)
|
||||
{
|
||||
battler = gBattlerTarget;
|
||||
gBattleStruct->bouncedMoveIsUsed = TRUE;
|
||||
@ -1257,11 +1264,11 @@ static void Cmd_attackcanceler(void)
|
||||
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
||||
}
|
||||
else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove)
|
||||
&& (effect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
||||
&& (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
|
||||
&& effect != EFFECT_SUCKER_PUNCH
|
||||
&& effect != EFFECT_COUNTER
|
||||
&& effect != EFFECT_UPPER_HAND)
|
||||
&& (ctx.moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
||||
&& (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
|
||||
&& ctx.moveEffect != EFFECT_SUCKER_PUNCH
|
||||
&& ctx.moveEffect != EFFECT_COUNTER
|
||||
&& ctx.moveEffect != EFFECT_UPPER_HAND)
|
||||
{
|
||||
if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove))
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE;
|
||||
@ -3238,7 +3245,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
||||
gBattlescriptCurrInstr++;
|
||||
break;
|
||||
case MOVE_EFFECT_PREVENT_ESCAPE:
|
||||
if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention)
|
||||
if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) // Do we need to check if the status is already set?
|
||||
{
|
||||
gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE;
|
||||
gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker;
|
||||
@ -6800,6 +6807,9 @@ static void Cmd_moveend(void)
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #endif
|
||||
}
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0)
|
||||
gBattleMons[gBattlerAttacker].volatiles.destinyBond--;
|
||||
gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
|
||||
gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE;
|
||||
gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE;
|
||||
@ -7572,7 +7582,7 @@ static void UpdateSentMonFlags(u32 battler)
|
||||
|
||||
static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId)
|
||||
{
|
||||
gBattleMons[battler].volatiles.destinyBond = FALSE;
|
||||
gBattleMons[battler].volatiles.destinyBond = 0;
|
||||
gHitMarker &= ~HITMARKER_DESTINYBOND;
|
||||
gBattleScripting.battler = battler;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = multistringId;
|
||||
@ -9659,17 +9669,12 @@ static void Cmd_manipulatedamage(void)
|
||||
|
||||
static void Cmd_trysetrest(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
CMD_ARGS();
|
||||
|
||||
const u8 *failInstr = cmd->failInstr;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP * (-1);
|
||||
|
||||
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
|
||||
{
|
||||
gBattlescriptCurrInstr = failInstr;
|
||||
}
|
||||
else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN))
|
||||
if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN))
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_ElectricTerrainPrevents;
|
||||
}
|
||||
@ -9691,16 +9696,8 @@ static void Cmd_trysetrest(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void Cmd_jumpifnotfirstturn(void)
|
||||
static void Cmd_unused_0x82(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *jumpInstr);
|
||||
|
||||
const u8 *jumpInstr = cmd->jumpInstr;
|
||||
|
||||
if (gDisableStructs[gBattlerAttacker].isFirstTurn && !(gSpecialStatuses[gBattlerAttacker].instructedChosenTarget))
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = jumpInstr;
|
||||
}
|
||||
|
||||
static void Cmd_unused_0x83(void)
|
||||
@ -9752,19 +9749,10 @@ static void Cmd_stockpile(void)
|
||||
switch (cmd->id)
|
||||
{
|
||||
case 0:
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter >= 3)
|
||||
{
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CANT_STOCKPILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gDisableStructs[gBattlerAttacker].stockpileCounter++;
|
||||
gDisableStructs[gBattlerAttacker].stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF];
|
||||
gDisableStructs[gBattlerAttacker].stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF];
|
||||
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter);
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STOCKPILED;
|
||||
}
|
||||
gDisableStructs[gBattlerAttacker].stockpileCounter++;
|
||||
gDisableStructs[gBattlerAttacker].stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF];
|
||||
gDisableStructs[gBattlerAttacker].stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF];
|
||||
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter);
|
||||
break;
|
||||
case 1: // Save def/sp def stats.
|
||||
if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
@ -9780,20 +9768,12 @@ static void Cmd_stockpile(void)
|
||||
|
||||
static void Cmd_stockpiletobasedamage(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
CMD_ARGS();
|
||||
|
||||
const u8 *failInstr = cmd->failInstr;
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0)
|
||||
{
|
||||
gBattlescriptCurrInstr = failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleCommunication[MISS_TYPE] != B_MSG_PROTECTED)
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
if (gBattleCommunication[MISS_TYPE] != B_MSG_PROTECTED)
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_stockpiletohpheal(void)
|
||||
@ -9802,40 +9782,31 @@ static void Cmd_stockpiletohpheal(void)
|
||||
|
||||
const u8 *failInstr = cmd->failInstr;
|
||||
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed)
|
||||
if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp)
|
||||
{
|
||||
gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
|
||||
gBattlescriptCurrInstr = failInstr;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FAILED;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp)
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter > 0)
|
||||
{
|
||||
gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
|
||||
gBattlescriptCurrInstr = failInstr;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FULL_HP;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
}
|
||||
else
|
||||
else // Snatched move
|
||||
{
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter > 0)
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
}
|
||||
else // Snatched move
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
||||
gBattleScripting.animTurn = 1;
|
||||
}
|
||||
|
||||
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = 1;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] *= -1;
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
||||
gBattleScripting.animTurn = 1;
|
||||
}
|
||||
|
||||
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = 1;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] *= -1;
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11488,23 +11459,8 @@ static inline bool32 IsDanamaxMonPresent(void)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void Cmd_trysetdestinybond(void)
|
||||
static void Cmd_unused_AA(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
|
||||
if (IsDanamaxMonPresent())
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_MoveBlockedByDynamax;
|
||||
}
|
||||
else if (DoesDestinyBondFail(gBattlerAttacker))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].volatiles.destinyBond = TRUE;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
static void TrySetDestinyBondToHappen(void)
|
||||
@ -12231,29 +12187,22 @@ static void Cmd_selectfirstvalidtarget(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_trysetfutureattack(void)
|
||||
static void Cmd_setfutureattack(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
CMD_ARGS();
|
||||
|
||||
if (gWishFutureKnock.futureSightCounter[gBattlerTarget] > gBattleTurnCounter)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK;
|
||||
gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove;
|
||||
gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker;
|
||||
gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker];
|
||||
gWishFutureKnock.futureSightCounter[gBattlerTarget] = gBattleTurnCounter + 3;
|
||||
|
||||
if (gCurrentMove == MOVE_DOOM_DESIRE)
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE;
|
||||
else
|
||||
{
|
||||
gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK;
|
||||
gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove;
|
||||
gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker;
|
||||
gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker];
|
||||
gWishFutureKnock.futureSightCounter[gBattlerTarget] = gBattleTurnCounter + 3;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FUTURE_SIGHT;
|
||||
|
||||
if (gCurrentMove == MOVE_DOOM_DESIRE)
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE;
|
||||
else
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FUTURE_SIGHT;
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_trydobeatup(void)
|
||||
@ -13054,18 +13003,8 @@ static void Cmd_jumpifhasnohp(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_jumpifnotcurrentmoveargtype(void)
|
||||
static void Cmd_unused_0xE4(void)
|
||||
{
|
||||
CMD_ARGS(u8 battler, const u8 *failInstr);
|
||||
|
||||
u8 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
const u8 *failInstr = cmd->failInstr;
|
||||
u32 type = GetMoveArgType(gCurrentMove);
|
||||
|
||||
if (!IS_BATTLER_OF_TYPE(battler, type))
|
||||
gBattlescriptCurrInstr = failInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_pickup(void)
|
||||
@ -14396,17 +14335,6 @@ void BS_CalcMetalBurstDmg(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BS_JumpIfCantFling(void)
|
||||
{
|
||||
NATIVE_ARGS(u8 battler, const u8 *jumpInstr);
|
||||
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
if (!CanFling(battler))
|
||||
gBattlescriptCurrInstr = cmd->jumpInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_JumpIfMoreThanHalfHP(void)
|
||||
{
|
||||
NATIVE_ARGS(u8 battler, const u8 *jumpInstr);
|
||||
@ -15070,13 +14998,6 @@ void BS_TrySetOctolock(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BS_SetGlaiveRush(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
gBattleMons[gBattlerAttacker].volatiles.glaiveRush = TRUE;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_SetPledge(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *jumpInstr);
|
||||
@ -17039,19 +16960,6 @@ void BS_SetLuckyChant(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BS_SuckerPunchCheck(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
if (gProtectStructs[gBattlerTarget].protected == PROTECT_OBSTRUCT)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else if (IsBattleMoveStatus(gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]) && !gProtectStructs[gBattlerTarget].noValidMoves)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_SetSimpleBeam(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
@ -17183,15 +17091,6 @@ void BS_HandleFormChange(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_TryLastResort(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
if (CanUseLastResort(gBattlerAttacker))
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
|
||||
void BS_TryAutotomize(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
@ -17441,8 +17340,7 @@ void BS_SetAuroraVeil(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
u32 side = GetBattlerSide(gBattlerAttacker);
|
||||
if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL
|
||||
|| !(HasWeatherEffect() && gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)))
|
||||
if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL)
|
||||
{
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
||||
@ -17877,9 +17775,7 @@ void BS_CutOneThirdHpAndRaiseStats(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
|
||||
bool8 atLeastOneStatBoosted = FALSE;
|
||||
u16 hpFraction = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3);
|
||||
|
||||
bool32 atLeastOneStatBoosted = FALSE;
|
||||
for (u32 stat = 1; stat < NUM_STATS; stat++)
|
||||
{
|
||||
if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
@ -17888,9 +17784,9 @@ void BS_CutOneThirdHpAndRaiseStats(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (atLeastOneStatBoosted && gBattleMons[gBattlerAttacker].hp > hpFraction)
|
||||
if (atLeastOneStatBoosted)
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = hpFraction;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
@ -17899,36 +17795,12 @@ void BS_CutOneThirdHpAndRaiseStats(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BS_CheckPoltergeist(void)
|
||||
void BS_SetPoltergeistMessage(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
if (gBattleMons[gBattlerTarget].item == ITEM_NONE
|
||||
|| gFieldStatuses & STATUS_FIELD_MAGIC_ROOM
|
||||
|| GetBattlerAbility(gBattlerTarget) == ABILITY_KLUTZ)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].item);
|
||||
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
void BS_TryNoRetreat(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
if (gDisableStructs[gBattlerTarget].noRetreat)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention)
|
||||
gDisableStructs[gBattlerTarget].noRetreat = TRUE;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].item);
|
||||
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_CureCertainStatuses(void)
|
||||
|
||||
@ -132,20 +132,19 @@ bool32 IsTypeStellarBoosted(u32 battler, u32 type)
|
||||
|
||||
// Returns the STAB power multiplier to use when Terastallized.
|
||||
// Power multipliers from Smogon Research thread.
|
||||
uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
|
||||
uq4_12_t GetTeraMultiplier(struct DamageContext *ctx)
|
||||
{
|
||||
u32 teraType = GetBattlerTeraType(battler);
|
||||
bool32 hasAdaptability = (GetBattlerAbility(battler) == ABILITY_ADAPTABILITY);
|
||||
u32 teraType = GetBattlerTeraType(ctx->battlerAtk);
|
||||
|
||||
// Safety check.
|
||||
if (GetActiveGimmick(battler) != GIMMICK_TERA)
|
||||
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_TERA)
|
||||
return UQ_4_12(1.0);
|
||||
|
||||
// Stellar-type checks.
|
||||
if (teraType == TYPE_STELLAR)
|
||||
{
|
||||
bool32 shouldBoost = IsTypeStellarBoosted(battler, type);
|
||||
if (IS_BATTLER_OF_BASE_TYPE(battler, type))
|
||||
bool32 shouldBoost = IsTypeStellarBoosted(ctx->battlerAtk, ctx->moveType);
|
||||
if (IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|
||||
{
|
||||
if (shouldBoost)
|
||||
return UQ_4_12(2.0);
|
||||
@ -158,18 +157,18 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
// Base and Tera type.
|
||||
if (type == teraType && IS_BATTLER_OF_BASE_TYPE(battler, type))
|
||||
if (ctx->moveType == teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|
||||
{
|
||||
if (hasAdaptability)
|
||||
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
|
||||
return UQ_4_12(2.25);
|
||||
else
|
||||
return UQ_4_12(2.0);
|
||||
}
|
||||
// Base or Tera type only.
|
||||
else if ((type == teraType && !IS_BATTLER_OF_BASE_TYPE(battler, type))
|
||||
|| (type != teraType && IS_BATTLER_OF_BASE_TYPE(battler, type)))
|
||||
else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|
||||
|| (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)))
|
||||
{
|
||||
if (hasAdaptability)
|
||||
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
|
||||
return UQ_4_12(2.0);
|
||||
else
|
||||
return UQ_4_12(1.5);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -819,7 +819,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_FIRST_TURN_ONLY] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectFirstTurnOnly,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 4,
|
||||
.encourageEncore = TRUE,
|
||||
},
|
||||
@ -1392,7 +1392,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_SUCKER_PUNCH] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectSuckerPunch,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
@ -1531,7 +1531,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_LAST_RESORT] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectLastResort,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
@ -1721,7 +1721,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_MAT_BLOCK] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectMatBlock,
|
||||
.battleScript = BattleScript_EffectProtect,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
.encourageEncore = TRUE,
|
||||
},
|
||||
@ -1774,7 +1774,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_FAIL_IF_NOT_ARG_TYPE] =
|
||||
{
|
||||
.battleScript = BattleScript_FailIfNotArgType,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
@ -1881,7 +1881,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_AURA_WHEEL] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectAuraWheel,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
@ -2233,7 +2233,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_STEEL_ROLLER] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectSteelRoller,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
|
||||
@ -96,3 +96,25 @@ SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect from all mu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail prevent Protean activation")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
|
||||
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
|
||||
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); }
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WATER_SHURIKEN); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_SHURIKEN, player);
|
||||
ABILITY_POPUP(player, ABILITY_PROTEAN);
|
||||
}
|
||||
ABILITY_POPUP(opponent, ability);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ SINGLE_BATTLE_TEST("Teraform Zero can be replaced")
|
||||
PLAYER(SPECIES_TERAPAGOS);
|
||||
OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_POUND); }
|
||||
TURN { MOVE(opponent, MOVE_WORRY_SEED); MOVE(player, MOVE_REST, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Whimsicott used Worry Seed!");
|
||||
|
||||
@ -903,7 +903,7 @@ SINGLE_BATTLE_TEST("Dynamax: Max Mindstorm sets up Psychic Terrain")
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Wobbuffet used Extreme Speed!");
|
||||
MESSAGE("Wobbuffet used Max Mindstorm!");
|
||||
MESSAGE("The opposing Wobbuffet cannot use Extreme Speed!");
|
||||
MESSAGE("Wobbuffet is protected by the Psychic Terrain!");
|
||||
MESSAGE("Wobbuffet used Max Mindstorm!");
|
||||
}
|
||||
}
|
||||
@ -1648,18 +1648,5 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamax is reverted before switch out")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dynamax: Destiny Bond fails if a dynamaxed battler is present on field")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_DESTINY_BOND); MOVE(player, MOVE_SCRATCH, gimmick: GIMMICK_DYNAMAX); }
|
||||
} SCENE {
|
||||
MESSAGE("The move was blocked by the power of Dynamax!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-lowering Max Moves, without showing a message")
|
||||
TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-increasing Max Moves, without showing a message")
|
||||
|
||||
@ -588,7 +588,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain")
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ZMOVE_ACTIVATE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GENESIS_SUPERNOVA, player);
|
||||
NOT { ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player); }
|
||||
MESSAGE("Mew cannot use Quick Attack!");
|
||||
MESSAGE("The opposing Wobbuffet is protected by the Psychic Terrain!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,35 @@ SINGLE_BATTLE_TEST("Aurora Veil can only be used in Hail and Snow")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aurora Veil will prevent Protean activation if it fails due to no Snow/Hail")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_AURORA_VEIL); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
NOT ABILITY_POPUP(player, ABILITY_PROTEAN);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aurora Veil wont prevent Protean activation when it fails due to being set up already")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_AURORA_VEIL); }
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN { MOVE(player, MOVE_AURORA_VEIL); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_PROTEAN);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Aurora Veil reduces damage done to the user by half in singles")
|
||||
TO_DO_BATTLE_TEST("Aurora Veil reduces damage done to the user by roughly a third in doubles")
|
||||
TO_DO_BATTLE_TEST("Aurora Veil's damage reduction is ignored by Critical Hits")
|
||||
|
||||
@ -1,11 +1,52 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Attack by 1 stage");
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Defense by 1 stage");
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Sp. Attack by 1 stage");
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Sp. Defense by 1 stage");
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Speed by 1 stage");
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul cuts the user's HP by 1/3");
|
||||
SINGLE_BATTLE_TEST("Clangorous Soul cuts the user's HP by 1/3")
|
||||
{
|
||||
s16 dmg;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); };
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CLANGOROUS_SOUL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CLANGOROUS_SOUL, player);
|
||||
HP_BAR(player, captureDamage: &dmg);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(gBattleMons[0].maxHP / 3, dmg);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Clangorous Soul raises the user's Atk, Def, Sp. Atk. Sp. Def and Speed by 1 stage")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); };
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CLANGOROUS_SOUL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CLANGOROUS_SOUL, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Clangorous Soul fails if the user's HP is less or equal than 1/3")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(100); MaxHP(300); };
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CLANGOROUS_SOUL); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CLANGOROUS_SOUL, player);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul fails if Attack, Defense, Sp. Attack, Sp. Defense and Speed are all maxed out");
|
||||
TO_DO_BATTLE_TEST("Clangorous Soul fails if the user's HP is less or equal than 1/3");
|
||||
|
||||
@ -42,7 +42,6 @@ TO_DO_BATTLE_TEST("Burn Up doesn't thaw the user if it fails due to the user not
|
||||
|
||||
SINGLE_BATTLE_TEST("Burn Up fails if the user has Protean/Libero and is not a Fire-type")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_6);
|
||||
PLAYER(SPECIES_REGIROCK);
|
||||
|
||||
@ -2,3 +2,60 @@
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write No Retreat (Move Effect) test titles")
|
||||
|
||||
SINGLE_BATTLE_TEST("No Retreat raises user's Atk/Def/Sp.Atk/Sp.Def/Speed unless No Retreat was already used by user")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_NO_RETREAT); }
|
||||
TURN { MOVE(player, MOVE_NO_RETREAT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
|
||||
bool32 escapePrevention = gBattleMons[0].volatiles.escapePrevention;
|
||||
EXPECT_EQ(escapePrevention, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Question: If No Retreat is used is the mon blocking the switch out changed?
|
||||
SINGLE_BATTLE_TEST("No Retreat won't fail if user is prevented from escaping")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_MEAN_LOOK); MOVE(player, MOVE_NO_RETREAT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MEAN_LOOK, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("No Retreat won't activate Protean if it fails due to already being used by the user")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_NO_RETREAT); MOVE(opponent, MOVE_SKILL_SWAP); }
|
||||
TURN { MOVE(player, MOVE_NO_RETREAT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player);
|
||||
ABILITY_POPUP(player, ABILITY_PROTEAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority mov
|
||||
TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_QUICK_ATTACK); }
|
||||
} SCENE {
|
||||
MESSAGE("Claydol used Psychic Terrain!");
|
||||
MESSAGE("Claydol cannot use Quick Attack!");
|
||||
MESSAGE("The opposing Wobbuffet is protected by the Psychic Terrain!");
|
||||
NOT { HP_BAR(opponent); }
|
||||
MESSAGE("The opposing Wobbuffet used Quick Attack!");
|
||||
HP_BAR(player);
|
||||
@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain increases power of Psychic-type moves by 30/
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the user")
|
||||
SINGLE_BATTLE_TEST("Psychic Terrain doesn't blocks priority moves that target the user")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); HP(1); }
|
||||
@ -142,3 +142,37 @@ SINGLE_BATTLE_TEST("Psychic Terrain lasts for 5 turns")
|
||||
MESSAGE("The weirdness disappeared from the battlefield!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority moves in doubles - Left")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CLAYDOL) { Ability(ABILITY_LEVITATE); }
|
||||
PLAYER(SPECIES_TAPU_LELE) { Ability(ABILITY_PSYCHIC_SURGE); }
|
||||
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_COTTON_SPORE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerRight, ABILITY_PSYCHIC_SURGE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_COTTON_SPORE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority moves in doubles - Right")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TAPU_LELE) { Ability(ABILITY_PSYCHIC_SURGE); }
|
||||
PLAYER(SPECIES_CLAYDOL) { Ability(ABILITY_LEVITATE); }
|
||||
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_COTTON_SPORE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_PSYCHIC_SURGE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_COTTON_SPORE, opponentLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Stockpile's count can go up only to 3")
|
||||
MESSAGE("Wobbuffet stockpiled 3!");
|
||||
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player);
|
||||
MESSAGE("Wobbuffet can't stockpile any more!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,9 +49,9 @@ SINGLE_BATTLE_TEST("Spit Up and Swallow don't work if used without Stockpile")
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
if (move == MOVE_SWALLOW)
|
||||
MESSAGE("But it failed to swallow a thing!");
|
||||
MESSAGE("But it failed!");
|
||||
else
|
||||
MESSAGE("But it failed to spit up a thing!");
|
||||
MESSAGE("But it failed!");
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player);
|
||||
MESSAGE("Wobbuffet stockpiled 1!");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user